]> granicus.if.org Git - postgresql/commitdiff
Upgrade ECPG to 2.0
authorMarc G. Fournier <scrappy@hub.org>
Tue, 21 Apr 1998 13:23:24 +0000 (13:23 +0000)
committerMarc G. Fournier <scrappy@hub.org>
Tue, 21 Apr 1998 13:23:24 +0000 (13:23 +0000)
Michael Meskes <meskes@topsystem.de>

20 files changed:
src/interfaces/ecpg/ChangeLog
src/interfaces/ecpg/TODO
src/interfaces/ecpg/include/Makefile
src/interfaces/ecpg/include/ecpglib.h
src/interfaces/ecpg/include/ecpgtype.h
src/interfaces/ecpg/lib/Makefile.in
src/interfaces/ecpg/lib/ecpglib.c
src/interfaces/ecpg/preproc/Makefile
src/interfaces/ecpg/preproc/c_keywords.c [new file with mode: 0644]
src/interfaces/ecpg/preproc/ecpg.c
src/interfaces/ecpg/preproc/ecpg_keywords.c [new file with mode: 0644]
src/interfaces/ecpg/preproc/extern.h
src/interfaces/ecpg/preproc/keywords.c [new file with mode: 0644]
src/interfaces/ecpg/preproc/pgc.l
src/interfaces/ecpg/preproc/preproc.y
src/interfaces/ecpg/preproc/type.c
src/interfaces/ecpg/preproc/type.h
src/interfaces/ecpg/test/Makefile
src/interfaces/ecpg/test/perftest.pgc
src/interfaces/ecpg/test/test2.pgc

index f20a717dbc4883e94bbebac933109061b7359b88..e06e4ffa73d7a22e9ae685dad5f59b9e82dd2e30 100644 (file)
@@ -86,3 +86,43 @@ Fri Mar 13 13:35:13 CET 1998
 Mon Mar 16 15:09:10 CET 1998
 
        - fixed parser to print correct filename and line number
+
+Wed Mar 18 14:28:49 CET 1998
+
+       - started working on indicator variables
+
+Mon Mar 23 13:49:15 CET 1998
+
+       - fixed some bugs in indicator variable handling
+       - completely rewrote parser for fetch and insert statements
+       - indicator variables are also allowed in insert statements now
+
+Mon Mar 23 16:09:05 CET 1998
+
+       - fixed whenever command goto to only allow valid lables
+
+Thu Mar 26 13:33:02 MEZ 1998
+
+       - some minor bugfixes
+
+Mon Apr 20 13:06:09 CEST 1998
+
+       - database name no longer has to entered as string constant, i.e.
+         just remove the '...' around the name
+
+Mon Apr 20 14:38:45 CEST 1998
+
+       - both test cases compile cleanly
+
+Mon Apr 20 16:13:25 CEST 1998
+
+       - Phew! Finally finished parser rewriting.
+
+Mon Apr 20 16:39:23 CEST 1998
+
+       - Cursor is opened when the open command is issued, not at declare time.
+
+Tue Apr 21 12:53:49 CEST 1998
+
+       - Set indicator to amount of data really written (truncation).
+
index 4c7c15f40f0a886d55d1094d185eeb66421717c9..c74c273274651f77017d2dfba1bc054c08823f0c 100644 (file)
@@ -1,15 +1,6 @@
 This list is still from Linus. MM
 
 The variables should be static.
-    
-Preprocessor cannot do syntax checking on your SQL statements Whatever you
-write is copied more or less exactly to the PostgreSQL and you will not be
-able to locate your errors until run-time.
-    
-No restriction to strings only The PQ interface, and most of all the PQexec
-function, that is used by the ecpg relies on that the request is built up as
-a string. In some cases, like when the data contains the null character,
-this will be a serious problem.
 
 There should be different error numbers for the different errors instead of
 just -1 for them all.
@@ -21,12 +12,6 @@ ecpg it is done for compatibility reasons only. For them to improve speed
 would require a lot more insight in the postgres internal mechanisms than I
 possess.
     
-Oracle has indicator variables that tell if a value is null or if it is
-empty. This largely simplifies array operations and provides for a way to
-hack around some design flaws in the handling of VARCHAR2 (like that an
-empty string isn't distinguishable from a null value). I am not sure if this
-is an Oracle extension or part of the ANSI standard.
-    
 As well as complex types like records and arrays, typedefs would be a good
 thing to take care of.
     
@@ -43,8 +28,6 @@ Now comes my list (MM):
 The return code is alway -1 in case of an error. You cannot see which error
 occured by examining the return code.
 
-The cursor is opened when the declare statement is issued.
-
 ecpg does not understand enum datatypes.
 
 There is no exec sql prepare statement.
@@ -59,7 +42,16 @@ There is no way yet to fill a complete array with one call except arrays of
 
 ecpg cannot use pointer variables except [unsigned] char *
 
-List all commands as sqlcommand, not just S_SYMBOL or even better rewrite
-pareser to be equivalent to backendĀ“s parser.
+give back the number of tuples affected via sqlca
+
+exec sql disconnect {current|default|all|connectionname|connection_hostvar};
+ oder <disconnect statement> ::=
+    DISCONNECT <disconnect object>
+
+ <disconnect object> ::=
+      <connection object>
+    | ALL
+    | CURRENT
+ commit release|commit work release auch disconnect
 
-Set standard include paths.
+It is not neccessary to check for sql not found after all commands.
index bfb6840b68c2ac0985961c55a3233fbd6bdbd7d8..caa13a8d9162c69d4e97c1a012fec985c5934f53 100644 (file)
@@ -6,13 +6,13 @@ all clean::
        @echo Nothing to be done.
 
 install::
-       $(INSTALL) $(INSTLOPTS) ecpglib.h $(HEADERDIR)  
-       $(INSTALL) $(INSTLOPTS) ecpgtype.h $(HEADERDIR) 
-       $(INSTALL) $(INSTLOPTS) sqlca.h $(HEADERDIR)    
+       $(INSTALL) $(INSTLOPTS) ecpglib.h $(DESTDIR)$(HEADERDIR)        
+       $(INSTALL) $(INSTLOPTS) ecpgtype.h $(DESTDIR)$(HEADERDIR)       
+       $(INSTALL) $(INSTLOPTS) sqlca.h $(DESTDIR)$(HEADERDIR)  
 
 uninstall::
-       rm -f $(HEADERDIR)/ecpglib.h
-       rm -f $(HEADERDIR)/ecpgtype.h
-       rm -f $(HEADERDIR)/sqlca.h
+       rm -f $(DESTDIR)$(HEADERDIR)/ecpglib.h
+       rm -f $(DESTDIR)$(HEADERDIR)/ecpgtype.h
+       rm -f $(DESTDIR)$(HEADERDIR)/sqlca.h
 
 dep depend:
index 6dd2f92aebfd9fcffdaa461370b39f6aa26487fd..b828763fa36940cfdecb169da8a1db41f1e03517 100644 (file)
@@ -13,11 +13,6 @@ bool         ECPGstatus(void);
 
 void           ECPGlog(const char *format,...);
 
-/* These functions are only kept for compatibility reasons. */
-/* Use ECPGtrans instead. */
-bool           ECPGcommit(int);
-bool           ECPGrollback(int);
-
 #ifdef LIBPQ_FE_H
 bool           ECPGsetdb(PGconn *);
 
index 30b1f557138ade2f11349b839772a79e67517924..54442e6e3dd6a4bea08b1aee8d3ae5dcc56e10cc 100644 (file)
@@ -43,7 +43,8 @@ enum ECPGttype
        ECPGt_array,
        ECPGt_record,
        ECPGt_EOIT,                                     /* End of insert types. */
-       ECPGt_EORT                                      /* End of result types. */
+       ECPGt_EORT,                                     /* End of result types. */
+       ECPGt_NO_INDICATOR                              /* no indicator */
 };
 
 #define IS_SIMPLE_TYPE(type) ((type) >= ECPGt_char && (type) <= ECPGt_varchar2)
index f4039edf99cef72c7abc7a965a96505e79295913..926b3b546964a7bbb3d42a45764f825754a52599 100644 (file)
@@ -3,8 +3,8 @@ include $(SRCDIR)/Makefile.global
 
 PQ_INCLUDE=-I$(SRCDIR)/interfaces/libpq
 
-SO_MAJOR_VERSION=1
-SO_MINOR_VERSION=1
+SO_MAJOR_VERSION=2
+SO_MINOR_VERSION=0
 
 PORTNAME=@PORTNAME@
 
@@ -16,6 +16,7 @@ endif
 shlib := 
 install-shlib-dep :=
 ifeq ($(PORTNAME), linux)
+  LINUX_ELF=@LINUX_ELF@
   ifdef LINUX_ELF
     install-shlib-dep := install-shlib
     shlib := libecpg.so.$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION)
index 87b2350bdb0207265d17b87222f298404ee7baa0..815f4bff0bc719290ac393292107880770b7b3be 100644 (file)
@@ -96,10 +96,11 @@ ECPGdo(int lineno, char *query,...)
         */
        while (type != ECPGt_EOIT)
        {
-               void       *value = NULL;
-               long            varcharsize;
-               long            size;
-               long            arrsize;
+               void       *value = NULL, *ind_value;
+               long            varcharsize, ind_varcharsize;
+               long            size, ind_size;
+               long            arrsize, ind_arrsize;
+               enum ECPGttype ind_type;
 
                char       *newcopy;
                char       *mallocedval = NULL;
@@ -117,9 +118,40 @@ ECPGdo(int lineno, char *query,...)
                varcharsize = va_arg(ap, long);
                size = va_arg(ap, long);
                arrsize = va_arg(ap, long);
-
-               switch (type)
+               ind_type = va_arg(ap, enum ECPGttype);
+               ind_value = va_arg(ap, void *);
+               ind_varcharsize = va_arg(ap, long);
+               ind_size = va_arg(ap, long);
+               ind_arrsize = va_arg(ap, long);
+
+               buff[0] = '\0';
+               
+               /* check for null value and set input buffer accordingly */
+               switch (ind_type)
                {
+                       case ECPGt_short:
+                       case ECPGt_unsigned_short:
+                               if (*(short *) ind_value < 0)
+                                       strcpy(buff, "null");
+                               break;
+                       case ECPGt_int:
+                       case ECPGt_unsigned_int:
+                               if (*(int *) ind_value < 0)
+                                       strcpy(buff, "null");
+                               break;
+                       case ECPGt_long:
+                       case ECPGt_unsigned_long:
+                               if (*(long *) ind_value < 0L)
+                                       strcpy(buff, "null");
+                               break;
+                       default:
+                               break;
+               }
+               
+               if (*buff == '\0')
+               {
+                  switch (type)
+                  {
                        case ECPGt_short:
                        case ECPGt_int:
                                sprintf(buff, "%d", *(int *) value);
@@ -205,7 +237,10 @@ ECPGdo(int lineno, char *query,...)
                                                           ECPGtype_name(type), lineno);
                                return false;
                                break;
+                  }
                }
+               else
+                  tobeinserted = buff;
 
                /*
                 * Now tobeinserted points to an area that is to be inserted at
@@ -266,7 +301,7 @@ ECPGdo(int lineno, char *query,...)
 
        if (committed)
        {
-               if ((results = PQexec(simple_connection, "begin")) == NULL)
+               if ((results = PQexec(simple_connection, "begin transaction")) == NULL)
                {
                        register_error(-1, "Error starting transaction line %d.", lineno);
                        return false;
@@ -324,10 +359,11 @@ ECPGdo(int lineno, char *query,...)
 
                                for (x = 0; x < m && status; x++)
                                {
-                                       void       *value = NULL;
-                                       long            varcharsize;
-                                       long            size;
-                                       long            arrsize;
+                                       void            *value = NULL, *ind_value;
+                                       long            varcharsize, ind_varcharsize;
+                                       long            size, ind_size;
+                                       long            arrsize, ind_arrsize;
+                                       enum ECPGttype  ind_type;
 
                                        char       *pval = PQgetvalue(results, 0, x);
 
@@ -339,14 +375,38 @@ ECPGdo(int lineno, char *query,...)
 
                                        ECPGlog("ECPGdo line %d: RESULT: %s\n", lineno, pval ? pval : "");
 
-                                       /* No the pval is a pointer to the value. */
+                                       /* Now the pval is a pointer to the value. */
                                        /* We will have to decode the value */
                                        type = va_arg(ap, enum ECPGttype);
                                        value = va_arg(ap, void *);
                                        varcharsize = va_arg(ap, long);
                                        size = va_arg(ap, long);
                                        arrsize = va_arg(ap, long);
-
+                                       ind_type = va_arg(ap, enum ECPGttype);
+                                       ind_value = va_arg(ap, void *);
+                                       ind_varcharsize = va_arg(ap, long);
+                                       ind_size = va_arg(ap, long);
+                                       ind_arrsize = va_arg(ap, long);
+                                       
+                                       /* check for null value and set indicator accordingly */
+                                       switch (ind_type)
+                                       {
+                                               case ECPGt_short:
+                                               case ECPGt_unsigned_short:
+                                                       *(short *) ind_value = -PQgetisnull(results, 0, x);
+                                                       break;
+                                               case ECPGt_int:
+                                               case ECPGt_unsigned_int:
+                                                       *(int *) ind_value = -PQgetisnull(results, 0, x);
+                                                       break;
+                                               case ECPGt_long:
+                                               case ECPGt_unsigned_long:
+                                                       *(long *) ind_value = -PQgetisnull(results, 0, x);
+                                                       break;
+                                               default:
+                                                       break;
+                                       }
+                                                                               
                                        switch (type)
                                        {
                                                        long            res;
@@ -486,7 +546,30 @@ ECPGdo(int lineno, char *query,...)
                                                                        ((char *) value)[strlen(pval)] = '\0';
                                                                }
                                                                else
+                                                               {
                                                                        strncpy((char *) value, pval, varcharsize);
+                                                                       if (varcharsize < strlen(pval))
+                                                                       {
+                                                                               /* truncation */
+                                                                               switch (ind_type)
+                                                                               {
+                                                                                       case ECPGt_short:
+                                                                                       case ECPGt_unsigned_short:
+                                                                                               *(short *) ind_value = varcharsize;
+                                                                                               break;
+                                                                                       case ECPGt_int:
+                                                                                       case ECPGt_unsigned_int:
+                                                                                               *(int *) ind_value = varcharsize;
+                                                                                               break;
+                                                                                       case ECPGt_long:
+                                                                                       case ECPGt_unsigned_long:
+                                                                                               *(long *) ind_value = varcharsize;
+                                                                                               break;
+                                                                                       default:
+                                                                                               break;
+                                                                               }
+                                                                       }
+                                                               }
                                                        }
                                                        break;
 
@@ -498,7 +581,28 @@ ECPGdo(int lineno, char *query,...)
                                                                strncpy(var->arr, pval, varcharsize);
                                                                var->len = strlen(pval);
                                                                if (var->len > varcharsize)
+                                                               {
+                                                                       /* truncation */
+                                                                       switch (ind_type)
+                                                                       {
+                                                                               case ECPGt_short:
+                                                                               case ECPGt_unsigned_short:
+                                                                                       *(short *) ind_value = varcharsize;
+                                                                                       break;
+                                                                               case ECPGt_int:
+                                                                               case ECPGt_unsigned_int:
+                                                                                       *(int *) ind_value = varcharsize;
+                                                                                       break;
+                                                                               case ECPGt_long:
+                                                                               case ECPGt_unsigned_long:
+                                                                                       *(long *) ind_value = varcharsize;
+                                                                                       break;
+                                                                               default:
+                                                                                       break;
+                                                                       }
+
                                                                        var->len = varcharsize;
+                                                               }
                                                        }
                                                        break;
 
@@ -587,19 +691,6 @@ ECPGtrans(int lineno, const char * transaction)
        return (TRUE);
 }
 
-/* include these for compatibility */
-bool
-ECPGcommit(int lineno)
-{
-       return(ECPGtrans(lineno, "end"));
-}
-
-bool
-ECPGrollback(int lineno)
-{
-       return(ECPGtrans(lineno, "abort"));
-}
-
 bool
 ECPGsetdb(PGconn *newcon)
 {
index 04d6ccb597b75ab3837b7ece84a89651bcb31cd0..73596c05fdd95b8a763d8c9ce9bcec47f3296272 100644 (file)
@@ -1,13 +1,16 @@
 SRCDIR= ../../..
 include $(SRCDIR)/Makefile.global
 
-MAJOR_VERSION=1
-MINOR_VERSION=1
+MAJOR_VERSION=2
+MINOR_VERSION=0
 PATCHLEVEL=0
 
 CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \
        -DMINOR_VERSION=$(MINOR_VERSION) -DPATCHLEVEL=$(PATCHLEVEL) \
-       -DINCLUDE_PATH=\"$(HEADERDIR)\"
+       -DINCLUDE_PATH=\"$(DESTDIR)$(HEADERDIR)\"
+
+OBJ=y.tab.o pgc.o type.o ecpg.o ecpg_keywords.o ../../../backend/parser/scansup.o \
+    keywords.o c_keywords.o ../lib/typename.o
 
 all:: ecpg
 
@@ -15,21 +18,22 @@ clean:
        rm -f *.o core a.out ecpg y.tab.h y.tab.c pgc.c *~
 
 install: all
-       $(INSTALL) $(INSTL_EXE_OPTS) ecpg $(BINDIR)
+       $(INSTALL) $(INSTL_EXE_OPTS) ecpg $(DESTDIR)$(BINDIR)
 
 uninstall:
-       rm -f $(BINDIR)/ecpg
-
-dep depend:
-       $(CC) -MM $(CFLAGS) *.c > depend
+       rm -f $(DESTDIR)$(BINDIR)/ecpg
 
 # Rule that really do something.
-ecpg: y.tab.o pgc.o type.o ecpg.o ../lib/typename.o
-       $(CC) -o ecpg y.tab.o pgc.o type.o ecpg.o ../lib/typename.o $(LEXLIB) $(LDFLAGS)
+ecpg: $(OBJ)
+       $(CC) -o ecpg $(OBJ) $(LEXLIB)
 
 y.tab.h y.tab.c: preproc.y
        $(YACC) $(YFLAGS) $<
 
-y.tab.o : y.tab.h ../include/ecpgtype.h
+y.tab.o : y.tab.h ../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c
 type.o : ../include/ecpgtype.h
-pgc.o : ../include/ecpgtype.h
+pgc.o : ../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c y.tab.h
+keywords.o: ../include/ecpgtype.h y.tab.h
+c_keywords.o: ../include/ecpgtype.h y.tab.h
+ecpg_keywords.o: ../include/ecpgtype.h y.tab.h
+
diff --git a/src/interfaces/ecpg/preproc/c_keywords.c b/src/interfaces/ecpg/preproc/c_keywords.c
new file mode 100644 (file)
index 0000000..d50de7b
--- /dev/null
@@ -0,0 +1,63 @@
+/*-------------------------------------------------------------------------
+ *
+ * keywords.c--
+ *       lexical token lookup for reserved words in postgres embedded SQL
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <ctype.h>
+#include <string.h>
+
+#include "postgres.h"
+#include "type.h"
+#include "y.tab.h"
+#include "extern.h"
+
+/*
+ * List of (keyword-name, keyword-token-value) pairs.
+ *
+ * !!WARNING!!: This list must be sorted, because binary
+ *              search is used to locate entries.
+ */
+static ScanKeyword ScanKeywords[] = {
+       /* name                                 value                   */
+       {"auto", S_AUTO},
+       {"bool", S_BOOL},
+       {"char", S_CHAR},
+       {"const", S_CONST},
+       {"double", S_DOUBLE},
+       {"extern", S_EXTERN},
+       {"float", S_FLOAT},
+       {"int", S_INT},
+       {"long", S_LONG},
+       {"register", S_REGISTER},
+       {"short", S_SHORT},
+       {"signed", S_SIGNED},
+       {"static", S_STATIC},
+       {"struct", S_STRUCT},
+       {"unsigned", S_UNSIGNED},
+       {"varchar", S_VARCHAR},
+};
+
+ScanKeyword *
+ScanCKeywordLookup(char *text)
+{
+       ScanKeyword *low = &ScanKeywords[0];
+       ScanKeyword *high = endof(ScanKeywords) - 1;
+       ScanKeyword *middle;
+       int                     difference;
+
+       while (low <= high)
+       {
+               middle = low + (high - low) / 2;
+               difference = strcmp(middle->name, text);
+               if (difference == 0)
+                       return (middle);
+               else if (difference < 0)
+                       low = middle + 1;
+               else
+                       high = middle - 1;
+       }
+
+       return (NULL);
+}
index a97b74e748bf5d6df420d1424e36aa90e00ab96f..e156468f2b8f9875d20df64ab3b7cda72831c8fb 100644 (file)
@@ -91,7 +91,7 @@ main(int argc, char *const argv[])
                /* after the options there must not be anything but filenames */
                for (fnr = optind; fnr < argc; fnr++)
                {
-                       char    *ptr2ext;
+                       char       *output_filename = NULL, *ptr2ext;
 
                        input_filename = mm_alloc(strlen(argv[fnr]) + 5);
 
@@ -113,7 +113,7 @@ main(int argc, char *const argv[])
 
                        if (out_option == 0)/* calculate the output name */
                        {
-                               char *output_filename = strdup(input_filename);
+                               output_filename = strdup(input_filename);
                                
                                ptr2ext = strrchr(output_filename, '.');
                                /* make extension = .c */
@@ -128,7 +128,6 @@ main(int argc, char *const argv[])
                                        free(input_filename);
                                        continue;
                                }
-                               free(output_filename);
                        }
 
                        yyin = fopen(input_filename, "r");
@@ -136,9 +135,25 @@ main(int argc, char *const argv[])
                                perror(argv[fnr]);
                        else
                        {
+                               struct cursor *ptr;
+                               
                                /* initialize lex */
                                lex_init();
-
+                               
+                               /* initialize cursor list */
+                               for (ptr = cur; ptr != NULL;)
+                               {
+                                       struct cursor *c;
+                                       
+                                       free(ptr->name);
+                                       free(ptr->command);
+                                       c = ptr;
+                                       ptr = ptr->next;
+                                       free(c);
+                               }
+                               
+                               cur = NULL;
+                               
                                /* we need two includes */
                                fprintf(yyout, "/* Processed by ecpg (%d.%d.%d) */\n/*These two include files are added by the preprocessor */\n#include <ecpgtype.h>\n#include <ecpglib.h>\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL);
 
@@ -150,6 +165,10 @@ main(int argc, char *const argv[])
                                if (out_option == 0)
                                        fclose(yyout);
                        }
+
+                       if (output_filename)
+                               free(output_filename);
+                               
                        free(input_filename);
                }
        }
diff --git a/src/interfaces/ecpg/preproc/ecpg_keywords.c b/src/interfaces/ecpg/preproc/ecpg_keywords.c
new file mode 100644 (file)
index 0000000..6fea8a4
--- /dev/null
@@ -0,0 +1,60 @@
+/*-------------------------------------------------------------------------
+ *
+ * keywords.c--
+ *       lexical token lookup for reserved words in postgres embedded SQL
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <ctype.h>
+#include <string.h>
+
+#include "postgres.h"
+#include "type.h"
+#include "y.tab.h"
+#include "extern.h"
+
+/*
+ * List of (keyword-name, keyword-token-value) pairs.
+ *
+ * !!WARNING!!: This list must be sorted, because binary
+ *              search is used to locate entries.
+ */
+static ScanKeyword ScanKeywords[] = {
+       /* name                                 value                   */
+       {"connect", SQL_CONNECT},
+       {"continue", SQL_CONTINUE},
+       {"found", SQL_FOUND},
+       {"go", SQL_GO},
+       {"goto", SQL_GOTO},
+       {"immediate", SQL_IMMEDIATE},
+       {"indicator", SQL_INDICATOR},
+       {"open", SQL_OPEN},
+       {"section", SQL_SECTION},
+       {"sqlerror", SQL_SQLERROR},
+       {"sqlprint", SQL_SQLPRINT},
+       {"stop", SQL_STOP},
+       {"whenever", SQL_WHENEVER},
+};
+
+ScanKeyword *
+ScanECPGKeywordLookup(char *text)
+{
+       ScanKeyword *low = &ScanKeywords[0];
+       ScanKeyword *high = endof(ScanKeywords) - 1;
+       ScanKeyword *middle;
+       int                     difference;
+
+       while (low <= high)
+       {
+               middle = low + (high - low) / 2;
+               difference = strcmp(middle->name, text);
+               if (difference == 0)
+                       return (middle);
+               else if (difference < 0)
+                       low = middle + 1;
+               else
+                       high = middle - 1;
+       }
+
+       return (NULL);
+}
index 53da42cfb12409497164da702ceecc71133549d3..96c7bc0ed30cde097edc5870b8320c7ffa5b38f9 100644 (file)
@@ -1,3 +1,5 @@
+#include "parser/keywords.h"
+
 /* variables */
 
 extern int     debugging,
@@ -14,9 +16,19 @@ struct _include_path {  char * path;
 
 extern struct _include_path *include_paths;
 
+struct cursor {        char *name;
+               char *command;
+               struct cursor *next;
+             };
+
+extern struct cursor *cur;
+
 /* functions */
 
 extern void lex_init(void);
 extern char *input_filename;
 extern int     yyparse(void);
 extern void *mm_alloc(size_t), *mm_realloc(void *, size_t);
+ScanKeyword * ScanECPGKeywordLookup(char *);
+ScanKeyword * ScanCKeywordLookup(char *);
+extern void yyerror(char *);
diff --git a/src/interfaces/ecpg/preproc/keywords.c b/src/interfaces/ecpg/preproc/keywords.c
new file mode 100644 (file)
index 0000000..4d8722f
--- /dev/null
@@ -0,0 +1,242 @@
+/*-------------------------------------------------------------------------
+ *
+ * keywords.c--
+ *       lexical token lookup for reserved words in postgres SQL
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *       $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.1 1998/04/21 13:23:06 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <ctype.h>
+#include <string.h>
+
+#include "postgres.h"
+#include "nodes/parsenodes.h"
+#include "nodes/pg_list.h"
+#include "type.h"
+#include "y.tab.h"
+#include "parser/keywords.h"
+#include "utils/elog.h"
+
+/*
+ * List of (keyword-name, keyword-token-value) pairs.
+ *
+ * !!WARNING!!: This list must be sorted, because binary
+ *              search is used to locate entries.
+ */
+static ScanKeyword ScanKeywords[] = {
+       /* name                                 value                   */
+       {"abort", ABORT_TRANS},
+       {"action", ACTION},
+       {"add", ADD},
+       {"after", AFTER},
+       {"aggregate", AGGREGATE},
+       {"all", ALL},
+       {"alter", ALTER},
+       {"analyze", ANALYZE},
+       {"and", AND},
+       {"any", ANY},
+       {"archive", ARCHIVE},
+       {"as", AS},
+       {"asc", ASC},
+       {"backward", BACKWARD},
+       {"before", BEFORE},
+       {"begin", BEGIN_TRANS},
+       {"between", BETWEEN},
+       {"binary", BINARY},
+       {"both", BOTH},
+       {"by", BY},
+       {"cache", CACHE},
+       {"cascade", CASCADE},
+       {"cast", CAST},
+       {"char", CHAR},
+       {"character", CHARACTER},
+       {"check", CHECK},
+       {"close", CLOSE},
+       {"cluster", CLUSTER},
+       {"collate", COLLATE},
+       {"column", COLUMN},
+       {"commit", COMMIT},
+       {"constraint", CONSTRAINT},
+       {"copy", COPY},
+       {"create", CREATE},
+       {"createdb", CREATEDB},
+       {"createuser", CREATEUSER},
+       {"cross", CROSS},
+       {"current", CURRENT},
+       {"current_date", CURRENT_DATE},
+       {"current_time", CURRENT_TIME},
+       {"current_timestamp", CURRENT_TIMESTAMP},
+       {"current_user", CURRENT_USER},
+       {"cursor", CURSOR},
+       {"cycle", CYCLE},
+       {"database", DATABASE},
+       {"day", DAY_P},
+       {"decimal", DECIMAL},
+       {"declare", DECLARE},
+       {"default", DEFAULT},
+       {"delete", DELETE},
+       {"delimiters", DELIMITERS},
+       {"desc", DESC},
+       {"distinct", DISTINCT},
+       {"do", DO},
+       {"double", DOUBLE},
+       {"drop", DROP},
+       {"each", EACH},
+       {"end", END_TRANS},
+       {"execute", EXECUTE},
+       {"exists", EXISTS},
+       {"explain", EXPLAIN},
+       {"extend", EXTEND},
+       {"extract", EXTRACT},
+       {"false", FALSE_P},
+       {"fetch", FETCH},
+       {"float", FLOAT},
+       {"for", FOR},
+       {"foreign", FOREIGN},
+       {"forward", FORWARD},
+       {"from", FROM},
+       {"full", FULL},
+       {"function", FUNCTION},
+       {"grant", GRANT},
+       {"group", GROUP},
+       {"handler", HANDLER},
+       {"having", HAVING},
+       {"hour", HOUR_P},
+       {"in", IN},
+       {"increment", INCREMENT},
+       {"index", INDEX},
+       {"inherits", INHERITS},
+       {"inner", INNER_P},
+       {"insert", INSERT},
+       {"instead", INSTEAD},
+       {"interval", INTERVAL},
+       {"into", INTO},
+       {"is", IS},
+       {"isnull", ISNULL},
+       {"join", JOIN},
+       {"key", KEY},
+       {"lancompiler", LANCOMPILER},
+       {"language", LANGUAGE},
+       {"leading", LEADING},
+       {"left", LEFT},
+       {"like", LIKE},
+       {"listen", LISTEN},
+       {"load", LOAD},
+       {"local", LOCAL},
+       {"location", LOCATION},
+       {"lock", LOCK_P},
+       {"match", MATCH},
+       {"maxvalue", MAXVALUE},
+       {"minute", MINUTE_P},
+       {"minvalue", MINVALUE},
+       {"month", MONTH_P},
+       {"move", MOVE},
+       {"national", NATIONAL},
+       {"natural", NATURAL},
+       {"nchar", NCHAR},
+       {"new", NEW},
+       {"no", NO},
+       {"nocreatedb", NOCREATEDB},
+       {"nocreateuser", NOCREATEUSER},
+       {"none", NONE},
+       {"not", NOT},
+       {"nothing", NOTHING},
+       {"notify", NOTIFY},
+       {"notnull", NOTNULL},
+       {"null", NULL_P},
+       {"numeric", NUMERIC},
+       {"oids", OIDS},
+       {"on", ON},
+       {"operator", OPERATOR},
+       {"option", OPTION},
+       {"or", OR},
+       {"order", ORDER},
+       {"outer", OUTER_P},
+       {"partial", PARTIAL},
+       {"password", PASSWORD},
+       {"position", POSITION},
+       {"precision", PRECISION},
+       {"primary", PRIMARY},
+       {"privileges", PRIVILEGES},
+       {"procedural", PROCEDURAL},
+       {"procedure", PROCEDURE},
+       {"public", PUBLIC},
+       {"recipe", RECIPE},
+       {"references", REFERENCES},
+       {"rename", RENAME},
+       {"reset", RESET},
+       {"returns", RETURNS},
+       {"revoke", REVOKE},
+       {"right", RIGHT},
+       {"rollback", ROLLBACK},
+       {"row", ROW},
+       {"rule", RULE},
+       {"second", SECOND_P},
+       {"select", SELECT},
+       {"sequence", SEQUENCE},
+       {"set", SET},
+       {"setof", SETOF},
+       {"show", SHOW},
+       {"start", START},
+       {"statement", STATEMENT},
+       {"stdin", STDIN},
+       {"stdout", STDOUT},
+       {"substring", SUBSTRING},
+       {"table", TABLE},
+       {"time", TIME},
+       {"to", TO},
+       {"trailing", TRAILING},
+       {"transaction", TRANSACTION},
+       {"trigger", TRIGGER},
+       {"trim", TRIM},
+       {"true", TRUE_P},
+       {"trusted", TRUSTED},
+       {"type", TYPE_P},
+       {"union", UNION},
+       {"unique", UNIQUE},
+       {"until", UNTIL},
+       {"update", UPDATE},
+       {"user", USER},
+       {"using", USING},
+       {"vacuum", VACUUM},
+       {"valid", VALID},
+       {"values", VALUES},
+       {"varchar", VARCHAR},
+       {"varying", VARYING},
+       {"verbose", VERBOSE},
+       {"version", VERSION},
+       {"view", VIEW},
+       {"where", WHERE},
+       {"with", WITH},
+       {"work", WORK},
+       {"year", YEAR_P},
+       {"zone", ZONE},
+};
+
+ScanKeyword *
+ScanKeywordLookup(char *text)
+{
+       ScanKeyword *low = &ScanKeywords[0];
+       ScanKeyword *high = endof(ScanKeywords) - 1;
+       ScanKeyword *middle;
+       int                     difference;
+
+       while (low <= high)
+       {
+               middle = low + (high - low) / 2;
+               difference = strcmp(middle->name, text);
+               if (difference == 0)
+                       return (middle);
+               else if (difference < 0)
+                       low = middle + 1;
+               else
+                       high = middle - 1;
+       }
+
+       return (NULL);
+}
index 8fc341400ea421bc95d7488f1d2beed266a41889..669da63a06825d13d6c52b893891d0cd75ac5443 100644 (file)
@@ -1,6 +1,8 @@
-/* Copyright comment! */
+/* This is a modified version of src/backend/parser/scan.l */
 %{
 #include "config.h"
+
+#include <ctype.h>
 #include <sys/types.h>
 #include <limits.h>
 #if defined(HAVE_STRING_H)
 #else
 #include <strings.h>
 #endif
+#include <errno.h>
 
+#include "postgres.h"
+#include "miscadmin.h"
+#include "nodes/pg_list.h"
+#include "nodes/parsenodes.h"
+#include "parser/gramparse.h"
+#include "parser/scansup.h"
 #include "type.h"
 #include "y.tab.h"
+#include "utils/builtins.h"
 
 #include "extern.h"
 
+/* some versions of lex define this as a macro */
+#if defined(yywrap)
+#undef yywrap
+#endif /* yywrap */
+
+int debugging = 0;
+extern YYSTYPE yylval;
+int llen;
+char literal[MAX_PARSE_BUFFER];
+
 struct _yy_buffer { YY_BUFFER_STATE    buffer;
                    long                lineno;
                    char              * filename;
                    struct _yy_buffer * next;
                  } *yy_buffer = NULL;
 
-#define dbg(arg)       if (debugging) fprintf(stderr, "DEBUG, %d: %s\n", yylineno, #arg);
 %}
 %option yylineno
 %s C SQL incl
-ccomment       \/\*([^*]|\*[^/]|\*\*[^/])*\*\/
-ws     ([ \t\n][ \t\n]*|{ccomment})*
-letter [A-Za-z_]
-digit  [0-9]
-length {digit}+
-symbol {letter}({letter}|{digit})*
-label  ({letter}|{digit})*
-string '[^']*'
-
-abort  [aA][bB][oO][rR][tT]
-begin  [bB][eE][gG][iI][nN]
-commit  [cC][oO][mM][mM][iI][tT]
-connect [cC][oO][nN][nN][eE][cC][tT]
-continue [cC][oO][nN][tT][iI][nN][uU][eE]
-declare [dD][eE][cC][lL][aA][rR][eE]
-do      [dD][oO]
-end    [eE][nN][dD]
-exec   [eE][xX][eE][cC]
-execute        [eE][xX][eE][cC][uU][tT][eE]
-fetch   [fF][eE][tT][cC][hH]
-found  [fF][oO][uU][nN][dD]
-from    [fF][rR][oO][mM]
-go     [gG][oO]
-goto    [gG][oO][tT][oO]
-immediate [iI][mM][mM][eE][dD][iI][aA][tT][eE]
+/* OK, here is a short description of lex/flex rules behavior.
+ * The longest pattern which matches an input string is always chosen.
+ * For equal-length patterns, the first occurring in the rules list is chosen.
+ * INITIAL is the starting condition, to which all non-conditional rules apply.
+ * When in an exclusive condition, only those rules defined for that condition apply.
+ *
+ * Exclusive states change parsing rules while the state is active.
+ * There are exclusive states for quoted strings, extended comments,
+ *  and to eliminate parsing troubles for numeric strings.
+ * Exclusive states:
+ *  <xb> binary numeric string - thomas 1997-11-16
+ *  <xc> extended C-style comments - tgl 1997-07-12
+ *  <xd> delimited identifiers (double-quoted identifiers) - tgl 1997-10-27
+ *  <xh> hexadecimal numeric string - thomas 1997-11-16
+ *  <xm> numeric strings with embedded minus sign - tgl 1997-09-05
+ *  <xq> quoted strings - tgl 1997-07-30
+ *
+ * The "extended comment" syntax closely resembles allowable operator syntax.
+ * So, when in condition <xc>, only strings which would terminate the
+ *  "extended comment" trigger any action other than "ignore".
+ * Be sure to match _any_ candidate comment, including those with appended
+ *     operator-like symbols. - thomas 1997-07-14
+ */
+
+%x xb
+%x xc
+%x xd
+%x xh
+%x xm
+%x xq
+
+/* Binary number
+ */
+xbstart                        [bB]{quote}
+xbstop                 {quote}
+xbinside               [^']*
+xbcat                  {quote}{space}*\n{space}*{quote}
+
+/* Hexadecimal number
+ */
+xhstart                        [xX]{quote}
+xhstop                 {quote}
+xhinside               [^']*
+xhcat                  {quote}{space}*\n{space}*{quote}
+
+/* Extended quote
+ * xqdouble implements SQL92 embedded quote
+ * xqcat allows strings to cross input lines
+ */
+quote                  '
+xqstart                        {quote}
+xqstop                 {quote}
+xqdouble               {quote}{quote}
+xqinside               [^\\']*
+xqembedded             "\\'"
+xqliteral              [\\](.|\n)
+xqcat                  {quote}{space}*\n{space}*{quote}
+
+/* Delimited quote
+ * Allows embedded spaces and other special characters into identifiers.
+ */
+dquote                 \"
+xdstart                        {dquote}
+xdstop                 {dquote}
+xdinside               [^"]*
+
+/* Comments
+ * Ignored by the scanner and parser.
+ */
+xcline                 [\/][\*].*[\*][\/]{space}*\n*
+xcstart                        [\/][\*]{op_and_self}*
+xcstop                 {op_and_self}*[\*][\/]({space}*|\n)
+xcinside               [^*]*
+xcstar                 [^/]
+
+digit                  [0-9]
+number                 [-+.0-9Ee]
+letter                 [\200-\377_A-Za-z]
+letter_or_digit        [\200-\377_A-Za-z0-9]
+
+identifier             {letter}{letter_or_digit}*
+
+typecast               "::"
+
+self                   [,()\[\].$\:\+\-\*\/\<\>\=\|]
+op_and_self            [\~\!\@\#\%\^\&\|\`\?\$\:\+\-\*\/\<\>\=]
+operator               {op_and_self}+
+
+xminteger              {integer}/-
+xmreal                 {real}/{space}*-{digit}
+xmstop                 -
+
+integer                        -?{digit}+
+real                   -?{digit}+\.{digit}+([Ee][-+]?{digit}+)?
+
+param                  \${integer}
+
+comment                        ("--"|"//").*\n
+
+space                  [ \t\n\f]
+other                  .
+
+/* some stuff needed for ecpg */
+ccomment        \/\*([^*]|\*[^/]|\*\*[^/])*\*\/
+exec    [eE][xX][eE][cC]
 include [iI][nN][cC][lL][uU][dD][eE]
-in     [iI][nN]
-into   [iI][nN][tT][oO]
-not    [nN][oO][tT]
-open   [oO][pP][eE][nN]
-release [rR][eE][lL][eE][aA][sS][eE]
-rollback [rR][oO][lL][lL][bB][aA][cC][kK]
-section        [sS][eE][cC][tT][iI][oO][nN]
-sql    [sS][qQ][lL]
-sqlerror [sS][qQ][lL][eE][rR][rR][oO][rR]
-sqlprint [sS][qQ][lL][pP][rR][iI][nN][tT]
-stop   [sS][tT][oO][pP]
-transaction [tT][rR][aA][nN][sS][aA][cC][tT][iI][oO][nN]
-to     [tT][oO]
-varchar        [vV][aA][rR][cC][hH][aA][rR]
-varchar2       [vV][aA][rR][cC][hH][aA][rR]2
-whenever [wW][hH][eE][nN][eE][vV][eE][rR]
-work    [wW][oO][rR][kK]
-vacuum [vV][aA][cC][uU][uU][mM]
+sql     [sS][qQ][lL]
+
+/* DO NOT PUT ANY COMMENTS IN THE FOLLOWING SECTION.
+ * AT&T lex does not properly handle C-style comments in this second lex block.
+ * So, put comments here. tgl - 1997-09-08
+ *
+ * Quoted strings must allow some special characters such as single-quote
+ *  and newline.
+ * Embedded single-quotes are implemented both in the SQL/92-standard
+ *  style of two adjacent single quotes "''" and in the Postgres/Java style
+ *  of escaped-quote "\'".
+ * Other embedded escaped characters are matched explicitly and the leading
+ *  backslash is dropped from the string. - thomas 1997-09-24
+ */
+
 %%
-<C>{exec}{ws}{sql}     { BEGIN SQL; dbg(SQL_START); return SQL_START; }
-<SQL>";"               { BEGIN C; dbg(SQL_SEMI); return SQL_SEMI; }
-<SQL>{abort}           { dbg(SQL_ABORT); return SQL_ABORT; }
-<SQL>{begin}           { dbg(SQL_BEGIN); return SQL_BEGIN; }
-<SQL>{end}             { dbg(SQL_END); return SQL_END; }
-<SQL>{declare}         { dbg(SQL_DECLARE); return SQL_DECLARE; }
-<SQL>{execute}         { dbg(SQL_EXECUTE); return SQL_EXECUTE; }
-<SQL>{immediate}       { dbg(SQL_IMMEDIATE); return SQL_IMMEDIATE; }
-<SQL>{section}         { dbg(SQL_SECTION); return SQL_SECTION; }
-<SQL>{connect}         { dbg(SQL_CONNECT); return SQL_CONNECT; }
-<SQL>{open}            { dbg(SQL_OPEN); return SQL_OPEN; }
-<SQL>{commit}          { dbg(SQL_COMMIT); return SQL_COMMIT; }
-<SQL>{release}         { dbg(SQL_RELEASE); return SQL_RELEASE; }
-<SQL>{work}            { dbg(SQL_WORK); return SQL_WORK; }
-<SQL>{fetch}           { dbg(SQL_FETCH); return SQL_FETCH; }
-<SQL>{rollback}                { dbg(SQL_ROLLBACK); return SQL_ROLLBACK; }
-<SQL>{whenever}                { dbg(SQL_WHENEVER); return SQL_WHENEVER; }
-<SQL>{sqlerror}                { dbg(SQL_SQLERROR); return SQL_SQLERROR; }
-<SQL>{sqlprint}                { dbg(SQL_SQLPRINT); return SQL_SQLPRINT; }
-<SQL>{not}{ws}{found}  { dbg(SQL_NOT_FOUND); return SQL_NOT_FOUND; }
-<SQL>{continue}                { dbg(SQL_CONTINUE); return SQL_CONTINUE; }
-<SQL>{into}            { dbg(SQL_INTO); return SQL_INTO; }
-<SQL>{in}              { dbg(SQL_IN); return SQL_IN; }
-<SQL>{goto}            { dbg(SQL_GOTO); return SQL_GOTO; }
-<SQL>{go}{ws}{to}      { dbg(SQL_GOTO); return SQL_GOTO; }
-<SQL>{stop}            { dbg(SQL_STOP); return SQL_STOP; }
-<SQL>{do}              { dbg(SQL_DO); return SQL_DO; }
-<SQL>{from}            { dbg(SQL_FROM); return SQL_FROM; }
-<SQL>{transaction}     { dbg(SQL_TRANSACTION); return SQL_TRANSACTION; }
-<SQL>{vacuum}          { dbg(SQL_VACUUM); return SQL_VACUUM; }
-
-
-<C>{exec}{ws}{sql}{ws}{include}        { BEGIN(incl); }
-<incl>{ws}             /* eat the whitespace */
+<SQL>{comment}         { /* ignore */ }
+
+<SQL>{xcline}          { /* ignore */ }
+
+<xc>{xcstar}   |
+<SQL>{xcstart}         { BEGIN(xc); }
+
+<xc>{xcstop}   { BEGIN(SQL); }
+
+<xc>{xcinside} { /* ignore */ }
+
+<SQL>{xbstart}         {
+                                       BEGIN(xb);
+                                       llen = 0;
+                                       *literal = '\0';
+                               }
+<xb>{xbstop}   {
+                                       char* endptr;
+
+                                       BEGIN(SQL);
+                                       errno = 0;
+                                       yylval.ival = strtol((char *)literal,&endptr,2);
+                                       if (*endptr != '\0' || errno == ERANGE)
+                                               yyerror("ERROR: Bad binary integer input!");
+                                       return (ICONST);
+                               }
+<xh>{xhinside} |
+<xb>{xbinside} {
+                                       if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
+                                               yyerror("ERROR: quoted string parse buffer exceeded");
+                                       memcpy(literal+llen, yytext, yyleng+1);
+                                       llen += yyleng;
+                               }
+<xh>{xhcat}            |
+<xb>{xbcat}            {
+                               }
+
+<SQL>{xhstart}         {
+                                       BEGIN(xh);
+                                       llen = 0;
+                                       *literal = '\0';
+                               }
+<xh>{xhstop}   {
+                                       char* endptr;
+
+                                       BEGIN(SQL);
+                                       errno = 0;
+                                       yylval.ival = strtol((char *)literal,&endptr,16);
+                                       if (*endptr != '\0' || errno == ERANGE)
+                                               yyerror("ERROR: Bad hexadecimal integer input");
+                                       return (ICONST);
+                               }
+
+<SQL>{xqstart}         {
+                                       BEGIN(xq);
+                                       llen = 0;
+                                       *literal = '\0';
+                               }
+<xq>{xqstop}   {
+                                       BEGIN(SQL);
+                                       yylval.str = strdup(scanstr(literal));
+                                       return (SCONST);
+                               }
+<xq>{xqdouble} |
+<xq>{xqinside} {
+                                       if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
+                                               yyerror("ERROR: quoted string parse buffer exceeded");
+                                       memcpy(literal+llen, yytext, yyleng+1);
+                                       llen += yyleng;
+                               }
+<xq>{xqembedded} {
+                                       if ((llen+yyleng-1) > (MAX_PARSE_BUFFER - 1))
+                                               yyerror("ERROR: quoted string parse buffer exceeded");
+                                       memcpy(literal+llen, yytext, yyleng+1);
+                                       *(literal+llen) = '\'';
+                                       llen += yyleng;
+                               }
+
+<xq>{xqliteral} {
+                                       if ((llen+yyleng-1) > (MAX_PARSE_BUFFER - 1))
+                                               yyerror("ERROR: quoted string parse buffer exceeded");
+                                       memcpy(literal+llen, yytext, yyleng+1);
+                                       llen += yyleng;
+                               }
+<xq>{xqcat}            {
+                               }
+
+
+<SQL>{xdstart}         {
+                                       BEGIN(xd);
+                                       llen = 0;
+                                       *literal = '\0';
+                               }
+<xd>{xdstop}   {
+                                       BEGIN(SQL);
+                                       yylval.str = strdup(literal);
+                                       return (IDENT);
+                               }
+<xd>{xdinside} {
+                                       if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
+                                               yyerror("ERROR: quoted string parse buffer exceeded");
+                                       memcpy(literal+llen, yytext, yyleng+1);
+                                       llen += yyleng;
+                               }
+
+
+<xm>{space}*   { /* ignore */ }
+<xm>{xmstop}   {
+                                       BEGIN(SQL);
+                                       return (yytext[0]);
+                               }
+
+
+<SQL>{typecast}                        {       return TYPECAST; }
+
+<SQL>{self}/-[\.0-9]           {
+                                       return (yytext[0]);
+                               }
+<SQL>{self}                    {       return (yytext[0]); }
+<SQL>{operator}/-[\.0-9]       {
+                                       yylval.str = strdup((char*)yytext);
+                                       return (Op);
+                               }
+<SQL>{operator}                {
+                                       if (strcmp((char*)yytext,"!=") == 0)
+                                               yylval.str = strdup("<>"); /* compatability */
+                                       else
+                                               yylval.str = strdup((char*)yytext);
+                                       return (Op);
+                               }
+<SQL>{param}                   {
+                                       yylval.ival = atoi((char*)&yytext[1]);
+                                       return (PARAM);
+                               }
+
+<SQL>{identifier}/{space}*-{number}    {
+                                       int i;
+                                       ScanKeyword             *keyword;
+
+                                       BEGIN(xm);
+                                       for(i = 0; yytext[i]; i++)
+                                               if (isupper(yytext[i]))
+                                                       yytext[i] = tolower(yytext[i]);
+
+                                       keyword = ScanKeywordLookup((char*)yytext);
+                                       if (keyword != NULL) {
+                                               return (keyword->value);
+                                       }
+                                       else
+                                       {
+                                               keyword = ScanECPGKeywordLookup((char*)yytext);
+                                               if (keyword != NULL) {
+                                                       return (keyword->value);
+                                               }
+                                               else
+                                               {
+                                                       yylval.str = strdup((char*)yytext);
+                                                       return (IDENT);
+                                               }
+                                       }
+                               }
+{integer}/{space}*-{number}    {
+                                       char* endptr;
+
+                                       BEGIN(xm);
+                                       errno = 0;
+                                       yylval.ival = strtol((char *)yytext,&endptr,10);
+                                       if (*endptr != '\0' || errno == ERANGE)
+                                       {
+                                               errno = 0;
+                                               yylval.dval = strtod(((char *)yytext),&endptr);
+                                               if (*endptr != '\0' || errno == ERANGE)
+                                                       yyerror("ERROR: Bad integer input");
+                                               yyerror("WARNING: Integer input is out of range; promoted to float");
+                                               return (FCONST);
+                                       }
+                                       return (ICONST);
+                               }
+{real}/{space}*-{number} {
+                                       char* endptr;
+
+                                       BEGIN(xm);
+                                       errno = 0;
+                                       yylval.dval = strtod(((char *)yytext),&endptr);
+                                       if (*endptr != '\0' || errno == ERANGE)
+                                               yyerror("ERROR: Bad float8 input");
+                                       return (FCONST);
+                               }
+{integer}              {
+                                       char* endptr;
+
+                                       errno = 0;
+                                       yylval.ival = strtol((char *)yytext,&endptr,10);
+                                       if (*endptr != '\0' || errno == ERANGE)
+                                       {
+                                               errno = 0;
+                                               yylval.dval = strtod(((char *)yytext),&endptr);
+                                               if (*endptr != '\0' || errno == ERANGE)
+                                                       yyerror("ERROR: Bad integer input");
+                                               yyerror("WARNING: Integer input is out of range; promoted to float");
+                                               return (FCONST);
+                                       }
+                                       return (ICONST);
+                               }
+{real}                 {
+                                       char* endptr;
+
+                                       errno = 0;
+                                       yylval.dval = strtod((char *)yytext,&endptr);
+                                       if (*endptr != '\0' || errno == ERANGE)
+                                               yyerror("ERROR: Bad float input");
+                                       return (FCONST);
+                               }
+
+<SQL>{identifier}      {
+                                       int i;
+                                       ScanKeyword             *keyword;
+
+                                       for(i = 0; yytext[i]; i++)
+                                               if (isupper(yytext[i]))
+                                                       yytext[i] = tolower(yytext[i]);
+
+                                       keyword = ScanKeywordLookup((char*)yytext);
+                                       if (keyword != NULL) {
+                                               return (keyword->value);
+                                       }
+                                       else
+                                       {
+                                               keyword = ScanECPGKeywordLookup((char*)yytext);
+                                               if (keyword != NULL) {
+                                                       return (keyword->value);
+                                               }
+                                               else
+                                               {
+                                                       yylval.str = strdup((char*)yytext);
+                                                       return (IDENT);
+                                               }
+                                       }
+                               }
+<SQL>{space}                   { /* ignore */ }
+<SQL>";"                       { BEGIN C; return SQL_SEMI; }
+<SQL>{other}                   { return (yytext[0]); }
+
+<C>{exec}{space}{sql}          { BEGIN SQL; return SQL_START; }
+<C>{identifier}        {
+                                       ScanKeyword             *keyword;
+
+                                       keyword = ScanCKeywordLookup((char*)yytext);
+                                       if (keyword != NULL) {
+                                               return (keyword->value);
+                                       }
+                                       else
+                                       {
+                                               yylval.str = strdup((char*)yytext);
+                                               return (IDENT);
+                                       }
+                               }
+<C>";"                 { return(';'); }
+<C>{space}             { ECHO; }
+\{                     { return('{'); }
+\}                     { return('}'); }
+\[                     { return('['); }
+\]                     { return(']'); }
+\=                     { return('='); }
+<C>{other}                     { return (S_ANYTHING); }
+<C>{exec}{space}{sql}{space}{include}  { BEGIN(incl); }
+<incl>{space}          /* eat the whitespace */
 <incl>[^ \t\n]+        { /* got the include file name */
                          struct _yy_buffer *yb;
                          struct _include_path *ip;
@@ -125,7 +454,7 @@ vacuum      [vV][aA][cC][uU][uU][mM]
                          {
                                if (strlen(ip->path) + strlen(yytext) + 3 > PATH_MAX)
                                {
-                                       fprintf(stderr, "Path %s/%s is too long, skipping.\n", ip->path, yytext);
+                                       fprintf(stderr, "Error: Path %s/%s is too long in line %d, skipping.\n", ip->path, yytext, yylineno);
                                        continue;
                                }
                                sprintf (inc_file, "%s/%s", ip->path, yytext);
@@ -142,7 +471,7 @@ vacuum      [vV][aA][cC][uU][uU][mM]
                          }
                          if (!yyin)
                          {
-                               fprintf(stderr, "Cannot open include file %s\n", yytext);
+                               fprintf(stderr, "Error: Cannot open include file %s in line %d\n", yytext, yylineno);
                                exit(1); 
                          }
 
@@ -153,79 +482,6 @@ vacuum     [vV][aA][cC][uU][uU][mM]
                          BEGIN C;
                        }
 <incl>";"              { BEGIN C; }
-{length}               { dbg(S_LENGTH); return S_LENGTH; }
-                         
-{varchar}              { dbg(S_VARCHAR); return S_VARCHAR; }
-{varchar2}             { dbg(S_VARCHAR2); return S_VARCHAR2; }
-long                   { dbg(S_LONG); return S_LONG; }
-short                  { dbg(S_SHORT); return S_SHORT; }
-int                    { dbg(S_INT); return S_INT; }
-char                   { dbg(S_CHAR); return S_CHAR; }
-float                  { dbg(S_FLOAT); return S_FLOAT; }
-double                 { dbg(S_DOUBLE); return S_DOUBLE; }
-bool                    { dbg(S_BOOL); return S_BOOL; }
-
-static                 { dbg(S_STATIC); return S_STATIC; }
-signed                 { dbg(S_SIGNED); return S_SIGNED; }
-extern                 { dbg(S_EXTERN); return S_EXTERN; }
-auto                   { dbg(S_AUTO); return S_AUTO; }
-const                  { dbg(S_CONST); return S_CONST; }
-register               { dbg(S_REGISTER); return S_REGISTER; }
-
-struct                 { dbg(S_STRUCT); return S_STRUCT; }
-
-{string}               { dbg(SQL_STRING); return SQL_STRING; }
-<SQL>{ws}              ; 
-{symbol}               { dbg(S_SYMBOL); return S_SYMBOL; }
-{label}                        { dbg(S_LABEL); return S_LABEL; }
-
-<SQL>"!<"              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"!>"              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"!^"              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"!|"              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"!~"              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"!~*"             { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"#<"              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"#<="             { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"#<>"             { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"#="              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"#>"              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"#>="             { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"&&"              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"&<"              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"&>"              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"<<"              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"<="              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"<===>"           { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"<>"              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"<?>"             { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"===>"            { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"===`"            { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"=|="             { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>">="              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>">>"              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"@@"              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"|/"              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"||/"             { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"~*"              { dbg(S_SYMBOL); return S_SYMBOL; }
-<SQL>"~="              { dbg(S_SYMBOL); return S_SYMBOL; }
-
-"["                    { dbg([); return '['; }
-"]"                    { dbg(]); return ']'; }
-";"                    { dbg(;); return ';'; }
-"="                    { dbg(=); return '='; }
-","                    { dbg(komma); return ','; }
-\(                     { dbg(braceopen); return '('; }
-\)                     { dbg(braceclose); return ')'; }
-\{                     { dbg(blockstart); return '{'; }
-\}                     { dbg(blockend); return '}'; }
-\*                     { dbg(*); return('*'); }
-
-<SQL>":"               { dbg(:); return ':'; }
-<SQL>"::"              { dbg(SQL_CONV); return SQL_CONV; }
-
-{ws}                   { ECHO; }
-.                      { dbg(.); return S_ANYTHING; }
 <<EOF>>                        { if (yy_buffer == NULL)
                                yyterminate();
                          else
@@ -260,4 +516,3 @@ int yywrap(void)
 { 
     return 1;
 }
-
index d3a2fc6d9ba47df7d70d57db02a15f504cf9e5cd..6eb4a88acd56d05759ecb202c9d924ece117facd 100644 (file)
@@ -3,23 +3,25 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include "catalog/catname.h"
 
 #include "type.h"
 #include "extern.h"
 
-static void yyerror(char *);
-
 /*
  * Variables containing simple states.
  */
-int    debugging = 0;
 static int     struct_level = 0;
-static char    *do_str = NULL;
+static char    *do_str = NULL, errortext[128];
 static int     do_length = 0;
+static int      QueryIsRule = 0;
 
 /* temporarily store record members while creating the data structure */
 struct ECPGrecord_member *record_member_list[128] = { NULL };
 
+/* keep a list of cursors */
+struct cursor *cur = NULL;
+
 /*
  * Handle the filename and line numbering.
  */
@@ -44,9 +46,9 @@ print_action(struct when *w)
        {
                case W_SQLPRINT: fprintf(yyout, "sqlprint();");
                                  break;
-               case W_GOTO:     fprintf(yyout, "goto %s;", w->str);
+               case W_GOTO:     fprintf(yyout, "goto %s;", w->command);
                                 break;
-               case W_DO:       fprintf(yyout, "%s;", w->str);
+               case W_DO:       fprintf(yyout, "%s;", w->command);
                                 break;
                case W_STOP:     fprintf(yyout, "exit (1);");
                                 break;
@@ -72,7 +74,7 @@ whenever_action()
 }
 
 /*
- * Handling of the variables.
+ * Handling of variables.
  */
 
 /*
@@ -95,6 +97,7 @@ static struct variable *
 find_variable(char * name)
 {
     struct variable * p;
+    char * errorstring = (char *) mm_alloc(strlen(name) + 100);
 
     for (p = allvariables; p; p = p->next)
     {
@@ -102,13 +105,10 @@ find_variable(char * name)
            return p;
     }
 
-    {
-       char * errorstring = (char *) malloc(strlen(name) + 100);
-
-       sprintf(errorstring, "The variable :%s is not declared.", name);
+    sprintf(errorstring, "The variable :%s is not declared", name);
+    yyerror(errorstring);
+    free (errorstring);
 
-       yyerror(errorstring);
-    }
     return NULL;
 }
 
@@ -116,7 +116,7 @@ find_variable(char * name)
 static void
 new_variable(const char * name, struct ECPGtype * type)
 {
-    struct variable * p = (struct variable*) malloc(sizeof(struct variable));
+    struct variable * p = (struct variable*) mm_alloc(sizeof(struct variable));
 
     p->name = strdup(name);
     p->type = type;
@@ -159,6 +159,7 @@ remove_variables(int brace_level)
  */
 struct arguments {
     struct variable * variable;
+    struct variable * indicator;
     struct arguments * next;
 };
 
@@ -166,6 +167,9 @@ struct arguments {
 static struct arguments * argsinsert = NULL;
 static struct arguments * argsresult = NULL;
 
+static struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, 0L, {NULL}};
+static struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL};
+
 static void
 reset_variables(void)
 {
@@ -176,10 +180,11 @@ reset_variables(void)
 
 /* Add a variable to a request. */
 static void
-add_variable(struct arguments ** list, struct variable * var)
+add_variable(struct arguments ** list, struct variable * var, struct variable * ind)
 {
-    struct arguments * p = (struct arguments *)malloc(sizeof(struct arguments));
+    struct arguments * p = (struct arguments *)mm_alloc(sizeof(struct arguments));
     p->variable = var;
+    p->indicator = ind;
     p->next = *list;
     *list = p;
 }
@@ -203,118 +208,3502 @@ dump_variables(struct arguments * list)
 
     dump_variables(list->next);
 
-    /* Then the current element. */
-    ECPGdump_a_type(yyout, list->variable->name, list->variable->type, NULL);
+    /* Then the current element and its indicator */
+    ECPGdump_a_type(yyout, list->variable->name, list->variable->type, list->indicator->name, list->indicator->type, NULL, NULL);
 
     /* Then release the list element. */
     free(list);
 }
+
+static void
+check_indicator(struct ECPGtype *var)
+{
+       /* make sure this is a valid indicator variable */
+       switch (var->typ)
+       {
+               struct ECPGrecord_member *p;
+
+               case ECPGt_short:
+               case ECPGt_int:
+               case ECPGt_long:
+               case ECPGt_unsigned_short:
+               case ECPGt_unsigned_int:
+               case ECPGt_unsigned_long:
+                       break;
+
+               case ECPGt_record:
+                       for (p = var->u.members; p; p = p->next)
+                               check_indicator(p->typ);
+                       break;
+
+               case ECPGt_array:
+                       check_indicator(var->u.element);
+                       break;
+               default: 
+                       yyerror ("indicator variable must be integer type");
+                       break;
+       }
+}
+
+static char *
+cat2_str(const char *str1, const char *str2)
+{ 
+       char * res_str  = (char *)mm_alloc(strlen(str1) + strlen(str2) + 1);
+
+       strcpy(res_str, str1);
+       strcat(res_str, str2);
+       return(res_str);
+}
+
+static char *
+make2_str(const char *str1, const char *str2)
+{ 
+       char * res_str  = (char *)mm_alloc(strlen(str1) + strlen(str2) + 2);
+
+       strcpy(res_str, str1);
+       strcat(res_str, " ");
+       strcat(res_str, str2);
+       return(res_str);
+}
+
+static char *
+cat3_str(const char *str1, const char *str2, const char * str3)
+{    
+        char * res_str  = (char *)mm_alloc(strlen(str1) + strlen(str2) + strlen(str3) + 1);
+     
+        strcpy(res_str, str1);
+        strcat(res_str, str2);
+       strcat(res_str, str3);
+        return(res_str);
+}    
+
+static char *
+make3_str(const char *str1, const char *str2, const char * str3)
+{    
+        char * res_str  = (char *)mm_alloc(strlen(str1) + strlen(str2) + strlen(str3) + 3);
+     
+        strcpy(res_str, str1);
+       strcat(res_str, " ");
+        strcat(res_str, str2);
+       strcat(res_str, " ");
+       strcat(res_str, str3);
+        return(res_str);
+}    
+
+static char *
+cat4_str(const char *str1, const char *str2, const char *str3, const char *str4)
+{    
+        char * res_str  = (char *)mm_alloc(strlen(str1) + strlen(str2) + strlen(str3) + strlen(str4) + 1);
+     
+        strcpy(res_str, str1);
+        strcat(res_str, str2);
+       strcat(res_str, str3);
+       strcat(res_str, str4);
+        return(res_str);
+}
+
+static char *
+make4_str(const char *str1, const char *str2, const char *str3, const char *str4)
+{    
+        char * res_str  = (char *)mm_alloc(strlen(str1) + strlen(str2) + strlen(str3) + strlen(str4) + 4);
+     
+        strcpy(res_str, str1);
+       strcat(res_str, " ");
+        strcat(res_str, str2);
+       strcat(res_str, " ");
+       strcat(res_str, str3);
+       strcat(res_str, " ");
+       strcat(res_str, str4);
+        return(res_str);
+}
+
+static char *
+cat5_str(const char *str1, const char *str2, const char *str3, const char *str4, const char *str5)
+{    
+        char * res_str  = (char *)mm_alloc(strlen(str1) + strlen(str2) + strlen(str3) + strlen(str4) + strlen(str5) + 1);
+     
+        strcpy(res_str, str1);
+        strcat(res_str, str2);
+       strcat(res_str, str3);
+       strcat(res_str, str4);
+       strcat(res_str, str5);
+        return(res_str);
+}    
+
+static char *
+make5_str(const char *str1, const char *str2, const char *str3, const char *str4, const char *str5)
+{    
+        char * res_str  = (char *)mm_alloc(strlen(str1) + strlen(str2) + strlen(str3) + strlen(str4) + strlen(str5) + 5);
+     
+        strcpy(res_str, str1);
+       strcat(res_str, " ");
+        strcat(res_str, str2);
+       strcat(res_str, " ");
+       strcat(res_str, str3);
+       strcat(res_str, " ");
+       strcat(res_str, str4);
+       strcat(res_str, " ");
+       strcat(res_str, str5);
+        return(res_str);
+}    
+
+static char *
+make_name(void)
+{
+       char * name = (char *)mm_alloc(yyleng + 1);
+
+       strncpy(name, yytext, yyleng);
+       name[yyleng] = '\0';
+       return(name);
+}
+
+static void
+output_statement(const char * stmt)
+{
+       fprintf(yyout, "ECPGdo(__LINE__, \"%s\", ", stmt);
+
+       /* dump variables to C file*/
+       dump_variables(argsinsert);
+       fputs("ECPGt_EOIT, ", yyout);
+       dump_variables(argsresult);
+       fputs("ECPGt_EORT);", yyout);
+       whenever_action();
+}
 %}
 
 %union {
-    int                                tagname;
-    struct ECPGtemp_type       type;
-    char *                     symbolname;
-    long                       indexsize;
-    enum ECPGttype             type_enum;
-    struct when                        action;
-}
-
-%token <tagname> SQL_START SQL_SEMI SQL_STRING SQL_INTO SQL_IN
-%token <tagname> SQL_BEGIN SQL_END SQL_DECLARE SQL_SECTION SQL_INCLUDE 
-%token <tagname> SQL_CONNECT SQL_OPEN SQL_EXECUTE SQL_IMMEDIATE
-%token <tagname> SQL_COMMIT SQL_ROLLBACK SQL_RELEASE SQL_WORK SQL_WHENEVER
-%token <tagname> SQL_SQLERROR SQL_NOT_FOUND SQL_CONTINUE SQL_FROM SQL_FETCH
-%token <tagname> SQL_DO SQL_GOTO SQL_SQLPRINT SQL_STOP SQL_CONV
-%token <tagname> SQL_ABORT SQL_TRANSACTION SQL_VACUUM
-
-%token <tagname> S_SYMBOL S_LENGTH S_ANYTHING S_LABEL
-%token <tagname> S_VARCHAR S_VARCHAR2
-%token <tagname> S_EXTERN S_STATIC S_AUTO S_CONST S_REGISTER S_STRUCT
-%token <tagname> S_UNSIGNED S_SIGNED
-%token <tagname> S_LONG S_SHORT S_INT S_CHAR S_FLOAT S_DOUBLE S_BOOL
-%token <tagname> '[' ']' ';' ',' '{' '}' '=' '*' '(' ')'
-
-%type <type> type type_detailed varchar_type simple_type struct_type string_type
-/* % type <type> array_type pointer_type */
-%type <symbolname> symbol label transactionstmt
-%type <tagname> maybe_storage_clause varchar_tag db_name cursor
-%type <type_enum> simple_tag char_tag
-%type <indexsize> index length
-%type <action> action
-%type <tagname> canything sqlanything both_anything vartext sqlcommand
-%type <tagname> transbegin, transend, transabort
-%%
-prog : statements;
-
-statements : /* empty */
-          | statements statement;
-
-statement : sqlconnect
-         | sqldeclaration
-         | sqlexecute
-         | sqlfetch
-         | sqlinclude
-         | sqlopen
-         | sqlstatement
-         | sqltransaction
-         | sqlwhenever
-         | blockstart
-         | blockend
-         | cthing;
-
-sqldeclaration : sql_startdeclare
-                variable_declarations
-                sql_enddeclare;
-
-sql_startdeclare : SQL_START SQL_BEGIN SQL_DECLARE SQL_SECTION SQL_SEMI        {
-    fprintf(yyout, "/* exec sql begin declare section */\n"); 
-    output_line_number();
+       double                  dval;
+        int                     ival;
+       char *                  str;
+       struct ECPGtemp_type    type;
+       struct when             action;
+       int                     tagname;
+       enum ECPGttype          type_enum;
 }
 
-sql_enddeclare : SQL_START SQL_END SQL_DECLARE SQL_SECTION SQL_SEMI {
-    fprintf(yyout,"/* exec sql end declare section */\n"); 
+/* special embedded SQL token */
+%token         SQL_CONNECT SQL_CONTINUE SQL_FOUND SQL_GO SQL_GOTO
+%token         SQL_IMMEDIATE SQL_INDICATOR SQL_OPEN
+%token         SQL_SECTION SQL_SEMI SQL_SQLERROR SQL_SQLPRINT SQL_START
+%token         SQL_STOP SQL_WHENEVER
+
+/* C token */
+%token         S_ANYTHING S_AUTO S_BOOL S_CHAR S_CONST S_DOUBLE S_EXTERN
+%token         S_FLOAT S_INT
+%token         S_LONG S_REGISTER S_SHORT S_SIGNED S_STATIC S_STRUCT S_UNSIGNED
+%token         S_VARCHAR
+
+/* I need this and don't know where it is defined inside the backend */
+%token         TYPECAST
+
+/* Keywords (in SQL92 reserved words) */
+%token  ACTION, ADD, ALL, ALTER, AND, ANY AS, ASC,
+                BEGIN_TRANS, BETWEEN, BOTH, BY,
+                CASCADE, CAST, CHAR, CHARACTER, CHECK, CLOSE, COLLATE, COLUMN, COMMIT, 
+                CONSTRAINT, CREATE, CROSS, CURRENT, CURRENT_DATE, CURRENT_TIME, 
+                CURRENT_TIMESTAMP, CURRENT_USER, CURSOR,
+                DAY_P, DECIMAL, DECLARE, DEFAULT, DELETE, DESC, DISTINCT, DOUBLE, DROP,
+                END_TRANS, EXECUTE, EXISTS, EXTRACT,
+                FETCH, FLOAT, FOR, FOREIGN, FROM, FULL,
+                GRANT, GROUP, HAVING, HOUR_P,
+                IN, INNER_P, INSERT, INTERVAL, INTO, IS,
+                JOIN, KEY, LANGUAGE, LEADING, LEFT, LIKE, LOCAL,
+                MATCH, MINUTE_P, MONTH_P,
+                NATIONAL, NATURAL, NCHAR, NO, NOT, NOTIFY, NULL_P, NUMERIC,
+                ON, OPTION, OR, ORDER, OUTER_P,
+                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,
+                VALUES, VARCHAR, VARYING, VIEW,
+                WHERE, WITH, WORK, YEAR_P, ZONE
+
+/* Keywords (in SQL3 reserved words) */
+%token  FALSE_P, TRIGGER, TRUE_P
+
+/* Keywords (in SQL92 non-reserved words) */
+%token  TYPE_P
+
+/* Keywords for Postgres support (not in SQL92 reserved words) */
+%token  ABORT_TRANS, AFTER, AGGREGATE, ANALYZE,
+                BACKWARD, BEFORE, BINARY, CACHE, CLUSTER, COPY, CYCLE,
+                DATABASE, DELIMITERS, DO, EACH, EXPLAIN, EXTEND,
+                FORWARD, FUNCTION, HANDLER,
+                INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL,
+                LANCOMPILER, LISTEN, LOAD, LOCK_P, LOCATION, MAXVALUE, MINVALUE, MOVE,
+                NEW, NONE, NOTHING, NOTNULL, OIDS, OPERATOR, PROCEDURAL,
+                RECIPE, RENAME, RESET, RETURNS, ROW, RULE,
+                SEQUENCE, SETOF, SHOW, START, STATEMENT, STDIN, STDOUT, TRUSTED,
+                VACUUM, VERBOSE, VERSION
+
+/* Keywords (obsolete; retain through next version for parser - thomas 1997-12-0 4) */
+%token  ARCHIVE
+
+/*
+ * Tokens for pg_passwd support.  The CREATEDB and CREATEUSER tokens should go a way
+ * when some sort of pg_privileges relation is introduced.
+ *
+ *                                    Todd A. Brandys
+ */
+%token  USER, PASSWORD, CREATEDB, NOCREATEDB, CREATEUSER, NOCREATEUSER, VALID, UNTIL
+
+/* Special keywords, not in the query language - see the "lex" file */
+%token <str>    IDENT SCONST Op
+%token <ival>   ICONST PARAM
+%token <dval>   FCONST
+
+/* these are not real. they are here so that they get generated as #define's*/
+%token                  OP
+
+/* precedence */
+%left          OR
+%left          AND
+%right         NOT
+%right         '='
+%nonassoc      '<' '>'
+%nonassoc      LIKE
+%nonassoc      BETWEEN
+%nonassoc      IN
+%nonassoc      Op                              /* multi-character ops and user-defined operators */
+%nonassoc      NOTNULL
+%nonassoc      ISNULL
+%nonassoc      IS
+%left          '+' '-'
+%left          '*' '/'
+%left          '|'                             /* this is the relation union op, not logical or */
+/* Unary Operators */
+%right         ':'
+%left          ';'                             /* end of statement or natural log */
+%right         UMINUS
+%left          '.'
+%left          '[' ']'
+%nonassoc      TYPECAST
+%nonassoc      REDUCE
+%left          UNION
+
+%type  <str>   Iconst Sconst TransactionStmt CreateStmt UserId
+%type  <str>   CreateAsElement OptCreateAs CreateAsList CreateAsStmt
+%type  <str>   OptArchiveType OptInherit key_reference key_action
+%type  <str>    key_match constraint_expr ColLabel SpecialRuleRelation
+%type  <str>   ColId default_expr ColQualifier columnDef ColQualList
+%type  <str>    ColConstraint ColConstraintElem default_list
+%type  <str>    OptTableElementList OptTableElement TableConstraint
+%type  <str>    ConstraintElem key_actions constraint_list TypeId
+%type  <str>    res_target_list res_target_el res_target_list2
+%type  <str>    res_target_el2 opt_id relation_name database_name
+%type  <str>    access_method attr_name class index_name name func_name
+%type  <str>    file_name recipe_name AexprConst ParamNo NumConst TypeId
+%type  <str>   in_expr_nodes not_in_expr_nodes a_expr b_expr
+%type  <str>   opt_indirection expr_list extract_list extract_arg
+%type  <str>   position_list position_expr substr_list substr_from
+%type  <str>   trim_list in_expr substr_for not_in_expr attr attrs
+%type  <str>   Typename Array Generic Numeric generic opt_float opt_numeric
+%type  <str>   opt_decimal Character character opt_varying opt_charset
+%type  <str>   opt_collate Datetime datetime opt_timezone opt_interval
+%type  <str>   numeric a_expr_or_null row_expr row_descriptor row_list
+%type  <str>   SelectStmt union_clause select_list SubSelect result
+%type  <str>   opt_table opt_union opt_unique sort_clause sortby_list
+%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 opt_array_bounds
+%type  <str>   nest_array_bounds opt_column_list insert_rest InsertStmt
+%type  <str>    columnList DeleteStmt LockStmt UpdateStmt CursorStmt
+%type  <str>    NotifyStmt columnElem copy_dirn OptimizableStmt
+%type  <str>    copy_delimiter ListenStmt CopyStmt copy_file_name opt_binary
+%type  <str>    opt_with_copy FetchStmt opt_direction fetch_how_many opt_portal_name
+%type  <str>    ClosePortalStmt DestroyStmt VacuumStmt opt_verbose
+%type  <str>    opt_analyze opt_va_list va_list ExplainStmt index_params
+%type  <str>    index_list func_index index_elem opt_type opt_class access_method_clause
+%type  <str>    index_opt_unique IndexStmt set_opt func_return def_rest
+%type  <str>    func_args_list func_args opt_with ProcedureStmt def_arg
+%type  <str>    def_elem def_list definition def_name def_type DefineStmt
+%type  <str>    opt_instead event event_object OptStmtMulti OptStmtBlock
+%type  <str>    OptStmtList RuleStmt opt_column opt_name oper_argtypes
+%type  <str>    MathOp RemoveOperStmt RemoveFuncStmt aggr_argtype
+%type  <str>    RemoveAggrStmt remove_type RemoveStmt ExtendStmt RecipeStmt
+%type  <str>    RemoveOperStmt RenameStmt all_Op user_valid_clause
+%type  <str>    VariableSetStmt var_value zone_value VariableShowStmt
+%type  <str>    VariableResetStmt AddAttrStmt alter_clause DropUserStmt
+%type  <str>    user_passwd_clause user_createdb_clause
+%type  <str>    user_createuser_clause user_group_list user_group_clause
+%type  <str>    CreateUserStmt AlterUserStmt CreateSeqStmt OptSeqList
+%type  <str>    OptSeqElem TriggerForSpec TriggerForOpt TriggerForType
+%type  <str>   TriggerFuncArgs DropTrigStmt TriggerOneEvent TriggerEvents
+%type  <str>    TriggerActionTime CreateTrigStmt DropPLangStmt PLangTrusted
+%type  <str>    CreatePLangStmt IntegerOnly TriggerFuncArgs TriggerFuncArg
+%type  <str>    ViewStmt LoadStmt CreatedbStmt opt_database location
+%type  <str>    DestroydbStmt ClusterStmt grantee RevokeStmt
+%type  <str>   GrantStmt privileges operation_commalist operation
+
+%type  <str>   ECPGWhenever ECPGConnect db_name ECPGOpen open_opts
+%type  <str>   indicator ECPGExecute c_expr
+%type  <str>   stmt symbol
+
+%type  <action> action
+
+%%
+prog: statements;
+
+statements: /* empty */
+       | statements statement
+
+statement: ecpgstart stmt SQL_SEMI
+       | ECPGDeclaration
+       | c_anything
+       | blockstart
+       | blockend
+
+stmt:  AddAttrStmt                     { output_statement($1); }
+               | AlterUserStmt         { output_statement($1); }
+               | ClosePortalStmt       { output_statement($1); }
+               | CopyStmt              { output_statement($1); }
+               | CreateStmt            { output_statement($1); }
+               | CreateAsStmt          { output_statement($1); }
+               | CreateSeqStmt         { output_statement($1); }
+               | CreatePLangStmt       { output_statement($1); }
+               | CreateTrigStmt        { output_statement($1); }
+               | CreateUserStmt        { output_statement($1); }
+               | ClusterStmt           { output_statement($1); }
+               | DefineStmt            { output_statement($1); }
+               | DestroyStmt           { output_statement($1); }
+               | DropPLangStmt         { output_statement($1); }
+               | DropTrigStmt          { output_statement($1); }
+               | DropUserStmt          { output_statement($1); }
+               | ExtendStmt            { output_statement($1); }
+               | ExplainStmt           { output_statement($1); }
+               | FetchStmt             { output_statement($1); }
+               | GrantStmt             { output_statement($1); }
+               | IndexStmt             { output_statement($1); }
+               | ListenStmt            { output_statement($1); }
+               | LockStmt              { output_statement($1); }
+               | ProcedureStmt         { output_statement($1); }
+               | RecipeStmt            { output_statement($1); }
+               | RemoveAggrStmt        { output_statement($1); }
+               | RemoveOperStmt        { output_statement($1); }
+               | RemoveFuncStmt        { output_statement($1); }
+               | RemoveStmt            { output_statement($1); }
+               | RenameStmt            { output_statement($1); }
+               | RevokeStmt            { output_statement($1); }
+               | OptimizableStmt       { /* already written out */ }
+               | RuleStmt              { output_statement($1); }
+               | TransactionStmt       {
+                                               fprintf(yyout, "ECPGtrans(__LINE__, \"%s\");", $1);
+                                               whenever_action();
+                                       }
+               | ViewStmt              { output_statement($1); }
+               | LoadStmt              { output_statement($1); }
+               | CreatedbStmt          { output_statement($1); }
+               | DestroydbStmt         { output_statement($1); }
+               | VacuumStmt            { output_statement($1); }
+               | VariableSetStmt       { output_statement($1); }
+               | VariableShowStmt      { output_statement($1); }
+               | VariableResetStmt     { output_statement($1); }
+               | ECPGConnect           {
+                                               fprintf(yyout, "ECPGconnect(\"%s\");", $1); 
+                                               whenever_action();
+                                       } 
+/*             | ECPGDisconnect        */
+               | ECPGExecute           {
+                                               fprintf(yyout, "ECPGdo(__LINE__, %s, ECPGt_EOIT, ECPGt_EORT);", $1);
+                                               whenever_action();
+                                       }
+               | ECPGOpen              { output_statement($1); }
+               | ECPGWhenever          {
+                                               fputs($1, yyout);
+                                               output_line_number();
+                                       }
+
+/*
+ * We start with a lot of stuff that's very similar to the backend's parsing
+ */
+
+/*****************************************************************************
+ *
+ * Create a new Postgres DBMS user
+ *
+ *
+ *****************************************************************************/
+
+CreateUserStmt:  CREATE USER UserId user_passwd_clause user_createdb_clause
+                       user_createuser_clause user_group_clause user_valid_clause
+                               {
+                                       $$ = make3_str(make5_str("create user", $3, $4, $5, $6), $7, $8);
+                               }
+               ;
+
+/*****************************************************************************
+ *
+ * Alter a postresql DBMS user
+ *
+ *
+ *****************************************************************************/
+
+AlterUserStmt:  ALTER USER UserId user_passwd_clause user_createdb_clause
+                       user_createuser_clause user_group_clause user_valid_clause
+                               {
+                                       $$ = make3_str(make5_str("alter user", $3, $4, $5, $6), $7, $8);
+                               }
+               ;
+
+/*****************************************************************************
+ *
+ * Drop a postresql DBMS user
+ *
+ *
+ *****************************************************************************/
+
+DropUserStmt:  DROP USER UserId
+                               {
+                                       $$ = make2_str("drop user", $3);
+                               }
+               ;
+
+user_passwd_clause:  WITH PASSWORD UserId      { $$ = make2_str("with password", $3); }
+                       | /*EMPTY*/             { $$ = ""; }
+               ;
+
+user_createdb_clause:  CREATEDB
+                               {
+                                       $$ = "createdb";
+                               }
+                       | NOCREATEDB
+                               {
+                                       $$ = "nocreatedb";
+                               }
+                       | /*EMPTY*/             { $$ = ""; }
+               ;
+
+user_createuser_clause:  CREATEUSER
+                               {
+                                       $$ = "createuser";
+                               }
+                       | NOCREATEUSER
+                               {
+                                       $$ = "nocreateuser";
+                               }
+                       | /*EMPTY*/             { $$ = NULL; }
+               ;
+
+user_group_list:  user_group_list ',' UserId
+                               {
+                                       $$ = make3_str($1, ",", $3);
+                               }
+                       | UserId
+                               {
+                                       $$ = $1;
+                               }
+               ;
+
+user_group_clause:  IN GROUP user_group_list   { $$ = make2_str("in group", $3); }
+                       | /*EMPTY*/             { $$ = ""; }
+               ;
+
+user_valid_clause:  VALID UNTIL SCONST                 { $$ = make2_str("valid until", $3);; }
+                       | /*EMPTY*/                     { $$ = ""; }
+               ;
+
+/*****************************************************************************
+ *
+ * Set PG internal variable
+ *       SET name TO 'var_value'
+ * Include SQL92 syntax (thomas 1997-10-22):
+ *    SET TIME ZONE 'var_value'
+ *
+ *****************************************************************************/
+
+VariableSetStmt:  SET ColId TO var_value
+                               {
+                                       $$ = make4_str("set", $2, "to", $4);
+                               }
+               | SET ColId '=' var_value
+                               {
+                                       $$ = make4_str("set", $2, "=", $4);
+                               }
+               | SET TIME ZONE zone_value
+                               {
+                                       $$ = make2_str("set time zone", $4);
+                               }
+               ;
+
+var_value:  Sconst                     { $$ = $1; }
+               | DEFAULT                       { $$ = "default"; }
+               ;
+
+zone_value:  Sconst                    { $$ = $1; }
+               | DEFAULT                       { $$ = "default"; }
+               | LOCAL                         { $$ = "local"; }
+               ;
+
+VariableShowStmt:  SHOW ColId
+                               {
+                                       $$ = make2_str("show", $2);
+                               }
+               | SHOW TIME ZONE
+                               {
+                                       $$ = "show time zone";
+                               }
+               ;
+
+VariableResetStmt:     RESET ColId
+                               {
+                                       $$ = make2_str("reset", $2);
+                               }
+               | RESET TIME ZONE
+                               {
+                                       $$ = "reset time zone";
+                               }
+               ;
+
+
+/*****************************************************************************
+ *
+ *             QUERY :
+ *                             addattr ( attr1 = type1 .. attrn = typen ) to <relname> [*]
+ *
+ *****************************************************************************/
+
+AddAttrStmt:  ALTER TABLE relation_name opt_inh_star alter_clause
+                               {
+                                       $$ = make4_str("alter table", $3, $4, $5);
+                               }
+               ;
+
+alter_clause:  ADD opt_column columnDef
+                               {
+                                       $$ = make3_str("add", $2, $3);
+                               }
+                       | ADD '(' OptTableElementList ')'
+                               {
+                                       $$ = cat3_str("add(", $3, ")");
+                               }
+                       | DROP opt_column ColId
+                               {       yyerror("ALTER TABLE/DROP COLUMN not yet implemented"); }
+                       | ALTER opt_column ColId SET DEFAULT default_expr
+                               {       yyerror("ALTER TABLE/ALTER COLUMN/SET DEFAULT not yet implemented"); }
+                       | ALTER opt_column ColId DROP DEFAULT
+                               {       yyerror("ALTER TABLE/ALTER COLUMN/DROP DEFAULT not yet implemented"); }
+                       | ADD ConstraintElem
+                               {       yyerror("ALTER TABLE/ADD CONSTRAINT not yet implemented"); }
+               ;
+
+/*****************************************************************************
+ *
+ *             QUERY :
+ *                             close <optname>
+ *
+ *****************************************************************************/
+
+ClosePortalStmt:  CLOSE opt_id
+                               {
+                                       $$ = make2_str("close", $2);
+                               }
+               ;
+
+
+/*****************************************************************************
+ *
+ *             QUERY :
+ *                             COPY [BINARY] <relname> FROM/TO
+ *                             [USING DELIMITERS <delimiter>]
+ *
+ *****************************************************************************/
+
+CopyStmt:  COPY opt_binary relation_name opt_with_copy copy_dirn copy_file_name copy_delimiter
+                               {
+                                       $$ = make3_str(make5_str("copy", $2, $3, $4, $5), $6, $7);
+                               }
+               ;
+
+copy_dirn:     TO
+                               { $$ = "to"; }
+               | FROM
+                               { $$ = "from"; }
+               ;
+
+/*
+ * copy_file_name NULL indicates stdio is used. Whether stdin or stdout is
+ * used depends on the direction. (It really doesn't make sense to copy from
+ * stdout. We silently correct the "typo".              - AY 9/94
+ */
+copy_file_name:  Sconst                                        { $$ = $1; }
+               | STDIN                                 { $$ = "stdin"; }
+               | STDOUT                                { $$ = "stdout"; }
+               ;
+
+opt_binary:  BINARY                                    { $$ = "binary"; }
+               | /*EMPTY*/                             { $$ = ""; }
+               ;
+
+opt_with_copy: WITH OIDS                               { $$ = "with oids"; }
+               | /*EMPTY*/                             { $$ = ""; }
+               ;
+
+/*
+ * the default copy delimiter is tab but the user can configure it
+ */
+copy_delimiter:  USING DELIMITERS Sconst               { $$ = make2_str("using delimiters", $3); }
+               | /*EMPTY*/                             { $$ = ""; }
+               ;
+
+
+
+/*****************************************************************************
+ *
+ *             QUERY :
+ *                             CREATE relname
+ *
+ *****************************************************************************/
+
+CreateStmt:  CREATE TABLE relation_name '(' OptTableElementList ')'
+                               OptInherit OptArchiveType
+                               {
+                                       $$ = make5_str("create table", $3,  cat3_str("(", $5, ")"), $7, $8);
+                               }
+               ;
+
+OptTableElementList:  OptTableElementList ',' OptTableElement
+                               {
+                                       $$ = make3_str($1, ",", $3);
+                               }
+                       | OptTableElement
+                               {
+                                       $$ = $1;
+                               }
+                       | /*EMPTY*/     { $$ = ""; }
+               ;
+
+OptTableElement:  columnDef            { $$ = $1; }
+                       | TableConstraint       { $$ = $1; }
+               ;
+
+columnDef:  ColId Typename ColQualifier
+                               {
+                                       $$ = make3_str($1, $2, $3);
+                               }
+               ;
+
+ColQualifier:  ColQualList     { $$ = $1; }
+                       | /*EMPTY*/     { $$ = ""; }
+               ;
+
+ColQualList:  ColQualList ColConstraint        { $$ = make2_str($1,$2); }
+                       | ColConstraint         { $$ = $1; }
+               ;
+
+ColConstraint:
+               CONSTRAINT name ColConstraintElem
+                               {
+                                       $$ = make3_str("constraint", $2, $3);
+                               }
+               | ColConstraintElem
+                               { $$ = $1; }
+               ;
+
+ColConstraintElem:  CHECK '(' constraint_expr ')'
+                               {
+                                       $$ = cat3_str("check(", $3, ")");
+                               }
+                       | DEFAULT default_expr
+                               {
+                                       $$ = make2_str("default", $2);
+                               }
+                       | NOT NULL_P
+                               {
+                                       $$ = "not null";
+                               }
+                       | UNIQUE
+                               {
+                                       $$ = "unique";
+                               }
+                       | PRIMARY KEY
+                               {
+                                       $$ = "primary key";
+                               }
+                       | REFERENCES ColId opt_column_list key_match key_actions
+                               {
+                                       fprintf(stderr, "CREATE TABLE/FOREIGN KEY clause ignored; not yet implemented");
+                                       $$ = "";
+                               }
+               ;
+
+default_list:  default_list ',' default_expr
+                               {
+                                       $$ = make3_str($1, ",", $3);
+                               }
+                       | default_expr
+                               {
+                                       $$ = $1;
+                               }
+               ;
+
+default_expr:  AexprConst
+                               {       $$ = $1; }
+                       | NULL_P
+                               {       $$ = "null"; }
+                       | '-' default_expr %prec UMINUS
+                               {       $$ = make2_str("-", $2); }
+                       | default_expr '+' default_expr
+                               {       $$ = make3_str($1, "+", $3); }
+                       | default_expr '-' default_expr
+                               {       $$ = make3_str($1, "-", $3); }
+                       | default_expr '/' default_expr
+                               {       $$ = make3_str($1, "/", $3); }
+                       | default_expr '*' default_expr
+                               {       $$ = make3_str($1, "*", $3); }
+                       | default_expr '=' default_expr
+                               {       yyerror("boolean expressions not supported in DEFAULT"); }
+                       | default_expr '<' default_expr
+                               {       yyerror("boolean expressions not supported in DEFAULT"); }
+                       | default_expr '>' default_expr
+                               {       yyerror("boolean expressions not supported in DEFAULT"); }
+/* not possible in embedded sql 
+                       | ':' default_expr
+                               {       $$ = make2_str(":", $2); }
+*/
+                       | ';' default_expr
+                               {       $$ = make2_str(";", $2); }
+                       | '|' default_expr
+                               {       $$ = make2_str("|", $2); }
+                       | default_expr TYPECAST Typename
+                               {       $$ = make3_str($1, "::", $3); }
+                       | CAST '(' default_expr AS Typename ')'
+                               {
+                                       $$ = make3_str(cat2_str("cast(", $3) , "as", cat2_str($5, ")"));
+                               }
+                       | '(' default_expr ')'
+                               {       $$ = cat3_str("(", $2, ")"); }
+                       | func_name '(' ')'
+                               {       $$ = make2_str($1, "()"); }
+                       | func_name '(' default_list ')'
+                               {       $$ = make2_str($1, cat3_str("(", $3, ")")); }
+                       | default_expr Op default_expr
+                               {
+                                       if (!strcmp("<=", $2) || !strcmp(">=", $2))
+                                               yyerror("boolean expressions not supported in DEFAULT");
+                                       $$ = make3_str($1, $2, $3);
+                               }
+                       | Op default_expr
+                               {       $$ = make2_str($1, $2); }
+                       | default_expr Op
+                               {       $$ = make2_str($1, $2); }
+                       /* XXX - thomas 1997-10-07 v6.2 function-specific code to be changed */
+                       | CURRENT_DATE
+                               {       $$ = "current_date"; }
+                       | CURRENT_TIME
+                               {       $$ = "current_time"; }
+                       | CURRENT_TIME '(' Iconst ')'
+                               {
+                                       if ($3 != 0)
+                                               fprintf(stderr, "CURRENT_TIME(%s) precision not implemented; zero used instead",$3);
+                                       $$ = "current_time";
+                               }
+                       | CURRENT_TIMESTAMP
+                               {       $$ = "current_timestamp"; }
+                       | CURRENT_TIMESTAMP '(' Iconst ')'
+                               {
+                                       if ($3 != 0)
+                                               fprintf(stderr, "CURRENT_TIMESTAMP(%s) precision not implemented; zero used instead",$3);
+                                       $$ = "current_timestamp";
+                               }
+                       | CURRENT_USER
+                               {       $$ = "current user"; }
+               ;
+
+/* ConstraintElem specifies constraint syntax which is not embedded into
+ *  a column definition. ColConstraintElem specifies the embedded form.
+ * - thomas 1997-12-03
+ */
+TableConstraint:  CONSTRAINT name ConstraintElem
+                               {
+                                               $$ = make3_str("constraint", $2, $3);
+                               }
+               | ConstraintElem
+                               { $$ = $1; }
+               ;
+
+ConstraintElem:  CHECK '(' constraint_expr ')'
+                               {
+                                       $$ = cat3_str("check(", $3, ")");
+                               }
+               | UNIQUE '(' columnList ')'
+                               {
+                                       $$ = cat3_str("unique(", $3, ")");
+                               }
+               | PRIMARY KEY '(' columnList ')'
+                               {
+                                       $$ = cat3_str("primary key(", $4, ")");
+                               }
+               | FOREIGN KEY '(' columnList ')' REFERENCES ColId opt_column_list key_match key_actions
+                               {
+                                       fprintf(stderr, "CREATE TABLE/FOREIGN KEY clause ignored; not yet implemented");
+                                       $$ = "";
+                               }
+               ;
+
+constraint_list:  constraint_list ',' constraint_expr
+                               {
+                                       $$ = make3_str($1, ",", $3);
+                               }
+                       | constraint_expr
+                               {
+                                       $$ = $1;
+                               }
+               ;
+
+constraint_expr:  AexprConst
+                               {       $$ = $1; }
+                       | NULL_P
+                               {       $$ = "null"; }
+                       | ColId
+                               {
+                                       $$ = $1;
+                               }
+                       | '-' constraint_expr %prec UMINUS
+                               {       $$ = make2_str("-", $2); }
+                       | constraint_expr '+' constraint_expr
+                               {       $$ = make3_str($1, "+", $3); }
+                       | constraint_expr '-' constraint_expr
+                               {       $$ = make3_str($1, "-", $3); }
+                       | constraint_expr '/' constraint_expr
+                               {       $$ = make3_str($1, "/", $3); }
+                       | constraint_expr '*' constraint_expr
+                               {       $$ = make3_str($1, "*", $3); }
+                       | constraint_expr '=' constraint_expr
+                               {       $$ = make3_str($1, "=", $3); }
+                       | constraint_expr '<' constraint_expr
+                               {       $$ = make3_str($1, "<", $3); }
+                       | constraint_expr '>' constraint_expr
+                               {       $$ = make3_str($1, ">", $3); }
+/* this one doesn't work with embedded sql anyway
+                       | ':' constraint_expr
+                               {       $$ = make2_str(":", $2); }
+*/
+                       | ';' constraint_expr
+                               {       $$ = make2_str(";", $2); }
+                       | '|' constraint_expr
+                               {       $$ = make2_str("|", $2); }
+                       | constraint_expr TYPECAST Typename
+                               {
+                                       $$ = make3_str($1, "::", $3);
+                               }
+                       | CAST '(' constraint_expr AS Typename ')'
+                               {
+                                       $$ = make3_str(cat2_str("cast(", $3), "as", cat2_str($5, ")")); 
+                               }
+                       | '(' constraint_expr ')'
+                               {       $$ = cat3_str("(", $2, ")"); }
+                       | func_name '(' ')'
+                               {
+                               {       $$ = make2_str($1, "()"); }
+                               }
+                       | func_name '(' constraint_list ')'
+                               {
+                                       $$ = make2_str($1, cat3_str("(", $3,
+")"));
+                               }
+                       | constraint_expr Op constraint_expr
+                               {       $$ = make3_str($1, $2, $3); }
+                       | constraint_expr LIKE constraint_expr
+                               {       $$ = make3_str($1, "like", $3); }
+                       | constraint_expr AND constraint_expr
+                               {       $$ = make3_str($1, "and", $3); }
+                       | constraint_expr OR constraint_expr
+                               {       $$ = make3_str($1, "or", $3); }
+                       | NOT constraint_expr
+                               {       $$ = make2_str("not", $2); }
+                       | Op constraint_expr
+                               {       $$ = make2_str($1, $2); }
+                       | constraint_expr Op
+                               {       $$ = make2_str($1, $2); }
+                       | constraint_expr ISNULL
+                               {       $$ = make2_str($1, "isnull"); }
+                       | constraint_expr IS NULL_P
+                               {       $$ = make2_str($1, "is null"); }
+                       | constraint_expr NOTNULL
+                               {       $$ = make2_str($1, "notnull"); }
+                       | constraint_expr IS NOT NULL_P
+                               {       $$ = make2_str($1, "is not null"); }
+                       | constraint_expr IS TRUE_P
+                               {       $$ = make2_str($1, "is true"); }
+                       | constraint_expr IS FALSE_P
+                               {       $$ = make2_str($1, "is false"); }
+                       | constraint_expr IS NOT TRUE_P
+                               {       $$ = make2_str($1, "is not true"); }
+                       | constraint_expr IS NOT FALSE_P
+                               {       $$ = make2_str($1, "is not false"); }
+               ;
+
+key_match:  MATCH FULL                                 { $$ = "match full"; }
+               | MATCH PARTIAL                                 { $$ = "match partial"; }
+               | /*EMPTY*/                                     { $$ = ""; }
+               ;
+
+key_actions:  key_action key_action            { $$ = make2_str($1, $2); }
+               | key_action                                    { $$ = $1; }
+               | /*EMPTY*/                                     { $$ = ""; }
+               ;
+
+key_action:  ON DELETE key_reference   { $$ = make2_str("on delete", $3); }
+               | ON UPDATE key_reference               { $$ = make2_str("on update", $3); }
+               ;
+
+key_reference:  NO ACTION      { $$ = "no action"; }
+               | CASCADE       { $$ = "cascade"; }
+               | SET DEFAULT   { $$ = "set default"; }
+               | SET NULL_P    { $$ = "set null"; }
+               ;
+
+OptInherit:  INHERITS '(' relation_name_list ')' { $$ = cat3_str("inherits (", $3, ")"); }
+               | /*EMPTY*/ { $$ = ""; }
+               ;
+
+/*
+ *     "ARCHIVE" keyword was removed in 6.3, but we keep it for now
+ *  so people can upgrade with old pg_dump scripts. - momjian 1997-11-20(?)
+ */
+OptArchiveType:  ARCHIVE '=' NONE { $$ = "archive = none"; }
+               | /*EMPTY*/       { $$ = ""; }                  
+               ;
+
+CreateAsStmt:  CREATE TABLE relation_name OptCreateAs AS SubSelect
+               {
+                       $$ = make5_str("create table", $3, $4, "as", $6); 
+               }
+               ;
+
+OptCreateAs:  '(' CreateAsList ')' { $$ = cat3_str("(", $2, ")"); }
+                       | /*EMPTY*/ { $$ = ""; }        
+               ;
+
+CreateAsList:  CreateAsList ',' CreateAsElement        { $$ = make3_str($1, ",", $3); }
+                       | CreateAsElement       { $$ = $1; }
+               ;
+
+CreateAsElement:  ColId { $$ = $1; }
+               ;
+
+/*****************************************************************************
+ *
+ *             QUERY :
+ *                             CREATE SEQUENCE seqname
+ *
+ *****************************************************************************/
+
+CreateSeqStmt:  CREATE SEQUENCE relation_name OptSeqList
+                               {
+                                       $$ = make3_str("create sequence", $3, $4);
+                               }
+               ;
+
+OptSeqList:  OptSeqList OptSeqElem
+                               { $$ = make2_str($1, $2); }
+                       |       { $$ = ""; }
+               ;
+
+OptSeqElem:  CACHE IntegerOnly
+                               {
+                                       $$ = make2_str("cache", $2);
+                               }
+                       | CYCLE
+                               {
+                                       $$ = "cycle";
+                               }
+                       | INCREMENT IntegerOnly
+                               {
+                                       $$ = make2_str("increment", $2);
+                               }
+                       | MAXVALUE IntegerOnly
+                               {
+                                       $$ = make2_str("maxvalue", $2);
+                               }
+                       | MINVALUE IntegerOnly
+                               {
+                                       $$ = make2_str("minvalue", $2);
+                               }
+                       | START IntegerOnly
+                               {
+                                       $$ = make2_str("start", $2);
+                               }
+               ;
+
+IntegerOnly:  Iconst
+                               {
+                                       $$ = $1;
+                               }
+                       | '-' Iconst
+                               {
+                                       $$ = make2_str("-", $2);
+                               }
+               ;
+
+/*****************************************************************************
+ *
+ *             QUERIES :
+ *                             CREATE PROCEDURAL LANGUAGE ...
+ *                             DROP PROCEDURAL LANGUAGE ...
+ *
+ *****************************************************************************/
+
+CreatePLangStmt:  CREATE PLangTrusted PROCEDURAL LANGUAGE Sconst 
+                       HANDLER def_name LANCOMPILER Sconst
+                       {
+                               $$ = make4_str(make5_str("create", $2, "precedural language", $5, "handler"), $7, "langcompiler", $9);
+                       }
+               ;
+
+PLangTrusted:          TRUSTED { $$ = "trusted"; }
+                       |       { $$ = ""; }
+
+DropPLangStmt:  DROP PROCEDURAL LANGUAGE Sconst
+                       {
+                               $$ = make2_str("drop procedural language", $4);
+                       }
+               ;
+
+/*****************************************************************************
+ *
+ *             QUERIES :
+ *                             CREATE TRIGGER ...
+ *                             DROP TRIGGER ...
+ *
+ *****************************************************************************/
+
+CreateTrigStmt:  CREATE TRIGGER name TriggerActionTime TriggerEvents ON
+                               relation_name TriggerForSpec EXECUTE PROCEDURE
+                               name '(' TriggerFuncArgs ')'
+                               {
+                                       $$ = make2_str(make5_str(make5_str("create trigger", $3, $4, $5, "on"), $7, $8, "execute procedure", $11), cat3_str("(", $13, ")"));
+                               }
+               ;
+
+TriggerActionTime:  BEFORE                             { $$ = "before"; }
+                       | AFTER                         { $$ = "after"; }
+               ;
+
+TriggerEvents: TriggerOneEvent
+                               {
+                                       $$ = $1;
+                               }
+                       | TriggerOneEvent OR TriggerOneEvent
+                               {
+                                       $$ = make3_str($1, "or", $3);
+                               }
+                       | TriggerOneEvent OR TriggerOneEvent OR TriggerOneEvent
+                               {
+                                       $$ = make5_str($1, "or", $3, "or", $5);
+                               }
+               ;
+
+TriggerOneEvent:  INSERT                               { $$ = "insert"; }
+                       | DELETE                        { $$ = "delete"; }
+                       | UPDATE                        { $$ = "update"; }
+               ;
+
+TriggerForSpec:  FOR TriggerForOpt TriggerForType
+                               {
+                                       $$ = make3_str("for", $2, $3);
+                               }
+               ;
+
+TriggerForOpt:  EACH                                   { $$ = "each"; }
+                       | /*EMPTY*/                     { $$ = ""; }
+               ;
+
+TriggerForType:  ROW                                   { $$ = "row"; }
+                       | STATEMENT                     { $$ = "statement"; }
+               ;
+
+TriggerFuncArgs:  TriggerFuncArg
+                               { $$ = $1 }
+                       | TriggerFuncArgs ',' TriggerFuncArg
+                               { $$ = make3_str($1, ",", $3); }
+                       | /*EMPTY*/
+                               { $$ = ""; }
+               ;
+
+TriggerFuncArg:  Iconst
+                               {
+                                       $$ = $1;
+                               }
+                       | FCONST
+                               {
+                                       $$ = make_name();
+                               }
+                       | Sconst        {  $$ = $1; }
+                       | IDENT         {  $$ = $1; }
+               ;
+
+DropTrigStmt:  DROP TRIGGER name ON relation_name
+                               {
+                                       $$ = make4_str("drop trigger", $3, "on", $5);
+                               }
+               ;
+
+/*****************************************************************************
+ *
+ *             QUERY :
+ *                             define (type,operator,aggregate)
+ *
+ *****************************************************************************/
+
+DefineStmt:  CREATE def_type def_rest
+                               {
+                                       $$ = make3_str("create", $2, $3);
+                               }
+               ;
+
+def_rest:  def_name definition
+                               {
+                                       $$ = make2_str($1, $2);
+                               }
+               ;
+
+def_type:  OPERATOR            { $$ = "operator"; }
+               | TYPE_P        { $$ = "type"; }
+               | AGGREGATE     { $$ = "aggregate"; }
+               ;
+
+def_name:  PROCEDURE           { $$ = "procedure"; }
+               | JOIN          { $$ = "join"; }
+               | ColId         { $$ = $1; }
+               | MathOp        { $$ = $1; }
+               | Op            { $$ = $1; }
+               ;
+
+definition:  '(' def_list ')'                          { $$ = cat3_str("(", $2, ")"); }
+               ;
+
+def_list:  def_elem                                    { $$ = $1; }
+               | def_list ',' def_elem                 { $$ = make3_str($1, ",", $3); }
+               ;
+
+def_elem:  def_name '=' def_arg        {
+                                       $$ = make3_str($1, "=", $3);
+                               }
+               | def_name
+                               {
+                                       $$ = $1;
+                               }
+               | DEFAULT '=' def_arg
+                               {
+                                       $$ = make2_str("default =", $3);
+                               }
+               ;
+
+def_arg:  ColId                        {  $$ = $1; }
+               | all_Op        {  $$ = $1; }
+               | NumConst      {  $$ = $1; /* already a Value */ }
+               | Sconst        {  $$ = $1; }
+               | SETOF ColId
+                               {
+                                       $$ = make2_str("setof", $2);
+                               }
+               ;
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             destroy <relname1> [, <relname2> .. <relnameN> ]
+ *
+ *****************************************************************************/
+
+DestroyStmt:  DROP TABLE relation_name_list
+                               {
+                                       $$ = make2_str("drop table", $3);
+                               }
+               | DROP SEQUENCE relation_name_list
+                               {
+                                       $$ = make2_str("drop sequence", $3);
+                               }
+               ;
+
+
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                     fetch/move [forward | backward] [number | all ] [ in <portalname> ]
+ *
+ *****************************************************************************/
+
+FetchStmt:     FETCH opt_direction fetch_how_many opt_portal_name INTO into_list
+                               {
+                                       $$ = make4_str("fetch", $2, $3, $4);
+                               }
+               |       MOVE opt_direction fetch_how_many opt_portal_name
+                               {
+                                       $$ = make4_str("fetch", $2, $3, $4);
+                               }
+               ;
+
+opt_direction: FORWARD         { $$ = "forward"; }
+               | BACKWARD      { $$ = "backward"; }
+               | /*EMPTY*/     { $$ = ""; /* default */ }
+               ;
+
+fetch_how_many:  Iconst
+                          { $$ = $1;
+                                if (atol($1) <= 0) yyerror("Please specify nonnegative count for fetch"); }
+               | ALL           { $$ = "all"; }
+               | /*EMPTY*/     { $$ = ""; /*default*/ }
+               ;
+
+opt_portal_name:  IN name              { $$ = make2_str("in", $2); }
+               | name                  { $$ = make2_str("in", $1); }
+               | /*EMPTY*/             { $$ = ""; }
+               ;
+
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             GRANT [privileges] ON [relation_name_list] TO [GROUP] grantee
+ *
+ *****************************************************************************/
+
+GrantStmt:  GRANT privileges ON relation_name_list TO grantee opt_with_grant
+                               {
+                                       $$ = make2_str(make5_str("grant", $2, "on", $4, "to"), $6);
+                               }
+               ;
+
+privileges:  ALL PRIVILEGES
+                               {
+                                $$ = "all privileges";
+                               }
+               | ALL
+                               {
+                                $$ = "all";
+                               }
+               | operation_commalist
+                               {
+                                $$ = $1;
+                               }
+               ;
+
+operation_commalist:  operation
+                               {
+                                               $$ = $1;
+                               }
+               | operation_commalist ',' operation
+                               {
+                                               $$ = make3_str($1, ",", $3);
+                               }
+               ;
+
+operation:  SELECT
+                               {
+                                               $$ = "select";
+                               }
+               | INSERT
+                               {
+                                               $$ = "insert";
+                               }
+               | UPDATE
+                               {
+                                               $$ = "update";
+                               }
+               | DELETE
+                               {
+                                               $$ = "delete";
+                               }
+               | RULE
+                               {
+                                               $$ = "rule";
+                               }
+               ;
+
+grantee:  PUBLIC
+                               {
+                                               $$ = "public";
+                               }
+               | GROUP ColId
+                               {
+                                               $$ = make2_str("group", $2);
+                               }
+               | ColId
+                               {
+                                               $$ = $1;
+                               }
+               ;
+
+opt_with_grant:  WITH GRANT OPTION
+                               {
+                                       yyerror("WITH GRANT OPTION is not supported.  Only relation owners can set privileges");
+                                }
+               | /*EMPTY*/ 
+               ;
+
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             REVOKE [privileges] ON [relation_name] FROM [user]
+ *
+ *****************************************************************************/
+
+RevokeStmt:  REVOKE privileges ON relation_name_list FROM grantee
+                               {
+                                       $$ = make2_str(make5_str("revoke", $2, "on", $4, "from"), $6);
+                               }
+               ;
+
+
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             create index <indexname> on <relname>
+ *                               using <access> "(" (<col> with <op>)+ ")" [with
+ *                               <target_list>]
+ *
+ *     [where <qual>] is not supported anymore
+ *****************************************************************************/
+
+IndexStmt:     CREATE index_opt_unique INDEX index_name ON relation_name
+                       access_method_clause '(' index_params ')' opt_with
+                               {
+                                       /* should check that access_method is valid,
+                                          etc ... but doesn't */
+                                       $$ = make5_str(make5_str("create", $2, "index", $4, "on"), $6, $7, cat3_str("(", $9, ")"), $11);
+                               }
+               ;
+
+index_opt_unique:  UNIQUE      { $$ = "unique"; }
+               | /*EMPTY*/     { $$ = ""; }
+               ;
+
+access_method_clause:  USING access_method     { $$ = make2_str("using", $2); }
+               | /*EMPTY*/                     { $$ = ""; }
+               ;
+
+index_params:  index_list                      { $$ = $1; }
+               | func_index                    { $$ = $1; }
+               ;
+
+index_list:  index_list ',' index_elem         { $$ = make3_str($1, ",", $3); }
+               | index_elem                    { $$ = $1; }
+               ;
+
+func_index:  func_name '(' name_list ')' opt_type opt_class
+                               {
+                                       $$ = make4_str($1, cat3_str("(", $3, ")"), $5, $6);
+                               }
+                 ;
+
+index_elem:  attr_name opt_type opt_class
+                               {
+                                       $$ = make3_str($1, $3, $3);
+                               }
+               ;
+
+opt_type:  ':' Typename                { $$ = make2_str(":", $2); }
+               | FOR Typename  { $$ = make2_str("for", $2); }
+               | /*EMPTY*/     { $$ = ""; }
+               ;
+
+/* opt_class "WITH class" conflicts with preceeding opt_type
+ *  for Typename of "TIMESTAMP WITH TIME ZONE"
+ * So, remove "WITH class" from the syntax. OK??
+ * - thomas 1997-10-12
+ *             | WITH class                                                    { $$ = $2; }
+ */
+opt_class:  class                              { $$ = $1; }
+               | USING class                   { $$ = make2_str("using", $2); }
+               | /*EMPTY*/                     { $$ = ""; }
+               ;
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             extend index <indexname> [where <qual>]
+ *
+ *****************************************************************************/
+
+ExtendStmt:  EXTEND INDEX index_name where_clause
+                               {
+                                       $$ = make3_str("extend index", $3, $4);
+                               }
+               ;
+
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             execute recipe <recipeName>
+ *
+ *****************************************************************************/
+
+RecipeStmt:  EXECUTE RECIPE recipe_name
+                               {
+                                       $$ = make2_str("execute recipe", $3);
+                               }
+               ;
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             define function <fname>
+ *                                        (language = <lang>, returntype = <typename>
+ *                                             [, arch_pct = <percentage | pre-defined>]
+ *                                             [, disk_pct = <percentage | pre-defined>]
+ *                                             [, byte_pct = <percentage | pre-defined>]
+ *                                             [, perbyte_cpu = <int | pre-defined>]
+ *                                             [, percall_cpu = <int | pre-defined>]
+ *                                             [, iscachable])
+ *                                             [arg is (<type-1> { , <type-n>})]
+ *                                             as <filename or code in language as appropriate>
+ *
+ *****************************************************************************/
+
+ProcedureStmt: CREATE FUNCTION func_name func_args
+                        RETURNS func_return opt_with AS Sconst LANGUAGE Sconst
+                               {
+                                       $$ = make2_str(make5_str(make5_str("create function", $3, $4, "returns", $6), $7, "as", $9, "language"), $11);
+                               }
+
+opt_with:  WITH definition                     { $$ = make2_str("with", $2); }
+               | /*EMPTY*/                     { $$ = ""; }
+               ;
+
+func_args:  '(' func_args_list ')'             { $$ = cat3_str("(", $2, ")"); }
+               | '(' ')'                       { $$ = "()"; }
+               ;
+
+func_args_list:  TypeId                                { $$ = $1; }
+               | func_args_list ',' TypeId
+                               {       $$ = make3_str($1, ",", $3); }
+               ;
+
+func_return:  set_opt TypeId
+                               {
+                                       $$ = make2_str($1, $2);
+                               }
+               ;
+
+set_opt:  SETOF                                        { $$ = "setof"; }
+               | /*EMPTY*/                     { $$ = ""; }
+               ;
+
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *
+ *             remove function <funcname>
+ *                             (REMOVE FUNCTION "funcname" (arg1, arg2, ...))
+ *             remove aggregate <aggname>
+ *                             (REMOVE AGGREGATE "aggname" "aggtype")
+ *             remove operator <opname>
+ *                             (REMOVE OPERATOR "opname" (leftoperand_typ rightoperand_typ))
+ *             remove type <typename>
+ *                             (REMOVE TYPE "typename")
+ *             remove rule <rulename>
+ *                             (REMOVE RULE "rulename")
+ *
+ *****************************************************************************/
+
+RemoveStmt:  DROP remove_type name
+                               {
+                                       $$ = make3_str("drop", $2, $3);;
+                               }
+               ;
+
+remove_type:  TYPE_P           {  $$ = "type"; }
+               | INDEX         {  $$ = "index"; }
+               | RULE          {  $$ = "rule"; }
+               | VIEW          {  $$ = "view"; }
+               ;
+
+
+RemoveAggrStmt:  DROP AGGREGATE name aggr_argtype
+                               {
+                                               $$ = make3_str("drop aggregate", $3, $4);
+                               }
+               ;
+
+aggr_argtype:  name                    { $$ = $1; }
+               | '*'                   { $$ = "*"; }
+               ;
+
+
+RemoveFuncStmt:  DROP FUNCTION func_name func_args
+                               {
+                                               $$ = make3_str("drop function", $3, $4);
+                               }
+               ;
+
+
+RemoveOperStmt:  DROP OPERATOR all_Op '(' oper_argtypes ')'
+                               {
+                                       $$ = make3_str("drop operator", $3, cat3_str("(", $5, ")"));
+                               }
+               ;
+
+all_Op:  Op | MathOp;
+
+MathOp:        '+'                             { $$ = "+"; }
+               | '-'                   { $$ = "-"; }
+               | '*'                   { $$ = "*"; }
+               | '/'                   { $$ = "/"; }
+               | '<'                   { $$ = "<"; }
+               | '>'                   { $$ = ">"; }
+               | '='                   { $$ = "="; }
+               ;
+
+oper_argtypes: name
+                               {
+                                  yyerror("parser: argument type missing (use NONE for unary operators)");
+                               }
+               | name ',' name
+                               { $$ = make3_str($1, ",", $3); }
+               | NONE ',' name                 /* left unary */
+                               { $$ = make2_str("none,", $3); }
+               | name ',' NONE                 /* right unary */
+                               { $$ = make2_str($1, ", none"); }
+               ;
+
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             rename <attrname1> in <relname> [*] to <attrname2>
+ *                             rename <relname1> to <relname2>
+ *
+ *****************************************************************************/
+
+RenameStmt:  ALTER TABLE relation_name opt_inh_star
+                                 RENAME opt_column opt_name TO name
+                               {
+                                       $$ = make4_str(make5_str("alter table", $3, $4, "rename", $6), $7, "to", $9);
+                               }
+               ;
+
+opt_name:  name                                                        { $$ = $1; }
+               | /*EMPTY*/                                     { $$ = ""; }
+               ;
+
+opt_column:  COLUMN                                    { $$ = "colmunn"; }
+               | /*EMPTY*/                             { $$ = ""; }
+               ;
+
+
+/*****************************************************************************
+ *
+ *             QUERY:  Define Rewrite Rule , Define Tuple Rule
+ *                             Define Rule <old rules >
+ *
+ *             only rewrite rule is supported -- ay 9/94
+ *
+ *****************************************************************************/
+
+RuleStmt:  CREATE RULE name AS
+                  { QueryIsRule=1; }
+                  ON event TO event_object where_clause
+                  DO opt_instead OptStmtList
+                               {
+                                       $$ = make2_str(make5_str(make5_str("create rule", $3, "as on", $7, "to"), $9, $10, "do", $12), $13);
+                               }
+               ;
+
+OptStmtList:  NOTHING                                  { $$ = "nothing"; }
+               | OptimizableStmt                       { $$ = $1; }
+               | '[' OptStmtBlock ']'                  { $$ = make3_str("[", $2, "]"); }
+               ;
+
+OptStmtBlock:  OptStmtMulti
+                               {  $$ = $1; }
+               | OptimizableStmt
+                               { $$ = $1; }
+               ;
+
+OptStmtMulti:  OptStmtMulti OptimizableStmt ';'
+                               {  $$ = make3_str($1, $2, ";"); }
+               | OptStmtMulti OptimizableStmt
+                               {  $$ = make2_str($1, $2); }
+               | OptimizableStmt ';'
+                               { $$ = $1; }
+               ;
+
+event_object:  relation_name '.' attr_name
+                               {
+                                       $$ = make3_str($1, ",", $3);
+                               }
+               | relation_name
+                               {
+                                       $$ = $1;
+                               }
+               ;
+
+/* change me to select, update, etc. some day */
+event: SELECT                                  { $$ = "select"; }
+               | UPDATE                        { $$ = "update"; }
+               | DELETE                        { $$ = "delete"; }
+               | INSERT                        { $$ = "insert"; }
+                ;
+
+opt_instead:  INSTEAD                                  { $$ = "instead"; }
+               | /*EMPTY*/                             { $$ = ""; }
+               ;
+
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             NOTIFY <relation_name>  can appear both in rule bodies and
+ *                             as a query-level command
+ *
+ *****************************************************************************/
+
+NotifyStmt:  NOTIFY relation_name
+                               {
+                                       $$ = make2_str("notify", $2);
+                               }
+               ;
+
+ListenStmt:  LISTEN relation_name
+                               {
+                                       $$ = make2_str("listen", $2);
+                                }
+;
+
+/*****************************************************************************
+ *
+ *              Transactions:
+ *
+ *              abort transaction
+ *                              (ABORT)
+ *              begin transaction
+ *                              (BEGIN)
+ *              end transaction  
+ *                              (END)
+ *
+ *****************************************************************************/
+TransactionStmt:  ABORT_TRANS TRANSACTION      { $$ = "rollback"; }
+       | BEGIN_TRANS TRANSACTION               { $$ = "begin transaction"; }
+       | BEGIN_TRANS WORK                      { $$ = "begin transaction"; }
+       | COMMIT WORK                           { $$ = "commit"; }
+       | END_TRANS TRANSACTION                 { $$ = "commit"; }
+       | ROLLBACK WORK                         { $$ = "rollback"; }
+       | ABORT_TRANS                           { $$ = "rollback"; }
+       | COMMIT                                { $$ = "commit"; }
+       | ROLLBACK                              { $$ = "rollback"; }
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             define view <viewname> '('target-list ')' [where <quals> ]
+ *
+ *****************************************************************************/
+
+ViewStmt:  CREATE VIEW name AS SelectStmt
+                               {
+                                       $$ = make4_str("create view", $3, "as", $5);
+                               }
+               ;
+
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             load "filename"
+ *
+ *****************************************************************************/
+
+LoadStmt:  LOAD file_name
+                               {
+                                       $$ = make2_str("load", $2);
+                               }
+               ;
+
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             createdb dbname
+ *
+ *****************************************************************************/
+
+CreatedbStmt:  CREATE DATABASE database_name opt_database
+                               {
+                                       $$ = make3_str("create database", $3, $4);
+                               }
+               ;
+
+opt_database:  WITH LOCATION '=' location      { $$ = make2_str("with location =", $4); }
+               | /*EMPTY*/                     { $$ = ""; }
+               ;
+
+location:  Sconst                              { $$ = $1; }
+               | DEFAULT                       { $$ = "default"; }
+               | /*EMPTY*/                     { $$ = ""; }
+               ;
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             destroydb dbname
+ *
+ *****************************************************************************/
+
+DestroydbStmt: DROP DATABASE database_name
+                               {
+                                       $$ = make2_str("drop database", $3);
+                               }
+               ;
+
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             cluster <index_name> on <relation_name>
+ *
+ *****************************************************************************/
+
+ClusterStmt:  CLUSTER index_name ON relation_name
+                               {
+                                  $$ = make4_str("cluster", $2, "on", $4);
+                               }
+               ;
+
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             vacuum
+ *
+ *****************************************************************************/
+
+VacuumStmt:  VACUUM opt_verbose opt_analyze
+                               {
+                                       $$ = make3_str("vacuum", $2, $3);
+                               }
+               | VACUUM opt_verbose opt_analyze relation_name opt_va_list
+                               {
+                                       if ( strlen($5) > 0 && strlen($4) == 0 )
+                                               yyerror("parser: syntax error at or near \"(\"");
+                                       $$ = make5_str("vacuum", $2, $3, $4, $5);
+                               }
+               ;
+
+opt_verbose:  VERBOSE                                  { $$ = "verbose"; }
+               | /*EMPTY*/                             { $$ = ""; }
+               ;
+
+opt_analyze:  ANALYZE                                  { $$ = "analyse"; }
+               | /*EMPTY*/                             { $$ = ""; }
+               ;
+
+opt_va_list:  '(' va_list ')'                          { $$ = cat3_str("(", $2, ")"); }
+               | /*EMPTY*/                             { $$ = ""; }
+               ;
+
+va_list:  name
+                               { $$=$1; }
+               | va_list ',' name
+                               { $$=make3_str($1, ",", $3); }
+               ;
+
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             EXPLAIN query
+ *
+ *****************************************************************************/
+
+ExplainStmt:  EXPLAIN opt_verbose OptimizableStmt
+                               {
+                                       $$ = make3_str("explain", $2, $3);
+                               }
+               ;
+
+
+/*****************************************************************************
+ *                                                                                                                                                      *
+ *             Optimizable Stmts:                                                                                                       *
+ *                                                                                                                                                      *
+ *             one of the five queries processed by the planner                                         *
+ *                                                                                                                                                      *
+ *             [ultimately] produces query-trees as specified                                           *
+ *             in the query-spec document in ~postgres/ref                                                      *
+ *                                                                                                                                                      *
+ *****************************************************************************/
+
+OptimizableStmt:  SelectStmt { output_statement($1); }
+               | CursorStmt { fputs($1, yyout); output_line_number(); }
+               | UpdateStmt { output_statement($1); }
+               | InsertStmt { output_statement($1); }
+               | NotifyStmt { output_statement($1); }
+               | DeleteStmt { output_statement($1); }
+               ;
+
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             INSERT STATEMENTS
+ *
+ *****************************************************************************/
+
+InsertStmt:  INSERT INTO relation_name opt_column_list insert_rest
+                               {
+                                       $$ = make4_str("insert into", $3, $4, $5);
+                               }
+               ;
+
+insert_rest:  VALUES '(' res_target_list2 ')'
+                               {
+                                       $$ = cat3_str("values(", $3, ")");
+                               }
+               | SELECT opt_unique res_target_list2
+                        from_clause where_clause
+                        group_clause having_clause
+                        union_clause
+                               {
+                                       $$ = make4_str(make5_str("select", $2, $3, $4, $5), $6, $7, $8);
+                               }
+               ;
+
+opt_column_list:  '(' columnList ')'                   { $$ = cat3_str("(", $2, ")"); }
+               | /*EMPTY*/                             { $$ = ""; }
+               ;
+
+columnList:
+                 columnList ',' columnElem
+                               { $$ = make3_str($1, ",", $3); }
+               | columnElem
+                               { $$ = $1; }
+               ;
+
+columnElem:  ColId opt_indirection
+                               {
+                                       $$ = make2_str($1, $2);
+                               }
+               ;
+
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             DELETE STATEMENTS
+ *
+ *****************************************************************************/
+
+DeleteStmt:  DELETE FROM relation_name
+                        where_clause
+                               {
+                                       $$ = make3_str("delete from", $3, $4);
+                               }
+               ;
+
+/*
+ *     Total hack to just lock a table inside a transaction.
+ *     Is it worth making this a separate command, with
+ *     its own node type and file.  I don't think so. bjm 1998/1/22
+ */
+LockStmt:  LOCK_P opt_table relation_name
+                               {
+                                       $$ = make3_str("lock", $2, $3);
+                               }
+               ;
+
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             UpdateStmt (UPDATE)
+ *
+ *****************************************************************************/
+
+UpdateStmt:  UPDATE relation_name
+                         SET res_target_list
+                         from_clause
+                         where_clause
+                               {
+                                       $$ = make2_str(make5_str("update", $2, "set", $4, $5), $6);
+                               }
+               ;
+
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             CURSOR STATEMENTS
+ *
+ *****************************************************************************/
+CursorStmt:  DECLARE name opt_binary CURSOR FOR
+                        SELECT opt_unique res_target_list2
+                        from_clause where_clause
+                        group_clause having_clause
+                        union_clause sort_clause
+                               {
+                                       struct cursor *ptr, *this = (struct cursor *) mm_alloc(sizeof(struct cursor));
+
+                                       this->name = $2;
+                                       this->command = make4_str(make5_str(make5_str("declare", $2, $3, "cursor for select", $7), $8, $9, $10, $11), $12, $13, $14);
+                                       this->next = NULL;
+
+                                       for (ptr = cur; ptr != NULL; ptr = ptr->next)
+                                       {
+                                               if (strcmp(this->name, ptr->name) == 0)
+                                               {
+                                                       /* re-definition */
+                                                       free(ptr->command);
+                                                       ptr->command = this->command;
+                                                       break;
+                                               }
+                                       }
+
+                                       if (ptr == NULL)
+                                       {
+                                               /* initial definition */
+                                               this->next = cur;
+                                               cur = this;
+                                       }
+
+                                       $$ = make5_str("/* declare cursor\"", $2, "\"statement has been moved to location of open cursor \"", $2, "\"statement. */");
+                               }
+               ;
+
+
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                             SELECT STATEMENTS
+ *
+ *****************************************************************************/
+
+SelectStmt:  SELECT opt_unique res_target_list2
+                        result from_clause where_clause
+                        group_clause having_clause
+                        union_clause sort_clause
+                               {
+                                       $$ = make2_str(make5_str(make5_str("select", $2, $3, $4, $5), $6, $7, $8, $9), $10);
+                               }
+               ;
+
+union_clause:  UNION opt_union select_list
+                               {
+                                       $$ = make3_str("union", $2, $3);
+                               }
+               | /*EMPTY*/
+                               { $$ = ""; }
+               ;
+
+select_list:  select_list UNION opt_union SubSelect
+                               {
+                                       $$ = make4_str($1, "union", $3, $4);
+                               }
+               | SubSelect
+                               { $$ = $1; }
+               ;
+
+SubSelect:     SELECT opt_unique res_target_list2
+                        from_clause where_clause
+                        group_clause having_clause
+                               {
+                                       $$ = make3_str(make5_str("select", $2, $3, $4, $5), $6, $7);
+                               }
+               ;
+
+result:  INTO opt_table relation_name                  { $$= make3_str("into", $2, $3); }
+               | INTO into_list                        { $$ = ""; }
+               | /*EMPTY*/                             { $$ = ""; }
+               ;
+
+opt_table:  TABLE                                      { $$ = "table"; }
+               | /*EMPTY*/                             { $$ = ""; }
+               ;
+
+opt_union:  ALL                                                { $$ = "all"; }
+               | /*EMPTY*/                             { $$ = ""; }
+               ;
+
+opt_unique:  DISTINCT                                  { $$ = "distinct"; }
+               | DISTINCT ON ColId                     { $$ = make2_str("distinct on", $3); }
+               | ALL                                   { $$ = "all"; }
+               | /*EMPTY*/                             { $$ = ""; }
+               ;
+
+sort_clause:  ORDER BY sortby_list                     { $$ = make2_str("order by", $3); }
+               | /*EMPTY*/                             { $$ = ""; }
+               ;
+
+sortby_list:  sortby                                   { $$ = $1; }
+               | sortby_list ',' sortby                { $$ = make3_str($1, ",", $3); }
+               ;
+
+sortby:  ColId OptUseOp
+                               {
+                                       $$ = make2_str($1, $2);
+                               }
+               | ColId '.' ColId OptUseOp
+                               {
+                                       $$ = make4_str($1, ".", $3, $4);
+                               }
+               | Iconst OptUseOp
+                               {
+                                       $$ = make2_str($1, $2);
+                               }
+               ;
+
+OptUseOp:  USING Op                            { $$ = make2_str("using", $2); }
+               | USING '<'                     { $$ = "using <"; }
+               | USING '>'                     { $$ = "using >"; }
+               | ASC                           { $$ = "asc"; }
+               | DESC                          { $$ = "desc"; }
+               | /*EMPTY*/                     { $$ = ""; }
+               ;
+
+/*
+ *     jimmy bell-style recursive queries aren't supported in the
+ *     current system.
+ *
+ *     ...however, recursive addattr and rename supported.  make special
+ *     cases for these.
+ */
+opt_inh_star:  '*'                                     { $$ = "*"; }
+               | /*EMPTY*/                             { $$ = ""; }
+               ;
+
+relation_name_list:  name_list { $$ = $1; };
+
+name_list:  name
+                               {       $$ = $1; }
+               | name_list ',' name
+                               {       $$ = make3_str($1, ",", $3); }
+               ;
+
+group_clause:  GROUP BY groupby_list                   { $$ = make2_str("groub by", $3); }
+               | /*EMPTY*/                             { $$ = ""; }
+               ;
+
+groupby_list:  groupby                                 { $$ = $1; }
+               | groupby_list ',' groupby              { $$ = make3_str($1, ",", $3); }
+               ;
+
+groupby:  ColId
+                               {
+                                       $$ = $1;
+                               }
+               | ColId '.' ColId
+                               {
+                                       $$ = make3_str($1, ",", $3);
+                               }
+               | Iconst
+                               {
+                                       $$ = $1;
+                               }
+               ;
+
+having_clause:  HAVING a_expr
+                               {
+                                       yyerror("HAVING clause not yet implemented");
+/*                                     $$ = make2_str("having", $2); use this line instead to enable HAVING */
+                               }
+               | /*EMPTY*/             { $$ = ""; }
+               ;
+
+
+/*****************************************************************************
+ *
+ *     clauses common to all Optimizable Stmts:
+ *             from_clause             -
+ *             where_clause    -
+ *
+ *****************************************************************************/
+
+from_clause:  FROM '(' relation_expr join_expr JOIN relation_expr join_spec ')'
+                               {
+                                       yyerror("JOIN not yet implemented");
+                               }
+               | FROM from_list        { $$ = make2_str("from", $2); }
+               | /*EMPTY*/             { $$ = ""; }
+               ;
+
+from_list:     from_list ',' from_val
+                               { $$ = make3_str($1, ",", $3); }
+               | from_val CROSS JOIN from_val
+                               { yyerror("CROSS JOIN not yet implemented"); }
+               | from_val
+                               { $$ = $1; }
+               ;
+
+from_val:  relation_expr AS ColLabel
+                               {
+                                       $$ = make3_str($1, "as", $3);
+                               }
+               | relation_expr ColId
+                               {
+                                       $$ = make2_str($1, $2);
+                               }
+               | relation_expr
+                               {
+                                       $$ = $1;
+                               }
+               ;
+
+join_expr:  NATURAL join_expr                                  { $$ = make2_str("natural", $2); }
+               | FULL join_outer
+                               { yyerror("FULL OUTER JOIN not yet implemented"); }
+               | LEFT join_outer
+                               { yyerror("LEFT OUTER JOIN not yet implemented"); }
+               | RIGHT join_outer
+                               { yyerror("RIGHT OUTER JOIN not yet implemented"); }
+               | OUTER_P
+                               { yyerror("OUTER JOIN not yet implemented"); }
+               | INNER_P
+                               { yyerror("INNER JOIN not yet implemented"); }
+               | UNION
+                               { yyerror("UNION JOIN not yet implemented"); }
+               | /*EMPTY*/
+                               { yyerror("INNER JOIN not yet implemented"); }
+               ;
+
+join_outer:  OUTER_P                           { $$ = "outer"; }
+               | /*EMPTY*/                     { $$ = "";  /* no qualifiers */ }
+               ;
+
+join_spec:     ON '(' a_expr ')'                       { $$ = cat3_str("on (", $3, ")"); }
+               | USING '(' join_list ')'               { $$ = cat3_str("using (", $3, ")"); }
+               | /*EMPTY*/                             { $$ = "";  /* no qualifiers */ }
+               ;
+
+join_list:  join_using                                 { $$ = $1; }
+               | join_list ',' join_using              { $$ = make3_str($1, ",", $3); }
+               ;
+
+join_using:  ColId
+                               {
+                                       $$ = $1;
+                               }
+               | ColId '.' ColId
+                               {
+                                       $$ = make3_str($1, ".", $3);
+                               }
+               | Iconst
+                               {
+                                       $$ = $1;;
+                               }
+               ;
+
+where_clause:  WHERE a_expr                    { $$ = make2_str("where", $2); }
+               | /*EMPTY*/                             { $$ = "";  /* no qualifiers */ }
+               ;
+
+relation_expr: relation_name
+                               {
+                                       /* normal relations */
+                                       $$ = $1;
+                               }
+               | relation_name '*'                               %prec '='
+                               {
+                                       /* inheritance query */
+                                       $$ = make2_str($1, "*");
+                               }
+
+opt_array_bounds:  '[' ']' nest_array_bounds
+                               {  $$ = make2_str("[]", $3); }
+               | '[' Iconst ']' nest_array_bounds
+                               {  $$ = make4_str("[", $2, "]", $4); }
+               | /* EMPTY */
+                               {  $$ = ""; }
+               ;
+
+nest_array_bounds:     '[' ']' nest_array_bounds
+                               {  $$ = make2_str("[]", $3); }
+               | '[' Iconst ']' nest_array_bounds
+                               {  $$ = make4_str("[", $2, "]", $4); }
+               | /*EMPTY*/
+                               {  $$ = ""; }
+               ;
+
+
+/*****************************************************************************
+ *
+ *     Type syntax
+ *             SQL92 introduces a large amount of type-specific syntax.
+ *             Define individual clauses to handle these cases, and use
+ *              the generic case to handle regular type-extensible Postgres syntax.
+ *             - thomas 1997-10-10
+ *
+ *****************************************************************************/
+
+Typename:  Array opt_array_bounds
+                               {
+                                       $$ = make2_str($1, $2);
+                               }
+               | Character     { $$ = $1; }
+               | SETOF Array
+                               {
+                                       $$ = make2_str("setof", $2);
+                               }
+               ;
+
+Array:  Generic
+               | Datetime      { $$ = $1; }
+               | Numeric       { $$ = $1; }
+               ;
+
+Generic:  generic
+                               {
+                                       $$ = $1;
+                               }
+               ;
+
+generic:  IDENT                                        { $$ = $1; }
+               | TYPE_P                        { $$ = "type"; }
+               ;
+
+/* SQL92 numeric data types
+ * Check FLOAT() precision limits assuming IEEE floating types.
+ * Provide rudimentary DECIMAL() and NUMERIC() implementations
+ *  by checking parameters and making sure they match what is possible with INTEGER.
+ * - thomas 1997-09-18
+ */
+Numeric:  FLOAT opt_float
+                               {
+                                       $$ = make2_str("float", $2);
+                               }
+               | DOUBLE PRECISION
+                               {
+                                       $$ = "double precision";
+                               }
+               | DECIMAL opt_decimal
+                               {
+                                       $$ = make2_str("decimal", $2);
+                               }
+               | NUMERIC opt_numeric
+                               {
+                                       $$ = make2_str("numeric", $2);
+                               }
+               ;
+
+numeric:  FLOAT
+                               {       $$ = "float"; }
+               | DOUBLE PRECISION
+                               {       $$ = "double precision"; }
+               | DECIMAL
+                               {       $$ = "decimal"; }
+               | NUMERIC
+                               {       $$ = "numeric"; }
+               ;
+
+opt_float:  '(' Iconst ')'
+                               {
+                                       if (atol($2) < 1)
+                                               yyerror("precision for FLOAT must be at least 1");
+                                       else if (atol($2) >= 16)
+                                               yyerror("precision for FLOAT must be less than 16");
+                                       $$ = cat3_str("(", $2, ")");
+                               }
+               | /*EMPTY*/
+                               {
+                                       $$ = "";
+                               }
+               ;
+
+opt_numeric:  '(' Iconst ',' Iconst ')'
+                               {
+                                       if (atol($2) != 9) {
+                                               sprintf(errortext, "NUMERIC precision %s must be 9", $2);
+                                               yyerror(errortext);
+                                       }
+                                       if (atol($4) != 0) {
+                                               sprintf(errortext, "NUMERIC scale %s must be zero", $4);
+                                               yyerror(errortext);
+                                       }
+                                       $$ = make3_str(cat2_str("(", $2), ",", cat2_str($4, ")"));
+                               }
+               | '(' Iconst ')'
+                               {
+                                       if (atol($2) != 9) {
+                                               sprintf("NUMERIC precision %s must be 9",$2);
+                                               yyerror(errortext);
+                                       }
+                                       $$ = cat3_str("(", $2, ")");
+                               }
+               | /*EMPTY*/
+                               {
+                                       $$ = "";
+                               }
+               ;
+
+opt_decimal:  '(' Iconst ',' Iconst ')'
+                               {
+                                       if (atol($2) != 9) {
+                                               sprintf(errortext, "DECIMAL precision %s exceeds implementation limit of 9", $2);
+                                               yyerror(errortext);
+                                       }
+                                       if (atol($4) != 0) {
+                                               sprintf(errortext, "DECIMAL scale %s must be zero",$4);
+                                                yyerror(errortext);
+                                        }
+                                       $$ = make3_str(cat2_str("(", $2), ",", cat2_str($4, ")"));
+                               }
+               | '(' Iconst ')'
+                               {
+                                       if (atol($2) != 9) {
+                                               sprintf(errortext, "DECIMAL precision %s exceeds implementation limit of 9",$2);
+                                                yyerror(errortext);
+                                        }
+                                       $$ = cat3_str("(", $2, ")");
+                               }
+               | /*EMPTY*/
+                               {
+                                       $$ = "";
+                               }
+               ;
+
+/* SQL92 character data types
+ * The following implements CHAR() and VARCHAR().
+ * We do it here instead of the 'Generic' production
+ * because we don't want to allow arrays of VARCHAR().
+ * I haven't thought about whether that will work or not.
+ *                                                             - ay 6/95
+ */
+Character:  character '(' Iconst ')'
+                               {
+                                       if (strncasecmp($1, "char", strlen("char")) && strncasecmp($1, "varchar", strlen("varchar")))
+                                               yyerror("parse error");
+                                       if (atol($3) < 1) {
+                                               sprintf(errortext, "length for '%s' type must be at least 1",$1);
+                                               yyerror(errortext);
+                                       }
+                                       else if (atol($3) > 4096) {
+                                               /* we can store a char() of length up to the size
+                                                * of a page (8KB) - page headers and friends but
+                                                * just to be safe here...      - ay 6/95
+                                                * XXX note this hardcoded limit - thomas 1997-07-13
+                                                */
+                                               sprintf(errortext, "length for type '%s' cannot exceed 4096",$1);
+                                               yyerror(errortext);
+                                       }
+
+                                       $$ = make2_str($1, cat3_str("(", $3, ")"));
+                               }
+               | character
+                               {
+                                       $$ = $1;
+                               }
+               ;
+
+character:  CHARACTER opt_varying opt_charset opt_collate
+                               {
+                                       if (strlen($4) > 0) {
+                                               sprintf(errortext, "COLLATE %s not yet implemented",$4);
+                                               yyerror(errortext);
+                                       }
+                                       $$ = make4_str("character", $2, $3, $4);
+                               }
+               | CHAR opt_varying      { $$ = make2_str("char", $2); }
+               | VARCHAR               { $$ = "varchar"; }
+               | NATIONAL CHARACTER opt_varying { $$ = make2_str("national character", $3); }
+               | NCHAR opt_varying             { $$ = make2_str("nchar", $2); }
+               ;
+
+opt_varying:  VARYING                  { $$ = "varying"; }
+               | /*EMPTY*/                     { $$ = ""; }
+               ;
+
+opt_charset:  CHARACTER SET ColId      { $$ = make2_str("character set", $3); }
+               | /*EMPTY*/                             { $$ = ""; }
+               ;
+
+opt_collate:  COLLATE ColId            { $$ = make2_str("collate", $2); }
+               | /*EMPTY*/                                     { $$ = ""; }
+               ;
+
+Datetime:  datetime
+                               {
+                                       $$ = $1;
+                               }
+               | TIMESTAMP opt_timezone
+                               {
+                                       $$ = make2_str("timestamp", $2);
+                               }
+               | TIME
+                               {
+                                       $$ = "time";
+                               }
+               | INTERVAL opt_interval
+                               {
+                                       $$ = make2_str("interval", $2);
+                               }
+               ;
+
+datetime:  YEAR_P                                                              { $$ = "year"; }
+               | MONTH_P                                                               { $$ = "month"; }
+               | DAY_P                                                                 { $$ = "day"; }
+               | HOUR_P                                                                { $$ = "hour"; }
+               | MINUTE_P                                                              { $$ = "minute"; }
+               | SECOND_P                                                              { $$ = "second"; }
+               ;
+
+opt_timezone:  WITH TIME ZONE                          { $$ = "with time zone"; }
+               | /*EMPTY*/                                     { $$ = ""; }
+               ;
+
+opt_interval:  datetime                                        { $$ = $1; }
+               | YEAR_P TO MONTH_P                     { $$ = "year to #month"; }
+               | DAY_P TO HOUR_P                       { $$ = "day to hour"; }
+               | DAY_P TO MINUTE_P                     { $$ = "day to minute"; }
+               | DAY_P TO SECOND_P                     { $$ = "day to second"; }
+               | HOUR_P TO MINUTE_P                    { $$ = "hour to minute"; }
+               | HOUR_P TO SECOND_P                    { $$ = "hour to second"; }
+               | /*EMPTY*/                                     { $$ = ""; }
+               ;
+
+
+/*****************************************************************************
+ *
+ *     expression grammar, still needs some cleanup
+ *
+ *****************************************************************************/
+
+a_expr_or_null:  a_expr
+                               { $$ = $1; }
+               | NULL_P
+                               {
+                                       $$ = "null";
+                               }
+               ;
+
+/* Expressions using row descriptors
+ * Define row_descriptor to allow yacc to break the reduce/reduce conflict
+ *  with singleton expressions.
+ */
+row_expr: '(' row_descriptor ')' IN '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ") in (", $6, ")");
+                               }
+               | '(' row_descriptor ')' NOT IN '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ") not in (", $7, ")");
+                               }
+               | '(' row_descriptor ')' Op '(' SubSelect ')'
+                               {
+                                       $$ = cat3_str(cat5_str("(", $2, ")", $4, "("), $6, ")");
+                               }
+               | '(' row_descriptor ')' '+' '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")+(", $6, ")");
+                               }
+               | '(' row_descriptor ')' '-' '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")-(", $6, ")");
+                               }
+               | '(' row_descriptor ')' '/' '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")/(", $6, ")");
+                               }
+               | '(' row_descriptor ')' '*' '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")*(", $6, ")");
+                               }
+               | '(' row_descriptor ')' '<' '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")<(", $6, ")");
+                               }
+               | '(' row_descriptor ')' '>' '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")>(", $6, ")");
+                               }
+               | '(' row_descriptor ')' '=' '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")=(", $6, ")");
+                               }
+               | '(' row_descriptor ')' Op ANY '(' SubSelect ')'
+                               {
+                                       $$ = make3_str(cat3_str("(", $2, ")"), $4, cat3_str("any(", $7, ")"));
+                               }
+               | '(' row_descriptor ')' '+' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")+any(", $7, ")");
+                               }
+               | '(' row_descriptor ')' '-' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")-any(", $7, ")");
+                               }
+               | '(' row_descriptor ')' '/' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")/any(", $7, ")");
+                               }
+               | '(' row_descriptor ')' '*' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")*any(", $7, ")");
+                               }
+               | '(' row_descriptor ')' '<' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")<any(", $7, ")");
+                               }
+               | '(' row_descriptor ')' '>' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")>any(", $7, ")");
+                               }
+               | '(' row_descriptor ')' '=' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")=any(", $7, ")");
+                               }
+               | '(' row_descriptor ')' Op ALL '(' SubSelect ')'
+                               {
+                                       $$ = make3_str(cat3_str("(", $2, ")"), $4, cat3_str("all(", $7, ")"));
+                               }
+               | '(' row_descriptor ')' '+' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")+all(", $7, ")");
+                               }
+               | '(' row_descriptor ')' '-' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")-all(", $7, ")");
+                               }
+               | '(' row_descriptor ')' '/' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")/all(", $7, ")");
+                               }
+               | '(' row_descriptor ')' '*' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")*all(", $7, ")");
+                               }
+               | '(' row_descriptor ')' '<' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")<all(", $7, ")");
+                               }
+               | '(' row_descriptor ')' '>' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")>all(", $7, ")");
+                               }
+               | '(' row_descriptor ')' '=' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")=all(", $7, ")");
+                               }
+               | '(' row_descriptor ')' Op '(' row_descriptor ')'
+                               {
+                                       $$ = make3_str(cat3_str("(", $2, ")"), $4, cat3_str("(", $6, ")"));
+                               }
+               | '(' row_descriptor ')' '+' '(' row_descriptor ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")+(", $6, ")");
+                               }
+               | '(' row_descriptor ')' '-' '(' row_descriptor ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")-(", $6, ")");
+                               }
+               | '(' row_descriptor ')' '/' '(' row_descriptor ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")/(", $6, ")");
+                               }
+               | '(' row_descriptor ')' '*' '(' row_descriptor ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")*(", $6, ")");
+                               }
+               | '(' row_descriptor ')' '<' '(' row_descriptor ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")<(", $6, ")");
+                               }
+               | '(' row_descriptor ')' '>' '(' row_descriptor ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")>(", $6, ")");
+                               }
+               | '(' row_descriptor ')' '=' '(' row_descriptor ')'
+                               {
+                                       $$ = cat5_str("(", $2, ")=(", $6, ")");
+                               }
+               ;
+
+row_descriptor:  row_list ',' a_expr
+                               {
+                                       $$ = make3_str($1, ",", $3);
+                               }
+               ;
+
+row_list:  row_list ',' a_expr
+                               {
+                                       $$ = make3_str($1, ",", $3);
+                               }
+               | a_expr
+                               {
+                                       $$ = $1;
+                               }
+               ;
+
+/*
+ * This is the heart of the expression syntax.
+ * Note that the BETWEEN clause looks similar to a boolean expression
+ *  and so we must define b_expr which is almost the same as a_expr
+ *  but without the boolean expressions.
+ * All operations are allowed in a BETWEEN clause if surrounded by parens.
+ */
+
+a_expr:  attr opt_indirection
+                               {
+                                       $$ = make2_str($1, $2);
+                               }
+               | row_expr
+                               {       $$ = $1;  }
+               | AexprConst
+                               {       $$ = $1;  }
+               | ColId
+                               {
+                                       $$ = $1;
+                               }
+               | '-' a_expr %prec UMINUS
+                               {       $$ = make2_str("-", $2); }
+               | a_expr '+' a_expr
+                               {       $$ = make3_str($1, "+", $3); }
+               | a_expr '-' a_expr
+                               {       $$ = make3_str($1, "-", $3); }
+               | a_expr '/' a_expr
+                               {       $$ = make3_str($1, "/", $3); }
+               | a_expr '*' a_expr
+                               {       $$ = make3_str($1, "*", $3); }
+               | a_expr '<' a_expr
+                               {       $$ = make3_str($1, "<", $3); }
+               | a_expr '>' a_expr
+                               {       $$ = make3_str($1, ">", $3); }
+               | a_expr '=' a_expr
+                               {       $$ = make3_str($1, "=", $3); }
+/* not possible in embedded sql                | ':' a_expr
+                               {       $$ = make2_str(":", $2); }
+*/
+               | ';' a_expr
+                               {       $$ = make2_str(";", $2); }
+               | '|' a_expr
+                               {       $$ = make2_str("|", $2); }
+               | a_expr TYPECAST Typename
+                               {
+                                       $$ = make3_str($1, "::", $3);
+                               }
+               | CAST '(' a_expr AS Typename ')'
+                               {
+                                       $$ = make3_str(cat2_str("cast(", $3), "as", cat2_str($5, ")"));
+                               }
+               | '(' a_expr_or_null ')'
+                               {       $$ = cat3_str("(", $2, ")"); }
+               | a_expr Op a_expr
+                               {       $$ = make3_str($1, $2, $3);     }
+               | a_expr LIKE a_expr
+                               {       $$ = make3_str($1, "like", $3); }
+               | a_expr NOT LIKE a_expr
+                               {       $$ = make3_str($1, "not like", $4); }
+               | Op a_expr
+                               {       $$ = make2_str($1, $2); }
+               | a_expr Op
+                               {       $$ = make2_str($1, $2); }
+               | func_name '(' '*' ')'
+                               {
+                                       $$ = make2_str($1, "(*)"); 
+                               }
+               | func_name '(' ')'
+                               {
+                                       $$ = make2_str($1, "()"); 
+                               }
+               | func_name '(' expr_list ')'
+                               {
+                                       $$ = cat4_str($1, "(", $3, ")"); 
+                               }
+               | CURRENT_DATE
+                               {
+                                       $$ = "current_date";
+                               }
+               | CURRENT_TIME
+                               {
+                                       $$ = "current_time";
+                               }
+               | CURRENT_TIME '(' Iconst ')'
+                               {
+                                       if (atol($3) != 0)
+                                               fprintf(stderr,"CURRENT_TIME(%s) precision not implemented; zero used instead", $3);
+                                       $$ = "current_time";
+                               }
+               | CURRENT_TIMESTAMP
+                               {
+                                       $$ = "current_timestamp";
+                               }
+               | CURRENT_TIMESTAMP '(' Iconst ')'
+                               {
+                                       if (atol($3) != 0)
+                                               fprintf(stderr,"CURRENT_TIMESTAMP(%s) precision not implemented; zero used instead",$3);
+                                       $$ = "current_timestamp";
+                               }
+               | CURRENT_USER
+                               {
+                                       $$ = "current_user";
+                               }
+               | EXISTS '(' SubSelect ')'
+                               {
+                                       $$ = cat3_str("exists(", $3, ")");
+                               }
+               | EXTRACT '(' extract_list ')'
+                               {
+                                       $$ = cat3_str("extract(", $3, ")");
+                               }
+               | POSITION '(' position_list ')'
+                               {
+                                       $$ = cat3_str("position(", $3, ")");
+                               }
+               | SUBSTRING '(' substr_list ')'
+                               {
+                                       $$ = cat3_str("substring(", $3, ")");
+                               }
+               /* various trim expressions are defined in SQL92 - thomas 1997-07-19 */
+               | TRIM '(' BOTH trim_list ')'
+                               {
+                                       $$ = cat3_str("trim(both", $4, ")");
+                               }
+               | TRIM '(' LEADING trim_list ')'
+                               {
+                                       $$ = cat3_str("trim(leading", $4, ")");
+                               }
+               | TRIM '(' TRAILING trim_list ')'
+                               {
+                                       $$ = cat3_str("trim(trailing", $4, ")");
+                               }
+               | TRIM '(' trim_list ')'
+                               {
+                                       $$ = cat3_str("trim(", $3, ")");
+                               }
+               | a_expr ISNULL
+                               {       $$ = make2_str($1, "isnull"); }
+               | a_expr IS NULL_P
+                               {       $$ = make2_str($1, "is null"); }
+               | a_expr NOTNULL
+                               {       $$ = make2_str($1, "notnull"); }
+               | a_expr IS NOT NULL_P
+                               {       $$ = make2_str($1, "is not null"); }
+               /* IS TRUE, IS FALSE, etc used to be function calls
+                *  but let's make them expressions to allow the optimizer
+                *  a chance to eliminate them if a_expr is a constant string.
+                * - thomas 1997-12-22
+                */
+               | a_expr IS TRUE_P
+                               {
+                               {       $$ = make2_str($1, "is true"); }
+                               }
+               | a_expr IS NOT FALSE_P
+                               {
+                               {       $$ = make2_str($1, "is not false"); }
+                               }
+               | a_expr IS FALSE_P
+                               {
+                               {       $$ = make2_str($1, "is false"); }
+                               }
+               | a_expr IS NOT TRUE_P
+                               {
+                               {       $$ = make2_str($1, "is not true"); }
+                               }
+               | a_expr BETWEEN b_expr AND b_expr
+                               {
+                                       $$ = make5_str($1, "between", $3, "and", $5); 
+                               }
+               | a_expr NOT BETWEEN b_expr AND b_expr
+                               {
+                                       $$ = make5_str($1, "not between", $4, "and", $6); 
+                               }
+               | a_expr IN '(' in_expr ')'
+                               {
+                                       $$ = cat4_str($1, "in (", $4, ")"); 
+                               }
+               | a_expr NOT IN '(' not_in_expr ')'
+                               {
+                                       $$ = cat4_str($1, "not in (", $5, ")"); 
+                               }
+               | a_expr Op '(' SubSelect ')'
+                               {
+                                       $$ = make3_str($1, $2, cat3_str("(", $4, ")")); 
+                               }
+               | a_expr '+' '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "+(", $4, ")"); 
+                               }
+               | a_expr '-' '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "-(", $4, ")"); 
+                               }
+               | a_expr '/' '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "/(", $4, ")"); 
+                               }
+               | a_expr '*' '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "*(", $4, ")"); 
+                               }
+               | a_expr '<' '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "<(", $4, ")"); 
+                               }
+               | a_expr '>' '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, ">(", $4, ")"); 
+                               }
+               | a_expr '=' '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "=(", $4, ")"); 
+                               }
+               | a_expr Op ANY '(' SubSelect ')'
+                               {
+                                       $$ = make3_str($1, $2, cat3_str("any(", $5, ")")); 
+                               }
+               | a_expr '+' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "+any(", $5, ")"); 
+                               }
+               | a_expr '-' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "-any(", $5, ")"); 
+                               }
+               | a_expr '/' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "/any(", $5, ")"); 
+                               }
+               | a_expr '*' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "*any(", $5, ")"); 
+                               }
+               | a_expr '<' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "<any(", $5, ")"); 
+                               }
+               | a_expr '>' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, ">any(", $5, ")"); 
+                               }
+               | a_expr '=' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "=any(", $5, ")"); 
+                               }
+               | a_expr Op ALL '(' SubSelect ')'
+                               {
+                                       $$ = make3_str($1, $2, cat3_str("all (", $5, ")")); 
+                               }
+               | a_expr '+' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "+all(", $5, ")"); 
+                               }
+               | a_expr '-' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "-all(", $5, ")"); 
+                               }
+               | a_expr '/' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "/all(", $5, ")"); 
+                               }
+               | a_expr '*' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "*all(", $5, ")"); 
+                               }
+               | a_expr '<' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "<all(", $5, ")"); 
+                               }
+               | a_expr '>' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, ">all(", $5, ")"); 
+                               }
+               | a_expr '=' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "=all(", $5, ")"); 
+                               }
+               | a_expr AND a_expr
+                               {       $$ = make3_str($1, "and", $3); }
+               | a_expr OR a_expr
+                               {       $$ = make3_str($1, "or", $3); }
+               | NOT a_expr
+                               {       $$ = make2_str("not", $2); }
+               | cinputvariable
+                               { $$ = ";;"; }
+               ;
+
+/*
+ * b_expr is a subset of the complete expression syntax
+ *  defined by a_expr. b_expr is used in BETWEEN clauses
+ *  to eliminate parser ambiguities stemming from the AND keyword.
+ */
+
+b_expr:  attr opt_indirection
+                               {
+                                       $$ = make2_str($1, $2);
+                               }
+               | AexprConst
+                               {       $$ = $1;  }
+               | ColId
+                               {
+                                       $$ = $1;
+                               }
+               | '-' b_expr %prec UMINUS
+                               {       $$ = make2_str("-", $2); }
+               | b_expr '+' b_expr
+                               {       $$ = make3_str($1, "+", $3); }
+               | b_expr '-' b_expr
+                               {       $$ = make3_str($1, "-", $3); }
+               | b_expr '/' b_expr
+                               {       $$ = make3_str($1, "/", $3); }
+               | b_expr '*' b_expr
+                               {       $$ = make3_str($1, "*", $3); }
+/* not possible in embedded sql                | ':' b_expr
+                               {       $$ = make2_str(":", $2); }
+*/
+               | ';' b_expr
+                               {       $$ = make2_str(";", $2); }
+               | '|' b_expr
+                               {       $$ = make2_str("|", $2); }
+               | b_expr TYPECAST Typename
+                               {
+                                       $$ = make3_str($1, "::", $3);
+                               }
+               | CAST '(' b_expr AS Typename ')'
+                               {
+                                       $$ = make3_str(cat2_str("cast(", $3), "as", cat2_str($5, ")"));
+                               }
+               | '(' a_expr ')'
+                               {       $$ = cat3_str("(", $2, ")"); }
+               | b_expr Op b_expr
+                               {       $$ = make3_str($1, $2, $3);     }
+               | Op b_expr
+                               {       $$ = make2_str($1, $2); }
+               | b_expr Op
+                               {       $$ = make2_str($1, $2); }
+               | func_name '(' ')'
+                               {
+                                       $$ = make2_str($1, "()"); 
+                               }
+               | func_name '(' expr_list ')'
+                               {
+                                       $$ = cat4_str($1, "(", $3, ")"); 
+                               }
+               | CURRENT_DATE
+                               {
+                                       $$ = "current_date";
+                               }
+               | CURRENT_TIME
+                               {
+                                       $$ = "current_time";
+                               }
+               | CURRENT_TIME '(' Iconst ')'
+                               {
+                                       if ($3 != 0)
+                                               fprintf(stderr,"CURRENT_TIME(%s) precision not implemented; zero used instead", $3);
+                                       $$ = "current_time";
+                               }
+               | CURRENT_TIMESTAMP
+                               {
+                                       $$ = "current_timestamp";
+                               }
+               | CURRENT_TIMESTAMP '(' Iconst ')'
+                               {
+                                       if (atol($3) != 0)
+                                               fprintf(stderr,"CURRENT_TIMESTAMP(%s) precision not implemented; zero used instead",$3);
+                                       $$ = "current_timestamp";
+                               }
+               | CURRENT_USER
+                               {
+                                       $$ = "current_user";
+                               }
+               | POSITION '(' position_list ')'
+                               {
+                                       $$ = cat3_str("position (", $3, ")");
+                               }
+               | SUBSTRING '(' substr_list ')'
+                               {
+                                       $$ = cat3_str("substring (", $3, ")");
+                               }
+               /* various trim expressions are defined in SQL92 - thomas 1997-07-19 */
+               | TRIM '(' BOTH trim_list ')'
+                               {
+                                       $$ = cat3_str("trim(both", $4, ")");
+                               }
+               | TRIM '(' LEADING trim_list ')'
+                               {
+                                       $$ = cat3_str("trim(leading", $4, ")");
+                               }
+               | TRIM '(' TRAILING trim_list ')'
+                               {
+                                       $$ = cat3_str("trim(trailing", $4, ")");
+                               }
+               | TRIM '(' trim_list ')'
+                               {
+                                       $$ = cat3_str("trim(", $3, ")");
+                               }
+               | civariableonly
+                               { $$ = ";;"; }
+               ;
+
+opt_indirection:  '[' c_expr ']' opt_indirection
+                               {
+                                       $$ = make4_str("[", $2, "]", $4);
+                               }
+               | '[' c_expr ':' c_expr ']' opt_indirection
+                               {
+                                       $$ = make2_str(make5_str("[", $2, ":", $4, "]"), $6);
+                               }
+               | /* EMPTY */
+                               {       $$ = ""; }
+               ;
+
+expr_list:  a_expr_or_null
+                               { $$ = $1; }
+               | expr_list ',' a_expr_or_null
+                               { $$ = make3_str($1, ",", $3); }
+               | expr_list USING a_expr
+                               { $$ = make3_str($1, "using", $3); }
+               ;
+
+extract_list:  extract_arg FROM a_expr
+                               {
+                                       $$ = make3_str($1, "from", $3);
+                               }
+               | /* EMPTY */
+                               {       $$ = ""; }
+               | cinputvariable
+                               { $$ = ";;"; }
+               ;
+
+/* 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; }
+               ;
+
+position_list:  position_expr IN position_expr
+                               {       $$ = make3_str($1, "in", $3); }
+               | /* EMPTY */
+                               {       $$ = ""; }
+               ;
+
+position_expr:  attr opt_indirection
+                               {
+                                       $$ = make2_str($1, $2);
+                               }
+               | AexprConst
+                               {       $$ = $1;  }
+               | '-' position_expr %prec UMINUS
+                               {       $$ = make2_str("-", $2); }
+               | position_expr '+' position_expr
+                               {       $$ = make3_str($1, "+", $3); }
+               | position_expr '-' position_expr
+                               {       $$ = make3_str($1, "-", $3); }
+               | position_expr '/' position_expr
+                               {       $$ = make3_str($1, "/", $3); }
+               | position_expr '*' position_expr
+                               {       $$ = make3_str($1, "*", $3); }
+               | '|' position_expr
+                               {       $$ = make2_str("|", $2); }
+               | position_expr TYPECAST Typename
+                               {
+                                       $$ = make3_str($1, "::", $3);
+                               }
+               | CAST '(' position_expr AS Typename ')'
+                               {
+                                       $$ = make3_str(cat2_str("cast(", $3), "as", cat2_str($5, ")"));
+                               }
+               | '(' position_expr ')'
+                               {       $$ = cat3_str("(", $2, ")"); }
+               | position_expr Op position_expr
+                               {       $$ = make3_str($1, $2, $3); }
+               | Op position_expr
+                               {       $$ = make2_str($1, $2); }
+               | position_expr Op
+                               {       $$ = make2_str($1, $2); }
+               | ColId
+                               {
+                                       $$ = $1;
+                               }
+               | func_name '(' ')'
+                               {
+                                       $$ = make2_str($1, "()");
+                               }
+               | func_name '(' expr_list ')'
+                               {
+                                       $$ = cat4_str($1, "(", $3, ")");
+                               }
+               | POSITION '(' position_list ')'
+                               {
+                                       $$ = cat3_str("position(", $3, ")");
+                               }
+               | SUBSTRING '(' substr_list ')'
+                               {
+                                       $$ = cat3_str("substring(", $3, ")");
+                               }
+               /* various trim expressions are defined in SQL92 - thomas 1997-07-19 */
+               | TRIM '(' BOTH trim_list ')'
+                               {
+                                       $$ = cat3_str("trim(both", $4, ")");
+                               }
+               | TRIM '(' LEADING trim_list ')'
+                               {
+                                       $$ = cat3_str("trim(leading", $4, ")");
+                               }
+               | TRIM '(' TRAILING trim_list ')'
+                               {
+                                       $$ = cat3_str("trim(trailing", $4, ")");
+                               }
+               | TRIM '(' trim_list ')'
+                               {
+                                       $$ = cat3_str("trim(", $3, ")");
+                               }
+               ;
+
+substr_list:  expr_list substr_from substr_for
+                               {
+                                       $$ = make3_str($1, $2, $3);
+                               }
+               | /* EMPTY */
+                               {       $$ = ""; }
+               ;
+
+substr_from:  FROM expr_list
+                               {       $$ = make2_str("from", $2); }
+               | /* EMPTY */
+                               {
+                                       $$ = "";
+                               }
+               ;
+
+substr_for:  FOR expr_list
+                               {       $$ = make2_str("for", $2); }
+               | /* EMPTY */
+                               {       $$ = ""; }
+               ;
+
+trim_list:  a_expr FROM expr_list
+                               { $$ = make3_str($1, "from", $3); }
+               | FROM expr_list
+                               { $$ = make2_str("from", $2); }
+               | expr_list
+                               { $$ = $1; }
+               ;
+
+in_expr:  SubSelect
+                               {
+                                       $$ = $1;
+                               }
+               | in_expr_nodes
+                               {       $$ = $1; }
+               ;
+
+in_expr_nodes:  AexprConst
+                               {       $$ = $1; }
+               | in_expr_nodes ',' AexprConst
+                               {       $$ = make3_str($1, ",", $3);}
+               ;
+
+not_in_expr:  SubSelect
+                               {
+                                       $$ = $1; 
+                               }
+               | not_in_expr_nodes
+                               {       $$ = $1; }
+               ;
+
+not_in_expr_nodes:  AexprConst
+                               {       $$ = $1; }
+               | not_in_expr_nodes ',' AexprConst
+                               {       $$ = make3_str($1, ",", $3);}
+               ;
+
+attr:  relation_name '.' attrs
+                               {
+                                       $$ = make3_str($1, ".", $3);
+                               }
+               | ParamNo '.' attrs
+                               {
+                                       $$ = make3_str($1, ".", $3);
+                               }
+               ;
+
+attrs:   attr_name
+                               { $$ = $1; }
+               | attrs '.' attr_name
+                               { $$ = make3_str($1, ".", $3); }
+               | attrs '.' '*'
+                               { $$ = make2_str($1, ".*"); }
+               ;
+
+
+/*****************************************************************************
+ *
+ *     target lists
+ *
+ *****************************************************************************/
+
+res_target_list:  res_target_list ',' res_target_el
+                               {       $$ = make3_str($1, ",",$3);  }
+               | res_target_el
+                               {       $$ = $1;  }
+               | '*'           { $$ = "*"; }
+               ;
+
+res_target_el:  ColId opt_indirection '=' a_expr_or_null
+                               {
+                                       $$ = make4_str($1, $2, "=", $4);
+                               }
+               | attr opt_indirection
+                               {
+                                       $$ = make2_str($1, $2);
+                               }
+               | relation_name '.' '*'
+                               {
+                                       $$ = make2_str($1, ".*");
+                               }
+               ;
+
+/*
+** target list for select.
+** should get rid of the other but is still needed by the defunct select into
+** and update (uses a subset)
+*/
+res_target_list2:  res_target_list2 ',' res_target_el2
+                               {       $$ = make3_str($1, ",", $3);  }
+               | res_target_el2
+                               {       $$ = $1;  }
+               ;
+
+/* AS is not optional because shift/red conflict with unary ops */
+res_target_el2:  a_expr_or_null AS ColLabel
+                               {
+                                       $$ = make3_str($1, "as", $3);
+                               }
+               | a_expr_or_null
+                               {
+                                       $$ = $1;
+                               }
+               | relation_name '.' '*'
+                               {
+                                       $$ = make2_str($1, ".*");
+                               }
+               | '*'
+                               {
+                                       $$ = "*";
+                               }
+               ;
+
+opt_id:  ColId                                                                 { $$ = $1; }
+               | /* EMPTY */                                                   { $$ = ""; }
+               ;
+
+relation_name: SpecialRuleRelation
+                               {
+                                       $$ = $1;
+                               }
+               | ColId
+                               {
+                                       /* disallow refs to variable system tables */
+                                       if (strcmp(LogRelationName, $1) == 0
+                                          || strcmp(VariableRelationName, $1) == 0) {
+                                               sprintf(errortext, "%s cannot be accessed by users",$1);
+                                               yyerror(errortext);
+                                       }
+                                       else
+                                               $$ = $1;
+                               }
+               ;
+
+database_name:                 ColId                   { $$ = $1; };
+access_method:                 IDENT                   { $$ = $1; };
+attr_name:                             ColId                   { $$ = $1; };
+class:                                 IDENT                   { $$ = $1; };
+index_name:                            ColId                   { $$ = $1; };
+
+/* Functions
+ * Include date/time keywords as SQL92 extension.
+ * Include TYPE as a SQL92 unreserved keyword. - thomas 1997-10-05
+ */
+name:                                  ColId                   { $$ = $1; };
+func_name:                             ColId                   { $$ = $1; };
+
+file_name:                             Sconst                  { $$ = $1; };
+recipe_name:                   IDENT                   { $$ = $1; };
+
+/* Constants
+ * Include TRUE/FALSE for SQL3 support. - thomas 1997-10-24
+ */
+AexprConst:  Iconst
+                               {
+                                       $$ = $1;
+                               }
+               | FCONST
+                               {
+                                       $$ = make_name();
+                               }
+               | Sconst
+                               {
+                                       $$ = $1;
+                               }
+               | Typename Sconst
+                               {
+                                       $$ = make2_str($1, $2);
+                               }
+               | ParamNo
+                               {       $$ = $1;  }
+               | TRUE_P
+                               {
+                                       $$ = "true";
+                               }
+               | FALSE_P
+                               {
+                                       $$ = "false";
+                               }
+               ;
+
+ParamNo:  PARAM
+                               {
+                                       $$ = make_name();
+                               }
+               ;
+
+NumConst:  Iconst                                              { $$ = $1; }
+               | FCONST                                                { $$ = make_name(); }
+               ;
+
+Iconst:  ICONST                                 { $$ = make_name();};
+Sconst:  SCONST                                 {
+                                                       $$ = (char *)mm_alloc(strlen($1) + 3);
+                                                       $$[0]='\'';
+                                                       strcpy($$+1, $1);
+                                                       $$[strlen($1)+2]='\0';
+                                                       $$[strlen($1)+1]='\'';
+                                               }
+UserId:  IDENT                                  { $$ = $1;};
+
+/* Column and type identifier
+ * Does not include explicit datetime types
+ *  since these must be decoupled in Typename syntax.
+ * Use ColId for most identifiers. - thomas 1997-10-21
+ */
+TypeId:  ColId
+                       {       $$ = $1; }
+               | numeric
+                       {       $$ = $1; }
+               | character
+                       {       $$ = $1; }
+               ;
+/* Column identifier
+ * Include date/time keywords as SQL92 extension.
+ * Include TYPE as a SQL92 unreserved keyword. - thomas 1997-10-05
+ * Add other keywords. Note that as the syntax expands,
+ *  some of these keywords will have to be removed from this
+ *  list due to shift/reduce conflicts in yacc. If so, move
+ *  down to the ColLabel entity. - thomas 1997-11-06
+ */
+ColId:  IDENT                                                  { $$ = $1; }
+               | datetime                                              { $$ = $1; }
+               | ACTION                                                { $$ = "action"; }
+               | CACHE                                                 { $$ = "cache"; }
+               | CYCLE                                                 { $$ = "cycle"; }
+               | DATABASE                                              { $$ = "database"; }
+               | DELIMITERS                                    { $$ = "delimiters"; }
+               | DOUBLE                                                { $$ = "double"; }
+               | EACH                                                  { $$ = "each"; }
+               | FUNCTION                                              { $$ = "function"; }
+               | INCREMENT                                             { $$ = "increment"; }
+               | INDEX                                                 { $$ = "index"; }
+               | KEY                                                   { $$ = "key"; }
+               | LANGUAGE                                              { $$ = "language"; }
+               | LOCATION                                              { $$ = "location"; }
+               | MATCH                                                 { $$ = "match"; }
+               | MAXVALUE                                              { $$ = "maxvalue"; }
+               | MINVALUE                                              { $$ = "minvalue"; }
+               | OPERATOR                                              { $$ = "operator"; }
+               | OPTION                                                { $$ = "option"; }
+               | PASSWORD                                              { $$ = "password"; }
+               | PRIVILEGES                                    { $$ = "privileges"; }
+               | RECIPE                                                { $$ = "recipe"; }
+               | ROW                                                   { $$ = "row"; }
+               | START                                                 { $$ = "start"; }
+               | STATEMENT                                             { $$ = "statement"; }
+               | TIME                                                  { $$ = "time"; }
+               | TRIGGER                                               { $$ = "trigger"; }
+               | TYPE_P                                                { $$ = "type"; }
+               | USER                                                  { $$ = "user"; }
+               | VALID                                                 { $$ = "valid"; }
+               | VERSION                                               { $$ = "version"; }
+               | ZONE                                                  { $$ = "zone"; }
+               ;
+
+/* Column label
+ * Allowed labels in "AS" clauses.
+ * Include TRUE/FALSE SQL3 reserved words for Postgres backward
+ *  compatibility. Cannot allow this for column names since the
+ *  syntax would not distinguish between the constant value and
+ *  a column name. - thomas 1997-10-24
+ * Add other keywords to this list. Note that they appear here
+ *  rather than in ColId if there was a shift/reduce conflict
+ *  when used as a full identifier. - thomas 1997-11-06
+ */
+ColLabel:  ColId                                               { $$ = $1; }
+               | ARCHIVE                                               { $$ = "archive"; }
+               | CLUSTER                                               { $$ = "cluster"; }
+               | CONSTRAINT                                    { $$ = "constraint"; }
+               | CROSS                                                 { $$ = "cross"; }
+               | FOREIGN                                               { $$ = "foreign"; }
+               | GROUP                                                 { $$ = "group"; }
+               | LOAD                                                  { $$ = "load"; }
+               | ORDER                                                 { $$ = "order"; }
+               | POSITION                                              { $$ = "position"; }
+               | PRECISION                                             { $$ = "precision"; }
+               | TABLE                                                 { $$ = "table"; }
+               | TRANSACTION                                   { $$ = "transaction"; }
+               | TRUE_P                                                { $$ = "true"; }
+               | FALSE_P                                               { $$ = "false"; }
+               ;
+
+SpecialRuleRelation:  CURRENT
+                               {
+                                       if (QueryIsRule)
+                                               $$ = "current";
+                                       else
+                                               yyerror("CURRENT used in non-rule query");
+                               }
+               | NEW
+                               {
+                                       if (QueryIsRule)
+                                               $$ = "new";
+                                       else
+                                               yyerror("NEW used in non-rule query");
+                               }
+               ;
+
+/*
+ * and now special embedded SQL stuff
+ */
+
+/*
+ * variable declaration inside the exec sql declare block
+ */
+ECPGDeclaration: sql_startdeclare variable_declarations sql_enddeclare {}
+
+sql_startdeclare : ecpgstart BEGIN_TRANS DECLARE SQL_SECTION SQL_SEMI {
+       fputs("/* exec sql begin declare section */\n", yyout);
+       output_line_number();
+ }
+
+sql_enddeclare: ecpgstart END_TRANS DECLARE SQL_SECTION SQL_SEMI {
+    fputs("/* exec sql end declare section */\n", yyout); 
     output_line_number();
 }
 
 variable_declarations : /* empty */
-                     | variable_declarations variable_declaration;
+                      | variable_declarations variable_declaration;
 
 /* Here is where we can enter support for typedef. */
-variable_declaration : type initializer ';'    { 
+variable_declaration: type initializer ';'     { 
     /* don't worry about our list when we're working on a struct */
     if (struct_level == 0)
     {
-       new_variable($<type>1.name, $<type>1.typ);
-       free((void *)$<type>1.name);
+        new_variable($<type>1.name, $<type>1.typ);
+        free((void *)$<type>1.name);
     }
-    fprintf(yyout, ";"); 
+    fputs(";", yyout); 
 }
 
 initializer : /*empty */
-           | '=' {fwrite(yytext, yyleng, 1, yyout);} vartext;
-
-vartext : /* empty */ {}
-       | vartext both_anything {
-       if (do_length == 0)
-               fwrite(yytext, yyleng, 1, yyout);
-       else
-       {
-               if (strlen(do_str) + yyleng + 1 >= do_length)
-                       do_str = mm_realloc(do_str, do_length += yyleng);
-
-               strcat(do_str, yytext);
-       }
-}
-
-symbol : S_SYMBOL { 
-    char * name = (char *)malloc(yyleng + 1);
-
-    strncpy(name, yytext, yyleng);
-    name[yyleng] = '\0';
-
-    $<symbolname>$ = name;
-}
+            | '=' {fwrite(yytext, yyleng, 1, yyout);} vartext;
 
 type : maybe_storage_clause type_detailed { $<type>$ = $<type>2; };
 type_detailed : varchar_type { $<type>$ = $<type>1; }
@@ -325,65 +3714,64 @@ type_detailed : varchar_type { $<type>$ = $<type>1; }
              | struct_type {$<type>$ = $<type>1; };
 
 varchar_type : varchar_tag symbol index {
-    if ($<indexsize>3 > 0L)
-       fprintf(yyout, "struct varchar_%s { int len; char arr[%ld]; } %s", $<symbolname>2, $<indexsize>3, $<symbolname>2);
+    if ($<ival>3 > 0L)
+       fprintf(yyout, "struct varchar_%s { int len; char arr[%d]; } %s", $2, $<ival>3, $2);
     else
-       fprintf(yyout, "struct varchar_%s { int len; char arr[]; } %s", $<symbolname>2, $<symbolname>2);
+       fprintf(yyout, "struct varchar_%s { int len; char arr[]; } %s", $2, $2);
     if (struct_level == 0)
     {
-       $<type>$.name = $<symbolname>2;
-       $<type>$.typ = ECPGmake_varchar_type(ECPGt_varchar, $<indexsize>3);
+       $<type>$.name = $2;
+       $<type>$.typ = ECPGmake_varchar_type(ECPGt_varchar, $<ival>3);
     }
     else
-       ECPGmake_record_member($<symbolname>2, ECPGmake_varchar_type(ECPGt_varchar, $<indexsize>3), &(record_member_list[struct_level-1]));
+       ECPGmake_record_member($2, ECPGmake_varchar_type(ECPGt_varchar, $<ival>3), &(record_member_list[struct_level-1]));
 }
 
-varchar_tag : S_VARCHAR { $<tagname>$ = $<tagname>1; }
-            | S_VARCHAR2 { $<tagname>$ = $<tagname>1; };
+varchar_tag: S_VARCHAR /*| S_VARCHAR2 */;
 
 simple_type : simple_tag symbol {
-    fprintf(yyout, "%s %s", ECPGtype_name($<type_enum>1), $<symbolname>2);
+    fprintf(yyout, "%s %s", ECPGtype_name($<type_enum>1), $2);
     if (struct_level == 0)
     {
-       $<type>$.name = $<symbolname>2;
+       $<type>$.name = $2;
        $<type>$.typ = ECPGmake_simple_type($<type_enum>1, 1);
     }
     else
-        ECPGmake_record_member($<symbolname>2, ECPGmake_simple_type($<type_enum>1, 1), &(record_member_list[struct_level-1]));
+        ECPGmake_record_member($2, ECPGmake_simple_type($<type_enum>1, 1), &(record_member_list[struct_level-1]));
 }
 
 string_type : char_tag symbol index {
-    if ($<indexsize>3 > 0L)
-           fprintf(yyout, "%s %s [%ld]", ECPGtype_name($<type_enum>1), $<symbolname>2, $<indexsize>3);
+    if ($<ival>3 > 0L)
+           fprintf(yyout, "%s %s [%d]", ECPGtype_name($<type_enum>1), $2, $<ival>3);
     else
-           fprintf(yyout, "%s %s []", ECPGtype_name($<type_enum>1), $<symbolname>2);
+           fprintf(yyout, "%s %s []", ECPGtype_name($<type_enum>1), $2);
     if (struct_level == 0)
     {
-       $<type>$.name = $<symbolname>2;
-       $<type>$.typ = ECPGmake_simple_type($<type_enum>1, $<indexsize>3);
+       $<type>$.name = $2;
+       $<type>$.typ = ECPGmake_simple_type($<type_enum>1, $<ival>3);
     }
     else
-       ECPGmake_record_member($<symbolname>2, ECPGmake_simple_type($<type_enum>1, $<indexsize>3), &(record_member_list[struct_level-1]));
+       ECPGmake_record_member($2, ECPGmake_simple_type($<type_enum>1, $<ival>3), &(record_member_list[struct_level-1]));
 }
        |       char_tag '*' symbol {
-    fprintf(yyout, "%s *%s", ECPGtype_name($<type_enum>1), $<symbolname>3);
+    fprintf(yyout, "%s *%s", ECPGtype_name($<type_enum>1), $3);
     if (struct_level == 0)
     {
-       $<type>$.name = $<symbolname>3;
+       $<type>$.name = $3;
        $<type>$.typ = ECPGmake_simple_type($<type_enum>1, 0);
     }
     else
-       ECPGmake_record_member($<symbolname>3, ECPGmake_simple_type($<type_enum>1, 0), &(record_member_list[struct_level-1]));
+       ECPGmake_record_member($3, ECPGmake_simple_type($<type_enum>1, 0), &(record_member_list[struct_level-1]));
 }
        |       char_tag symbol {
-    fprintf(yyout, "%s %s", ECPGtype_name($<type_enum>1), $<symbolname>2);
+    fprintf(yyout, "%s %s", ECPGtype_name($<type_enum>1), $2);
     if (struct_level == 0)
     {
-       $<type>$.name = $<symbolname>2;
+       $<type>$.name = $2;
        $<type>$.typ = ECPGmake_simple_type($<type_enum>1, 1);
     }
     else
-        ECPGmake_record_member($<symbolname>2, ECPGmake_simple_type($<type_enum>1, 1), &(record_member_list[struct_level-1]));
+        ECPGmake_record_member($2, ECPGmake_simple_type($<type_enum>1, 1), &(record_member_list[struct_level-1]));
 }
 
 char_tag : S_CHAR { $<type_enum>$ = ECPGt_char; }
@@ -391,46 +3779,46 @@ char_tag : S_CHAR { $<type_enum>$ = ECPGt_char; }
 
 /*
 array_type : simple_tag symbol index {
-    if ($<indexsize>3 > 0)
-           fprintf(yyout, "%s %s [%ld]", ECPGtype_name($<type_enum>1), $<symbolname>2, $<indexsize>3);
+    if ($<ival>3 > 0)
+           fprintf(yyout, "%s %s [%ld]", ECPGtype_name($<type_enum>1), $2, $<ival>3);
     else
-           fprintf(yyout, "%s %s []", ECPGtype_name($<type_enum>1), $<symbolname>2);
+           fprintf(yyout, "%s %s []", ECPGtype_name($<type_enum>1), $2);
     if (struct_level == 0)
     {
-       $<type>$.name = $<symbolname>2;
-       $<type>$.typ = ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), $<indexsize>3);
+       $<type>$.name = $2;
+       $<type>$.typ = ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), $<ival>3);
     }
     else
-       ECPGmake_record_member($<symbolname>2, ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), $<indexsize>3), &(record_member_list[struct_level-1]));
+       ECPGmake_record_member($2, ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), $<ival>3), &(record_member_list[struct_level-1]));
 }
 
 pointer_type : simple_tag '*' symbol {
-    fprintf(yyout, "%s * %s", ECPGtype_name($<type_enum>1), $<symbolname>3);
+    fprintf(yyout, "%s * %s", ECPGtype_name($<type_enum>1), $3);
     if (struct_level == 0)
     {
-       $<type>$.name = $<symbolname>3;
+       $<type>$.name = $3;
        $<type>$.typ = ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), 0);
     }
     else
-       ECPGmake_record_member($<symbolname>3, ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), 0), &(record_member_list[struct_level-1]));
+       ECPGmake_record_member($3, ECPGmake_array_type(ECPGmake_simple_type($<type_enum>1), 0), &(record_member_list[struct_level-1]));
 }
 */
 
 s_struct : S_STRUCT symbol {
     struct_level++;
-    fprintf(yyout, "struct %s {", $<symbolname>2);
+    fprintf(yyout, "struct %s {", $2);
 }
 
 struct_type : s_struct '{' variable_declarations '}' symbol {
     struct_level--;
     if (struct_level == 0)
     {
-       $<type>$.name = $<symbolname>5;
+       $<type>$.name = $5;
        $<type>$.typ = ECPGmake_record_type(record_member_list[struct_level]);
     }
     else
-       ECPGmake_record_member($<symbolname>5, ECPGmake_record_type(record_member_list[struct_level]), &(record_member_list[struct_level-1])); 
-    fprintf(yyout, "} %s", $<symbolname>5);
+       ECPGmake_record_member($5, ECPGmake_record_type(record_member_list[struct_level]), &(record_member_list[struct_level-1])); 
+    fprintf(yyout, "} %s", $5);
     record_member_list[struct_level] = NULL;
 }
 
@@ -452,24 +3840,17 @@ maybe_storage_clause : S_EXTERN { fwrite(yytext, yyleng, 1, yyout); }
                       | S_AUTO { fwrite(yytext, yyleng, 1, yyout); }
                        | /* empty */ { };
         
-index : '[' length ']' { $<indexsize>$ = $<indexsize>2; }
-       | '[' ']' { $<indexsize>$ = 0L; }
-
-length : S_LENGTH { $<indexsize>$ = atol(yytext); }
-
-sqlinclude : SQL_START SQL_INCLUDE { fprintf(yyout, "#include \""); }
-       filename SQL_SEMI { fprintf(yyout, ".h\""); output_line_number(); };
+index : '[' Iconst ']' { $<ival>$ = atol($2); }
+       | '[' ']' { $<ival>$ = 0L; }
 
-filename : cthing
-        | filename cthing;
-
-sqlconnect : SQL_START SQL_CONNECT { fprintf(yyout, "ECPGconnect("); }
-            db_name
-            SQL_SEMI { fprintf(yyout, ");"); whenever_action();}
+/*
+ * the exec sql connect statement: connect to the given database 
+ */
+ECPGConnect : SQL_CONNECT db_name { $$ = $2; }
 
-db_name : SQL_STRING { fprintf(yyout, "\""); fwrite(yytext + 1, yyleng - 2, 1, yyout); fprintf(yyout, "\""); }
-       | ':' symbol { /* check if we have a char variable */
-                       struct variable *p = find_variable($<symbolname>2);
+db_name : database_name { $$ = $1; }
+       | ':' name { /* check if we have a char variable */
+                       struct variable *p = find_variable($2);
                        enum ECPGttype typ = p->type->typ;
 
                        /* if array see what's inside */
@@ -478,213 +3859,436 @@ db_name : SQL_STRING { fprintf(yyout, "\""); fwrite(yytext + 1, yyleng - 2, 1, y
 
                        if (typ != ECPGt_char && typ != ECPGt_unsigned_char)
                                yyerror("invalid datatype");
-
-                       fprintf(yyout, "%s", $<symbolname>2);
+                       $$ = $2;
        }
 
-/* Open is an open cursor. Removed. */
-sqlopen : SQL_START SQL_OPEN sqlgarbage SQL_SEMI { output_line_number(); };
-
-sqlgarbage : /* Empty */
-          | sqlgarbage sqlanything;
-           
-
-sqltransaction : SQL_START transactionstmt SQL_SEMI {
-    fprintf(yyout, "ECPGtrans(__LINE__, \"%s\");", $<symbolname>2);
-    whenever_action();
-}
+/*
+ * execute a given string as sql command
+ */
+ECPGExecute : EXECUTE SQL_IMMEDIATE  ':' name { $$ = $4; };
 
+/*
+ * open is an open cursor, at the moment this has to be removed
+ */
+ECPGOpen: SQL_OPEN name open_opts {
+               struct cursor *ptr;
 
-transactionstmt:  transbegin 
+               for (ptr = cur; ptr != NULL; ptr=ptr->next)
+               {
+                       if (strcmp(ptr->name, $2) == 0)
                        {
-                               $<symbolname>$="begin";
-                       }
-               | transend
-                       {
-                               $<symbolname>$="end";
-                       }
-               | transabort
-                       {
-                               $<symbolname>$="abort";
+                               $$ = ptr->command;
+                               break;
                        }
+               }
 
-transabort: SQL_ABORT SQL_TRANSACTION | SQL_ROLLBACK SQL_WORK
-         | SQL_ABORT | SQL_ROLLBACK;
-
-transend: SQL_END SQL_TRANSACTION | SQL_COMMIT | SQL_COMMIT SQL_RELEASE
-       | SQL_COMMIT SQL_WORK SQL_RELEASE;
-
-transbegin: SQL_BEGIN SQL_TRANSACTION | SQL_BEGIN SQL_WORK;
-
-sqlexecute : SQL_START SQL_EXECUTE SQL_IMMEDIATE  ':' symbol  SQL_SEMI {  
-    fprintf(yyout, "ECPGdo(__LINE__, %s, ECPGt_EOIT, ECPGt_EORT );", $5);
-    whenever_action();
+               if (ptr == NULL)
+               {
+                       sprintf(errortext, "unknown cursor %s opened", $2);
+                       yyerror(errortext);
+               }
 };
 
-sqlwhenever : SQL_START SQL_WHENEVER SQL_SQLERROR {
-       fprintf(yyout, "/* exec sql whenever sqlerror ");
-}      action SQL_SEMI{
-       when_error.code = $<action>5.code;
-       when_error.str = $<action>5.str;
-       fprintf(yyout, "; */\n");
+open_opts: /* empty */         { $$ = ""; }
+       | USING ':' name        {
+                                       yyerror ("open cursor with variables not implemented yet");
+                               }
+
+/*
+ * whenever statement: decide what to do in case of error/no dat
+ */
+ECPGWhenever: SQL_WHENEVER SQL_SQLERROR action {
+       when_error.code = $<action>3.code;
+       when_error.command = $<action>3.command;
+       $$ = make3_str("/* exec sql whenever sqlerror ", $3.str, "; */\n");
 }
-       | SQL_START SQL_WHENEVER SQL_NOT_FOUND {
-       fprintf(yyout, "/* exec sql whenever not found ");
-}       action SQL_SEMI{
-       when_nf.code = $<action>5.code;
-       when_nf.str=$<action>5.str;
-       fprintf(yyout, "; */\n");
+       | SQL_WHENEVER NOT SQL_FOUND action {
+       when_nf.code = $<action>4.code;
+       when_nf.command = $<action>4.command;
+       $$ = make3_str("/* exec sql whenever not found ", $4.str, "; */\n");
 }
 
 action : SQL_CONTINUE {
        $<action>$.code = W_NOTHING;
-       $<action>$.str = NULL;
-       fprintf(yyout, "continue");
+       $<action>$.command = NULL;
+       $<action>$.str = "continue";
 }
        | SQL_SQLPRINT {
        $<action>$.code = W_SQLPRINT;
-       $<action>$.str = NULL;
-       fprintf(yyout, "sqlprint");
+       $<action>$.command = NULL;
+       $<action>$.str = "sqlprint";
 }
        | SQL_STOP {
        $<action>$.code = W_STOP;
-       $<action>$.str = NULL;
-       fprintf(yyout, "stop");
+       $<action>$.command = NULL;
+       $<action>$.str = "stop";
 }
-       | SQL_GOTO label {
-       $<action>$.code = W_GOTO;
-       $<action>$.str = $<symbolname>2;
-       fprintf(yyout, "goto %s", $<symbolname>2);
+       | SQL_GOTO name {
+        $<action>$.code = W_GOTO;
+        $<action>$.command = $2;
+       $<action>$.str = make2_str("goto ", $2);
 }
-       | SQL_GOTO symbol {
+       | SQL_GO TO name {
         $<action>$.code = W_GOTO;
-        $<action>$.str = $<symbolname>2;
-       fprintf(yyout, "goto %s", $<symbolname>2);
+        $<action>$.command = $3;
+       $<action>$.str = make2_str("goto ", $3);
 }
-       | SQL_DO symbol '(' {
-       do_str = (char *) mm_alloc(do_length = strlen($<symbolname>2) + 4);
-       sprintf(do_str, "%s (", $<symbolname>2);
-} vartext ')' {
+       | DO name '(' {
+       do_str = (char *) mm_alloc(do_length = strlen($2) + 4);
+       sprintf(do_str, "%s (", $2);
+} dotext ')' {
        do_str[strlen(do_str)+1]='\0';
        do_str[strlen(do_str)]=')';
        $<action>$.code = W_DO;
-       $<action>$.str = do_str;
-       fprintf(yyout, "do %s", do_str);
+       $<action>$.command = do_str;
+       $<action>$.str = make2_str("do ", do_str);
        do_str = NULL;
        do_length = 0;
 }
 
-label : S_LABEL {
-    char * name = (char *)malloc(yyleng + 1);
-
-    strncpy(name, yytext, yyleng);
-    name[yyleng] = '\0';
-
-    $<symbolname>$ = name;
-}
-
-sqlfetch: SQL_START SQL_FETCH {
-    reset_variables();
-    fprintf(yyout, "ECPGdo(__LINE__, \"fetch in ");
-} cursor {
-    fwrite(yytext, yyleng, 1, yyout);
-    fwrite(" ", 1, 1, yyout);
-} SQL_INTO into_list SQL_SEMI {
-    /* Dump */
-    fprintf(yyout, "\", ");               
-    dump_variables(argsinsert);
-    fprintf(yyout, "ECPGt_EOIT, ");
-    dump_variables(argsresult);
-    fprintf(yyout, "ECPGt_EORT );");
-    whenever_action();
-}
-
-cursor: SQL_IN S_SYMBOL | S_SYMBOL;
-
-sqlstatement : SQL_START { /* Reset stack */
-    reset_variables();
-    fprintf(yyout, "ECPGdo(__LINE__, \"");
-} sqlcommand {
-    fwrite(yytext, yyleng, 1, yyout);
-    fwrite(" ", 1, 1, yyout);
-} sqlstatement_words SQL_SEMI {  
-    /* Dump */
-    fprintf(yyout, "\", ");               
-    dump_variables(argsinsert);
-    fprintf(yyout, "ECPGt_EOIT, ");
-    dump_variables(argsresult);
-    fprintf(yyout, "ECPGt_EORT );");
-    whenever_action();
-}
-
-/* FIXME: instead of S_SYMBOL we should list all possible commands */
-sqlcommand : S_SYMBOL | SQL_DECLARE | SQL_VACUUM;
-
-sqlstatement_words : /* empty */
-                  | sqlstatement_words sqlstatement_word;
-       
-sqlstatement_word : ':' symbol 
-                  {
-                     add_variable(&argsinsert, find_variable($2));
-                     fprintf(yyout, " ;; ");
-                 }
-                 | SQL_INTO into_list SQL_FROM {
-                     fwrite(yytext, yyleng, 1, yyout);
-                     fwrite(" ", 1, 1, yyout);
-                 }
-                 | sqlanything 
-                  { 
-                     fwrite(yytext, yyleng, 1, yyout);
-                     fwrite(" ", 1, 1, yyout);
-                 }
-                 | SQL_INTO sqlanything 
-                 {
-                     fprintf(yyout, " into ");
-                     fwrite(yytext, yyleng, 1, yyout);
-                     fwrite(" ", 1, 1, yyout);
-                 };
-
-into_list : ':' symbol {
-    add_variable(&argsresult, find_variable($2)); 
-}
-         | into_list ',' ':' symbol{
-    add_variable(&argsresult, find_variable($4)); 
-};
+/* some other stuff for ecpg */
+
+c_expr:  attr opt_indirection
+                               {
+                                       $$ = make2_str($1, $2);
+                               }
+               | row_expr
+                               {       $$ = $1;  }
+               | AexprConst
+                               {       $$ = $1;  }
+               | ColId
+                               {
+                                       $$ = $1;
+                               }
+               | '-' c_expr %prec UMINUS
+                               {       $$ = make2_str("-", $2); }
+               | a_expr '+' c_expr
+                               {       $$ = make3_str($1, "+", $3); }
+               | a_expr '-' c_expr
+                               {       $$ = make3_str($1, "-", $3); }
+               | a_expr '/' c_expr
+                               {       $$ = make3_str($1, "/", $3); }
+               | a_expr '*' c_expr
+                               {       $$ = make3_str($1, "*", $3); }
+               | a_expr '<' c_expr
+                               {       $$ = make3_str($1, "<", $3); }
+               | a_expr '>' c_expr
+                               {       $$ = make3_str($1, ">", $3); }
+               | a_expr '=' c_expr
+                               {       $$ = make3_str($1, "=", $3); }
+       /*      | ':' c_expr
+                               {       $$ = make2_str(":", $2); }*/
+               | ';' c_expr
+                               {       $$ = make2_str(";", $2); }
+               | '|' c_expr
+                               {       $$ = make2_str("|", $2); }
+               | a_expr TYPECAST Typename
+                               {
+                                       $$ = make3_str($1, "::", $3);
+                               }
+               | CAST '(' a_expr AS Typename ')'
+                               {
+                                       $$ = make3_str(cat2_str("cast(", $3), "as", cat2_str($5, ")"));
+                               }
+               | '(' a_expr_or_null ')'
+                               {       $$ = cat3_str("(", $2, ")"); }
+               | a_expr Op c_expr
+                               {       $$ = make3_str($1, $2, $3);     }
+               | a_expr LIKE c_expr
+                               {       $$ = make3_str($1, "like", $3); }
+               | a_expr NOT LIKE c_expr
+                               {       $$ = make3_str($1, "not like", $4); }
+               | Op c_expr
+                               {       $$ = make2_str($1, $2); }
+               | a_expr Op
+                               {       $$ = make2_str($1, $2); }
+               | func_name '(' '*' ')'
+                               {
+                                       $$ = make2_str($1, "(*)"); 
+                               }
+               | func_name '(' ')'
+                               {
+                                       $$ = make2_str($1, "()"); 
+                               }
+               | func_name '(' expr_list ')'
+                               {
+                                       $$ = cat4_str($1, "(", $3, ")"); 
+                               }
+               | CURRENT_DATE
+                               {
+                                       $$ = "current_date";
+                               }
+               | CURRENT_TIME
+                               {
+                                       $$ = "current_time";
+                               }
+               | CURRENT_TIME '(' Iconst ')'
+                               {
+                                       if (atol($3) != 0)
+                                               fprintf(stderr,"CURRENT_TIME(%s) precision not implemented; zero used instead", $3);
+                                       $$ = "current_time";
+                               }
+               | CURRENT_TIMESTAMP
+                               {
+                                       $$ = "current_timestamp";
+                               }
+               | CURRENT_TIMESTAMP '(' Iconst ')'
+                               {
+                                       if (atol($3) != 0)
+                                               fprintf(stderr,"CURRENT_TIMESTAMP(%s) precision not implemented; zero used instead",$3);
+                                       $$ = "current_timestamp";
+                               }
+               | CURRENT_USER
+                               {
+                                       $$ = "current_user";
+                               }
+               | EXISTS '(' SubSelect ')'
+                               {
+                                       $$ = cat3_str("exists(", $3, ")");
+                               }
+               | EXTRACT '(' extract_list ')'
+                               {
+                                       $$ = cat3_str("extract(", $3, ")");
+                               }
+               | POSITION '(' position_list ')'
+                               {
+                                       $$ = cat3_str("position(", $3, ")");
+                               }
+               | SUBSTRING '(' substr_list ')'
+                               {
+                                       $$ = cat3_str("substring(", $3, ")");
+                               }
+               /* various trim expressions are defined in SQL92 - thomas 1997-07-19 */
+               | TRIM '(' BOTH trim_list ')'
+                               {
+                                       $$ = cat3_str("trim(both", $4, ")");
+                               }
+               | TRIM '(' LEADING trim_list ')'
+                               {
+                                       $$ = cat3_str("trim(leading", $4, ")");
+                               }
+               | TRIM '(' TRAILING trim_list ')'
+                               {
+                                       $$ = cat3_str("trim(trailing", $4, ")");
+                               }
+               | TRIM '(' trim_list ')'
+                               {
+                                       $$ = cat3_str("trim(", $3, ")");
+                               }
+               | a_expr ISNULL
+                               {       $$ = make2_str($1, "isnull"); }
+               | a_expr IS NULL_P
+                               {       $$ = make2_str($1, "is null"); }
+               | a_expr NOTNULL
+                               {       $$ = make2_str($1, "notnull"); }
+               | a_expr IS NOT NULL_P
+                               {       $$ = make2_str($1, "is not null"); }
+               /* IS TRUE, IS FALSE, etc used to be function calls
+                *  but let's make them expressions to allow the optimizer
+                *  a chance to eliminate them if a_expr is a constant string.
+                * - thomas 1997-12-22
+                */
+               | a_expr IS TRUE_P
+                               {
+                               {       $$ = make2_str($1, "is true"); }
+                               }
+               | a_expr IS NOT FALSE_P
+                               {
+                               {       $$ = make2_str($1, "is not false"); }
+                               }
+               | a_expr IS FALSE_P
+                               {
+                               {       $$ = make2_str($1, "is false"); }
+                               }
+               | a_expr IS NOT TRUE_P
+                               {
+                               {       $$ = make2_str($1, "is not true"); }
+                               }
+               | a_expr BETWEEN b_expr AND b_expr
+                               {
+                                       $$ = make5_str($1, "between", $3, "and", $5); 
+                               }
+               | a_expr NOT BETWEEN b_expr AND b_expr
+                               {
+                                       $$ = make5_str($1, "not between", $4, "and", $6); 
+                               }
+               | a_expr IN '(' in_expr ')'
+                               {
+                                       $$ = cat4_str($1, "in (", $4, ")"); 
+                               }
+               | a_expr NOT IN '(' not_in_expr ')'
+                               {
+                                       $$ = cat4_str($1, "not in (", $5, ")"); 
+                               }
+               | a_expr Op '(' SubSelect ')'
+                               {
+                                       $$ = make3_str($1, $2, cat3_str("(", $4,
+")")); 
+                               }
+               | a_expr '+' '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "+(", $4, ")"); 
+                               }
+               | a_expr '-' '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "-(", $4, ")"); 
+                               }
+               | a_expr '/' '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "/(", $4, ")"); 
+                               }
+               | a_expr '*' '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "*(", $4, ")"); 
+                               }
+               | a_expr '<' '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "<(", $4, ")"); 
+                               }
+               | a_expr '>' '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, ">(", $4, ")"); 
+                               }
+               | a_expr '=' '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "=(", $4, ")"); 
+                               }
+               | a_expr Op ANY '(' SubSelect ')'
+                               {
+                                       $$ = make3_str($1, $2, cat3_str("any (", $5, ")")); 
+                               }
+               | a_expr '+' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "+any(", $5, ")"); 
+                               }
+               | a_expr '-' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "-any(", $5, ")"); 
+                               }
+               | a_expr '/' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "/any(", $5, ")"); 
+                               }
+               | a_expr '*' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "*any(", $5, ")"); 
+                               }
+               | a_expr '<' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "<any(", $5, ")"); 
+                               }
+               | a_expr '>' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, ">any(", $5, ")"); 
+                               }
+               | a_expr '=' ANY '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "=any(", $5, ")"); 
+                               }
+               | a_expr Op ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat3_str($1, $2, cat3_str("all (", $5, ")")); 
+                               }
+               | a_expr '+' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "+all(", $5, ")"); 
+                               }
+               | a_expr '-' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "-all(", $5, ")"); 
+                               }
+               | a_expr '/' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "/all(", $5, ")"); 
+                               }
+               | a_expr '*' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "*all(", $5, ")"); 
+                               }
+               | a_expr '<' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "<all(", $5, ")"); 
+                               }
+               | a_expr '>' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, ">all(", $5, ")"); 
+                               }
+               | a_expr '=' ALL '(' SubSelect ')'
+                               {
+                                       $$ = cat4_str($1, "=all(", $5, ")"); 
+                               }
+               | a_expr AND c_expr
+                               {       $$ = make3_str($1, "and", $3); }
+               | a_expr OR c_expr
+                               {       $$ = make3_str($1, "or", $3); }
+               | NOT c_expr
+                               {       $$ = make2_str("not", $2); }
+               | civariableonly
+                               { $$ = ";;"; }
+               ;
+
+into_list : coutputvariable | into_list ',' coutputvariable;
+
+ecpgstart: SQL_START { reset_variables();}
 
-cthing : canything {
-    fwrite(yytext, yyleng, 1, yyout);
+dotext: /* empty */
+       | dotext sql_anything {
+                if (strlen(do_str) + yyleng + 1 >= do_length)
+                        do_str = mm_realloc(do_str, do_length += yyleng);
+
+                strcat(do_str, yytext);
+}
+
+vartext: both_anything { fwrite(yytext, yyleng, 1, yyout); }
+        | vartext both_anything { fwrite(yytext, yyleng, 1, yyout); }
+
+coutputvariable : ':' name indicator {
+               add_variable(&argsresult, find_variable($2), ($3 == NULL) ? &no_indicator : find_variable($3)); 
+}
+
+cinputvariable : ':' name indicator {
+               add_variable(&argsinsert, find_variable($2), ($3 == NULL) ? &no_indicator : find_variable($3)); 
+}
+
+civariableonly : ':' name {
+               add_variable(&argsinsert, find_variable($2), &no_indicator); 
 }
 
-canything : both_anything
-         | SQL_INTO
-         | ';';
+indicator: /* empty */                 { $$ = NULL; }
+       | ':' name                      { check_indicator((find_variable($2))->type); $$ = $2; }
+       | SQL_INDICATOR ':' name        { check_indicator((find_variable($3))->type); $$ = $3; }
+       | SQL_INDICATOR name            { check_indicator((find_variable($2))->type); $$ = $2; }
+
+/*
+ * C stuff
+ */
 
-sqlanything : both_anything;
+symbol: IDENT  { $$ = $1; }
 
-both_anything : S_LENGTH | S_VARCHAR | S_VARCHAR2 
-         | S_LONG | S_SHORT | S_INT | S_CHAR | S_FLOAT | S_DOUBLE | S_BOOL 
-         | SQL_OPEN | SQL_CONNECT
-         | SQL_STRING | SQL_CONV
-         | SQL_BEGIN | SQL_END 
-         | SQL_DECLARE | SQL_SECTION | SQL_FETCH | SQL_FROM
-         | SQL_INCLUDE | SQL_IN
-         | S_SYMBOL | S_LABEL
-         | S_STATIC | S_EXTERN | S_AUTO | S_CONST | S_REGISTER | S_STRUCT
-         | '[' | ']' | ',' | '=' | '*' | '(' | ')'
-         | S_ANYTHING;
+c_anything: both_anything      { fwrite(yytext, yyleng, 1, yyout); }
+       | ';'                   { fputc(';', yyout); }
+
+sql_anything: IDENT {} | ICONST {} | FCONST {}
+
+both_anything: IDENT {} | ICONST {} | FCONST {}
+       | S_AUTO | S_BOOL | S_CHAR | S_CONST | S_DOUBLE | S_EXTERN | S_FLOAT
+       | S_INT | S_LONG | S_REGISTER | S_SHORT | S_SIGNED | S_STATIC
+       | S_STRUCT | S_UNSIGNED | S_VARCHAR | S_ANYTHING
+       | '[' | ']' | '(' | ')' | '='
 
 blockstart : '{' {
     braces_open++;
-    fwrite(yytext, yyleng, 1, yyout);
+    fputc('{', yyout);
 }
 
 blockend : '}' {
     remove_variables(braces_open--);
-    fwrite(yytext, yyleng, 1, yyout);
+    fputc('}', yyout);
 }
+
 %%
 
-static void yyerror(char * error)
+void yyerror(char * error)
 {
     fprintf(stderr, "%s in line %d\n", error, yylineno);
     exit(1);
index 074e8b74933dbc182831f1e9d38bc127bb0e59f3..2b43fa9976aa31e2f8a97a1467b1b09e618b1d79 100644 (file)
@@ -123,22 +123,27 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
                                  long varcharsize,
                                  long arrsiz, const char *siz, const char *prefix);
 void
-ECPGdump_a_record(FILE *o, const char *name, long arrsiz,
-                 struct ECPGtype * typ, const char *offset, const char *prefix);
+ECPGdump_a_record(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);
 
 
 void
-ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *prefix)
+ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *ind_name, struct ECPGtype * ind_typ, const char *prefix, const char *ind_prefix)
 {
        if (IS_SIMPLE_TYPE(typ->typ))
        {
                ECPGdump_a_simple(o, name, typ->typ, typ->size, 0, 0, prefix);
+                ECPGdump_a_simple(o, ind_name, ind_typ->typ, ind_typ->size, 0, 0, ind_prefix);
        }
        else if (typ->typ == ECPGt_array)
        {
                if (IS_SIMPLE_TYPE(typ->u.element->typ))
+               {
                        ECPGdump_a_simple(o, name, typ->u.element->typ,
                                                          typ->u.element->size, typ->size, 0, prefix);
+                       ECPGdump_a_simple(o, ind_name, ind_typ->u.element->typ,
+                                                         ind_typ->u.element->size, ind_typ->size, 0, prefix);
+               }                                 
                else if (typ->u.element->typ == ECPGt_array)
                {
                        abort();                        /* Array of array, */
@@ -146,7 +151,7 @@ ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *pr
                else if (typ->u.element->typ == ECPGt_record)
                {
                        /* Array of records. */
-                       ECPGdump_a_record(o, name, typ->size, typ->u.element, 0, prefix);
+                       ECPGdump_a_record(o, name, ind_name, typ->size, typ->u.element, ind_typ->u.element, 0, prefix, ind_prefix);
                }
                else
                {
@@ -155,7 +160,7 @@ ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *pr
        }
        else if (typ->typ == ECPGt_record)
        {
-               ECPGdump_a_record(o, name, 0, typ, 0, prefix);
+               ECPGdump_a_record(o, name, ind_name, 0, typ, ind_typ, 0, prefix, ind_prefix);
        }
        else
        {
@@ -171,7 +176,8 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
                                  long varcharsize,
                                  long arrsiz,
                                  const char *siz,
-                                 const char *prefix)
+                                 const char *prefix
+                                 )
 {
        switch (typ)
        {
@@ -241,15 +247,19 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
                                                varcharsize,
                                                arrsiz, siz);
                        break;
+               case ECPGt_NO_INDICATOR: /* no indicator */
+                       fprintf(o, "\n\tECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ");
+                       break;
                default:
                        abort();
        }
+                                   
 }
 
 
 /* Penetrate a record and dump the contents. */
 void
-ECPGdump_a_record(FILE *o, const char *name, long arrsiz, struct ECPGtype * typ, const char *offsetarg, const char *prefix)
+ECPGdump_a_record(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)
 {
 
        /*
@@ -257,9 +267,9 @@ ECPGdump_a_record(FILE *o, const char *name, long arrsiz, struct ECPGtype * typ,
         * then we are in a record in a record and the offset is used as
         * offset.
         */
-       struct ECPGrecord_member *p;
+       struct ECPGrecord_member *p, *ind_p;
        char            obuf[BUFSIZ];
-       char            pbuf[BUFSIZ];
+       char            pbuf[BUFSIZ], ind_pbuf[BUFSIZ];
        const char *offset;
 
        if (offsetarg == NULL)
@@ -274,63 +284,13 @@ ECPGdump_a_record(FILE *o, const char *name, long arrsiz, struct ECPGtype * typ,
 
        sprintf(pbuf, "%s%s.", prefix ? prefix : "", name);
        prefix = pbuf;
+       
+       sprintf(ind_pbuf, "%s%s.", ind_prefix ? ind_prefix : "", ind_name);
+       ind_prefix = ind_pbuf;
 
-       for (p = typ->u.members; p; p = p->next)
+       for (p = typ->u.members, ind_p = ind_typ->u.members; p; p = p->next, ind_p = ind_p->next)
        {
-#if 0
-               if (IS_SIMPLE_TYPE(p->typ->typ))
-               {
-                       sprintf(buf, "%s.%s", name, p->name);
-                       ECPGdump_a_simple(o, buf, p->typ->typ, p->typ->size,
-                                                         arrsiz, offset);
-               }
-               else if (p->typ->typ == ECPGt_array)
-               {
-                       int                     i;
-
-                       for (i = 0; i < p->typ->size; i++)
-                       {
-                               if (IS_SIMPLE_TYPE(p->typ->u.element->typ))
-                               {
-                                       /* sprintf(buf, "%s.%s[%d]", name, p->name, i); */
-                                       sprintf(buf, "%s.%s", name, p->name);
-                                       ECPGdump_a_simple(o, buf, p->typ->u.element->typ, p->typ->u.element->size,
-                                                                         p->typ->u.element->size, offset);
-                               }
-                               else if (p->typ->u.element->typ == ECPGt_array)
-                               {
-                                       /* Array within an array. NOT implemented. */
-                                       abort();
-                               }
-                               else if (p->typ->u.element->typ == ECPGt_record)
-                               {
-
-                                       /*
-                                        * Record within array within record. NOT implemented
-                                        * yet.
-                                        */
-                                       abort();
-                               }
-                               else
-                               {
-                                       /* Unknown type */
-                                       abort();
-                               }
-                       }
-               }
-               else if (p->typ->typ == ECPGt_record)
-               {
-                       /* Record within a record */
-                       sprintf(buf, "%s.%s", name, p->name);
-                       ECPGdump_a_record(o, buf, arrsiz, p->typ, offset);
-               }
-               else
-               {
-                       /* Unknown type */
-                       abort();
-               }
-#endif
-               ECPGdump_a_type(o, p->name, p->typ, prefix);
+               ECPGdump_a_type(o, p->name, p->typ, ind_p->name, ind_p->typ, prefix, ind_prefix);
        }
 }
 
index 69bea16b52dcf92642273ae92a1916ae29fcff83..92d87055ee9961f18001a574060012d8a4570eaa 100644 (file)
@@ -45,7 +45,7 @@ void          ECPGfree_type(struct ECPGtype *);
    size is the maxsize in case it is a varchar. Otherwise it is the size of
           the variable (required to do array fetches of records).
  */
-void           ECPGdump_a_type(FILE *, const char *name, struct ECPGtype *, const char *);
+void           ECPGdump_a_type(FILE *, const char *, struct ECPGtype *,  const char *, struct ECPGtype *, const char *, const char *);
 
 /* A simple struct to keep a variable and its type. */
 struct ECPGtemp_type
@@ -71,5 +71,6 @@ enum WHEN
 struct when
 {
        enum WHEN       code;
-       char       *str;
+       char            *command;
+       char            *str;
 };
index 164d4978c83bca37beff161be3fafdcb0f738419..50768a6541bf6214afc17fbd3a6699f69fa8a32e 100644 (file)
@@ -1,16 +1,14 @@
 all: test2 perftest
 
 test2: test2.c
-       gcc -g -I ../include -I ../../libpq -o test2 test2.c -L../lib -lecpg -L../../libpq -lpq -lcrypt
+       gcc -g -I ../include -I ../../libpq -o test2 test2.c -L../lib -lecpg -L../../libpq -lpq -lcrypt --static
 test2.c: test2.pgc
-       ecpg test2.pgc
+       ../preproc/ecpg test2.pgc
 
 perftest: perftest.c
-       gcc -g -I ../include -I ../../libpq -o perftest perftest.c -L../lib -lecpg -L../../libpq -lpq -lcrypt
+       gcc -g -I ../include -I ../../libpq -o perftest perftest.c -L../lib -lecpg -L../../libpq -lpq -lcrypt --static
 perftest.c: perftest.pgc
-       ecpg perftest.pgc
+       ../preproc/ecpg perftest.pgc
 
 clean:
        /bin/rm test2 test2.c perftest perftest.c log
-
-dep depend:
index 46df24b4d52698b376adfa763ddf1b4ae84c2e97..45ca62abfe156bc209faa118508484d53e607f4c 100644 (file)
@@ -16,7 +16,8 @@ print_result(long sec, long usec, char *text)
                usec+=1000000;
        }
        printf("I needed %ld seconds and %ld microseconds for the %s test.\n", sec, usec, text);
-       exec sql vacuum analyze;
+       exec sql vacuum;
+       sleep(1);
 }
 
 int
@@ -27,9 +28,9 @@ exec sql begin declare section;
 exec sql end declare section;
        struct timeval tvs, tve;
 
-       exec sql connect 'mm';
+       exec sql connect mm;
 
-       exec sql create table perftest1(number int4, ascii char16);
+       exec sql create table perftest1(number int4, ascii char(16));
 
        exec sql create unique index number1 on perftest1(number);
 
@@ -100,6 +101,16 @@ exec sql end declare section;
 
        print_result(tve.tv_sec - tvs.tv_sec, tve.tv_usec - tvs.tv_usec, "update");
 
+       gettimeofday(&tvs, NULL);
+
+       exec sql delete from perftest2;
+
+       exec sql commit;
+
+       gettimeofday(&tve, NULL);
+
+       print_result(tve.tv_sec - tvs.tv_sec, tve.tv_usec - tvs.tv_usec, "delete");
+
        exec sql drop index number2;
 
        exec sql drop table perftest2;
index 6500ba89a94a5a2b68dcfb8088ddb6bb9115e7bd..e0bdac9287a3a294d1d9ab6282f055792fa3a98e 100644 (file)
@@ -2,8 +2,6 @@
 
 exec sql include header_test;
 
-extern void ECPGdebug(int n, FILE *dbgs);
-
 static int not_found = 0;
 static void
 set_not_found(void)
@@ -18,39 +16,53 @@ exec sql begin declare section;
        struct personal_struct  {       varchar name[8];
                                        struct birth_struct {   long born;
                                                                short age;
-                                                           } birth;
+                                       } birth;
                                } personal;
+       struct personal_indicator {     short name;
+                                       struct birth_indicator {        short born;
+                                                                       int age;
+                                       } ind_birth;
+                                 } ind_personal;
+       long ind_married;
+       char married[9]="a";
 exec sql end declare section;
-       char msg[128];
+       char msg[128], command[128];
        FILE *dbgs;
 
        if ((dbgs = fopen("log", "w")) != NULL)
-               ECPGdebug(1, dbgs);
+                ECPGdebug(1, dbgs);
 
        strcpy(msg, "connect");
-       exec sql connect 'mm';
+       exec sql connect mm;
 
        strcpy(msg, "create");
-       exec sql create table meskes(name char8, born int4, age int2);
+       exec sql create table meskes(name char(8), born integer, age smallint, married char(8));
 
        strcpy(msg, "insert");
-       exec sql insert into meskes(name, born, age) values ('Petra', 19661202, 31);
-       exec sql insert into meskes(name, born, age) values ('Michael', 19660117, 32);
+       exec sql insert into meskes(name, born, age, married) values ('Petra', 19661202, 31, '19900404');
+       exec sql insert into meskes(name, born, age, married) values ('Michael', 19660117, 32, '19900404');
        exec sql insert into meskes(name, born, age) values ('Carsten', 19910103, 7);
        exec sql insert into meskes(name, born, age) values ('Marc', 19930907, 4);
-       exec sql insert into meskes(name, born, age) values ('Chris', 19970923, 0);
+
+       sprintf(command, "insert into meskes(name, born, age) values ('Chris', 19970923, 0)");
+       strcpy(msg, "execute");
+       exec sql execute immediate :command;
+
+       strcpy(msg, "commit");
+       exec sql commit;
 
        strcpy(msg, "declare");
        exec sql declare cur cursor for 
-               select name, born, age from meskes;
+               select name, born, age, married from meskes;
 
+       strcpy(msg, "open");
        exec sql open cur;
 
        while (not_found == 0) {
                strcpy(msg, "fetch");
-               exec sql fetch cur into :personal;
+               exec sql fetch cur into :personal:ind_personal, :married:ind_married;
                if (not_found == 0)
-                       printf ("%8.8s was born %d (age = %d)\n", personal.name.arr, personal.birth.born, personal.birth.age);
+                       printf ("%8.8s was born %d (age = %d) %s%s\n", personal.name.arr, personal.birth.born, personal.birth.age, ind_married ? "" : "and married ", ind_married ? "" : married);
        }
 
        strcpy(msg, "close");
@@ -63,7 +75,7 @@ exec sql end declare section;
        exec sql commit;
 
        if (dbgs != NULL)
-               fclose(dbgs);
+                fclose(dbgs);
 
        return (0);
 }