From: Michael Meskes <Michael_Meskes@topmail.de>
authorMarc G. Fournier <scrappy@hub.org>
Tue, 23 Feb 1999 12:57:03 +0000 (12:57 +0000)
committerMarc G. Fournier <scrappy@hub.org>
Tue, 23 Feb 1999 12:57:03 +0000 (12:57 +0000)
+
+ 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

18 files changed:
src/interfaces/ecpg/ChangeLog
src/interfaces/ecpg/TODO
src/interfaces/ecpg/include/ecpglib.h
src/interfaces/ecpg/include/ecpgtype.h
src/interfaces/ecpg/lib/Makefile.in
src/interfaces/ecpg/lib/ecpglib.c
src/interfaces/ecpg/preproc/Makefile
src/interfaces/ecpg/preproc/c_keywords.c
src/interfaces/ecpg/preproc/ecpg.c
src/interfaces/ecpg/preproc/ecpg_keywords.c
src/interfaces/ecpg/preproc/extern.h
src/interfaces/ecpg/preproc/pgc.l
src/interfaces/ecpg/preproc/preproc.y
src/interfaces/ecpg/preproc/type.c
src/interfaces/ecpg/preproc/type.h
src/interfaces/ecpg/test/Makefile
src/interfaces/ecpg/test/test1.pgc
src/interfaces/ecpg/test/test2.pgc

index eac1b96e800be28b24089337e69206261b410771..152484943461dc7b66affe553361594ff98a00c1 100644 (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
index 82b8a5d8b85b070dbe2eb82a6de7d08fc1b04ce7..0b4be6dd9f4da286f1f33f10c0ea772a4ee962f0 100644 (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
index 4e1d6f9cde4b44d7c14b649f6aa5949a0fd3f7d6..98153747f6f8f37a954da5cd402e9f07036c8759 100644 (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 *);
index e92220481da0df7176ca975970582e73992b7254..8ca4d697c158e887dd7ffd1cddc016c4978ca2fb 100644 (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)
index 4872e8c0fd5ae229f9e4563f852ff21e18719de0..ef2373fa78e49fd5aa40661e243451d50afd815c 100644 (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
index 2a7745f2a6747067cd84ab9ab8781d4ec72a2228..e686edd512d4e007ce48983973fe4ab6b424ae57 100644 (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;
-
-       ECPGlog("ECPGsetconn: setting actual connection to %s\n", connection_name);
+       struct connection *con = get_connection(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;
         
index 87e788c83ccdf2b4e4ef9cc404c0b236b2921073..66c8911c5a8f04f94b59f47c8ebec258c5842e18 100644 (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) \
index 5395b533d3845b5a690b837534ebc83aefa1ffee..9a8b94bd256d0b0311f2a6ffcc83602f3d19b5e6 100644 (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},
 };
index 2594718cd124bdcbd1e78207c0ba66e63860bb70..6b37442c836ad0e66f7185f91defdcc9f44643a3 100644 (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)
                                        {
index 52eea065b8373faa30f8484aae60ecf35e246aa4..25c1f2b9813babb23710fee42f822834db565671 100644 (file)
@@ -20,6 +20,7 @@
  */
 static ScanKeyword ScanKeywords[] = {
        /* name                                 value                   */
+       {"at", SQL_AT},
        {"bool", SQL_BOOL},
        {"break", SQL_BREAK},
        {"call", SQL_CALL},
index d5bc1fc9cabb4afa5379bc861629e84c987627df..94c76a507af5f544995c7e375bae68998008baa7 100644 (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,
index 5ddac659bbc4cef6f3f57f22db512f6b4144023c..82369690763a1ad45c73145fb02866498031edf2 100644 (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;
index 7bb95d77e8cb8c2e58546e922c2c1f51daa6c8fa..ae5edf294d96474b2254588514afac21a68da649 100644 (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(); }
index dd3546b50ad83ea186461a496e5ba17fe9c9d412..b5144d5d9a7ef60e0c63c54899cf64217c6f1210 100644 (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);
 }
index f9642d92766e922b74c12454201b615e5cb2f09c..59cf3be9009e4e0cd3266161fad563892569b4bc 100644 (file)
@@ -101,6 +101,7 @@ struct cursor
 {
        char       *name;
        char       *command;
+       char       *connection;
        struct arguments *argsinsert;
        struct arguments *argsresult;
        struct cursor *next;
index 45d65fb44c67c4c5ceaf584d569307cf64ec596f..2c4ba01ee0da0de121c99566b14203037eaa3063 100644 (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
index ac2dbdc04e165ded68688c8da6b99e780dcabeb8..a1e13bb517554d62e259c563a3a6054ea28a000b 100644 (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);
index ed06f179bc488b4d4d90badc733f6cb0214a09e8..568add1463440ba10a5a0908a181b24721f0ffe2 100644 (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');
        }