aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1998-04-21 13:23:24 +0000
committerMarc G. Fournier <scrappy@hub.org>1998-04-21 13:23:24 +0000
commit64e35e1468e1b4d24c980e63e568cf1f54c7057b (patch)
treebab54f1313a885316ac01f4cf44cf0e1571b5163 /src
parent5e6b0a574b38debb3a1b5879f6800d2818f9e5a8 (diff)
downloadpostgresql-64e35e1468e1b4d24c980e63e568cf1f54c7057b.tar.gz
postgresql-64e35e1468e1b4d24c980e63e568cf1f54c7057b.zip
Upgrade ECPG to 2.0
Michael Meskes <meskes@topsystem.de>
Diffstat (limited to 'src')
-rw-r--r--src/interfaces/ecpg/ChangeLog40
-rw-r--r--src/interfaces/ecpg/TODO32
-rw-r--r--src/interfaces/ecpg/include/Makefile12
-rw-r--r--src/interfaces/ecpg/include/ecpglib.h5
-rw-r--r--src/interfaces/ecpg/include/ecpgtype.h3
-rw-r--r--src/interfaces/ecpg/lib/Makefile.in5
-rw-r--r--src/interfaces/ecpg/lib/ecpglib.c143
-rw-r--r--src/interfaces/ecpg/preproc/Makefile28
-rw-r--r--src/interfaces/ecpg/preproc/c_keywords.c63
-rw-r--r--src/interfaces/ecpg/preproc/ecpg.c27
-rw-r--r--src/interfaces/ecpg/preproc/ecpg_keywords.c60
-rw-r--r--src/interfaces/ecpg/preproc/extern.h12
-rw-r--r--src/interfaces/ecpg/preproc/keywords.c242
-rw-r--r--src/interfaces/ecpg/preproc/pgc.l565
-rw-r--r--src/interfaces/ecpg/preproc/preproc.y4242
-rw-r--r--src/interfaces/ecpg/preproc/type.c88
-rw-r--r--src/interfaces/ecpg/preproc/type.h5
-rw-r--r--src/interfaces/ecpg/test/Makefile10
-rw-r--r--src/interfaces/ecpg/test/perftest.pgc17
-rw-r--r--src/interfaces/ecpg/test/test2.pgc40
20 files changed, 5000 insertions, 639 deletions
diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog
index f20a717dbc4..e06e4ffa73d 100644
--- a/src/interfaces/ecpg/ChangeLog
+++ b/src/interfaces/ecpg/ChangeLog
@@ -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).
+
diff --git a/src/interfaces/ecpg/TODO b/src/interfaces/ecpg/TODO
index 4c7c15f40f0..c74c2732746 100644
--- a/src/interfaces/ecpg/TODO
+++ b/src/interfaces/ecpg/TODO
@@ -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.
diff --git a/src/interfaces/ecpg/include/Makefile b/src/interfaces/ecpg/include/Makefile
index bfb6840b68c..caa13a8d916 100644
--- a/src/interfaces/ecpg/include/Makefile
+++ b/src/interfaces/ecpg/include/Makefile
@@ -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:
diff --git a/src/interfaces/ecpg/include/ecpglib.h b/src/interfaces/ecpg/include/ecpglib.h
index 6dd2f92aebf..b828763fa36 100644
--- a/src/interfaces/ecpg/include/ecpglib.h
+++ b/src/interfaces/ecpg/include/ecpglib.h
@@ -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 *);
diff --git a/src/interfaces/ecpg/include/ecpgtype.h b/src/interfaces/ecpg/include/ecpgtype.h
index 30b1f557138..54442e6e3dd 100644
--- a/src/interfaces/ecpg/include/ecpgtype.h
+++ b/src/interfaces/ecpg/include/ecpgtype.h
@@ -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)
diff --git a/src/interfaces/ecpg/lib/Makefile.in b/src/interfaces/ecpg/lib/Makefile.in
index f4039edf99c..926b3b54696 100644
--- a/src/interfaces/ecpg/lib/Makefile.in
+++ b/src/interfaces/ecpg/lib/Makefile.in
@@ -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)
diff --git a/src/interfaces/ecpg/lib/ecpglib.c b/src/interfaces/ecpg/lib/ecpglib.c
index 87b2350bdb0..815f4bff0bc 100644
--- a/src/interfaces/ecpg/lib/ecpglib.c
+++ b/src/interfaces/ecpg/lib/ecpglib.c
@@ -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,10 +118,41 @@ 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);
tobeinserted = buff;
@@ -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)
{
diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile
index 04d6ccb597b..73596c05fdd 100644
--- a/src/interfaces/ecpg/preproc/Makefile
+++ b/src/interfaces/ecpg/preproc/Makefile
@@ -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
index 00000000000..d50de7bd6e7
--- /dev/null
+++ b/src/interfaces/ecpg/preproc/c_keywords.c
@@ -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);
+}
diff --git a/src/interfaces/ecpg/preproc/ecpg.c b/src/interfaces/ecpg/preproc/ecpg.c
index a97b74e748b..e156468f2b8 100644
--- a/src/interfaces/ecpg/preproc/ecpg.c
+++ b/src/interfaces/ecpg/preproc/ecpg.c
@@ -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
index 00000000000..6fea8a46bb3
--- /dev/null
+++ b/src/interfaces/ecpg/preproc/ecpg_keywords.c
@@ -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);
+}
diff --git a/src/interfaces/ecpg/preproc/extern.h b/src/interfaces/ecpg/preproc/extern.h
index 53da42cfb12..96c7bc0ed30 100644
--- a/src/interfaces/ecpg/preproc/extern.h
+++ b/src/interfaces/ecpg/preproc/extern.h
@@ -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
index 00000000000..4d8722f69df
--- /dev/null
+++ b/src/interfaces/ecpg/preproc/keywords.c
@@ -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);
+}
diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l
index 8fc341400ea..669da63a068 100644
--- a/src/interfaces/ecpg/preproc/pgc.l
+++ b/src/interfaces/ecpg/preproc/pgc.l
@@ -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)
@@ -8,101 +10,428 @@
#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;
}
-
diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y
index d3a2fc6d9ba..6eb4a88acd5 100644
--- a/src/interfaces/ecpg/preproc/preproc.y
+++ b/src/interfaces/ecpg/preproc/preproc.y
@@ -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);
diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c
index 074e8b74933..2b43fa9976a 100644
--- a/src/interfaces/ecpg/preproc/type.c
+++ b/src/interfaces/ecpg/preproc/type.c
@@ -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);
}
}
diff --git a/src/interfaces/ecpg/preproc/type.h b/src/interfaces/ecpg/preproc/type.h
index 69bea16b52d..92d87055ee9 100644
--- a/src/interfaces/ecpg/preproc/type.h
+++ b/src/interfaces/ecpg/preproc/type.h
@@ -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;
};
diff --git a/src/interfaces/ecpg/test/Makefile b/src/interfaces/ecpg/test/Makefile
index 164d4978c83..50768a6541b 100644
--- a/src/interfaces/ecpg/test/Makefile
+++ b/src/interfaces/ecpg/test/Makefile
@@ -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:
diff --git a/src/interfaces/ecpg/test/perftest.pgc b/src/interfaces/ecpg/test/perftest.pgc
index 46df24b4d52..45ca62abfe1 100644
--- a/src/interfaces/ecpg/test/perftest.pgc
+++ b/src/interfaces/ecpg/test/perftest.pgc
@@ -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;
diff --git a/src/interfaces/ecpg/test/test2.pgc b/src/interfaces/ecpg/test/test2.pgc
index 6500ba89a94..e0bdac9287a 100644
--- a/src/interfaces/ecpg/test/test2.pgc
+++ b/src/interfaces/ecpg/test/test2.pgc
@@ -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);
}