From: Michael Meskes <Michael_Meskes@topmail.de>

+
+ Son Feb 21 14:10:47 CET 1999
+
+       - Fixed variable detection in libecpg.
+
+ Mon Feb 22 19:47:45 CET 1999
+
+       - Added 'at <db_connection>' option to all commands it is apllicable
+         to. Due to changing the API of some libecpg functions this
+         requires me to increase the major version number.
+       - Synced pgc.l with scan.l.
+       - Added support for unions.
+       - Set library version to 3.0.0
+       - Set ecpg version to 3.0.0
This commit is contained in:
Marc G. Fournier 1999-02-23 12:57:03 +00:00
parent e17d8448f2
commit fa9db42a6e
18 changed files with 240 additions and 98 deletions

View File

@ -463,3 +463,17 @@ Fri Feb 19 21:40:14 CET 1999
- Fixed bug in libecpg that caused it to start transactions only for
the first connection.
- Set library version to 2.7.1
Son Feb 21 14:10:47 CET 1999
- Fixed variable detection in libecpg.
Mon Feb 22 19:47:45 CET 1999
- Added 'at <db_connection>' option to all commands it is apllicable
to. Due to changing the API of some libecpg functions this
requires me to increase the major version number.
- Synced pgc.l with scan.l.
- Added support for unions.
- Set library version to 3.0.0
- Set ecpg version to 3.0.0

View File

@ -11,9 +11,9 @@ DESCRIPTOR statement will be ignored.
it would be nice to be able to use :var[:index] as cvariable
'at DB connection' is missing for several commands (is this standard?)
support for dynamic SQL with unknown number of variables with SQLDA structure
support for unions
allocate memory for pointers as C input variables
Missing statements:
- exec sql allocate

View File

@ -8,8 +8,8 @@ extern "C"
void ECPGdebug(int, FILE *);
bool ECPGsetconn(int, const char *);
bool ECPGconnect(int, const char *, const char *, const char *, const char *);
bool ECPGdo(int, char *,...);
bool ECPGtrans(int, const char *);
bool ECPGdo(int, const char *, char *,...);
bool ECPGtrans(int, const char *, const char *);
bool ECPGdisconnect(int, const char *);
bool ECPGprepare(int, char *, char *);
bool ECPGdeallocate(int, char *);

View File

@ -43,10 +43,10 @@ extern "C"
ECPGt_varchar, ECPGt_varchar2,
ECPGt_array,
ECPGt_struct,
ECPGt_char_variable,
ECPGt_EOIT, /* End of insert types. */
ECPGt_EORT, /* End of result types. */
ECPGt_NO_INDICATOR, /* no indicator */
ECPGt_char_variable
ECPGt_NO_INDICATOR /* no indicator */
};
#define IS_SIMPLE_TYPE(type) ((type) >= ECPGt_char && (type) <= ECPGt_varchar2)

View File

@ -6,13 +6,13 @@
# Copyright (c) 1994, Regents of the University of California
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.42 1999/02/21 03:02:35 scrappy Exp $
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.43 1999/02/23 12:56:55 scrappy Exp $
#
#-------------------------------------------------------------------------
NAME= ecpg
SO_MAJOR_VERSION= 2
SO_MINOR_VERSION= 7.1
SO_MAJOR_VERSION= 3
SO_MINOR_VERSION= 0.0
SRCDIR= @top_srcdir@
include $(SRCDIR)/Makefile.global

View File

@ -17,6 +17,7 @@
#include <unistd.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <libpq-fe.h>
#include <libpq/pqcomm.h>
@ -78,6 +79,7 @@ struct statement
{
int lineno;
char *command;
struct connection *connection;
struct variable *inlist;
struct variable *outlist;
};
@ -104,6 +106,21 @@ register_error(long code, char *fmt,...)
sqlca.sqlerrm.sqlerrml = strlen(sqlca.sqlerrm.sqlerrmc);
}
static struct connection *
get_connection(const char *connection_name)
{
struct connection *con = all_connections;;
if (connection_name == NULL || strcmp(connection_name, "CURRENT") == 0)
return actual_connection;
for (; con && strcmp(connection_name, con->name) != 0; con = con->next);
if (con)
return con;
else
return NULL;
}
static void
ECPGfinish(struct connection * act)
{
@ -145,7 +162,6 @@ ecpg_alloc(long size, int lineno)
if (!new)
{
ECPGfinish(actual_connection);
ECPGlog("out of memory\n");
register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
return NULL;
@ -162,7 +178,6 @@ ecpg_strdup(const char *string, int lineno)
if (!new)
{
ECPGfinish(actual_connection);
ECPGlog("out of memory\n");
register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
return NULL;
@ -238,9 +253,26 @@ quote_strings(char *arg, int lineno)
return res;
}
/* create a list of variables */
/*
* create a list of variables
* The variables are listed with input variables preceeding outputvariables
* The end of each group is marked by an end marker.
* per variable we list:
* type - as defined in ecpgtype.h
* value - where to store the data
* varcharsize - length of string in case we have a stringvariable, else 0
* arraysize - 0 for pointer (we don't know the size of the array),
* 1 for simple variable, size for arrays
* offset - offset between ith and (i+1)th entry in an array,
* normally that means sizeof(type)
* ind_type - type of indicator variable
* ind_value - pointer to indicator variable
* ind_varcharsize - empty
* ind_arraysize - arraysize of indicator array
* ind_offset - indicator offset
*/
static bool
create_statement(int lineno, struct statement ** stmt, char *query, va_list ap)
create_statement(int lineno, struct connection *connection, struct statement ** stmt, char *query, va_list ap)
{
struct variable **list = &((*stmt)->inlist);
enum ECPGttype type;
@ -249,6 +281,7 @@ create_statement(int lineno, struct statement ** stmt, char *query, va_list ap)
return false;
(*stmt)->command = query;
(*stmt)->connection = connection;
(*stmt)->lineno = lineno;
list = &((*stmt)->inlist);
@ -278,7 +311,8 @@ create_statement(int lineno, struct statement ** stmt, char *query, va_list ap)
var->ind_arrsize = va_arg(ap, long);
var->ind_offset = va_arg(ap, long);
var->next = NULL;
/* if variable is NULL, the statement hasn't been prepared */
if (var->value == NULL)
{
ECPGlog("create_statement: invalid statement name\n");
@ -564,27 +598,27 @@ ECPGexecute(struct statement * stmt)
/* Now the request is built. */
if (actual_connection->committed && !no_auto_trans)
if (stmt->connection->committed && !no_auto_trans)
{
if ((results = PQexec(actual_connection->connection, "begin transaction")) == NULL)
if ((results = PQexec(stmt->connection->connection, "begin transaction")) == NULL)
{
register_error(ECPG_TRANS, "Error starting transaction line %d.", stmt->lineno);
return false;
}
PQclear(results);
actual_connection->committed = false;
stmt->connection->committed = false;
}
ECPGlog("ECPGexecute line %d: QUERY: %s\n", stmt->lineno, copiedquery);
results = PQexec(actual_connection->connection, copiedquery);
ECPGlog("ECPGexecute line %d: QUERY: %s on connection %s\n", stmt->lineno, copiedquery, stmt->connection->name);
results = PQexec(stmt->connection->connection, copiedquery);
free(copiedquery);
if (results == NULL)
{
ECPGlog("ECPGexecute line %d: error: %s", stmt->lineno,
PQerrorMessage(actual_connection->connection));
PQerrorMessage(stmt->connection->connection));
register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
PQerrorMessage(actual_connection->connection), stmt->lineno);
PQerrorMessage(stmt->connection->connection), stmt->lineno);
}
else
{
@ -642,6 +676,7 @@ ECPGexecute(struct statement * stmt)
status = false;
break;
}
for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
{
pval = PQgetvalue(results, act_tuple, act_field);
@ -909,18 +944,18 @@ ECPGexecute(struct statement * stmt)
case PGRES_FATAL_ERROR:
case PGRES_BAD_RESPONSE:
ECPGlog("ECPGexecute line %d: Error: %s",
stmt->lineno, PQerrorMessage(actual_connection->connection));
stmt->lineno, PQerrorMessage(stmt->connection->connection));
register_error(ECPG_PGSQL, "Error: %s line %d.",
PQerrorMessage(actual_connection->connection), stmt->lineno);
PQerrorMessage(stmt->connection->connection), stmt->lineno);
status = false;
break;
case PGRES_COPY_OUT:
ECPGlog("ECPGexecute line %d: Got PGRES_COPY_OUT ... tossing.\n", stmt->lineno);
PQendcopy(actual_connection->connection);
PQendcopy(stmt->connection->connection);
break;
case PGRES_COPY_IN:
ECPGlog("ECPGexecute line %d: Got PGRES_COPY_IN ... tossing.\n", stmt->lineno);
PQendcopy(actual_connection->connection);
PQendcopy(stmt->connection->connection);
break;
default:
ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n",
@ -932,7 +967,7 @@ ECPGexecute(struct statement * stmt)
}
/* check for asynchronous returns */
notify = PQnotifies(actual_connection->connection);
notify = PQnotifies(stmt->connection->connection);
if (notify)
{
ECPGlog("ECPGexecute line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
@ -944,20 +979,27 @@ ECPGexecute(struct statement * stmt)
}
bool
ECPGdo(int lineno, char *query,...)
ECPGdo(int lineno, const char *connection_name, char *query,...)
{
va_list args;
struct statement *stmt;
struct connection *con = get_connection(connection_name);
if (con == NULL)
{
register_error(ECPG_NO_CONN, "No such connection %s in line %d", connection_name, lineno);
return (false);
}
va_start(args, query);
if (create_statement(lineno, &stmt, query, args) == false)
if (create_statement(lineno, con, &stmt, query, args) == false)
return (false);
va_end(args);
/* are we connected? */
if (actual_connection == NULL || actual_connection->connection == NULL)
if (con == NULL || con->connection == NULL)
{
ECPGlog("ECPGdo: not connected\n");
ECPGlog("ECPGdo: not connected to %s\n", con->name);
register_error(ECPG_NOT_CONN, "Not connected in line %d", lineno);
return false;
}
@ -967,16 +1009,23 @@ ECPGdo(int lineno, char *query,...)
bool
ECPGtrans(int lineno, const char *transaction)
ECPGtrans(int lineno, const char *connection_name, const char *transaction)
{
PGresult *res;
struct connection *con = get_connection(connection_name);
if (con == NULL)
{
register_error(ECPG_NO_CONN, "No such connection %s in line %d", connection_name, lineno);
return (false);
}
ECPGlog("ECPGtrans line %d action = %s\n", lineno, transaction);
ECPGlog("ECPGtrans line %d action = %s connection = %s\n", lineno, transaction, con->name);
/* if we have no connection we just simulate the command */
if (actual_connection && actual_connection->connection)
if (con && con->connection)
{
if ((res = PQexec(actual_connection->connection, transaction)) == NULL)
if ((res = PQexec(con->connection, transaction)) == NULL)
{
register_error(ECPG_TRANS, "Error in transaction processing line %d.", lineno);
return FALSE;
@ -987,7 +1036,7 @@ ECPGtrans(int lineno, const char *transaction)
{
struct prepared_statement *this;
actual_connection->committed = true;
con->committed = true;
/* deallocate all prepared statements */
for (this = prep_stmts; this != NULL; this = this->next)
@ -1005,11 +1054,8 @@ ECPGtrans(int lineno, const char *transaction)
bool
ECPGsetconn(int lineno, const char *connection_name)
{
struct connection *con = all_connections;
struct connection *con = get_connection(connection_name);
ECPGlog("ECPGsetconn: setting actual connection to %s\n", connection_name);
for (; con && strcmp(connection_name, con->name) != 0; con = con->next);
if (con)
{
actual_connection = con;
@ -1070,9 +1116,7 @@ ECPGdisconnect(int lineno, const char *connection_name)
{
struct connection *con;
if (strcmp(connection_name, "CURRENT") == 0)
ECPGfinish(actual_connection);
else if (strcmp(connection_name, "ALL") == 0)
if (strcmp(connection_name, "ALL") == 0)
{
for (con = all_connections; con;)
{
@ -1084,7 +1128,8 @@ ECPGdisconnect(int lineno, const char *connection_name)
}
else
{
for (con = all_connections; con && strcmp(con->name, connection_name) != 0; con = con->next);
con = get_connection(connection_name);
if (con == NULL)
{
ECPGlog("disconnect: not connected to connection %s\n", connection_name);
@ -1136,6 +1181,21 @@ sqlprint(void)
printf("sql error %s\n", sqlca.sqlerrm.sqlerrmc);
}
static bool
isvarchar(unsigned char c)
{
if (isalnum(c))
return true;
if (c == '_' || c == '>' || c == '-' || c == '.')
return true;
if (c >= 128)
return true;
return(false);
}
static void
replace_variables(char *text)
{
@ -1150,7 +1210,7 @@ replace_variables(char *text)
if (!string && *ptr == ':')
{
ptr[0] = ptr[1] = ';';
for (ptr += 2; *ptr && *ptr != ' '; ptr++)
for (ptr += 2; *ptr && isvarchar(*ptr); ptr++)
*ptr = ' ';
}
}
@ -1162,7 +1222,7 @@ ECPGprepare(int lineno, char *name, char *variable)
{
struct statement *stmt;
struct prepared_statement *this;
/* check if we already have prepared this statement */
for (this = prep_stmts; this != NULL && strcmp(this->name, name) != 0; this = this->next);
if (this)
@ -1186,6 +1246,7 @@ ECPGprepare(int lineno, char *name, char *variable)
/* create statement */
stmt->lineno = lineno;
stmt->connection = NULL;
stmt->command = ecpg_strdup(variable, lineno);
stmt->inlist = stmt->outlist = NULL;

View File

@ -1,8 +1,8 @@
SRCDIR= ../../..
include $(SRCDIR)/Makefile.global
MAJOR_VERSION=2
MINOR_VERSION=5
MAJOR_VERSION=3
MINOR_VERSION=0
PATCHLEVEL=0
CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \

View File

@ -36,6 +36,7 @@ static ScanKeyword ScanKeywords[] = {
{"signed", S_SIGNED},
{"static", S_STATIC},
{"struct", S_STRUCT},
{"union", S_UNION},
{"unsigned", S_UNSIGNED},
{"varchar", S_VARCHAR},
};

View File

@ -165,6 +165,7 @@ main(int argc, char *const argv[])
struct arguments *l1, *l2;
free(ptr->command);
free(ptr->connection);
free(ptr->name);
for (l1 = ptr->argsinsert; l1; l1 = l2)
{

View File

@ -20,6 +20,7 @@
*/
static ScanKeyword ScanKeywords[] = {
/* name value */
{"at", SQL_AT},
{"bool", SQL_BOOL},
{"break", SQL_BREAK},
{"call", SQL_CALL},

View File

@ -6,7 +6,7 @@
extern int braces_open,
no_auto_trans, struct_level;
extern char *yytext;
extern char *yytext, errortext[128];
extern int yylineno,
yyleng;
extern FILE *yyin,

View File

@ -105,7 +105,6 @@ xqstart {quote}
xqstop {quote}
xqdouble {quote}{quote}
xqinside [^\\']*
xqembedded "\\'"
xqliteral [\\](.|\n)
xqcat {quote}{space}*\n{space}*{quote}
@ -244,22 +243,9 @@ cppline {space}*#.*(\\{space}*\n)*\n*
return SCONST;
}
<xq>{xqdouble} |
<xq>{xqinside} {
if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
yyerror("ERROR: quoted string parse buffer exceeded");
memcpy(literal+llen, yytext, yyleng+1);
llen += yyleng;
}
<xq>{xqembedded} {
if ((llen+yyleng-1) > (MAX_PARSE_BUFFER - 1))
yyerror("ERROR: quoted string parse buffer exceeded");
memcpy(literal+llen, yytext, yyleng+1);
*(literal+llen) = '\'';
llen += yyleng;
}
<xq>{xqinside} |
<xq>{xqliteral} {
if ((llen+yyleng-1) > (MAX_PARSE_BUFFER - 1))
if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
yyerror("ERROR: quoted string parse buffer exceeded");
memcpy(literal+llen, yytext, yyleng+1);
llen += yyleng;

View File

@ -18,7 +18,8 @@
* Variables containing simple states.
*/
int struct_level = 0;
static char errortext[128];
char errortext[128];
static char *connection = NULL;
static int QueryIsRule = 0, ForUpdateNotAllowed = 0;
static struct this_type actual_type[STRUCT_DEPTH];
static char *actual_storage[STRUCT_DEPTH];
@ -489,7 +490,7 @@ output_statement(char * stmt, int mode)
{
int i, j=strlen(stmt);
fputs("ECPGdo(__LINE__, \"", yyout);
fprintf(yyout, "ECPGdo(__LINE__, %s, \"", connection ? connection : "NULL");
/* do this char by char as we have to filter '\"' */
for (i = 0;i < j; i++)
@ -504,6 +505,8 @@ output_statement(char * stmt, int mode)
fputs("ECPGt_EORT);", yyout);
whenever_action(mode);
free(stmt);
if (connection != NULL)
free(connection);
}
static struct typedefs *
@ -612,7 +615,7 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
}
/* special embedded SQL token */
%token SQL_BOOL SQL_BREAK
%token SQL_AT SQL_BOOL SQL_BREAK
%token SQL_CALL SQL_CONNECT SQL_CONNECTION SQL_CONTINUE
%token SQL_DEALLOCATE SQL_DISCONNECT SQL_ENUM
%token SQL_FOUND SQL_FREE SQL_GO SQL_GOTO
@ -625,8 +628,8 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
/* C token */
%token S_ANYTHING S_AUTO S_BOOL S_CHAR S_CONST S_DOUBLE S_ENUM S_EXTERN
%token S_FLOAT S_INT S
%token S_LONG S_REGISTER S_SHORT S_SIGNED S_STATIC S_STRUCT
%token S_UNSIGNED S_VARCHAR
%token S_LONG S_REGISTER S_SHORT S_SIGNED S_STATIC S_STRUCT
%token S_UNION S_UNSIGNED S_VARCHAR
/* I need this and don't know where it is defined inside the backend */
%token TYPECAST
@ -785,8 +788,9 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
%type <str> ECPGSetConnection c_line cpp_line s_enum ECPGTypedef
%type <str> enum_type civariableonly ECPGCursorStmt ECPGDeallocate
%type <str> ECPGFree ECPGDeclare ECPGVar sql_variable_declarations
%type <str> sql_declaration sql_variable_list sql_variable
%type <str> sql_declaration sql_variable_list sql_variable opt_at
%type <str> struct_type s_struct declaration variable_declarations
%type <str> s_struct_or_union sql_struct_or_union
%type <type_enum> simple_type varchar_type
@ -803,13 +807,16 @@ prog: statements;
statements: /* empty */
| statements statement
statement: ecpgstart stmt SQL_SEMI
statement: ecpgstart opt_at stmt SQL_SEMI { connection = NULL; }
| ecpgstart stmt SQL_SEMI
| ECPGDeclaration
| c_thing { fprintf(yyout, "%s", $1); free($1); }
| cpp_line { fprintf(yyout, "%s", $1); free($1); }
| blockstart { fputs($1, yyout); free($1); }
| blockend { fputs($1, yyout); free($1); }
opt_at: SQL_AT connection_target { connection = $2; }
stmt: AddAttrStmt { output_statement($1, 0); }
| AlterUserStmt { output_statement($1, 0); }
| ClosePortalStmt { output_statement($1, 0); }
@ -853,7 +860,7 @@ stmt: AddAttrStmt { output_statement($1, 0); }
}
| RuleStmt { output_statement($1, 0); }
| TransactionStmt {
fprintf(yyout, "ECPGtrans(__LINE__, \"%s\");", $1);
fprintf(yyout, "ECPGtrans(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1);
whenever_action(0);
free($1);
}
@ -866,6 +873,9 @@ stmt: AddAttrStmt { output_statement($1, 0); }
| VariableShowStmt { output_statement($1, 0); }
| VariableResetStmt { output_statement($1, 0); }
| ECPGConnect {
if (connection)
yyerror("no at option for connect statement.\n");
fprintf(yyout, "no_auto_trans = %d;\n", no_auto_trans);
fprintf(yyout, "ECPGconnect(__LINE__, %s);", $1);
whenever_action(0);
@ -876,6 +886,9 @@ stmt: AddAttrStmt { output_statement($1, 0); }
free($1);
}
| ECPGDeallocate {
if (connection)
yyerror("no at option for connect statement.\n");
fputs($1, yyout);
whenever_action(0);
free($1);
@ -885,6 +898,9 @@ stmt: AddAttrStmt { output_statement($1, 0); }
free($1);
}
| ECPGDisconnect {
if (connection)
yyerror("no at option for disconnect statement.\n");
fprintf(yyout, "ECPGdisconnect(__LINE__, \"%s\");", $1);
whenever_action(0);
free($1);
@ -893,7 +909,7 @@ stmt: AddAttrStmt { output_statement($1, 0); }
output_statement($1, 0);
}
| ECPGFree {
fprintf(yyout, "ECPGdeallocate(__LINE__, \"%s\");", $1);
fprintf(yyout, "ECPGdeallocate(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1);
whenever_action(0);
free($1);
}
@ -912,7 +928,7 @@ stmt: AddAttrStmt { output_statement($1, 0); }
yyerror(errortext);
}
fprintf(yyout, "ECPGdo(__LINE__, \"%s\",", ptr->command);
fprintf(yyout, "ECPGdo(__LINE__, %s, \"%s\",", ptr->connection ? ptr->connection : "NULL", ptr->command);
/* dump variables to C file*/
dump_variables(ptr->argsinsert, 0);
dump_variables(argsinsert, 0);
@ -923,25 +939,40 @@ stmt: AddAttrStmt { output_statement($1, 0); }
free($1);
}
| ECPGPrepare {
if (connection)
yyerror("no at option for set connection statement.\n");
fprintf(yyout, "ECPGprepare(__LINE__, %s);", $1);
whenever_action(0);
free($1);
}
| ECPGRelease { /* output already done */ }
| ECPGSetConnection {
if (connection)
yyerror("no at option for set connection statement.\n");
fprintf(yyout, "ECPGsetconn(__LINE__, %s);", $1);
whenever_action(0);
free($1);
}
| ECPGTypedef {
if (connection)
yyerror("no at option for typedef statement.\n");
fputs($1, yyout);
free($1);
}
| ECPGVar {
if (connection)
yyerror("no at option for var statement.\n");
fputs($1, yyout);
free($1);
}
| ECPGWhenever {
if (connection)
yyerror("no at option for whenever statement.\n");
fputs($1, yyout);
output_line_number();
free($1);
@ -2727,6 +2758,7 @@ CursorStmt: DECLARE name opt_cursor CURSOR FOR SelectStmt cursor_clause
/* initial definition */
this->next = cur;
this->name = $2;
this->connection = connection;
this->command = cat2_str(cat5_str(make1_str("declare"), mm_strdup($2), $3, make1_str("cursor for"), $6), $7);
this->argsinsert = argsinsert;
this->argsresult = argsresult;
@ -3103,6 +3135,7 @@ Generic: generic
generic: ident { $$ = $1; }
| TYPE_P { $$ = make1_str("type"); }
| SQL_AT { $$ = make1_str("at"); }
| SQL_BOOL { $$ = make1_str("bool"); }
| SQL_BREAK { $$ = make1_str("break"); }
| SQL_CALL { $$ = make1_str("call"); }
@ -4306,6 +4339,7 @@ ColId: ident { $$ = $1; }
| VALID { $$ = make1_str("valid"); }
| VERSION { $$ = make1_str("version"); }
| ZONE { $$ = make1_str("zone"); }
| SQL_AT { $$ = make1_str("at"); }
| SQL_BOOL { $$ = make1_str("bool"); }
| SQL_BREAK { $$ = make1_str("break"); }
| SQL_CALL { $$ = make1_str("call"); }
@ -4602,6 +4636,7 @@ ECPGCursorStmt: DECLARE name opt_cursor CURSOR FOR ident cursor_clause
/* initial definition */
this->next = cur;
this->name = $2;
this->connection = connection;
this->command = cat5_str(make1_str("declare"), mm_strdup($2), $3, make1_str("cursor for ;;"), $7);
this->argsresult = NULL;
@ -4731,14 +4766,17 @@ struct_type: s_struct '{' variable_declarations '}'
$$ = cat4_str($1, make1_str("{"), $3, make1_str("}"));
}
s_struct : S_STRUCT opt_symbol
s_struct : s_struct_or_union opt_symbol
{
struct_member_list[struct_level++] = NULL;
if (struct_level >= STRUCT_DEPTH)
yyerror("Too many levels in nested structure definition");
$$ = cat2_str(make1_str("struct"), $2);
$$ = cat2_str($1, $2);
}
s_struct_or_union: S_STRUCT { $$ = make1_str("struct"); }
| S_UNION { $$ = make1_str("union"); }
opt_symbol: /* empty */ { $$ = make1_str(""); }
| symbol { $$ = $1; }
@ -4940,7 +4978,7 @@ ECPGRelease: TransactionStmt SQL_RELEASE
if (strncmp($1, "begin", 5) == 0)
yyerror("RELEASE does not make sense when beginning a transaction");
fprintf(yyout, "ECPGtrans(__LINE__, \"%s\");", $1);
fprintf(yyout, "ECPGtrans(__LINE__, %s, \"%s\");", connection, $1);
whenever_action(0);
fprintf(yyout, "ECPGdisconnect(\"\");");
whenever_action(0);
@ -5151,7 +5189,7 @@ ctype: CHAR
$$.type_index = -1;
$$.type_dimension = -1;
}
| SQL_STRUCT
| sql_struct_or_union
{
struct_member_list[struct_level++] = NULL;
if (struct_level >= STRUCT_DEPTH)
@ -5159,7 +5197,7 @@ ctype: CHAR
} '{' sql_variable_declarations '}'
{
ECPGfree_struct_member(struct_member_list[struct_level--]);
$$.type_str = cat3_str(make1_str("struct {"), $4, make1_str("}"));
$$.type_str = cat4_str($1, make1_str("{"), $4, make1_str("}"));
$$.type_enum = ECPGt_struct;
$$.type_index = -1;
$$.type_dimension = -1;
@ -5175,6 +5213,9 @@ ctype: CHAR
struct_member_list[struct_level] = this->struct_member_list;
}
sql_struct_or_union: SQL_STRUCT { $$ = make1_str("struct"); }
| UNION { $$ = make1_str("union"); }
opt_signed: SQL_SIGNED | /* empty */
sql_variable_declarations: /* empty */
@ -5735,6 +5776,7 @@ c_anything: IDENT { $$ = $1; }
| S_SIGNED { $$ = make1_str("signed"); }
| S_STATIC { $$ = make1_str("static"); }
| S_STRUCT { $$ = make1_str("struct"); }
| S_UNION { $$ = make1_str("union"); }
| S_UNSIGNED { $$ = make1_str("unsigned"); }
| S_VARCHAR { $$ = make1_str("varchar"); }
| S_ANYTHING { $$ = make_name(); }

View File

@ -164,7 +164,8 @@ get_type(enum ECPGttype typ)
return ("ECPGt_char_variable");
break;
default:
abort();
sprintf(errortext, "illegal variable type %d\n", typ);
yyerror(errortext);
}
}
@ -357,7 +358,8 @@ ECPGfree_type(struct ECPGtype * typ)
if (IS_SIMPLE_TYPE(typ->u.element->typ))
free(typ->u.element);
else if (typ->u.element->typ == ECPGt_array)
abort(); /* Array of array, */
/* Array of array, */
yyerror("internal error, found multi-dimensional array\n");
else if (typ->u.element->typ == ECPGt_struct)
{
/* Array of structs. */
@ -365,7 +367,10 @@ ECPGfree_type(struct ECPGtype * typ)
free(typ->u.members);
}
else
abort();
{
sprintf(errortext, "illegal variable type %d\n", typ);
yyerror(errortext);
}
}
else if (typ->typ == ECPGt_struct)
{
@ -373,7 +378,10 @@ ECPGfree_type(struct ECPGtype * typ)
free(typ->u.members);
}
else
abort();
{
sprintf(errortext, "illegal variable type %d\n", typ);
yyerror(errortext);
}
}
free(typ);
}

View File

@ -101,6 +101,7 @@ struct cursor
{
char *name;
char *command;
char *connection;
struct arguments *argsinsert;
struct arguments *argsresult;
struct cursor *next;

View File

@ -15,4 +15,4 @@ perftest.c:perftest.pgc
/usr/local/pgsql/bin/ecpg $?
clean:
/bin/rm test1 test2 perftest *.c log
-/bin/rm test1 test2 perftest *.c log

View File

@ -4,7 +4,7 @@ exec sql whenever sqlerror sqlprint;
exec sql include sqlca;
exec sql define AMOUNT 8;
exec sql define AMOUNT 4;
exec sql type intarray is int[AMOUNT];
exec sql type string is char(6);
@ -30,21 +30,31 @@ exec sql end declare section;
ECPGdebug(1, dbgs);
strcpy(msg, "connect");
exec sql connect to mm;
exec sql connect to mm as main;
strcpy(msg, "connect");
exec sql connect to pm;
strcpy(msg, "create");
exec sql at main create table test(name char(6), amount int, letter char(1));
exec sql create table test(name char(6), amount int, letter char(1));
strcpy(msg, "commit");
exec sql at main commit;
exec sql commit;
strcpy(msg, "set connection");
exec sql set connection main;
strcpy(msg, "execute insert 1");
sprintf(command, "insert into test(name, amount, letter) values ('foobar', 1, 'f')");
sprintf(command, "insert into test(name, amount, letter) values ('db: mm', 1, 'f')");
exec sql execute immediate :command;
sprintf(command, "insert into test(name, amount, letter) values ('db: mm', 2, 't')");
exec sql execute immediate :command;
strcpy(msg, "execute insert 2");
sprintf(command, "insert into test(name, amount, letter) select name, amount+1, letter from test");
exec sql execute immediate :command;
sprintf(command, "insert into test(name, amount, letter) values ('db: pm', 1, 'f')");
exec sql at pm execute immediate :command;
strcpy(msg, "execute insert 3");
sprintf(command, "insert into test(name, amount, letter) select name, amount+10, letter from test");
@ -55,27 +65,35 @@ exec sql end declare section;
strcpy(msg, "execute insert 4");
sprintf(command, "insert into test(name, amount, letter) select name, amount+;;, letter from test");
exec sql prepare I from :command;
exec sql execute I using :increment;
exec sql at pm execute I using :increment;
printf("Inserted %d tuples via prepared execute\n", sqlca.sqlerrd[2]);
strcpy(msg, "commit");
exec sql commit;
exec sql at pm commit;
strcpy(msg, "select");
exec sql select name, amount, letter into :name, :amount, :letter from test;
for (i=0, j=sqlca.sqlerrd[2]; i<j; i++)
printf("name[%d]=%6.6s\tamount[%d]=%d\tletter[%d]=%c\n", i, name[i], i, amount[i],i, letter[i][0]);
exec sql at pm select name, amount, letter into :name, :amount, :letter from test;
for (i=0, j=sqlca.sqlerrd[2]; i<j; i++)
printf("name[%d]=%6.6s\tamount[%d]=%d\tletter[%d]=%c\n", i, name[i], i, amount[i],i, letter[i][0]);
strcpy(msg, "drop");
exec sql drop table test;
exec sql at pm drop table test;
strcpy(msg, "commit");
exec sql commit;
exec sql at pm commit;
strcpy(msg, "disconnect");
exec sql disconnect;
exec sql disconnect all;
if (dbgs != NULL)
fclose(dbgs);

View File

@ -5,6 +5,9 @@ exec sql include header_test;
exec sql type c is char reference;
typedef char* c;
exec sql type ind is union { int integer; short smallinteger; };
typedef union { int integer; short smallinteger; } ind;
int
main ()
{
@ -18,15 +21,17 @@ exec sql begin declare section;
birthinfo ind_birth;
} ind_personal;
int ind_married;
ind children;
ind ind_children;
char married[9];
c testname="Petra";
char *query="select name, born, age, married from meskes where name = :var1";
char *query="select name, born, age, married, children from meskes where name = :var1";
exec sql end declare section;
exec sql var ind_married is long;
exec sql declare cur cursor for
select name, born, age, married from meskes;
select name, born, age, married, children from meskes;
char msg[128], command[128];
FILE *dbgs;
@ -38,11 +43,11 @@ exec sql end declare section;
exec sql connect to unix:postgresql://localhost:5432/mm;
strcpy(msg, "create");
exec sql create table meskes(name char(8), born integer, age smallint, married char(8));
exec sql create table meskes(name char(8), born integer, age smallint, married char(8), children integer);
strcpy(msg, "insert");
exec sql insert into meskes(name, married) values ('Petra', '19900404');
exec sql insert into meskes(name, born, age, married) values ('Michael', 19660117, 33, '19900404');
exec sql insert into meskes(name, married, children) values ('Petra', '19900404', 3);
exec sql insert into meskes(name, born, age, married, children) values ('Michael', 19660117, 33, '19900404', 3);
exec sql insert into meskes(name, born, age) values ('Carsten', 19910103, 8);
exec sql insert into meskes(name, born, age) values ('Marc', 19930907, 5);
exec sql insert into meskes(name, born, age) values ('Chris', 19970923, 1);
@ -57,7 +62,7 @@ exec sql end declare section;
while (1) {
strcpy(msg, "fetch");
exec sql fetch in cur into :personal:ind_personal, :married:ind_married;
exec sql fetch in cur into :personal:ind_personal, :married:ind_married, :children.integer:ind_children.smallinteger;
printf("%8.8s", personal.name.arr);
if (!ind_personal.ind_birth.born)
printf(", born %d", personal.birth.born);
@ -65,6 +70,8 @@ exec sql end declare section;
printf(", age = %d", personal.birth.age);
if (!ind_married)
printf(", married %s", married);
if (!ind_children.smallinteger)
printf(", children = %d", children.integer);
putchar('\n');
}
@ -82,7 +89,7 @@ exec sql end declare section;
while (1) {
strcpy(msg, "fetch");
exec sql fetch in prep into :personal:ind_personal, :married:ind_married;
exec sql fetch in prep into :personal:ind_personal, :married:ind_married, :children.integer:ind_children.smallinteger;
printf("%8.8s", personal.name.arr);
if (!ind_personal.ind_birth.born)
printf(", born %d", personal.birth.born);
@ -90,6 +97,8 @@ exec sql end declare section;
printf(", age = %d", personal.birth.age);
if (!ind_married)
printf(", married %s", married);
if (!ind_children.smallinteger)
printf(", children = %d", children.integer);
putchar('\n');
}