]> granicus.if.org Git - postgresql/commitdiff
From: Michael Meskes <meskes@topsystem.de>
authorMarc G. Fournier <scrappy@hub.org>
Mon, 18 May 1998 16:05:05 +0000 (16:05 +0000)
committerMarc G. Fournier <scrappy@hub.org>
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:
+               - <dbname>[@<server>][:<port>]
+               - esql:postgresql://<server>[:<port>][/<dbname>]
+
+ 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:
+               - <dbname>[@<server>][:<port>]
+               - esql:postgresql://<server>[:<port>][/<dbname>]
+
+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 <errno.h>
+
 /* 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 <errno.h>
 
 /* 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);
 
 <SQL>{typecast}                        {       return TYPECAST; }
 
-<SQL>{self}/-[\.0-9]           {
+<SQL>{self}/{space}*-[\.0-9]   {
+                                       BEGIN(xm);
                                        return (yytext[0]);
                                }
 <SQL>{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 <str>    IDENT SCONST Op CSTRING CVARIABLE
@@ -620,7 +640,7 @@ output_statement(char * stmt, int mode)
 %type  <str>   sortby OptUseOp opt_inh_star relation_name_list name_list
 %type  <str>   group_clause groupby_list groupby having_clause from_clause
 %type  <str>   from_list from_val join_expr join_outer join_spec join_list
-%type  <str>   join_using where_clause relation_expr
+%type  <str>   join_using where_clause relation_expr row_op sub_type
 %type  <str>   opt_column_list insert_rest InsertStmt
 %type  <str>    columnList DeleteStmt LockStmt UpdateStmt CursorStmt
 %type  <str>    NotifyStmt columnElem copy_dirn OptimizableStmt
@@ -650,12 +670,16 @@ output_statement(char * stmt, int mode)
 %type  <str>    DestroydbStmt ClusterStmt grantee RevokeStmt
 %type  <str>   GrantStmt privileges operation_commalist operation
 
-%type  <str>   ECPGWhenever ECPGConnect db_name ECPGOpen open_opts
+%type  <str>   ECPGWhenever ECPGConnect connection_target ECPGOpen open_opts
 %type  <str>   indicator ECPGExecute c_expr variable_list dotext
 %type  <str>    storage_clause opt_initializer vartext c_anything blockstart
 %type  <str>    blockend variable_list variable var_anything sql_anything
 %type  <str>   opt_pointer ecpg_ident cvariable ECPGDisconnect dis_name
-%type  <str>   stmt symbol opt_symbol ECPGRelease execstring
+%type  <str>   stmt symbol opt_symbol ECPGRelease execstring server_name
+%type  <str>   connection_object opt_server opt_port
+%type  <str>    user_name opt_user char_variable ora_user ident
+%type  <str>    db_prefix server opt_options opt_connection_name
+%type  <str>   ECPGSetConnection
 
 %type  <type_enum> 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(")<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 ')' 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(")<all("), $7, 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 ')' {
        $<action>$.code = W_DO;
        $<action>$.command = make4_str($2, make1_str("("), $4, make1_str(")"));
-       $<action>$.str = cat2_str(make1_str("do"), $<action>$.command);
+       $<action>$.str = cat2_str(make1_str("do"), strdup($<action>$.command));
 }
        | DO SQL_BREAK {
         $<action>$.code = W_BREAK;
@@ -4173,7 +4246,7 @@ action : SQL_CONTINUE {
        | SQL_CALL name '(' dotext ')' {
        $<action>$.code = W_DO;
        $<action>$.command = make4_str($2, make1_str("("), $4, make1_str(")"));
-       $<action>$.str = cat2_str(make1_str("call"), $<action>$.command);
+       $<action>$.str = cat2_str(make1_str("call"), strdup($<action>$.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));