Commit fa9db42a authored by Marc G. Fournier's avatar Marc G. Fournier

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
parent e17d8448
...@@ -463,3 +463,17 @@ Fri Feb 19 21:40:14 CET 1999 ...@@ -463,3 +463,17 @@ Fri Feb 19 21:40:14 CET 1999
- Fixed bug in libecpg that caused it to start transactions only for - Fixed bug in libecpg that caused it to start transactions only for
the first connection. the first connection.
- Set library version to 2.7.1 - 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
...@@ -11,9 +11,9 @@ DESCRIPTOR statement will be ignored. ...@@ -11,9 +11,9 @@ DESCRIPTOR statement will be ignored.
it would be nice to be able to use :var[:index] as cvariable 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: Missing statements:
- exec sql allocate - exec sql allocate
......
...@@ -8,8 +8,8 @@ extern "C" ...@@ -8,8 +8,8 @@ extern "C"
void ECPGdebug(int, FILE *); void ECPGdebug(int, FILE *);
bool ECPGsetconn(int, const char *); bool ECPGsetconn(int, const char *);
bool ECPGconnect(int, const char *, const char *, const char *, const char *); bool ECPGconnect(int, const char *, const char *, const char *, const char *);
bool ECPGdo(int, char *,...); bool ECPGdo(int, const char *, char *,...);
bool ECPGtrans(int, const char *); bool ECPGtrans(int, const char *, const char *);
bool ECPGdisconnect(int, const char *); bool ECPGdisconnect(int, const char *);
bool ECPGprepare(int, char *, char *); bool ECPGprepare(int, char *, char *);
bool ECPGdeallocate(int, char *); bool ECPGdeallocate(int, char *);
......
...@@ -43,10 +43,10 @@ extern "C" ...@@ -43,10 +43,10 @@ extern "C"
ECPGt_varchar, ECPGt_varchar2, ECPGt_varchar, ECPGt_varchar2,
ECPGt_array, ECPGt_array,
ECPGt_struct, ECPGt_struct,
ECPGt_char_variable,
ECPGt_EOIT, /* End of insert types. */ ECPGt_EOIT, /* End of insert types. */
ECPGt_EORT, /* End of result types. */ ECPGt_EORT, /* End of result types. */
ECPGt_NO_INDICATOR, /* no indicator */ ECPGt_NO_INDICATOR /* no indicator */
ECPGt_char_variable
}; };
#define IS_SIMPLE_TYPE(type) ((type) >= ECPGt_char && (type) <= ECPGt_varchar2) #define IS_SIMPLE_TYPE(type) ((type) >= ECPGt_char && (type) <= ECPGt_varchar2)
......
...@@ -6,13 +6,13 @@ ...@@ -6,13 +6,13 @@
# Copyright (c) 1994, Regents of the University of California # Copyright (c) 1994, Regents of the University of California
# #
# IDENTIFICATION # 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 NAME= ecpg
SO_MAJOR_VERSION= 2 SO_MAJOR_VERSION= 3
SO_MINOR_VERSION= 7.1 SO_MINOR_VERSION= 0.0
SRCDIR= @top_srcdir@ SRCDIR= @top_srcdir@
include $(SRCDIR)/Makefile.global include $(SRCDIR)/Makefile.global
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <unistd.h> #include <unistd.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <ctype.h>
#include <libpq-fe.h> #include <libpq-fe.h>
#include <libpq/pqcomm.h> #include <libpq/pqcomm.h>
...@@ -78,6 +79,7 @@ struct statement ...@@ -78,6 +79,7 @@ struct statement
{ {
int lineno; int lineno;
char *command; char *command;
struct connection *connection;
struct variable *inlist; struct variable *inlist;
struct variable *outlist; struct variable *outlist;
}; };
...@@ -104,6 +106,21 @@ register_error(long code, char *fmt,...) ...@@ -104,6 +106,21 @@ register_error(long code, char *fmt,...)
sqlca.sqlerrm.sqlerrml = strlen(sqlca.sqlerrm.sqlerrmc); 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 static void
ECPGfinish(struct connection * act) ECPGfinish(struct connection * act)
{ {
...@@ -145,7 +162,6 @@ ecpg_alloc(long size, int lineno) ...@@ -145,7 +162,6 @@ ecpg_alloc(long size, int lineno)
if (!new) if (!new)
{ {
ECPGfinish(actual_connection);
ECPGlog("out of memory\n"); ECPGlog("out of memory\n");
register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno); register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
return NULL; return NULL;
...@@ -162,7 +178,6 @@ ecpg_strdup(const char *string, int lineno) ...@@ -162,7 +178,6 @@ ecpg_strdup(const char *string, int lineno)
if (!new) if (!new)
{ {
ECPGfinish(actual_connection);
ECPGlog("out of memory\n"); ECPGlog("out of memory\n");
register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno); register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
return NULL; return NULL;
...@@ -238,9 +253,26 @@ quote_strings(char *arg, int lineno) ...@@ -238,9 +253,26 @@ quote_strings(char *arg, int lineno)
return res; 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 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); struct variable **list = &((*stmt)->inlist);
enum ECPGttype type; enum ECPGttype type;
...@@ -249,6 +281,7 @@ create_statement(int lineno, struct statement ** stmt, char *query, va_list ap) ...@@ -249,6 +281,7 @@ create_statement(int lineno, struct statement ** stmt, char *query, va_list ap)
return false; return false;
(*stmt)->command = query; (*stmt)->command = query;
(*stmt)->connection = connection;
(*stmt)->lineno = lineno; (*stmt)->lineno = lineno;
list = &((*stmt)->inlist); list = &((*stmt)->inlist);
...@@ -279,6 +312,7 @@ create_statement(int lineno, struct statement ** stmt, char *query, va_list ap) ...@@ -279,6 +312,7 @@ create_statement(int lineno, struct statement ** stmt, char *query, va_list ap)
var->ind_offset = va_arg(ap, long); var->ind_offset = va_arg(ap, long);
var->next = NULL; var->next = NULL;
/* if variable is NULL, the statement hasn't been prepared */
if (var->value == NULL) if (var->value == NULL)
{ {
ECPGlog("create_statement: invalid statement name\n"); ECPGlog("create_statement: invalid statement name\n");
...@@ -564,27 +598,27 @@ ECPGexecute(struct statement * stmt) ...@@ -564,27 +598,27 @@ ECPGexecute(struct statement * stmt)
/* Now the request is built. */ /* 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); register_error(ECPG_TRANS, "Error starting transaction line %d.", stmt->lineno);
return false; return false;
} }
PQclear(results); PQclear(results);
actual_connection->committed = false; stmt->connection->committed = false;
} }
ECPGlog("ECPGexecute line %d: QUERY: %s\n", stmt->lineno, copiedquery); ECPGlog("ECPGexecute line %d: QUERY: %s on connection %s\n", stmt->lineno, copiedquery, stmt->connection->name);
results = PQexec(actual_connection->connection, copiedquery); results = PQexec(stmt->connection->connection, copiedquery);
free(copiedquery); free(copiedquery);
if (results == NULL) if (results == NULL)
{ {
ECPGlog("ECPGexecute line %d: error: %s", stmt->lineno, 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.", register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
PQerrorMessage(actual_connection->connection), stmt->lineno); PQerrorMessage(stmt->connection->connection), stmt->lineno);
} }
else else
{ {
...@@ -642,6 +676,7 @@ ECPGexecute(struct statement * stmt) ...@@ -642,6 +676,7 @@ ECPGexecute(struct statement * stmt)
status = false; status = false;
break; break;
} }
for (act_tuple = 0; act_tuple < ntuples; act_tuple++) for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
{ {
pval = PQgetvalue(results, act_tuple, act_field); pval = PQgetvalue(results, act_tuple, act_field);
...@@ -909,18 +944,18 @@ ECPGexecute(struct statement * stmt) ...@@ -909,18 +944,18 @@ ECPGexecute(struct statement * stmt)
case PGRES_FATAL_ERROR: case PGRES_FATAL_ERROR:
case PGRES_BAD_RESPONSE: case PGRES_BAD_RESPONSE:
ECPGlog("ECPGexecute line %d: Error: %s", 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.", register_error(ECPG_PGSQL, "Error: %s line %d.",
PQerrorMessage(actual_connection->connection), stmt->lineno); PQerrorMessage(stmt->connection->connection), stmt->lineno);
status = false; status = false;
break; break;
case PGRES_COPY_OUT: case PGRES_COPY_OUT:
ECPGlog("ECPGexecute line %d: Got PGRES_COPY_OUT ... tossing.\n", stmt->lineno); ECPGlog("ECPGexecute line %d: Got PGRES_COPY_OUT ... tossing.\n", stmt->lineno);
PQendcopy(actual_connection->connection); PQendcopy(stmt->connection->connection);
break; break;
case PGRES_COPY_IN: case PGRES_COPY_IN:
ECPGlog("ECPGexecute line %d: Got PGRES_COPY_IN ... tossing.\n", stmt->lineno); ECPGlog("ECPGexecute line %d: Got PGRES_COPY_IN ... tossing.\n", stmt->lineno);
PQendcopy(actual_connection->connection); PQendcopy(stmt->connection->connection);
break; break;
default: default:
ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n", ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n",
...@@ -932,7 +967,7 @@ ECPGexecute(struct statement * stmt) ...@@ -932,7 +967,7 @@ ECPGexecute(struct statement * stmt)
} }
/* check for asynchronous returns */ /* check for asynchronous returns */
notify = PQnotifies(actual_connection->connection); notify = PQnotifies(stmt->connection->connection);
if (notify) if (notify)
{ {
ECPGlog("ECPGexecute line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n", ECPGlog("ECPGexecute line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
...@@ -944,20 +979,27 @@ ECPGexecute(struct statement * stmt) ...@@ -944,20 +979,27 @@ ECPGexecute(struct statement * stmt)
} }
bool bool
ECPGdo(int lineno, char *query,...) ECPGdo(int lineno, const char *connection_name, char *query,...)
{ {
va_list args; va_list args;
struct statement *stmt; 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); va_start(args, query);
if (create_statement(lineno, &stmt, query, args) == false) if (create_statement(lineno, con, &stmt, query, args) == false)
return (false); return (false);
va_end(args); va_end(args);
/* are we connected? */ /* 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); register_error(ECPG_NOT_CONN, "Not connected in line %d", lineno);
return false; return false;
} }
...@@ -967,16 +1009,23 @@ ECPGdo(int lineno, char *query,...) ...@@ -967,16 +1009,23 @@ ECPGdo(int lineno, char *query,...)
bool bool
ECPGtrans(int lineno, const char *transaction) ECPGtrans(int lineno, const char *connection_name, const char *transaction)
{ {
PGresult *res; PGresult *res;
struct connection *con = get_connection(connection_name);
ECPGlog("ECPGtrans line %d action = %s\n", lineno, transaction); 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 connection = %s\n", lineno, transaction, con->name);
/* if we have no connection we just simulate the command */ /* 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); register_error(ECPG_TRANS, "Error in transaction processing line %d.", lineno);
return FALSE; return FALSE;
...@@ -987,7 +1036,7 @@ ECPGtrans(int lineno, const char *transaction) ...@@ -987,7 +1036,7 @@ ECPGtrans(int lineno, const char *transaction)
{ {
struct prepared_statement *this; struct prepared_statement *this;
actual_connection->committed = true; con->committed = true;
/* deallocate all prepared statements */ /* deallocate all prepared statements */
for (this = prep_stmts; this != NULL; this = this->next) for (this = prep_stmts; this != NULL; this = this->next)
...@@ -1005,11 +1054,8 @@ ECPGtrans(int lineno, const char *transaction) ...@@ -1005,11 +1054,8 @@ ECPGtrans(int lineno, const char *transaction)
bool bool
ECPGsetconn(int lineno, const char *connection_name) 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) if (con)
{ {
actual_connection = con; actual_connection = con;
...@@ -1070,9 +1116,7 @@ ECPGdisconnect(int lineno, const char *connection_name) ...@@ -1070,9 +1116,7 @@ ECPGdisconnect(int lineno, const char *connection_name)
{ {
struct connection *con; struct connection *con;
if (strcmp(connection_name, "CURRENT") == 0) if (strcmp(connection_name, "ALL") == 0)
ECPGfinish(actual_connection);
else if (strcmp(connection_name, "ALL") == 0)
{ {
for (con = all_connections; con;) for (con = all_connections; con;)
{ {
...@@ -1084,7 +1128,8 @@ ECPGdisconnect(int lineno, const char *connection_name) ...@@ -1084,7 +1128,8 @@ ECPGdisconnect(int lineno, const char *connection_name)
} }
else else
{ {
for (con = all_connections; con && strcmp(con->name, connection_name) != 0; con = con->next); con = get_connection(connection_name);
if (con == NULL) if (con == NULL)
{ {
ECPGlog("disconnect: not connected to connection %s\n", connection_name); ECPGlog("disconnect: not connected to connection %s\n", connection_name);
...@@ -1136,6 +1181,21 @@ sqlprint(void) ...@@ -1136,6 +1181,21 @@ sqlprint(void)
printf("sql error %s\n", sqlca.sqlerrm.sqlerrmc); 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 static void
replace_variables(char *text) replace_variables(char *text)
{ {
...@@ -1150,7 +1210,7 @@ replace_variables(char *text) ...@@ -1150,7 +1210,7 @@ replace_variables(char *text)
if (!string && *ptr == ':') if (!string && *ptr == ':')
{ {
ptr[0] = ptr[1] = ';'; ptr[0] = ptr[1] = ';';
for (ptr += 2; *ptr && *ptr != ' '; ptr++) for (ptr += 2; *ptr && isvarchar(*ptr); ptr++)
*ptr = ' '; *ptr = ' ';
} }
} }
...@@ -1186,6 +1246,7 @@ ECPGprepare(int lineno, char *name, char *variable) ...@@ -1186,6 +1246,7 @@ ECPGprepare(int lineno, char *name, char *variable)
/* create statement */ /* create statement */
stmt->lineno = lineno; stmt->lineno = lineno;
stmt->connection = NULL;
stmt->command = ecpg_strdup(variable, lineno); stmt->command = ecpg_strdup(variable, lineno);
stmt->inlist = stmt->outlist = NULL; stmt->inlist = stmt->outlist = NULL;
......
SRCDIR= ../../.. SRCDIR= ../../..
include $(SRCDIR)/Makefile.global include $(SRCDIR)/Makefile.global
MAJOR_VERSION=2 MAJOR_VERSION=3
MINOR_VERSION=5 MINOR_VERSION=0
PATCHLEVEL=0 PATCHLEVEL=0
CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \ CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \
......
...@@ -36,6 +36,7 @@ static ScanKeyword ScanKeywords[] = { ...@@ -36,6 +36,7 @@ static ScanKeyword ScanKeywords[] = {
{"signed", S_SIGNED}, {"signed", S_SIGNED},
{"static", S_STATIC}, {"static", S_STATIC},
{"struct", S_STRUCT}, {"struct", S_STRUCT},
{"union", S_UNION},
{"unsigned", S_UNSIGNED}, {"unsigned", S_UNSIGNED},
{"varchar", S_VARCHAR}, {"varchar", S_VARCHAR},
}; };
......
...@@ -165,6 +165,7 @@ main(int argc, char *const argv[]) ...@@ -165,6 +165,7 @@ main(int argc, char *const argv[])
struct arguments *l1, *l2; struct arguments *l1, *l2;
free(ptr->command); free(ptr->command);
free(ptr->connection);
free(ptr->name); free(ptr->name);
for (l1 = ptr->argsinsert; l1; l1 = l2) for (l1 = ptr->argsinsert; l1; l1 = l2)
{ {
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
*/ */
static ScanKeyword ScanKeywords[] = { static ScanKeyword ScanKeywords[] = {
/* name value */ /* name value */
{"at", SQL_AT},
{"bool", SQL_BOOL}, {"bool", SQL_BOOL},
{"break", SQL_BREAK}, {"break", SQL_BREAK},
{"call", SQL_CALL}, {"call", SQL_CALL},
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
extern int braces_open, extern int braces_open,
no_auto_trans, struct_level; no_auto_trans, struct_level;
extern char *yytext; extern char *yytext, errortext[128];
extern int yylineno, extern int yylineno,
yyleng; yyleng;
extern FILE *yyin, extern FILE *yyin,
......
...@@ -105,7 +105,6 @@ xqstart {quote} ...@@ -105,7 +105,6 @@ xqstart {quote}
xqstop {quote} xqstop {quote}
xqdouble {quote}{quote} xqdouble {quote}{quote}
xqinside [^\\']* xqinside [^\\']*
xqembedded "\\'"
xqliteral [\\](.|\n) xqliteral [\\](.|\n)
xqcat {quote}{space}*\n{space}*{quote} xqcat {quote}{space}*\n{space}*{quote}
...@@ -244,22 +243,9 @@ cppline {space}*#.*(\\{space}*\n)*\n* ...@@ -244,22 +243,9 @@ cppline {space}*#.*(\\{space}*\n)*\n*
return SCONST; return SCONST;
} }
<xq>{xqdouble} | <xq>{xqdouble} |
<xq>{xqinside} { <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>{xqliteral} { <xq>{xqliteral} {
if ((llen+yyleng-1) > (MAX_PARSE_BUFFER - 1)) if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
yyerror("ERROR: quoted string parse buffer exceeded"); yyerror("ERROR: quoted string parse buffer exceeded");
memcpy(literal+llen, yytext, yyleng+1); memcpy(literal+llen, yytext, yyleng+1);
llen += yyleng; llen += yyleng;
......
...@@ -18,7 +18,8 @@ ...@@ -18,7 +18,8 @@
* Variables containing simple states. * Variables containing simple states.
*/ */
int struct_level = 0; int struct_level = 0;
static char errortext[128]; char errortext[128];
static char *connection = NULL;
static int QueryIsRule = 0, ForUpdateNotAllowed = 0; static int QueryIsRule = 0, ForUpdateNotAllowed = 0;
static struct this_type actual_type[STRUCT_DEPTH]; static struct this_type actual_type[STRUCT_DEPTH];
static char *actual_storage[STRUCT_DEPTH]; static char *actual_storage[STRUCT_DEPTH];
...@@ -489,7 +490,7 @@ output_statement(char * stmt, int mode) ...@@ -489,7 +490,7 @@ output_statement(char * stmt, int mode)
{ {
int i, j=strlen(stmt); 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 '\"' */ /* do this char by char as we have to filter '\"' */
for (i = 0;i < j; i++) for (i = 0;i < j; i++)
...@@ -504,6 +505,8 @@ output_statement(char * stmt, int mode) ...@@ -504,6 +505,8 @@ output_statement(char * stmt, int mode)
fputs("ECPGt_EORT);", yyout); fputs("ECPGt_EORT);", yyout);
whenever_action(mode); whenever_action(mode);
free(stmt); free(stmt);
if (connection != NULL)
free(connection);
} }
static struct typedefs * static struct typedefs *
...@@ -612,7 +615,7 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim ...@@ -612,7 +615,7 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
} }
/* special embedded SQL token */ /* 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_CALL SQL_CONNECT SQL_CONNECTION SQL_CONTINUE
%token SQL_DEALLOCATE SQL_DISCONNECT SQL_ENUM %token SQL_DEALLOCATE SQL_DISCONNECT SQL_ENUM
%token SQL_FOUND SQL_FREE SQL_GO SQL_GOTO %token SQL_FOUND SQL_FREE SQL_GO SQL_GOTO
...@@ -626,7 +629,7 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim ...@@ -626,7 +629,7 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
%token S_ANYTHING S_AUTO S_BOOL S_CHAR S_CONST S_DOUBLE S_ENUM S_EXTERN %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_FLOAT S_INT S
%token S_LONG S_REGISTER S_SHORT S_SIGNED S_STATIC S_STRUCT %token S_LONG S_REGISTER S_SHORT S_SIGNED S_STATIC S_STRUCT
%token S_UNSIGNED S_VARCHAR %token S_UNION S_UNSIGNED S_VARCHAR
/* I need this and don't know where it is defined inside the backend */ /* I need this and don't know where it is defined inside the backend */
%token TYPECAST %token TYPECAST
...@@ -785,8 +788,9 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim ...@@ -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> ECPGSetConnection c_line cpp_line s_enum ECPGTypedef
%type <str> enum_type civariableonly ECPGCursorStmt ECPGDeallocate %type <str> enum_type civariableonly ECPGCursorStmt ECPGDeallocate
%type <str> ECPGFree ECPGDeclare ECPGVar sql_variable_declarations %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> struct_type s_struct declaration variable_declarations
%type <str> s_struct_or_union sql_struct_or_union
%type <type_enum> simple_type varchar_type %type <type_enum> simple_type varchar_type
...@@ -803,13 +807,16 @@ prog: statements; ...@@ -803,13 +807,16 @@ prog: statements;
statements: /* empty */ statements: /* empty */
| statements statement | statements statement
statement: ecpgstart stmt SQL_SEMI statement: ecpgstart opt_at stmt SQL_SEMI { connection = NULL; }
| ecpgstart stmt SQL_SEMI
| ECPGDeclaration | ECPGDeclaration
| c_thing { fprintf(yyout, "%s", $1); free($1); } | c_thing { fprintf(yyout, "%s", $1); free($1); }
| cpp_line { fprintf(yyout, "%s", $1); free($1); } | cpp_line { fprintf(yyout, "%s", $1); free($1); }
| blockstart { fputs($1, yyout); free($1); } | blockstart { fputs($1, yyout); free($1); }
| blockend { 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); } stmt: AddAttrStmt { output_statement($1, 0); }
| AlterUserStmt { output_statement($1, 0); } | AlterUserStmt { output_statement($1, 0); }
| ClosePortalStmt { output_statement($1, 0); } | ClosePortalStmt { output_statement($1, 0); }
...@@ -853,7 +860,7 @@ stmt: AddAttrStmt { output_statement($1, 0); } ...@@ -853,7 +860,7 @@ stmt: AddAttrStmt { output_statement($1, 0); }
} }
| RuleStmt { output_statement($1, 0); } | RuleStmt { output_statement($1, 0); }
| TransactionStmt { | TransactionStmt {
fprintf(yyout, "ECPGtrans(__LINE__, \"%s\");", $1); fprintf(yyout, "ECPGtrans(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1);
whenever_action(0); whenever_action(0);
free($1); free($1);
} }
...@@ -866,6 +873,9 @@ stmt: AddAttrStmt { output_statement($1, 0); } ...@@ -866,6 +873,9 @@ stmt: AddAttrStmt { output_statement($1, 0); }
| VariableShowStmt { output_statement($1, 0); } | VariableShowStmt { output_statement($1, 0); }
| VariableResetStmt { output_statement($1, 0); } | VariableResetStmt { output_statement($1, 0); }
| ECPGConnect { | ECPGConnect {
if (connection)
yyerror("no at option for connect statement.\n");
fprintf(yyout, "no_auto_trans = %d;\n", no_auto_trans); fprintf(yyout, "no_auto_trans = %d;\n", no_auto_trans);
fprintf(yyout, "ECPGconnect(__LINE__, %s);", $1); fprintf(yyout, "ECPGconnect(__LINE__, %s);", $1);
whenever_action(0); whenever_action(0);
...@@ -876,6 +886,9 @@ stmt: AddAttrStmt { output_statement($1, 0); } ...@@ -876,6 +886,9 @@ stmt: AddAttrStmt { output_statement($1, 0); }
free($1); free($1);
} }
| ECPGDeallocate { | ECPGDeallocate {
if (connection)
yyerror("no at option for connect statement.\n");
fputs($1, yyout); fputs($1, yyout);
whenever_action(0); whenever_action(0);
free($1); free($1);
...@@ -885,6 +898,9 @@ stmt: AddAttrStmt { output_statement($1, 0); } ...@@ -885,6 +898,9 @@ stmt: AddAttrStmt { output_statement($1, 0); }
free($1); free($1);
} }
| ECPGDisconnect { | ECPGDisconnect {
if (connection)
yyerror("no at option for disconnect statement.\n");
fprintf(yyout, "ECPGdisconnect(__LINE__, \"%s\");", $1); fprintf(yyout, "ECPGdisconnect(__LINE__, \"%s\");", $1);
whenever_action(0); whenever_action(0);
free($1); free($1);
...@@ -893,7 +909,7 @@ stmt: AddAttrStmt { output_statement($1, 0); } ...@@ -893,7 +909,7 @@ stmt: AddAttrStmt { output_statement($1, 0); }
output_statement($1, 0); output_statement($1, 0);
} }
| ECPGFree { | ECPGFree {
fprintf(yyout, "ECPGdeallocate(__LINE__, \"%s\");", $1); fprintf(yyout, "ECPGdeallocate(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1);
whenever_action(0); whenever_action(0);
free($1); free($1);
} }
...@@ -912,7 +928,7 @@ stmt: AddAttrStmt { output_statement($1, 0); } ...@@ -912,7 +928,7 @@ stmt: AddAttrStmt { output_statement($1, 0); }
yyerror(errortext); 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 to C file*/
dump_variables(ptr->argsinsert, 0); dump_variables(ptr->argsinsert, 0);
dump_variables(argsinsert, 0); dump_variables(argsinsert, 0);
...@@ -923,25 +939,40 @@ stmt: AddAttrStmt { output_statement($1, 0); } ...@@ -923,25 +939,40 @@ stmt: AddAttrStmt { output_statement($1, 0); }
free($1); free($1);
} }
| ECPGPrepare { | ECPGPrepare {
if (connection)
yyerror("no at option for set connection statement.\n");
fprintf(yyout, "ECPGprepare(__LINE__, %s);", $1); fprintf(yyout, "ECPGprepare(__LINE__, %s);", $1);
whenever_action(0); whenever_action(0);
free($1); free($1);
} }
| ECPGRelease { /* output already done */ } | ECPGRelease { /* output already done */ }
| ECPGSetConnection { | ECPGSetConnection {
if (connection)
yyerror("no at option for set connection statement.\n");
fprintf(yyout, "ECPGsetconn(__LINE__, %s);", $1); fprintf(yyout, "ECPGsetconn(__LINE__, %s);", $1);
whenever_action(0); whenever_action(0);
free($1); free($1);
} }
| ECPGTypedef { | ECPGTypedef {
if (connection)
yyerror("no at option for typedef statement.\n");
fputs($1, yyout); fputs($1, yyout);
free($1); free($1);
} }
| ECPGVar { | ECPGVar {
if (connection)
yyerror("no at option for var statement.\n");
fputs($1, yyout); fputs($1, yyout);
free($1); free($1);
} }
| ECPGWhenever { | ECPGWhenever {
if (connection)
yyerror("no at option for whenever statement.\n");
fputs($1, yyout); fputs($1, yyout);
output_line_number(); output_line_number();
free($1); free($1);
...@@ -2727,6 +2758,7 @@ CursorStmt: DECLARE name opt_cursor CURSOR FOR SelectStmt cursor_clause ...@@ -2727,6 +2758,7 @@ CursorStmt: DECLARE name opt_cursor CURSOR FOR SelectStmt cursor_clause
/* initial definition */ /* initial definition */
this->next = cur; this->next = cur;
this->name = $2; 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->command = cat2_str(cat5_str(make1_str("declare"), mm_strdup($2), $3, make1_str("cursor for"), $6), $7);
this->argsinsert = argsinsert; this->argsinsert = argsinsert;
this->argsresult = argsresult; this->argsresult = argsresult;
...@@ -3103,6 +3135,7 @@ Generic: generic ...@@ -3103,6 +3135,7 @@ Generic: generic
generic: ident { $$ = $1; } generic: ident { $$ = $1; }
| TYPE_P { $$ = make1_str("type"); } | TYPE_P { $$ = make1_str("type"); }
| SQL_AT { $$ = make1_str("at"); }
| SQL_BOOL { $$ = make1_str("bool"); } | SQL_BOOL { $$ = make1_str("bool"); }
| SQL_BREAK { $$ = make1_str("break"); } | SQL_BREAK { $$ = make1_str("break"); }
| SQL_CALL { $$ = make1_str("call"); } | SQL_CALL { $$ = make1_str("call"); }
...@@ -4306,6 +4339,7 @@ ColId: ident { $$ = $1; } ...@@ -4306,6 +4339,7 @@ ColId: ident { $$ = $1; }
| VALID { $$ = make1_str("valid"); } | VALID { $$ = make1_str("valid"); }
| VERSION { $$ = make1_str("version"); } | VERSION { $$ = make1_str("version"); }
| ZONE { $$ = make1_str("zone"); } | ZONE { $$ = make1_str("zone"); }
| SQL_AT { $$ = make1_str("at"); }
| SQL_BOOL { $$ = make1_str("bool"); } | SQL_BOOL { $$ = make1_str("bool"); }
| SQL_BREAK { $$ = make1_str("break"); } | SQL_BREAK { $$ = make1_str("break"); }
| SQL_CALL { $$ = make1_str("call"); } | SQL_CALL { $$ = make1_str("call"); }
...@@ -4602,6 +4636,7 @@ ECPGCursorStmt: DECLARE name opt_cursor CURSOR FOR ident cursor_clause ...@@ -4602,6 +4636,7 @@ ECPGCursorStmt: DECLARE name opt_cursor CURSOR FOR ident cursor_clause
/* initial definition */ /* initial definition */
this->next = cur; this->next = cur;
this->name = $2; this->name = $2;
this->connection = connection;
this->command = cat5_str(make1_str("declare"), mm_strdup($2), $3, make1_str("cursor for ;;"), $7); this->command = cat5_str(make1_str("declare"), mm_strdup($2), $3, make1_str("cursor for ;;"), $7);
this->argsresult = NULL; this->argsresult = NULL;
...@@ -4731,14 +4766,17 @@ struct_type: s_struct '{' variable_declarations '}' ...@@ -4731,14 +4766,17 @@ struct_type: s_struct '{' variable_declarations '}'
$$ = cat4_str($1, make1_str("{"), $3, make1_str("}")); $$ = 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; struct_member_list[struct_level++] = NULL;
if (struct_level >= STRUCT_DEPTH) if (struct_level >= STRUCT_DEPTH)
yyerror("Too many levels in nested structure definition"); 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(""); } opt_symbol: /* empty */ { $$ = make1_str(""); }
| symbol { $$ = $1; } | symbol { $$ = $1; }
...@@ -4940,7 +4978,7 @@ ECPGRelease: TransactionStmt SQL_RELEASE ...@@ -4940,7 +4978,7 @@ ECPGRelease: TransactionStmt SQL_RELEASE
if (strncmp($1, "begin", 5) == 0) if (strncmp($1, "begin", 5) == 0)
yyerror("RELEASE does not make sense when beginning a transaction"); 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); whenever_action(0);
fprintf(yyout, "ECPGdisconnect(\"\");"); fprintf(yyout, "ECPGdisconnect(\"\");");
whenever_action(0); whenever_action(0);
...@@ -5151,7 +5189,7 @@ ctype: CHAR ...@@ -5151,7 +5189,7 @@ ctype: CHAR
$$.type_index = -1; $$.type_index = -1;
$$.type_dimension = -1; $$.type_dimension = -1;
} }
| SQL_STRUCT | sql_struct_or_union
{ {
struct_member_list[struct_level++] = NULL; struct_member_list[struct_level++] = NULL;
if (struct_level >= STRUCT_DEPTH) if (struct_level >= STRUCT_DEPTH)
...@@ -5159,7 +5197,7 @@ ctype: CHAR ...@@ -5159,7 +5197,7 @@ ctype: CHAR
} '{' sql_variable_declarations '}' } '{' sql_variable_declarations '}'
{ {
ECPGfree_struct_member(struct_member_list[struct_level--]); 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_enum = ECPGt_struct;
$$.type_index = -1; $$.type_index = -1;
$$.type_dimension = -1; $$.type_dimension = -1;
...@@ -5175,6 +5213,9 @@ ctype: CHAR ...@@ -5175,6 +5213,9 @@ ctype: CHAR
struct_member_list[struct_level] = this->struct_member_list; 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 */ opt_signed: SQL_SIGNED | /* empty */
sql_variable_declarations: /* empty */ sql_variable_declarations: /* empty */
...@@ -5735,6 +5776,7 @@ c_anything: IDENT { $$ = $1; } ...@@ -5735,6 +5776,7 @@ c_anything: IDENT { $$ = $1; }
| S_SIGNED { $$ = make1_str("signed"); } | S_SIGNED { $$ = make1_str("signed"); }
| S_STATIC { $$ = make1_str("static"); } | S_STATIC { $$ = make1_str("static"); }
| S_STRUCT { $$ = make1_str("struct"); } | S_STRUCT { $$ = make1_str("struct"); }
| S_UNION { $$ = make1_str("union"); }
| S_UNSIGNED { $$ = make1_str("unsigned"); } | S_UNSIGNED { $$ = make1_str("unsigned"); }
| S_VARCHAR { $$ = make1_str("varchar"); } | S_VARCHAR { $$ = make1_str("varchar"); }
| S_ANYTHING { $$ = make_name(); } | S_ANYTHING { $$ = make_name(); }
......
...@@ -164,7 +164,8 @@ get_type(enum ECPGttype typ) ...@@ -164,7 +164,8 @@ get_type(enum ECPGttype typ)
return ("ECPGt_char_variable"); return ("ECPGt_char_variable");
break; break;
default: default:
abort(); sprintf(errortext, "illegal variable type %d\n", typ);
yyerror(errortext);
} }
} }
...@@ -357,7 +358,8 @@ ECPGfree_type(struct ECPGtype * typ) ...@@ -357,7 +358,8 @@ ECPGfree_type(struct ECPGtype * typ)
if (IS_SIMPLE_TYPE(typ->u.element->typ)) if (IS_SIMPLE_TYPE(typ->u.element->typ))
free(typ->u.element); free(typ->u.element);
else if (typ->u.element->typ == ECPGt_array) 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) else if (typ->u.element->typ == ECPGt_struct)
{ {
/* Array of structs. */ /* Array of structs. */
...@@ -365,7 +367,10 @@ ECPGfree_type(struct ECPGtype * typ) ...@@ -365,7 +367,10 @@ ECPGfree_type(struct ECPGtype * typ)
free(typ->u.members); free(typ->u.members);
} }
else else
abort(); {
sprintf(errortext, "illegal variable type %d\n", typ);
yyerror(errortext);
}
} }
else if (typ->typ == ECPGt_struct) else if (typ->typ == ECPGt_struct)
{ {
...@@ -373,7 +378,10 @@ ECPGfree_type(struct ECPGtype * typ) ...@@ -373,7 +378,10 @@ ECPGfree_type(struct ECPGtype * typ)
free(typ->u.members); free(typ->u.members);
} }
else else
abort(); {
sprintf(errortext, "illegal variable type %d\n", typ);
yyerror(errortext);
}
} }
free(typ); free(typ);
} }
...@@ -101,6 +101,7 @@ struct cursor ...@@ -101,6 +101,7 @@ struct cursor
{ {
char *name; char *name;
char *command; char *command;
char *connection;
struct arguments *argsinsert; struct arguments *argsinsert;
struct arguments *argsresult; struct arguments *argsresult;
struct cursor *next; struct cursor *next;
......
...@@ -15,4 +15,4 @@ perftest.c:perftest.pgc ...@@ -15,4 +15,4 @@ perftest.c:perftest.pgc
/usr/local/pgsql/bin/ecpg $? /usr/local/pgsql/bin/ecpg $?
clean: clean:
/bin/rm test1 test2 perftest *.c log -/bin/rm test1 test2 perftest *.c log
...@@ -4,7 +4,7 @@ exec sql whenever sqlerror sqlprint; ...@@ -4,7 +4,7 @@ exec sql whenever sqlerror sqlprint;
exec sql include sqlca; exec sql include sqlca;
exec sql define AMOUNT 8; exec sql define AMOUNT 4;
exec sql type intarray is int[AMOUNT]; exec sql type intarray is int[AMOUNT];
exec sql type string is char(6); exec sql type string is char(6);
...@@ -30,21 +30,31 @@ exec sql end declare section; ...@@ -30,21 +30,31 @@ exec sql end declare section;
ECPGdebug(1, dbgs); ECPGdebug(1, dbgs);
strcpy(msg, "connect"); 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"); 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)); exec sql create table test(name char(6), amount int, letter char(1));
strcpy(msg, "commit"); strcpy(msg, "commit");
exec sql at main commit;
exec sql commit; exec sql commit;
strcpy(msg, "set connection");
exec sql set connection main;
strcpy(msg, "execute insert 1"); 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; exec sql execute immediate :command;
strcpy(msg, "execute insert 2"); strcpy(msg, "execute insert 2");
sprintf(command, "insert into test(name, amount, letter) select name, amount+1, letter from test"); sprintf(command, "insert into test(name, amount, letter) values ('db: pm', 1, 'f')");
exec sql execute immediate :command; exec sql at pm execute immediate :command;
strcpy(msg, "execute insert 3"); strcpy(msg, "execute insert 3");
sprintf(command, "insert into test(name, amount, letter) select name, amount+10, letter from test"); sprintf(command, "insert into test(name, amount, letter) select name, amount+10, letter from test");
...@@ -55,27 +65,35 @@ exec sql end declare section; ...@@ -55,27 +65,35 @@ exec sql end declare section;
strcpy(msg, "execute insert 4"); strcpy(msg, "execute insert 4");
sprintf(command, "insert into test(name, amount, letter) select name, amount+;;, letter from test"); sprintf(command, "insert into test(name, amount, letter) select name, amount+;;, letter from test");
exec sql prepare I from :command; 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]); printf("Inserted %d tuples via prepared execute\n", sqlca.sqlerrd[2]);
strcpy(msg, "commit"); strcpy(msg, "commit");
exec sql commit; exec sql commit;
exec sql at pm commit;
strcpy(msg, "select"); strcpy(msg, "select");
exec sql select name, amount, letter into :name, :amount, :letter from test; 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++) 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]); 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"); strcpy(msg, "drop");
exec sql drop table test; exec sql drop table test;
exec sql at pm drop table test;
strcpy(msg, "commit"); strcpy(msg, "commit");
exec sql commit; exec sql commit;
exec sql at pm commit;
strcpy(msg, "disconnect"); strcpy(msg, "disconnect");
exec sql disconnect; exec sql disconnect all;
if (dbgs != NULL) if (dbgs != NULL)
fclose(dbgs); fclose(dbgs);
......
...@@ -5,6 +5,9 @@ exec sql include header_test; ...@@ -5,6 +5,9 @@ exec sql include header_test;
exec sql type c is char reference; exec sql type c is char reference;
typedef char* c; typedef char* c;
exec sql type ind is union { int integer; short smallinteger; };
typedef union { int integer; short smallinteger; } ind;
int int
main () main ()
{ {
...@@ -18,15 +21,17 @@ exec sql begin declare section; ...@@ -18,15 +21,17 @@ exec sql begin declare section;
birthinfo ind_birth; birthinfo ind_birth;
} ind_personal; } ind_personal;
int ind_married; int ind_married;
ind children;
ind ind_children;
char married[9]; char married[9];
c testname="Petra"; 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 end declare section;
exec sql var ind_married is long; exec sql var ind_married is long;
exec sql declare cur cursor for 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]; char msg[128], command[128];
FILE *dbgs; FILE *dbgs;
...@@ -38,11 +43,11 @@ exec sql end declare section; ...@@ -38,11 +43,11 @@ exec sql end declare section;
exec sql connect to unix:postgresql://localhost:5432/mm; exec sql connect to unix:postgresql://localhost:5432/mm;
strcpy(msg, "create"); 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"); strcpy(msg, "insert");
exec sql insert into meskes(name, married) values ('Petra', '19900404'); exec sql insert into meskes(name, married, children) values ('Petra', '19900404', 3);
exec sql insert into meskes(name, born, age, married) values ('Michael', 19660117, 33, '19900404'); 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 ('Carsten', 19910103, 8);
exec sql insert into meskes(name, born, age) values ('Marc', 19930907, 5); exec sql insert into meskes(name, born, age) values ('Marc', 19930907, 5);
exec sql insert into meskes(name, born, age) values ('Chris', 19970923, 1); exec sql insert into meskes(name, born, age) values ('Chris', 19970923, 1);
...@@ -57,7 +62,7 @@ exec sql end declare section; ...@@ -57,7 +62,7 @@ exec sql end declare section;
while (1) { while (1) {
strcpy(msg, "fetch"); 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); printf("%8.8s", personal.name.arr);
if (!ind_personal.ind_birth.born) if (!ind_personal.ind_birth.born)
printf(", born %d", personal.birth.born); printf(", born %d", personal.birth.born);
...@@ -65,6 +70,8 @@ exec sql end declare section; ...@@ -65,6 +70,8 @@ exec sql end declare section;
printf(", age = %d", personal.birth.age); printf(", age = %d", personal.birth.age);
if (!ind_married) if (!ind_married)
printf(", married %s", married); printf(", married %s", married);
if (!ind_children.smallinteger)
printf(", children = %d", children.integer);
putchar('\n'); putchar('\n');
} }
...@@ -82,7 +89,7 @@ exec sql end declare section; ...@@ -82,7 +89,7 @@ exec sql end declare section;
while (1) { while (1) {
strcpy(msg, "fetch"); 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); printf("%8.8s", personal.name.arr);
if (!ind_personal.ind_birth.born) if (!ind_personal.ind_birth.born)
printf(", born %d", personal.birth.born); printf(", born %d", personal.birth.born);
...@@ -90,6 +97,8 @@ exec sql end declare section; ...@@ -90,6 +97,8 @@ exec sql end declare section;
printf(", age = %d", personal.birth.age); printf(", age = %d", personal.birth.age);
if (!ind_married) if (!ind_married)
printf(", married %s", married); printf(", married %s", married);
if (!ind_children.smallinteger)
printf(", children = %d", children.integer);
putchar('\n'); putchar('\n');
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment