From: Michael Meskes
authorMarc G. Fournier
Tue, 23 Feb 1999 12:57:03 +0000 (12:57 +0000)
committerMarc G. Fournier
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 ' 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 ' 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 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -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;
                }
 {xqdouble} |
-{xqinside} {
-                   if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
-                       yyerror("ERROR: quoted string parse buffer exceeded");
-                   memcpy(literal+llen, yytext, yyleng+1);
-                   llen += yyleng;
-               }
-{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;
-               }
-
+{xqinside}  |
 {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     ECPGSetConnection c_line cpp_line s_enum ECPGTypedef
 %type     enum_type civariableonly ECPGCursorStmt ECPGDeallocate
 %type     ECPGFree ECPGDeclare ECPGVar sql_variable_declarations
-%type     sql_declaration sql_variable_list sql_variable
+%type     sql_declaration sql_variable_list sql_variable opt_at
 %type      struct_type s_struct declaration variable_declarations
+%type      s_struct_or_union sql_struct_or_union
 
 %type   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
+            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
             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');
    }