From: Michael Meskes
authorMarc G. Fournier
Mon, 18 May 1998 16:05:05 +0000 (16:05 +0000)
committerMarc G. Fournier
Mon, 18 May 1998 16:05:05 +0000 (16:05 +0000)
+
+ Wed May  6 16:09:45 CEST 1998
+
+       - Some more cleanups in the library.
+
+ Thu May  7 12:34:28 CEST 1998
+
+       - Made CONNECT and DISCONNECT statement more SQL3 compliant.
+       - Changed the API for the ECPGconnect function to be able to handle
+         hostnames and ports
+
+ Fri May  8 13:54:45 CEST 1998
+       - More changes to the parser. The connect statement now allows
+         ORACLE style logins.
+       - db-name is accepted in two ways:
+               - [@][:]
+               - esql:postgresql://[:][/]
+
+ Mon May 11 10:28:37 CEST 1998
+
+       - Added '? options' to connect call.
+       - Also allow USING as keyword for the password
+
+ Thu May 14 15:09:58 CEST 1998
+
+       - Changed preproc.y and pgc.l according to the parser changes in the
+         backend.
+
+ Fri May 15 09:55:21 CEST 1998
+
+       - Added connection_name handling
+
+
+ Mon May 18 10:33:58 CEST 1998
+
+       - Fixed some more bugs
+       - Set version to 2.3.1
+       - Set library version to 2.2

15 files changed:
src/interfaces/ecpg/ChangeLog
src/interfaces/ecpg/include/ecpgerrno.h
src/interfaces/ecpg/include/ecpglib.h
src/interfaces/ecpg/lib/Makefile.in
src/interfaces/ecpg/lib/ecpglib.c
src/interfaces/ecpg/preproc/Makefile
src/interfaces/ecpg/preproc/ecpg_keywords.c
src/interfaces/ecpg/preproc/extern.h
src/interfaces/ecpg/preproc/keywords.c
src/interfaces/ecpg/preproc/pgc.l
src/interfaces/ecpg/preproc/preproc.y
src/interfaces/ecpg/preproc/type.c
src/interfaces/ecpg/test/perftest.pgc
src/interfaces/ecpg/test/test1.pgc
src/interfaces/ecpg/test/test2.pgc

index 5828ef8a81b90f8b309469b0dba84cfd662b731c..c7acdf023dfe5937d51c4cec77c719d98aa4b2aa 100644 (file)
@@ -189,3 +189,42 @@ Wed May  6 11:42:48 CEST 1998
           an example)
    - Set version to 2.3.0
    - Set library version to 2.1
+
+Wed May  6 16:09:45 CEST 1998
+
+   - Some more cleanups in the library.
+
+Thu May  7 12:34:28 CEST 1998
+
+   - Made CONNECT and DISCONNECT statement more SQL3 compliant.
+   - Changed the API for the ECPGconnect function to be able to handle
+     hostnames and ports
+
+Fri May  8 13:54:45 CEST 1998
+   - More changes to the parser. The connect statement now allows
+     ORACLE style logins.
+   - db-name is accepted in two ways:
+       - [@][:]
+       - esql:postgresql://[:][/]
+
+Mon May 11 10:28:37 CEST 1998
+
+   - Added '? options' to connect call.
+   - Also allow USING as keyword for the password
+
+Thu May 14 15:09:58 CEST 1998
+
+   - Changed preproc.y and pgc.l according to the parser changes in the
+     backend.
+
+Fri May 15 09:55:21 CEST 1998
+
+   - Added connection_name handling
+
+
+Mon May 18 10:33:58 CEST 1998
+
+   - Fixed some more bugs
+   - Set version to 2.3.1
+   - Set library version to 2.2
+
index 1be718216d794ad5ea3f3292e82ed4393e04a05a..cddc7e6a686afca3966a63079895d007c9da360b 100644 (file)
@@ -1,22 +1,32 @@
 #ifndef _ECPG_ERROR_H
 #define _ECPG_ERROR_H
 
+#include 
+
 /* This is a list of all error codes the embedded SQL program can return */
 #define    ECPG_NO_ERROR       0
 #define ECPG_NOT_FOUND     100
 
-#define ECPG_PGSQL     -1
-#define ECPG_UNSUPPORTED   -2
-#define ECPG_TOO_MANY_ARGUMENTS    -3
-#define ECPG_TOO_FEW_ARGUMENTS -4
-#define ECPG_TRANS     -5
-#define ECPG_TOO_MANY_MATCHES  -6
-#define ECPG_INT_FORMAT        -7
-#define ECPG_UINT_FORMAT   -8
-#define ECPG_FLOAT_FORMAT  -9
-#define ECPG_CONVERT_BOOL  -10
-#define ECPG_EMPTY     -11
-#define ECPG_CONNECT       -12
-#define ECPG_DISCONNECT        -13
+/* system error codes returned by ecpglib get the correct number,
+ * but are made negative
+ */
+#define ECPG_OUT_OF_MEMORY -ENOMEM
+
+/* first we have a set of ecpg messages, they start at 200 */
+#define ECPG_UNSUPPORTED   -200
+#define ECPG_TOO_MANY_ARGUMENTS    -201
+#define ECPG_TOO_FEW_ARGUMENTS -202
+#define ECPG_TOO_MANY_MATCHES  -203
+#define ECPG_INT_FORMAT        -204
+#define ECPG_UINT_FORMAT   -205
+#define ECPG_FLOAT_FORMAT  -206
+#define ECPG_CONVERT_BOOL  -207
+#define ECPG_EMPTY     -208
+#define ECPG_NO_CONN       -209
+
+/* finally the backend error messages, they start at 300 */
+#define ECPG_PGSQL     -300
+#define ECPG_TRANS     -301
+#define ECPG_CONNECT       -302
 
 #endif /* !_ECPG_ERROR_H */
index 9a5c2732d8ff5208b7768d8e9d8004f5022f0b5b..c0603b2e7f547b79fb3bbfb7a32ec4d8785f483c 100644 (file)
@@ -5,11 +5,11 @@ extern "C" {
 #endif
 
 void       ECPGdebug(int, FILE *);
-bool       ECPGconnect(const char *);
+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       ECPGfinish(void);
-bool       ECPGdisconnect(const char *);
+bool       ECPGdisconnect(int, const char *);
 
 void       ECPGlog(const char *format,...);
 
index 0fb1d6f0261900c91286bd948495c2c436f97812..c402afc8446a0e2e23e31756aaaf2c8a42b00a55 100644 (file)
@@ -4,7 +4,7 @@ include $(SRCDIR)/Makefile.global
 PQ_INCLUDE=-I$(SRCDIR)/interfaces/libpq
 
 SO_MAJOR_VERSION=2
-SO_MINOR_VERSION=1
+SO_MINOR_VERSION=2
 
 PORTNAME=@PORTNAME@
 
index 4f40a2e1020c4b565f5894e520470429b990d57c..445776ec828ec845864a57b60e0ea5c3813611ff 100644 (file)
 
 extern int no_auto_trans;
 
-static PGconn *simple_connection = NULL;
+static struct connection
+{
+   char *name;
+   PGconn *connection;
+   struct connection *next;
+} *all_connections = NULL, *actual_connection = NULL;
+
 static int simple_debug = 0;
 static FILE *debugstream = NULL;
 static int committed = true;
@@ -54,6 +60,9 @@ quote_postgres(char *arg)
    int         i,
                ri;
 
+   if (!res)
+       return(res);
+       
    for (i = 0, ri = 0; arg[i]; i++, ri++)
    {
        switch (arg[i])
@@ -73,6 +82,40 @@ quote_postgres(char *arg)
 }
 
 
+static void
+ECPGfinish(struct connection *act)
+{
+   if (act != NULL)
+   {
+       ECPGlog("ECPGfinish: finishing %s.\n", act->name);
+       PQfinish(act->connection);
+       /* remove act from the list */
+       if (act == all_connections)
+       {
+           all_connections = act->next;
+           free(act->name);
+           free(act);
+       }
+       else
+       {
+           struct connection *con;
+           
+           for (con = all_connections; con->next && con->next !=  act; con = con->next);
+           if (con->next)
+           {
+               con->next = act->next;
+               free(act->name);
+               free(act);
+           }
+       }
+       
+       if (actual_connection == act)
+           actual_connection = all_connections;
+   }
+   else
+       ECPGlog("ECPGfinish: called an extra time.\n");
+}
+
 bool
 ECPGdo(int lineno, char *query,...)
 {
@@ -195,14 +238,40 @@ ECPGdo(int lineno, char *query,...)
                {
                    /* set slen to string length if type is char * */
                    int         slen = (varcharsize == 0) ? strlen((char *) value) : varcharsize;
+                   char * tmp;
 
                    newcopy = (char *) malloc(slen + 1);
+                   if (!newcopy)
+                   {
+                       ECPGfinish(actual_connection);
+                       ECPGlog("out of memory\n");
+                               register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+                       return false;
+                   }
+                       
                    strncpy(newcopy, (char *) value, slen);
                    newcopy[slen] = '\0';
 
                    mallocedval = (char *) malloc(2 * strlen(newcopy) + 3);
+                   if (!mallocedval)
+                   {
+                       ECPGfinish(actual_connection);
+                       ECPGlog("out of memory\n");
+                               register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+                       return false;
+                   }
+                       
                    strcpy(mallocedval, "'");
-                   strcat(mallocedval, quote_postgres(newcopy));
+                   tmp = quote_postgres(newcopy);
+                   if (!tmp)
+                   {
+                       ECPGfinish(actual_connection);
+                       ECPGlog("out of memory\n");
+                               register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+                       return false;
+                   }
+                       
+                   strcat(mallocedval, tmp);
                    strcat(mallocedval, "'");
 
                    free(newcopy);
@@ -215,14 +284,40 @@ ECPGdo(int lineno, char *query,...)
                {
                    struct ECPGgeneric_varchar *var =
                    (struct ECPGgeneric_varchar *) value;
+                   char *tmp;
 
                    newcopy = (char *) malloc(var->len + 1);
+                   if (!newcopy)
+                   {
+                       ECPGfinish(actual_connection);
+                       ECPGlog("out of memory\n");
+                               register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+                       return false;
+                   }
+                       
                    strncpy(newcopy, var->arr, var->len);
                    newcopy[var->len] = '\0';
 
                    mallocedval = (char *) malloc(2 * strlen(newcopy) + 3);
+                   if (!mallocedval)
+                   {
+                       ECPGfinish(actual_connection);
+                       ECPGlog("out of memory\n");
+                               register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+                       return false;
+                   }
+                   
                    strcpy(mallocedval, "'");
-                   strcat(mallocedval, quote_postgres(newcopy));
+                   tmp = quote_postgres(newcopy);
+                   if (!tmp)
+                   {
+                       ECPGfinish(actual_connection);
+                       ECPGlog("out of memory\n");
+                               register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+                       return false;
+                   }
+                                                                   
+                   strcat(mallocedval, tmp);
                    strcat(mallocedval, "'");
 
                    free(newcopy);
@@ -249,6 +344,14 @@ ECPGdo(int lineno, char *query,...)
        newcopy = (char *) malloc(strlen(copiedquery)
                                  + strlen(tobeinserted)
                                  + 1);
+       if (!newcopy)
+       {
+           ECPGfinish(actual_connection);
+           ECPGlog("out of memory\n");
+                   register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+           return false;
+       }
+           
        strcpy(newcopy, copiedquery);
        if ((p = strstr(newcopy, ";;")) == NULL)
        {
@@ -301,7 +404,7 @@ ECPGdo(int lineno, char *query,...)
 
    if (committed && !no_auto_trans)
    {
-       if ((results = PQexec(simple_connection, "begin transaction")) == NULL)
+       if ((results = PQexec(actual_connection->connection, "begin transaction")) == NULL)
        {
            register_error(ECPG_TRANS, "Error starting transaction line %d.", lineno);
            return false;
@@ -311,15 +414,15 @@ ECPGdo(int lineno, char *query,...)
    }
 
    ECPGlog("ECPGdo line %d: QUERY: %s\n", lineno, copiedquery);
-   results = PQexec(simple_connection, copiedquery);
+   results = PQexec(actual_connection->connection, copiedquery);
    free(copiedquery);
 
    if (results == NULL)
    {
        ECPGlog("ECPGdo line %d: error: %s", lineno,
-               PQerrorMessage(simple_connection));
+               PQerrorMessage(actual_connection->connection));
        register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
-                      PQerrorMessage(simple_connection), lineno);
+                      PQerrorMessage(actual_connection->connection), lineno);
    }
    else
    {
@@ -644,9 +747,9 @@ ECPGdo(int lineno, char *query,...)
            case PGRES_FATAL_ERROR:
            case PGRES_BAD_RESPONSE:
                ECPGlog("ECPGdo line %d: Error: %s",
-                       lineno, PQerrorMessage(simple_connection));
+                       lineno, PQerrorMessage(actual_connection->connection));
                register_error(ECPG_PGSQL, "Error: %s line %d.",
-                              PQerrorMessage(simple_connection), lineno);
+                              PQerrorMessage(actual_connection->connection), lineno);
                status = false;
                break;
            case PGRES_COPY_OUT:
@@ -667,7 +770,7 @@ ECPGdo(int lineno, char *query,...)
    }
 
    /* check for asynchronous returns */
-   notify = PQnotifies(simple_connection);
+   notify = PQnotifies(actual_connection->connection);
    if (notify)
    {
        ECPGlog("ECPGdo line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
@@ -686,7 +789,7 @@ ECPGtrans(int lineno, const char * transaction)
    PGresult   *res;
 
    ECPGlog("ECPGtrans line %d action = %s\n", lineno, transaction);
-   if ((res = PQexec(simple_connection, transaction)) == NULL)
+   if ((res = PQexec(actual_connection->connection, transaction)) == NULL)
    {
        register_error(ECPG_TRANS, "Error in transaction processing line %d.", lineno);
        return (FALSE);
@@ -698,59 +801,101 @@ ECPGtrans(int lineno, const char * transaction)
 }
 
 bool
-ECPGsetdb(PGconn *newcon)
+ECPGsetconn(int lineno, const char *connection_name)
 {
-   ECPGfinish();
-   simple_connection = newcon;
-   return true;
+   struct connection *con = all_connections;
+   
+   for (; con && strcmp(connection_name, con->name) == 0; con=con->next);
+   if (con)
+   {
+       actual_connection = con;
+       return true;
+   }
+   else
+   {
+       register_error(ECPG_NO_CONN, "No such connection %s in line %d", connection_name, lineno);
+       return false;
+   }
 }
 
 bool
-ECPGconnect(const char *dbname)
+ECPGconnect(int lineno, const char *dbname, const char *user, const char *passwd, const char * connection_name)
 {
-   char       *name = strdup(dbname);
-
-   ECPGlog("ECPGconnect: opening database %s\n", name);
+   struct connection *this = malloc(sizeof(struct connection));
 
-   sqlca.sqlcode = 0;
+   if (!this)
+   {
+       ECPGlog("out of memory\n");
+                register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
+       return false;
+   }
+               
+   if (dbname == NULL && connection_name == NULL)
+       connection_name = "DEFAULT";
+   
+   /* add connection to our list */
+   if (connection_name != NULL)
+       this->name = strdup(connection_name);
+   else
+       this->name = strdup(dbname);
+   
+   if (all_connections == NULL)
+       this->next = NULL;
+   else
+       this->next = all_connections;
 
-   ECPGsetdb(PQsetdb(NULL, NULL, NULL, NULL, name));
+   actual_connection = all_connections = this;
+       
+   ECPGlog("ECPGconnect: opening database %s %s%s\n", dbname ? dbname : "NULL", user ? "for user ": "", user ? user : "");
 
-   free(name);
-   name = NULL;
+   sqlca.sqlcode = 0;
 
-   if (PQstatus(simple_connection) == CONNECTION_BAD)
+   this->connection = PQsetdbLogin(NULL, NULL, NULL, NULL, dbname, user, passwd);
+        
+   if (PQstatus(this->connection) == CONNECTION_BAD)
    {
-       ECPGfinish();
-       ECPGlog("connect: could not open database %s\n", dbname);
-       register_error(ECPG_CONNECT, "connect: could not open database %s.", dbname);
+       ECPGfinish(this);
+                ECPGlog("connect: could not open database %s %s%s in line %d\n", dbname ? dbname : "NULL", user ? "for user ": "", user ? user : "", lineno);
+                
+       register_error(ECPG_CONNECT, "connect: could not open database %s.", dbname ? dbname : "NULL");
        return false;
    }
+   
    return true;
 }
 
 bool
-ECPGdisconnect(const char *dbname)
+ECPGdisconnect(int lineno, const char *connection_name)
 {
-   if (strlen(dbname) > 0 && strcmp(PQdb(simple_connection), dbname) != 0)
+   struct connection *con;
+   
+   if (strcmp(connection_name, "CURRENT") == 0)
+       ECPGfinish(actual_connection);
+   else if (strcmp(connection_name, "ALL") == 0)
    {
-       ECPGlog("disconnect: not connected to database %s\n", dbname);
-       register_error(ECPG_DISCONNECT, "disconnect: not connected to database %s.", dbname);
-       return false;
+       for (con = all_connections; con;)
+       {
+           struct connection *f = con;
+           
+           con = con->next;
+           ECPGfinish(f);
+       }
    }
-   return ECPGfinish();
-}
-
-bool
-ECPGfinish(void)
-{
-   if (simple_connection != NULL)
+   else 
    {
-       ECPGlog("ECPGfinish: finishing.\n");
-       PQfinish(simple_connection);
+       for (con = all_connections; con && strcmp(con->name, connection_name);con = con->next);
+       if (con == NULL)
+       {       
+           ECPGlog("disconnect: not connected to connection %s\n", connection_name);
+           register_error(ECPG_NO_CONN, "No such connection %s in line %d", connection_name, lineno);
+           return false;
+       }
+       else
+       {
+           ECPGfinish(con);
+       }
    }
-   else
-       ECPGlog("ECPGfinish: called an extra time.\n");
+   
    return true;
 }
 
@@ -771,6 +916,9 @@ ECPGlog(const char *format,...)
    {
        char       *f = (char *) malloc(strlen(format) + 100);
 
+       if (!f)
+           return;
+                       
        sprintf(f, "[%d]: %s", getpid(), format);
 
        va_start(ap, format);
index 5cb3861c22a5b3a58334fa82c0180327a2757fd9..1410087832a7ad1450061dbd82dc5fdae9245397 100644 (file)
@@ -3,7 +3,7 @@ include $(SRCDIR)/Makefile.global
 
 MAJOR_VERSION=2
 MINOR_VERSION=3
-PATCHLEVEL=0
+PATCHLEVEL=1
 
 CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \
    -DMINOR_VERSION=$(MINOR_VERSION) -DPATCHLEVEL=$(PATCHLEVEL) \
index 3badb9399741263e095c235905725b42225a8943..bc724c54b311767b9c577c59ee9c691e9e08d04d 100644 (file)
@@ -24,12 +24,14 @@ static ScanKeyword ScanKeywords[] = {
    {"break", SQL_BREAK},
    {"call", SQL_CALL},
    {"connect", SQL_CONNECT},
+   {"connection", SQL_CONNECTION},
    {"continue", SQL_CONTINUE},
    {"disconnect", SQL_DISCONNECT},
    {"found", SQL_FOUND},
    {"go", SQL_GO},
    {"goto", SQL_GOTO},
-   {"immediate", SQL_IMMEDIATE},
+        {"identified", SQL_IDENTIFIED},
+        {"immediate", SQL_IMMEDIATE},
    {"indicator", SQL_INDICATOR},
    {"open", SQL_OPEN},
    {"release", SQL_RELEASE},
index 6faa36be883a988b3870d9d0d25a36ebc0ce7eeb..e18bb33219c78e81099188e0e17646a01226f288 100644 (file)
@@ -1,4 +1,5 @@
 #include "parser/keywords.h"
+#include 
 
 /* variables */
 
@@ -47,7 +48,8 @@ extern void yyerror(char *);
 /* return codes */
 
 #define OK     0
-#define NO_INCLUDE_FILE    1
-#define PARSE_ERROR    2
-#define OUT_OF_MEMORY  3
-#define ILLEGAL_OPTION 4
+#define PARSE_ERROR    -1
+#define ILLEGAL_OPTION -2
+
+#define NO_INCLUDE_FILE    ENOENT
+#define OUT_OF_MEMORY  ENOMEM
index 4d8722f69df69a9ccc8db99413f54c04038f82bb..9f953cb98f510bd53c1ea7b7e3a1cdc45c3be76f 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.1 1998/04/21 13:23:06 scrappy Exp $
+ *   $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.2 1998/05/18 16:05:00 scrappy Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -189,6 +189,8 @@ static ScanKeyword ScanKeywords[] = {
    {"substring", SUBSTRING},
    {"table", TABLE},
    {"time", TIME},
+   {"timezone_hour", TIMEZONE_HOUR},
+   {"timezone_minute", TIMEZONE_MINUTE},
    {"to", TO},
    {"trailing", TRAILING},
    {"transaction", TRANSACTION},
index 146938bf7df963d74774426a8c92d7087ac895d1..c9f0cd459b5d2f810127e146b13d357b690838bd 100644 (file)
@@ -139,12 +139,13 @@ self          [,()\[\].$\:\+\-\*\/\<\>\=\|]
 op_and_self        [\~\!\@\#\%\^\&\|\`\?\$\:\+\-\*\/\<\>\=]
 operator       {op_and_self}+
 
-xminteger              {integer}/-
-xmreal                 {real}/{space}*-{digit}
 xmstop         -
 
-integer            -?{digit}+
-real           -?{digit}+\.{digit}+([Ee][-+]?{digit}+)?
+integer            [\-]?{digit}+
+/*
+real           [\-]?{digit}+\.{digit}+([Ee][-+]?{digit}+)?
+*/
+real           [\-]?(((({digit}*\.{digit}+)|({digit}+\.{digit}*))([Ee][-+]?{digit}+)?)|({digit}+[Ee][-+]?{digit}+))
 
 param          \${integer}
 
@@ -309,7 +310,8 @@ before_comment);
 
 {typecast}            {   return TYPECAST; }
 
-{self}/-[\.0-9]       {
+{self}/{space}*-[\.0-9]   {
+                   BEGIN(xm);
                    return (yytext[0]);
                }
 {self}                {   return (yytext[0]); }
index b4fa4f2e38c5d6f401db3c60521b406ffc7a2b46..5e99e7190d9630a4d45fcb6e609d3c0a8f716f0b 100644 (file)
@@ -70,11 +70,13 @@ whenever_action(int mode)
 {
    if (mode == 1 && when_nf.code != W_NOTHING)
    {
+       output_line_number();
        fprintf(yyout, "\nif (sqlca.sqlcode == ECPG_NOT_FOUND) ");
        print_action(&when_nf);
    }
    if (when_error.code != W_NOTHING)
         {
+       output_line_number();
                 fprintf(yyout, "\nif (sqlca.sqlcode < 0) ");
        print_action(&when_error);
         }
@@ -112,7 +114,7 @@ static struct variable * find_variable(char * name);
 static struct variable *
 find_struct_member(char *name, char *str, struct ECPGstruct_member *members)
 {
-    char *next = strpbrk(++str, ".-"), c = '\0';
+    char *next = strchr(++str, '.'), c = '\0';
 
     if (next != NULL)
     {
@@ -129,6 +131,8 @@ find_struct_member(char *name, char *str, struct ECPGstruct_member *members)
            /* found the end */
            switch (members->typ->typ)
            {
+              case ECPGt_array:
+               return(new_variable(name, ECPGmake_array_type(members->typ->u.element, members->typ->size)));
               case ECPGt_struct:
                return(new_variable(name, ECPGmake_struct_type(members->typ->u.members)));
               default:
@@ -138,8 +142,12 @@ find_struct_member(char *name, char *str, struct ECPGstruct_member *members)
        else
        {
            *next = c;
-           if (c == '-') next++;
-           return(find_struct_member(name, next, members->typ->u.members));
+           if (c == '-')
+           {
+               next++;
+               return(find_struct_member(name, next, members->typ->u.element->u.members));
+           }
+           else return(find_struct_member(name, next, members->typ->u.members));
        }
    }
     }
@@ -159,9 +167,12 @@ find_struct(char * name, char *next)
 
     /* restore the name, we will need it later on */
     *next = c;
-    if (*next == '-') next++;
-
-    return (find_struct_member(name, next, p->type->u.members));
+    if (c == '-')
+    {
+   next++;
+   return (find_struct_member(name, next, p->type->u.element->u.members));
+    }
+    else return (find_struct_member(name, next, p->type->u.members));
 }
 
 static struct variable *
@@ -178,12 +189,20 @@ find_simple(char * name)
     return(NULL);
 }
 
+/* Note that this function will end the program in case of an unknown */
+/* variable */
 static struct variable *
 find_variable(char * name)
 {
     char * next;
-    struct variable * p =
-       ((next = strpbrk(name, ".-")) != NULL) ? find_struct(name, next) : find_simple(name);
+    struct variable * p;
+
+    if ((next = strchr(name, '.')) != NULL)
+   p = find_struct(name, next);
+    else if ((next = strstr(name, "->")) != NULL)
+   p = find_struct(name, next);
+    else
+   p = find_simple(name);
 
     if (p == NULL)
     {
@@ -231,7 +250,6 @@ struct arguments {
     struct arguments * next;
 };
 
-
 static struct arguments * argsinsert = NULL;
 static struct arguments * argsresult = NULL;
 
@@ -495,8 +513,9 @@ output_statement(char * stmt, int mode)
 }
 
 /* special embedded SQL token */
-%token     SQL_BREAK SQL_CALL SQL_CONNECT SQL_CONTINUE SQL_DISCONNECT SQL_FOUND SQL_GO SQL_GOTO
-%token     SQL_IMMEDIATE SQL_INDICATOR SQL_OPEN SQL_RELEASE
+%token     SQL_BREAK SQL_CALL SQL_CONNECT SQL_CONNECTION SQL_CONTINUE
+%token     SQL_DISCONNECT SQL_FOUND SQL_GO SQL_GOTO
+%token     SQL_IDENTIFIED SQL_IMMEDIATE SQL_INDICATOR SQL_OPEN SQL_RELEASE
 %token     SQL_SECTION SQL_SEMI SQL_SQLERROR SQL_SQLPRINT SQL_START
 %token     SQL_STOP SQL_WHENEVER
 
@@ -527,8 +546,9 @@ output_statement(char * stmt, int mode)
                 PARTIAL, POSITION, PRECISION, PRIMARY, PRIVILEGES, PROCEDURE, PUBLIC,
                 REFERENCES, REVOKE, RIGHT, ROLLBACK,
                 SECOND_P, SELECT, SET, SUBSTRING,
-                TABLE, TIME, TIMESTAMP, TO, TRAILING, TRANSACTION, TRIM,
-                UNION, UNIQUE, UPDATE, USING,
+                TABLE, TIME, TIMESTAMP, TIMEZONE_HOUR, TIMEZONE_MINUTE,
+       TO, TRAILING, TRANSACTION, TRIM,
+                UNION, UNIQUE, UPDATE, USER, USING,
                 VALUES, VARCHAR, VARYING, VIEW,
                 WHERE, WITH, WORK, YEAR_P, ZONE
 
@@ -559,7 +579,7 @@ output_statement(char * stmt, int mode)
  *
  *                                    Todd A. Brandys
  */
-%token  USER, PASSWORD, CREATEDB, NOCREATEDB, CREATEUSER, NOCREATEUSER, VALID, UNTIL
+%token  PASSWORD, CREATEDB, NOCREATEDB, CREATEUSER, NOCREATEUSER, VALID, UNTIL
 
 /* Special keywords, not in the query language - see the "lex" file */
 %token     IDENT SCONST Op CSTRING CVARIABLE
@@ -620,7 +640,7 @@ output_statement(char * stmt, int mode)
 %type     sortby OptUseOp opt_inh_star relation_name_list name_list
 %type     group_clause groupby_list groupby having_clause from_clause
 %type     from_list from_val join_expr join_outer join_spec join_list
-%type     join_using where_clause relation_expr
+%type     join_using where_clause relation_expr row_op sub_type
 %type     opt_column_list insert_rest InsertStmt
 %type      columnList DeleteStmt LockStmt UpdateStmt CursorStmt
 %type      NotifyStmt columnElem copy_dirn OptimizableStmt
@@ -650,12 +670,16 @@ output_statement(char * stmt, int mode)
 %type      DestroydbStmt ClusterStmt grantee RevokeStmt
 %type     GrantStmt privileges operation_commalist operation
 
-%type     ECPGWhenever ECPGConnect db_name ECPGOpen open_opts
+%type     ECPGWhenever ECPGConnect connection_target ECPGOpen open_opts
 %type     indicator ECPGExecute c_expr variable_list dotext
 %type      storage_clause opt_initializer vartext c_anything blockstart
 %type      blockend variable_list variable var_anything sql_anything
 %type     opt_pointer ecpg_ident cvariable ECPGDisconnect dis_name
-%type     stmt symbol opt_symbol ECPGRelease execstring
+%type     stmt symbol opt_symbol ECPGRelease execstring server_name
+%type     connection_object opt_server opt_port
+%type      user_name opt_user char_variable ora_user ident
+%type      db_prefix server opt_options opt_connection_name
+%type     ECPGSetConnection
 
 %type   simple_type type struct_type
 
@@ -721,12 +745,12 @@ stmt:  AddAttrStmt            { output_statement($1, 0); }
        | VariableShowStmt  { output_statement($1, 0); }
        | VariableResetStmt { output_statement($1, 0); }
        | ECPGConnect       {
-                       fprintf(yyout, "ECPGconnect(\"%s\");", $1); 
+                       fprintf(yyout, "ECPGconnect(__LINE__, %s);", $1);
                        whenever_action(0);
                        free($1);
                    } 
        | ECPGDisconnect    {
-                       fprintf(yyout, "ECPGdisconnect(\"%s\");", $1); 
+                       fprintf(yyout, "ECPGdisconnect(__LINE__, \"%s\");", $1); 
                        whenever_action(0);
                        free($1);
                    } 
@@ -737,6 +761,11 @@ stmt:  AddAttrStmt         { output_statement($1, 0); }
                    }
        | ECPGOpen      { output_statement($1, 0); }
        | ECPGRelease       { /* output already done */ }
+       | ECPGSetConnection     {
+                       fprintf(yyout, "ECPGsetcon(__LINE__, %s);", $1);
+                       whenever_action(0);
+                                               free($1);
+                   }
        | ECPGWhenever      {
                        fputs($1, yyout);
                        output_line_number();
@@ -828,7 +857,7 @@ user_group_clause:  IN GROUP user_group_list    { $$ = cat2_str(make1_str("in group
            | /*EMPTY*/     { $$ = make1_str(""); }
        ;
 
-user_valid_clause:  VALID UNTIL SCONST         { $$ = cat2_str(make1_str("valid until"), $3);; }
+user_valid_clause:  VALID UNTIL Sconst         { $$ = cat2_str(make1_str("valid until"), $3);; }
            | /*EMPTY*/         { $$ = make1_str(""); }
        ;
 
@@ -853,6 +882,7 @@ VariableSetStmt:  SET ColId TO var_value
                {
                    $$ = cat2_str(make1_str("set time zone"), $4);
                }
+
        ;
 
 var_value:  Sconst         { $$ = $1; }
@@ -1136,7 +1166,9 @@ default_expr:  AexprConst
                    $$ = "current_timestamp";
                }
            | CURRENT_USER
-               {   $$ = make1_str("current user"); }
+               {   $$ = make1_str("current_user"); }
+           | USER
+               {       $$ = make1_str("user"); }
        ;
 
 /* ConstraintElem specifies constraint syntax which is not embedded into
@@ -1459,7 +1491,7 @@ TriggerFuncArg:  Iconst
                    $$ = make_name();
                }
            | Sconst    {  $$ = $1; }
-           | ecpg_ident        {  $$ = $1; }
+           | ident     {  $$ = $1; }
        ;
 
 DropTrigStmt:  DROP TRIGGER name ON relation_name
@@ -2434,8 +2466,10 @@ groupby:  ColId
 
 having_clause:  HAVING a_expr
                {
+#if FALSE
                    yyerror("HAVING clause not yet implemented");
-/*                 $$ = cat2_str(make1_str("having"), $2); use this line instead to enable HAVING */
+#endif
+                   $$ = cat2_str(make1_str("having"), $2);
                }
        | /*EMPTY*/     { $$ = make1_str(""); }
        ;
@@ -2610,7 +2644,7 @@ Generic:  generic
                }
        ;
 
-generic:  ecpg_ident                   { $$ = $1; }
+generic:  ident                    { $$ = $1; }
        | TYPE_P            { $$ = make1_str("type"); }
        ;
 
@@ -2724,7 +2758,7 @@ opt_decimal:  '(' Iconst ',' Iconst ')'
 Character:  character '(' Iconst ')'
                {
                    if (strncasecmp($1, "char", strlen("char")) && strncasecmp($1, "varchar", strlen("varchar")))
-                       yyerror("parse error");
+                       yyerror("internal parsing error; unrecognized character type");
                    if (atol($3) < 1) {
                        sprintf(errortext, "length for '%s' type must be at least 1",$1);
                        yyerror(errortext);
@@ -2749,10 +2783,9 @@ Character:  character '(' Iconst ')'
 
 character:  CHARACTER opt_varying opt_charset opt_collate
                {
-                   if (strlen($4) > 0) {
-                       sprintf(errortext, "COLLATE %s not yet implemented",$4);
-                       yyerror(errortext);
-                   }
+                   if (strlen($4) > 0) 
+                       fprintf(stderr, "COLLATE %s not yet implemented",$4);
+
                    $$ = cat4_str(make1_str("character"), $2, $3, $4);
                }
        | CHAR opt_varying  { $$ = cat2_str(make1_str("char"), $2); }
@@ -2809,6 +2842,7 @@ opt_interval:  datetime                   { $$ = $1; }
        | DAY_P TO MINUTE_P         { $$ = make1_str("day to minute"); }
        | DAY_P TO SECOND_P         { $$ = make1_str("day to second"); }
        | HOUR_P TO MINUTE_P            { $$ = make1_str("hour to minute"); }
+       | MINUTE_P TO SECOND_P          { $$ = make1_str("minute to second"); }
        | HOUR_P TO SECOND_P            { $$ = make1_str("hour to second"); }
        | /*EMPTY*/                 { $$ = make1_str(""); }
        ;
@@ -2831,6 +2865,11 @@ a_expr_or_null:  a_expr
 /* Expressions using row descriptors
  * Define row_descriptor to allow yacc to break the reduce/reduce conflict
  *  with singleton expressions.
+ * Eliminated lots of code by defining row_op and sub_type clauses.
+ * However, can not consolidate EXPR_LINK case with others subselects
+ *  due to shift/reduce conflict with the non-subselect clause (the parser
+ *  would have to look ahead more than one token to resolve the conflict).
+ * - thomas 1998-05-09
  */
 row_expr: '(' row_descriptor ')' IN '(' SubSelect ')'
                {
@@ -2840,134 +2879,18 @@ row_expr: '(' row_descriptor ')' IN '(' SubSelect ')'
                {
                    $$ = make5_str(make1_str("("), $2, make1_str(") not in ("), $7, make1_str(")"));
                }
-       | '(' row_descriptor ')' Op '(' SubSelect ')'
-               {
-                   $$ = make3_str(make5_str(make1_str("("), $2, make1_str(")"), $4, make1_str("(")), $6, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '+' '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")+("), $6, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '-' '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")-("), $6, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '/' '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")/("), $6, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '*' '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")*("), $6, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '<' '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")<("), $6, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '>' '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")>("), $6, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '=' '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")=("), $6, make1_str(")"));
-               }
-       | '(' row_descriptor ')' Op ANY '(' SubSelect ')'
-               {
-                   $$ = cat3_str(make3_str(make1_str("("), $2, make1_str(")")), $4, make3_str(make1_str("any("), $7, make1_str(")")));
-               }
-       | '(' row_descriptor ')' '+' ANY '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")+any("), $7, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '-' ANY '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")-any("), $7, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '/' ANY '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")/any("), $7, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '*' ANY '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")*any("), $7, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '<' ANY '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")
-               }
-       | '(' row_descriptor ')' '>' ANY '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")>any("), $7, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '=' ANY '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")=any("), $7, make1_str(")"));
-               }
-       | '(' row_descriptor ')' Op ALL '(' SubSelect ')'
-               {
-                   $$ = cat3_str(make3_str(make1_str("("), $2, make1_str(")")), $4, make3_str(make1_str("all("), $7, make1_str(")")));
-               }
-       | '(' row_descriptor ')' '+' ALL '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")+all("), $7, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '-' ALL '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")-all("), $7, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '/' ALL '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")/all("), $7, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '*' ALL '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")*all("), $7, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '<' ALL '(' SubSelect ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")
-               }
-       | '(' row_descriptor ')' '>' ALL '(' SubSelect ')'
+       | '(' row_descriptor ')' row_op sub_type  '(' SubSelect ')'
                {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")>all("), $7, make1_str(")"));
+                   $$ = make4_str(make5_str(make1_str("("), $2, make1_str(")"), $4, $5), make1_str("("), $7, make1_str(")"));
                }
-       | '(' row_descriptor ')' '=' ALL '(' SubSelect ')'
+       | '(' row_descriptor ')' row_op '(' SubSelect ')'
                {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")=all("), $7, make1_str(")"));
+                   $$ = make3_str(make5_str(make1_str("("), $2, make1_str(")"), $4, make1_str("(")), $6, make1_str(")"));
                }
-       | '(' row_descriptor ')' Op '(' row_descriptor ')'
+       | '(' row_descriptor ')' row_op '(' row_descriptor ')'
                {
                    $$ = cat3_str(make3_str(make1_str("("), $2, make1_str(")")), $4, make3_str(make1_str("("), $6, make1_str(")")));
                }
-       | '(' row_descriptor ')' '+' '(' row_descriptor ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")+("), $6, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '-' '(' row_descriptor ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")-("), $6, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '/' '(' row_descriptor ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")/("), $6, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '*' '(' row_descriptor ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")*("), $6, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '<' '(' row_descriptor ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")<("), $6, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '>' '(' row_descriptor ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")>("), $6, make1_str(")"));
-               }
-       | '(' row_descriptor ')' '=' '(' row_descriptor ')'
-               {
-                   $$ = make5_str(make1_str("("), $2, make1_str(")=("), $6, make1_str(")"));
-               }
        ;
 
 row_descriptor:  row_list ',' a_expr
@@ -2976,6 +2899,21 @@ row_descriptor:  row_list ',' a_expr
                }
        ;
 
+row_op:  Op            { $$ = $1; }
+   | '<'                   { $$ = "<"; }
+        | '='                   { $$ = "="; }
+        | '>'                   { $$ = ">"; }
+        | '+'                   { $$ = "+"; }
+        | '-'                   { $$ = "-"; }
+        | '*'                   { $$ = "*"; }
+        | '/'                   { $$ = "/"; }
+              ;
+
+sub_type:  ANY                  { $$ = make1_str("ANY"); }
+         | ALL                  { $$ = make1_str("ALL"); }
+              ;
+
+
 row_list:  row_list ',' a_expr
                {
                    $$ = cat3_str($1, make1_str(","), $3);
@@ -3089,6 +3027,11 @@ a_expr:  attr opt_indirection
                {
                    $$ = make1_str("current_user");
                }
+       | USER
+               {
+                           $$ = make1_str("user");
+                   }
+
        | EXISTS '(' SubSelect ')'
                {
                    $$ = make3_str(make1_str("exists("), $3, make1_str(")"));
@@ -3358,6 +3301,10 @@ b_expr:  attr opt_indirection
                {
                    $$ = make1_str("current_user");
                }
+       | USER
+               {
+                   $$ = make1_str("user");
+               }
        | POSITION '(' position_list ')'
                {
                    $$ = make3_str(make1_str("position ("), $3, make1_str(")"));
@@ -3417,12 +3364,9 @@ extract_list:  extract_arg FROM a_expr
                    { $$ = make1_str(";;"); }
        ;
 
-/* Add in TIMEZONE_HOUR and TIMEZONE_MINUTE for SQL92 compliance
- *  for next release. Just set up extract_arg for now...
- * - thomas 1998-04-08
- */
-extract_arg:  datetime
-               {   $$ = $1; }
+extract_arg:  datetime     { $$ = $1; }
+   | TIMEZONE_HOUR     { $$ = make1_str("timezone_hour"); }    
+   | TIMEZONE_MINUTE   { $$ = make1_str("timezone_minute"); }  
        ;
 
 position_list:  position_expr IN position_expr
@@ -3660,9 +3604,9 @@ relation_name:    SpecialRuleRelation
        ;
 
 database_name:         ColId           { $$ = $1; };
-access_method:         ecpg_ident          { $$ = $1; };
+access_method:         ident           { $$ = $1; };
 attr_name:             ColId           { $$ = $1; };
-class:                 ecpg_ident          { $$ = $1; };
+class:                 ident           { $$ = $1; };
 index_name:                ColId           { $$ = $1; };
 
 /* Functions
@@ -3673,7 +3617,7 @@ name:                 ColId           { $$ = $1; };
 func_name:             ColId           { $$ = $1; };
 
 file_name:             Sconst          { $$ = $1; };
-recipe_name:           ecpg_ident          { $$ = $1; };
+recipe_name:           ident           { $$ = $1; };
 
 /* Constants
  * Include TRUE/FALSE for SQL3 support. - thomas 1997-10-24
@@ -3723,8 +3667,9 @@ Sconst:  SCONST                                 {
                                    strcpy($$+1, $1);
                            $$[strlen($1)+2]='\0';
                            $$[strlen($1)+1]='\'';
+                           free($1);
                        }
-UserId:  ecpg_ident                                  { $$ = $1;};
+UserId:  ident                                  { $$ = $1;};
 
 /* Column and type identifier
  * Does not include explicit datetime types
@@ -3746,7 +3691,7 @@ TypeId:  ColId
  *  list due to shift/reduce conflicts in yacc. If so, move
  *  down to the ColLabel entity. - thomas 1997-11-06
  */
-ColId:  ecpg_ident                         { $$ = $1; }
+ColId:  ident                          { $$ = $1; }
        | datetime                      { $$ = $1; }
        | ACTION                        { $$ = make1_str("action"); }
        | CACHE                         { $$ = make1_str("cache"); }
@@ -3773,9 +3718,10 @@ ColId:  ecpg_ident                           { $$ = $1; }
        | START                         { $$ = make1_str("start"); }
        | STATEMENT                     { $$ = make1_str("statement"); }
        | TIME                          { $$ = make1_str("time"); }
+       | TIMEZONE_HOUR                                 { $$ = make1_str("timezone_hour"); }
+                | TIMEZONE_MINUTE                               { $$ = make1_str("timezone_minute"); }
        | TRIGGER                       { $$ = make1_str("trigger"); }
        | TYPE_P                        { $$ = make1_str("type"); }
-       | USER                          { $$ = make1_str("user"); }
        | VALID                         { $$ = make1_str("valid"); }
        | VERSION                       { $$ = make1_str("version"); }
        | ZONE                          { $$ = make1_str("zone"); }
@@ -4011,8 +3957,8 @@ variable: opt_pointer symbol opt_array_bounds opt_initializer
            if (struct_level == 0)
                new_variable($2, type);
            else
-                   ECPGmake_struct_member($2, type, &(struct_member_list[struct_level-1]));
-           
+               ECPGmake_struct_member($2, type, &(struct_member_list[struct_level - 1]))->typ;
+
            free($1);
            free($2);
            free($3.str);
@@ -4028,10 +3974,114 @@ opt_pointer: /* empty */   { $$ = make1_str(""); }
 /*
  * the exec sql connect statement: connect to the given database 
  */
-ECPGConnect: SQL_CONNECT db_name { $$ = $2; }
+ECPGConnect: SQL_CONNECT TO connection_target opt_connection_name opt_user
+       {
+           $$ = make5_str($3, make1_str(","), $5, make1_str(","), $4);
+                }
+   | SQL_CONNECT TO DEFAULT
+           {
+                   $$ = make1_str("NULL,NULL,NULL,\"DEFAULT\"");
+                }
+      /* also allow ORACLE syntax */
+        | SQL_CONNECT ora_user
+                {
+              $$ = make3_str(make1_str("NULL,"), $2, make1_str(",NULL"));
+       }
+
+connection_target: database_name opt_server opt_port
+                {
+         /* old style: dbname[@server][:port] */
+         if (strlen($2) > 0 && *($2) != '@')
+         {
+           sprintf(errortext, "parse error at or near '%s'", $2);
+           yyerror(errortext);
+         }
 
-db_name: database_name { $$ = $1; }
-   | cvariable { /* check if we have a char variable */
+         $$ = make5_str(make1_str("\""), $1, $2, $3, make1_str("\""));
+       }
+        |  db_prefix server opt_port '/' database_name opt_options
+                {
+         /* new style: esql:postgresql://server[:port][/dbname] */
+                  if (strncmp($2, "://", 3) != 0)
+         {
+           sprintf(errortext, "parse error at or near '%s'", $2);
+           yyerror(errortext);
+         }
+   
+         $$ = make4_str(make5_str(make1_str("\""), $1, $2, $3, make1_str("/")), $5, $6, make1_str("\""));
+       }
+   | char_variable
+                {
+         $$ = $1;
+       }
+
+db_prefix: ident cvariable
+                {
+         if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0)
+         {
+           sprintf(errortext, "parse error at or near '%s'", $2);
+           yyerror(errortext); 
+         }
+
+         if (strcmp($1, "esql") != 0 && strcmp($1, "ecpg") != 0 && strcmp($1, "sql") != 0 && strcmp($1, "isql") != 0 && strcmp($1, "proc") != 0)
+         {
+           sprintf(errortext, "Illegal connection type %s", $1);
+           yyerror(errortext);
+         }
+
+         $$ = make3_str($1, make1_str(":"), $2);
+       }
+        
+server: Op server_name
+                {
+         if (strcmp($1, "@") != 0 && strcmp($1, "://") != 0)
+         {
+           sprintf(errortext, "parse error at or near '%s'", $1);
+           yyerror(errortext);
+         }
+
+         $$ = make2_str($1, $2);
+           }
+
+opt_server: server { $$ = $1; }
+        | /* empty */ { $$ = make1_str(""); }
+
+server_name: ColId   { $$ = $1; }
+        | ColId '.' server_name { $$ = make3_str($1, make1_str("."), $3); }
+
+opt_port: ':' Iconst { $$ = make2_str(make1_str(":"), $2); }
+        | /* empty */ { $$ = make1_str(""); }
+
+opt_connection_name: AS connection_target { $$ = $2; }
+        | /* empty */ { $$ = make1_str("NULL"); }
+
+opt_user: USER ora_user { $$ = $2; }
+          | /* empty */ { $$ = make1_str("NULL,NULL"); }
+
+ora_user: user_name
+       {
+                        $$ = make2_str($1, make1_str(",NULL"));
+           }
+   | user_name '/' ColId
+       {
+               $$ = make3_str($1, make1_str(","), $3);
+                }
+        | user_name SQL_IDENTIFIED BY user_name
+                {
+               $$ = make3_str($1, make1_str(","), $4);
+                }
+        | user_name USING user_name
+                {
+               $$ = make3_str($1, make1_str(","), $3);
+                }
+
+user_name: UserId       { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); }
+        | char_variable { $$ = $1; }
+        | CSTRING       { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); }
+        | SCONST        { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); }
+
+char_variable: cvariable
+       { /* check if we have a char variable */
            struct variable *p = find_variable($1);
            enum ECPGttype typ = p->type->typ;
 
@@ -4039,33 +4089,48 @@ db_name: database_name { $$ = $1; }
            if (typ == ECPGt_array)
                typ = p->type->u.element->typ;
 
-           if (typ != ECPGt_char && typ != ECPGt_unsigned_char)
-               yyerror("invalid datatype");
-           $$ = $1;
-   }
+                        switch (typ)
+                        {
+                            case ECPGt_char:
+                            case ECPGt_unsigned_char:
+                                $$ = $1;
+                                break;
+                            case ECPGt_varchar:
+                                $$ = make2_str($1, make1_str(".arr"));
+                                break;
+                            default:
+                                yyerror("invalid datatype");
+                                break;
+                        }
+       }
+
+opt_options: Op ColId
+       {
+           if (strlen($1) == 0)
+               yyerror("parse error");
+               
+           if (strcmp($1, "?") != 0)
+           {
+               sprintf(errortext, "parse error at or near %s", $1);
+               yyerror(errortext);
+           }
+           
+           $$ = make2_str(make1_str("?"), $2);
+       }
+   | /* empty */ { $$ = make1_str(""); }
 
 /*
  * the exec sql disconnect statement: disconnect from the given database 
  */
 ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; }
 
-dis_name: database_name    { $$ = $1; }
-   | cvariable { /* check if we have a char variable */
-               struct variable *p = find_variable($1);
-               enum ECPGttype typ = p->type->typ;
+dis_name: connection_object    { $$ = $1; }
+   | CURRENT   { $$ = make1_str("CURRENT"); }
+   | ALL       { $$ = make1_str("ALL"); }
+   | /* empty */   { $$ = make1_str("CURRENT"); }
 
-               /* if array see what's inside */
-               if (typ == ECPGt_array)
-                   typ = p->type->u.element->typ;
-
-               if (typ != ECPGt_char && typ != ECPGt_unsigned_char)
-                   yyerror("invalid datatype");
-               $$ = $1;
-           }
-   | CURRENT   { $$ = make1_str(""); }
-   | DEFAULT   { $$ = make1_str(""); }
-   | ALL       { $$ = make1_str(""); }
-   | /* empty */   { $$ = make1_str(""); }
+connection_object: connection_target { $$ = $1; }
+   | DEFAULT   { $$ = make1_str("DEFAULT"); }
 
 /*
  * execute a given string as sql command
@@ -4118,6 +4183,14 @@ ECPGRelease: TransactionStmt SQL_RELEASE
        free($1);
    }
 
+/* 
+ * set the actual connection, this needs a differnet handling as the other
+ * set commands
+ */
+ECPGSetConnection:  SET SQL_CONNECTION connection_object
+                   {
+               $$ = $3;
+                        }
 /*
  * whenever statement: decide what to do in case of error/no data found
  * according to SQL standards we miss: SQLSTATE, CONSTRAINT, SQLEXCEPTION
@@ -4163,7 +4236,7 @@ action : SQL_CONTINUE {
        | DO name '(' dotext ')' {
    $$.code = W_DO;
    $$.command = make4_str($2, make1_str("("), $4, make1_str(")"));
-   $$.str = cat2_str(make1_str("do"), $$.command);
+   $$.str = cat2_str(make1_str("do"), strdup($$.command));
 }
        | DO SQL_BREAK {
         $$.code = W_BREAK;
@@ -4173,7 +4246,7 @@ action : SQL_CONTINUE {
        | SQL_CALL name '(' dotext ')' {
    $$.code = W_DO;
    $$.command = make4_str($2, make1_str("("), $4, make1_str(")"));
-   $$.str = cat2_str(make1_str("call"), $$.command);
+   $$.str = cat2_str(make1_str("call"), strdup($$.command));
 }
 
 /* some other stuff for ecpg */
@@ -4478,14 +4551,16 @@ civariableonly : cvariable name {
        add_variable(&argsinsert, find_variable($1), &no_indicator); 
 }
 
-cvariable: CVARIABLE           { $$ = $1; }
+cvariable: CVARIABLE           { $$ = make1_str($1); }
 
 indicator: /* empty */         { $$ = NULL; }
    | cvariable         { check_indicator((find_variable($1))->type); $$ = $1; }
    | SQL_INDICATOR cvariable   { check_indicator((find_variable($2))->type); $$ = $2; }
    | SQL_INDICATOR name        { check_indicator((find_variable($2))->type); $$ = $2; }
 
-ecpg_ident: IDENT  { $$ = $1; }
+ident: IDENT   { $$ = make1_str($1); }
+
+ecpg_ident: ident  { $$ = $1; }
    | CSTRING   { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); }
 /*
  * C stuff
index cbc7446909e37a12944ba6d6afe3e58c5fe3a6f2..ce0e1b0cd20f844d47a341c7cd070e4ad4add6f7 100644 (file)
@@ -20,21 +20,6 @@ mm_alloc(size_t size)
    return (ptr);
 }
 
-/* realloc + error check */
-void *
-mm_realloc(void *ptr, size_t size)
-{
-   ptr = realloc(ptr, size);
-
-   if (ptr == NULL)
-   {
-       fprintf(stderr, "Out of memory\n");
-       exit(OUT_OF_MEMORY);
-   }
-
-   return (ptr);
-}
-
 /* duplicate memberlist */
 static struct ECPGstruct_member *
 struct_member_dup(struct ECPGstruct_member * rm)
@@ -43,7 +28,22 @@ struct_member_dup(struct ECPGstruct_member * rm)
 
   while (rm)
     {
-      ECPGmake_struct_member(rm->name, rm->typ, &new);
+      struct ECPGtype *type;
+      
+      switch(rm->typ->typ)
+      {
+       case ECPGt_struct:
+           type = ECPGmake_struct_type(rm->typ->u.members);
+           break;
+       case ECPGt_array:
+           type = ECPGmake_array_type(ECPGmake_simple_type(rm->typ->u.element->typ, rm->typ->u.element->size), rm->typ->size);
+       break;          
+       default:
+           type = ECPGmake_simple_type(rm->typ->typ, rm->typ->size);
+           break;
+      }
+      
+      ECPGmake_struct_member(rm->name, type, &new);
    
       rm = rm->next;
     }
@@ -165,11 +165,11 @@ static const char *get_type(enum ECPGttype typ)
    size is the maxsize in case it is a varchar. Otherwise it is the size of
    the variable (required to do array fetches of structs).
  */
-void
+static void
 ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
                  long varcharsize,
                  long arrsiz, const char *siz, const char *prefix);
-void
+static void
 ECPGdump_a_struct(FILE *o, const char *name, const char *ind_name, long arrsiz,
          struct ECPGtype * typ, struct ECPGtype * ind_typ, const char *offset, const char *prefix, const char * ind_prefix);
 
@@ -223,7 +223,7 @@ ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *in
 
 /* If siz is NULL, then the offset is 0, if not use siz as a
    string, it represents the offset needed if we are in an array of structs. */
-void
+static void
 ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
                  long varcharsize,
                  long arrsize,
@@ -272,7 +272,7 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
 
 
 /* Penetrate a struct and dump the contents. */
-void
+static void
 ECPGdump_a_struct(FILE *o, const char *name, const char * ind_name, long arrsiz, struct ECPGtype * typ, struct ECPGtype * ind_typ, const char *offsetarg, const char *prefix, const char *ind_prefix)
 {
 
@@ -319,6 +319,7 @@ ECPGfree_struct_member(struct ECPGstruct_member * rm)
       
       rm = rm->next;
       free(p->name);
+      free(p->typ);
       free(p);
     }
 }
@@ -337,7 +338,7 @@ ECPGfree_type(struct ECPGtype * typ)
            else if (typ->u.element->typ == ECPGt_struct)
            {
                /* Array of structs. */
-                   ECPGfree_struct_member(typ->u.members);
+                   ECPGfree_struct_member(typ->u.element->u.members);
                free(typ->u.members);
            }
            else
index f56d814dd98fb269d86ac9fc12dcc1c9e835f36f..6ec604d47f7a1b58c182c97ff39b45e40ce315f2 100644 (file)
@@ -28,7 +28,7 @@ exec sql begin declare section;
 exec sql end declare section;
    struct timeval tvs, tve;
 
-   exec sql connect mm;
+   exec sql connect to mm;
 
    exec sql create table perftest1(number int4, ascii char(16));
 
index 3363af07b1ff50b1f08e5453b6fd86774dce07fb..c485a487fce68b5d2efe39d3721f25aa7765540a 100644 (file)
@@ -19,7 +19,7 @@ exec sql end declare section;
                 ECPGdebug(1, dbgs);
 
    strcpy(msg, "connect");
-   exec sql connect mm;
+   exec sql connect to mm;
 
    strcpy(msg, "create");
    exec sql create table test(name char(8), amount int);
index ed0599cdeaf70ac8c29318bce125f672c3e3638c..3b7ff3f9d55e7ab791d5ec6d838dec6cba6b89a1 100644 (file)
@@ -11,9 +11,9 @@ exec sql begin declare section;
                                short age;
                    } birth;
                } personal;
-   struct personal_indicator { short name;
-                   struct birth_indicator {    short born;
-                                   int age;
+   struct personal_indicator { short ind_name;
+                   struct birth_indicator {    short ind_born;
+                                   int ind_age;
                    } ind_birth;
                  } ind_personal;
    long ind_married;
@@ -26,7 +26,7 @@ exec sql end declare section;
                 ECPGdebug(1, dbgs);
 
    strcpy(msg, "connect");
-   exec sql connect mm;
+   exec sql connect to mm;
 
    strcpy(msg, "create");
    exec sql create table meskes(name char(8), born integer, age smallint, married char(8));