summaryrefslogtreecommitdiff
path: root/src/interfaces/ecpg/preproc
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1999-02-20 07:01:08 +0000
committerMarc G. Fournier <scrappy@hub.org>1999-02-20 07:01:08 +0000
commitbf6636baa69cd343c12b27df87f23809c1ce04c1 (patch)
treeae14fe2336482a9223bd334a337edfce2c7875a4 /src/interfaces/ecpg/preproc
parent3eb22085b578bc112a824efae2402545ce93d991 (diff)
downloadpostgresql-bf6636baa69cd343c12b27df87f23809c1ce04c1.tar.gz
From: Michael Meskes <Michael_Meskes@topmail.de>
See Changes file...
Diffstat (limited to 'src/interfaces/ecpg/preproc')
-rw-r--r--src/interfaces/ecpg/preproc/Makefile28
-rw-r--r--src/interfaces/ecpg/preproc/c_keywords.c3
-rw-r--r--src/interfaces/ecpg/preproc/ecpg.c23
-rw-r--r--src/interfaces/ecpg/preproc/ecpg_keywords.c16
-rw-r--r--src/interfaces/ecpg/preproc/extern.h53
-rw-r--r--src/interfaces/ecpg/preproc/keywords.c11
-rw-r--r--src/interfaces/ecpg/preproc/pgc.l50
-rw-r--r--src/interfaces/ecpg/preproc/preproc.y1250
-rw-r--r--src/interfaces/ecpg/preproc/type.c29
-rw-r--r--src/interfaces/ecpg/preproc/type.h53
10 files changed, 1123 insertions, 393 deletions
diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile
index 7fd98c8f06..87e788c83c 100644
--- a/src/interfaces/ecpg/preproc/Makefile
+++ b/src/interfaces/ecpg/preproc/Makefile
@@ -2,20 +2,25 @@ SRCDIR= ../../..
include $(SRCDIR)/Makefile.global
MAJOR_VERSION=2
-MINOR_VERSION=4
-PATCHLEVEL=9
+MINOR_VERSION=5
+PATCHLEVEL=0
CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \
-DMINOR_VERSION=$(MINOR_VERSION) -DPATCHLEVEL=$(PATCHLEVEL) \
- -DINCLUDE_PATH=\"$(DESTDIR)$(HEADERDIR)\"
+ -DINCLUDE_PATH=\"$(DESTDIR)$(HEADERDIR)\"
-OBJ=y.tab.o pgc.o type.o ecpg.o ecpg_keywords.o ../../../backend/parser/scansup.o \
+OBJ=preproc.o pgc.o type.o ecpg.o ecpg_keywords.o ../../../backend/parser/scansup.o \
keywords.o c_keywords.o ../lib/typename.o
all:: ecpg
+preproc.c preproc.h: preproc.y
+ $(YACC) $(YFLAGS) $<
+ mv y.tab.c preproc.c
+ mv y.tab.h preproc.h
+
clean:
- rm -f *.o core a.out ecpg$(X) y.tab.h y.tab.c pgc.c *~
+ rm -f *.o core a.out ecpg$(X) *~
install: all
$(INSTALL) $(INSTL_EXE_OPTS) ecpg$(X) $(DESTDIR)$(BINDIR)
@@ -31,13 +36,10 @@ pgc.c: pgc.l
$(LEX) $<
mv lex.yy.c pgc.c
-y.tab.h y.tab.c: preproc.y
- $(YACC) $(YFLAGS) $<
-
-y.tab.o : y.tab.h ../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c
+preproc.o : preproc.h ../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c
type.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
+pgc.o : ../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c preproc.h
+keywords.o: ../include/ecpgtype.h preproc.h
+c_keywords.o: ../include/ecpgtype.h preproc.h
+ecpg_keywords.o: ../include/ecpgtype.h preproc.h
diff --git a/src/interfaces/ecpg/preproc/c_keywords.c b/src/interfaces/ecpg/preproc/c_keywords.c
index 8629b0d133..5395b533d3 100644
--- a/src/interfaces/ecpg/preproc/c_keywords.c
+++ b/src/interfaces/ecpg/preproc/c_keywords.c
@@ -9,9 +9,8 @@
#include <string.h>
#include "postgres.h"
-#include "type.h"
-#include "y.tab.h"
#include "extern.h"
+#include "preproc.h"
/*
* List of (keyword-name, keyword-token-value) pairs.
diff --git a/src/interfaces/ecpg/preproc/ecpg.c b/src/interfaces/ecpg/preproc/ecpg.c
index 11ed36ef65..2594718cd1 100644
--- a/src/interfaces/ecpg/preproc/ecpg.c
+++ b/src/interfaces/ecpg/preproc/ecpg.c
@@ -25,6 +25,7 @@ extern char *optarg;
struct _include_path *include_paths;
int no_auto_trans = 0;
struct cursor *cur = NULL;
+struct typedefs *types = NULL;
static void
usage(char *progname)
@@ -155,22 +156,22 @@ main(int argc, char *const argv[])
{
struct cursor *ptr;
struct _defines *defptr;
-
+ struct typedefs *typeptr;
+
/* remove old cursor definitions if any are still there */
for (ptr = cur; ptr != NULL;)
{
struct cursor *this = ptr;
- struct arguments *l1,
- *l2;
+ struct arguments *l1, *l2;
free(ptr->command);
free(ptr->name);
- for (l1 = argsinsert; l1; l1 = l2)
+ for (l1 = ptr->argsinsert; l1; l1 = l2)
{
l2 = l1->next;
free(l1);
}
- for (l1 = argsresult; l1; l1 = l2)
+ for (l1 = ptr->argsresult; l1; l1 = l2)
{
l2 = l1->next;
free(l1);
@@ -189,7 +190,19 @@ main(int argc, char *const argv[])
defptr = defptr->next;
free(this);
}
+
+ /* and old typedefs */
+ for (typeptr = types; typeptr != NULL;)
+ {
+ struct typedefs *this = typeptr;
+ free(typeptr->name);
+ free(typeptr->type);
+ ECPGfree_struct_member(typeptr->struct_member_list);
+ typeptr = typeptr->next;
+ free(this);
+ }
+
/* initialize lex */
lex_init();
diff --git a/src/interfaces/ecpg/preproc/ecpg_keywords.c b/src/interfaces/ecpg/preproc/ecpg_keywords.c
index 5a1bfb8ee0..52eea065b8 100644
--- a/src/interfaces/ecpg/preproc/ecpg_keywords.c
+++ b/src/interfaces/ecpg/preproc/ecpg_keywords.c
@@ -9,9 +9,8 @@
#include <string.h>
#include "postgres.h"
-#include "type.h"
#include "extern.h"
-#include "y.tab.h"
+#include "preproc.h"
/*
* List of (keyword-name, keyword-token-value) pairs.
@@ -21,25 +20,38 @@
*/
static ScanKeyword ScanKeywords[] = {
/* name value */
+ {"bool", SQL_BOOL},
{"break", SQL_BREAK},
{"call", SQL_CALL},
{"connect", SQL_CONNECT},
{"connection", SQL_CONNECTION},
{"continue", SQL_CONTINUE},
+ {"deallocate", SQL_DEALLOCATE},
{"disconnect", SQL_DISCONNECT},
+ {"enum", SQL_ENUM},
{"found", SQL_FOUND},
+ {"free", SQL_FREE},
{"go", SQL_GO},
{"goto", SQL_GOTO},
{"identified", SQL_IDENTIFIED},
{"immediate", SQL_IMMEDIATE},
{"indicator", SQL_INDICATOR},
+ {"int", SQL_INT},
+ {"long", SQL_LONG},
{"open", SQL_OPEN},
+ {"prepare", SQL_PREPARE},
+ {"reference", SQL_REFERENCE},
{"release", SQL_RELEASE},
{"section", SQL_SECTION},
+ {"short", SQL_SHORT},
+ {"signed", SQL_SIGNED},
{"sqlerror", SQL_SQLERROR},
{"sqlprint", SQL_SQLPRINT},
{"sqlwarning", SQL_SQLWARNING},
{"stop", SQL_STOP},
+ {"struct", SQL_STRUCT},
+ {"unsigned", SQL_UNSIGNED},
+ {"var", SQL_VAR},
{"whenever", SQL_WHENEVER},
};
diff --git a/src/interfaces/ecpg/preproc/extern.h b/src/interfaces/ecpg/preproc/extern.h
index c7bb651a58..d5bc1fc9ca 100644
--- a/src/interfaces/ecpg/preproc/extern.h
+++ b/src/interfaces/ecpg/preproc/extern.h
@@ -1,63 +1,23 @@
#include "parser/keywords.h"
+#include "type.h"
#include <errno.h>
/* variables */
extern int braces_open,
- no_auto_trans;
+ no_auto_trans, struct_level;
extern char *yytext;
extern int yylineno,
yyleng;
extern FILE *yyin,
*yyout;
-struct _include_path
-{
- char *path;
- struct _include_path *next;
-};
-
extern struct _include_path *include_paths;
-
-struct cursor
-{
- char *name;
- char *command;
- struct arguments *argsinsert;
- struct arguments *argsresult;
- struct cursor *next;
-};
-
extern struct cursor *cur;
-
-struct _defines
-{
- char *old;
- char *new;
- struct _defines *next;
-};
-
+extern struct typedefs *types;
extern struct _defines *defines;
-
-/* This is a linked list of the variable names and types. */
-struct variable
-{
- char *name;
- struct ECPGtype *type;
- int brace_level;
- struct variable *next;
-};
-
extern struct ECPGtype ecpg_no_indicator;
extern struct variable no_indicator;
-
-struct arguments
-{
- struct variable *variable;
- struct variable *indicator;
- struct arguments *next;
-};
-
extern struct arguments *argsinsert;
extern struct arguments *argsresult;
@@ -74,9 +34,10 @@ extern void yyerror(char *);
/* return codes */
-#define OK 0
-#define PARSE_ERROR -1
-#define ILLEGAL_OPTION -2
+#define OK 0
+#define PARSE_ERROR -1
+#define ILLEGAL_OPTION -2
+#define INDICATOR_NOT_ARRAY -3
#define NO_INCLUDE_FILE ENOENT
#define OUT_OF_MEMORY ENOMEM
diff --git a/src/interfaces/ecpg/preproc/keywords.c b/src/interfaces/ecpg/preproc/keywords.c
index c12504b392..bcbb3242de 100644
--- a/src/interfaces/ecpg/preproc/keywords.c
+++ b/src/interfaces/ecpg/preproc/keywords.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.10 1999/02/13 23:22:35 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.11 1999/02/20 07:01:00 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,7 +18,7 @@
#include "nodes/parsenodes.h"
#include "nodes/pg_list.h"
#include "type.h"
-#include "y.tab.h"
+#include "preproc.h"
#include "parser/keywords.h"
#include "utils/elog.h"
@@ -69,9 +69,6 @@ static ScanKeyword ScanKeywords[] = {
{"createdb", CREATEDB},
{"createuser", CREATEUSER},
{"cross", CROSS},
- {"current", CURRENT}, /* 6.4 to 6.5 is migration time! CURRENT
- * will be removed in 6.5! Use OLD keyword
- * in rules. Jan */
{"current_date", CURRENT_DATE},
{"current_time", CURRENT_TIME},
{"current_timestamp", CURRENT_TIMESTAMP},
@@ -96,6 +93,7 @@ static ScanKeyword ScanKeywords[] = {
{"end", END_TRANS},
/***S*I***/
{"except", EXCEPT},
+
{"execute", EXECUTE},
{"exists", EXISTS},
{"explain", EXPLAIN},
@@ -125,6 +123,7 @@ static ScanKeyword ScanKeywords[] = {
{"instead", INSTEAD},
/***S*I***/
{"intersect", INTERSECT},
+
{"interval", INTERVAL},
{"into", INTO},
{"is", IS},
@@ -138,6 +137,7 @@ static ScanKeyword ScanKeywords[] = {
{"left", LEFT},
{"level", LEVEL},
{"like", LIKE},
+ {"limit", LIMIT},
{"listen", LISTEN},
{"load", LOAD},
{"local", LOCAL},
@@ -167,6 +167,7 @@ static ScanKeyword ScanKeywords[] = {
{"nullif", NULLIF},
{"numeric", NUMERIC},
{"of", OF},
+ {"offset", OFFSET},
{"oids", OIDS},
{"old", CURRENT},
{"on", ON},
diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l
index e6ef819a59..5ddac659bb 100644
--- a/src/interfaces/ecpg/preproc/pgc.l
+++ b/src/interfaces/ecpg/preproc/pgc.l
@@ -24,9 +24,8 @@
#include "nodes/parsenodes.h"
#include "parser/gramparse.h"
#include "parser/scansup.h"
-#include "type.h"
#include "extern.h"
-#include "y.tab.h"
+#include "preproc.h"
#include "utils/builtins.h"
/* some versions of lex define this as a macro */
@@ -241,7 +240,7 @@ cppline {space}*#.*(\\{space}*\n)*\n*
}
<xq>{xqstop} {
BEGIN(SQL);
- yylval.str = strdup(scanstr(literal));
+ yylval.str = mm_strdup(scanstr(literal));
return SCONST;
}
<xq>{xqdouble} |
@@ -276,7 +275,7 @@ cppline {space}*#.*(\\{space}*\n)*\n*
}
<xd>{xdstop} {
BEGIN(SQL);
- yylval.str = strdup(literal);
+ yylval.str = mm_strdup(literal);
return CSTRING;
}
<xd>{xdinside} {
@@ -292,7 +291,7 @@ cppline {space}*#.*(\\{space}*\n)*\n*
}
<xdc>{xdstop} {
BEGIN(C);
- yylval.str = strdup(literal);
+ yylval.str = mm_strdup(literal);
return CSTRING;
}
<xdc>{xdinside} {
@@ -316,14 +315,14 @@ cppline {space}*#.*(\\{space}*\n)*\n*
}
<SQL>{self} { return yytext[0]; }
<SQL>{operator}/-[\.0-9] {
- yylval.str = strdup((char*)yytext);
+ yylval.str = mm_strdup((char*)yytext);
return Op;
}
<SQL>{operator} {
if (strcmp((char*)yytext,"!=") == 0)
- yylval.str = strdup("<>"); /* compatability */
+ yylval.str = mm_strdup("<>"); /* compatability */
else
- yylval.str = strdup((char*)yytext);
+ yylval.str = mm_strdup((char*)yytext);
return Op;
}
<SQL>{param} {
@@ -342,7 +341,6 @@ cppline {space}*#.*(\\{space}*\n)*\n*
if (isascii((unsigned char)lower_text[i]) && isupper(lower_text[i]))
lower_text[i] = tolower(lower_text[i]);
-printf("yyt= %s, lt = %s\n", yytext, lower_text);
keyword = ScanKeywordLookup((char*)lower_text);
if (keyword != NULL) {
return keyword->value;
@@ -367,7 +365,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
yb->buffer = YY_CURRENT_BUFFER;
yb->lineno = yylineno;
- yb->filename = strdup(input_filename);
+ yb->filename = mm_strdup(input_filename);
yb->next = yy_buffer;
yy_buffer = yb;
@@ -378,7 +376,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
}
if (ptr == NULL)
{
- yylval.str = strdup((char*)yytext);
+ yylval.str = mm_strdup((char*)yytext);
return IDENT;
}
}
@@ -470,7 +468,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
return ICONST;
}
<SQL>:{identifier}(("->"|\.){identifier})* {
- yylval.str = strdup((char*)yytext+1);
+ yylval.str = mm_strdup((char*)yytext+1);
return(CVARIABLE);
}
<SQL>{identifier} {
@@ -484,7 +482,6 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
if (isascii((unsigned char)lower_text[i]) && isupper(lower_text[i]))
lower_text[i] = tolower(lower_text[i]);
-printf("yyt= %s, lt = %s\n", yytext, lower_text);
keyword = ScanKeywordLookup((char*)lower_text);
if (keyword != NULL) {
return keyword->value;
@@ -509,7 +506,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
yb->buffer = YY_CURRENT_BUFFER;
yb->lineno = yylineno;
- yb->filename = strdup(input_filename);
+ yb->filename = mm_strdup(input_filename);
yb->next = yy_buffer;
yy_buffer = yb;
@@ -520,19 +517,26 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
}
if (ptr == NULL)
{
- yylval.str = strdup((char*)yytext);
+ yylval.str = mm_strdup((char*)yytext);
return IDENT;
}
}
}
}
<SQL>{space} { /* ignore */ }
-<SQL>";" { BEGIN C; return SQL_SEMI; }
+<SQL>";" { /*
+ * We may find a ';' inside a structure
+ * definition in a TYPE or VAR statement.
+ * This is not a EOL marker.
+ */
+ if (struct_level == 0)
+ BEGIN C;
+ return SQL_SEMI; }
<SQL>{other} { return yytext[0]; }
<C>{exec}{space}{sql} { BEGIN SQL; return SQL_START; }
<C>{ccomment} { /* ignore */ }
<C>{cppline} {
- yylval.str = strdup((char*)yytext);
+ yylval.str = mm_strdup((char*)yytext);
return(CPP_LINE);
}
<C>{identifier} {
@@ -556,7 +560,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
yb->buffer = YY_CURRENT_BUFFER;
yb->lineno = yylineno;
- yb->filename = strdup(input_filename);
+ yb->filename = mm_strdup(input_filename);
yb->next = yy_buffer;
yy_buffer = yb;
@@ -567,7 +571,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
}
if (ptr == NULL)
{
- yylval.str = strdup((char*)yytext);
+ yylval.str = mm_strdup((char*)yytext);
return IDENT;
}
}
@@ -585,7 +589,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
<C>{exec}{space}{sql}{space}{define} {BEGIN(def_ident);}
<def_ident>{space} {}
<def_ident>{identifier} {
- old = strdup(yytext);
+ old = mm_strdup(yytext);
BEGIN(def);
llen = 0;
*literal = '\0';
@@ -599,7 +603,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
if (strcmp(old, ptr->old) == 0)
{
free(ptr->new);
- ptr->new = strdup(scanstr(literal));
+ ptr->new = mm_strdup(scanstr(literal));
}
}
if (ptr == NULL)
@@ -608,7 +612,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
/* initial definition */
this->old = old;
- this->new = strdup(scanstr(literal));
+ this->new = mm_strdup(scanstr(literal));
this->next = defines;
defines = this;
}
@@ -666,7 +670,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
exit(NO_INCLUDE_FILE);
}
- input_filename = strdup(inc_file);
+ input_filename = mm_strdup(inc_file);
yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
yylineno = 0;
diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y
index 355bf31dda..7bb95d77e8 100644
--- a/src/interfaces/ecpg/preproc/preproc.y
+++ b/src/interfaces/ecpg/preproc/preproc.y
@@ -6,7 +6,6 @@
#include "catalog/catname.h"
#include "utils/numeric.h"
-#include "type.h"
#include "extern.h"
#ifdef MULTIBYTE
@@ -18,10 +17,10 @@
/*
* Variables containing simple states.
*/
-static int struct_level = 0;
+int struct_level = 0;
static char errortext[128];
static int QueryIsRule = 0, ForUpdateNotAllowed = 0;
-static enum ECPGttype actual_type[STRUCT_DEPTH];
+static struct this_type actual_type[STRUCT_DEPTH];
static char *actual_storage[STRUCT_DEPTH];
/* temporarily store struct members while creating the data structure */
@@ -30,6 +29,8 @@ struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = { NULL };
struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, 0L, {NULL}};
struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL};
+struct ECPGtype ecpg_query = {ECPGt_char_variable, 0L, {NULL}};
+
/*
* Handle the filename and line numbering.
*/
@@ -505,6 +506,98 @@ output_statement(char * stmt, int mode)
free(stmt);
}
+static struct typedefs *
+get_typedef(char *name)
+{
+ struct typedefs *this;
+
+ for (this = types; this && strcmp(this->name, name); this = this->next);
+ if (!this)
+ {
+ sprintf(errortext, "invalid datatype '%s'", name);
+ yyerror(errortext);
+ }
+
+ return(this);
+}
+
+static void
+adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dimension, int type_index, bool pointer)
+{
+ if (type_index >= 0)
+ {
+ if (*length >= 0)
+ yyerror("No multi-dimensional array support");
+
+ *length = type_index;
+ }
+
+ if (type_dimension >= 0)
+ {
+ if (*dimension >= 0 && *length >= 0)
+ yyerror("No multi-dimensional array support");
+
+ if (*dimension >= 0)
+ *length = *dimension;
+
+ *dimension = type_dimension;
+ }
+
+ switch (type_enum)
+ {
+ case ECPGt_struct:
+ /* pointer has to get dimension 0 */
+ if (pointer)
+ {
+ *length = *dimension;
+ *dimension = 0;
+ }
+
+ if (*length >= 0)
+ yyerror("No multi-dimensional array support for structures");
+
+ break;
+ case ECPGt_varchar:
+ /* pointer has to get length 0 */
+ if (pointer)
+ *length=0;
+
+ /* one index is the string length */
+ if (*length < 0)
+ {
+ *length = *dimension;
+ *dimension = -1;
+ }
+
+ break;
+ case ECPGt_char:
+ case ECPGt_unsigned_char:
+ /* pointer has to get length 0 */
+ if (pointer)
+ *length=0;
+
+ /* one index is the string length */
+ if (*length < 0)
+ {
+ *length = (*dimension < 0) ? 1 : *dimension;
+ *dimension = -1;
+ }
+
+ break;
+ default:
+ /* a pointer has dimension = 0 */
+ if (pointer) {
+ *length = *dimension;
+ *dimension = 0;
+ }
+
+ if (*length >= 0)
+ yyerror("No multi-dimensional array support for simple data types");
+
+ break;
+ }
+}
+
%}
%union {
@@ -519,12 +612,15 @@ output_statement(char * stmt, int mode)
}
/* special embedded SQL token */
-%token SQL_BREAK SQL_CALL SQL_CONNECT SQL_CONNECTION SQL_CONTINUE
-%token SQL_DISCONNECT SQL_FOUND SQL_GO SQL_GOTO
-%token SQL_IDENTIFIED SQL_IMMEDIATE SQL_INDICATOR SQL_OPEN
-%token SQL_PREPARE SQL_RELEASE
-%token SQL_SECTION SQL_SEMI SQL_SQLERROR SQL_SQLPRINT SQL_START
-%token SQL_STOP SQL_WHENEVER SQL_SQLWARNING
+%token SQL_BOOL SQL_BREAK
+%token SQL_CALL SQL_CONNECT SQL_CONNECTION SQL_CONTINUE
+%token SQL_DEALLOCATE SQL_DISCONNECT SQL_ENUM
+%token SQL_FOUND SQL_FREE SQL_GO SQL_GOTO
+%token SQL_IDENTIFIED SQL_IMMEDIATE SQL_INDICATOR SQL_INT SQL_LONG
+%token SQL_OPEN SQL_PREPARE SQL_RELEASE SQL_REFERENCE
+%token SQL_SECTION SQL_SEMI SQL_SHORT SQL_SIGNED SQL_SQLERROR SQL_SQLPRINT
+%token SQL_SQLWARNING SQL_START SQL_STOP SQL_STRUCT SQL_UNSIGNED
+%token SQL_VAR SQL_WHENEVER
/* C token */
%token S_ANYTHING S_AUTO S_BOOL S_CHAR S_CONST S_DOUBLE S_ENUM S_EXTERN
@@ -577,9 +673,9 @@ output_statement(char * stmt, int mode)
DATABASE, DELIMITERS, DO, EACH, ENCODING, EXPLAIN, EXTEND,
FORWARD, FUNCTION, HANDLER,
INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL,
- LANCOMPILER, LISTEN, UNLISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE, MINVALUE, MOVE,
+ LANCOMPILER, LIMIT, LISTEN, UNLISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE, MINVALUE, MOVE,
NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL,
- OIDS, OPERATOR, PASSWORD, PROCEDURAL,
+ OFFSET, OIDS, OPERATOR, PASSWORD, PROCEDURAL,
RECIPE, RENAME, RESET, RETURNS, ROW, RULE,
SERIAL, SEQUENCE, SETOF, SHOW, START, STATEMENT, STDIN, STDOUT, TRUSTED,
UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION
@@ -654,8 +750,9 @@ output_statement(char * stmt, int mode)
%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> opt_instead event event_object RuleActionList,
+%type <str> RuleActionBlock RuleActionMulti
+%type <str> RuleStmt opt_column opt_name oper_argtypes
%type <str> MathOp RemoveFuncStmt aggr_argtype for_update_clause
%type <str> RemoveAggrStmt remove_type RemoveStmt ExtendStmt RecipeStmt
%type <str> RemoveOperStmt RenameStmt all_Op user_valid_clause
@@ -665,7 +762,7 @@ output_statement(char * stmt, int mode)
%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> DropTrigStmt TriggerOneEvent TriggerEvents
+%type <str> DropTrigStmt TriggerOneEvent TriggerEvents RuleActionStmt
%type <str> TriggerActionTime CreateTrigStmt DropPLangStmt PLangTrusted
%type <str> CreatePLangStmt IntegerOnly TriggerFuncArgs TriggerFuncArg
%type <str> ViewStmt LoadStmt CreatedbStmt opt_database1 opt_database2 location
@@ -673,27 +770,32 @@ output_statement(char * stmt, int mode)
%type <str> GrantStmt privileges operation_commalist operation
%type <str> cursor_clause opt_cursor opt_readonly opt_of opt_lmode
%type <str> case_expr when_clause_list case_default case_arg when_clause
-%type <str> select_w_o_sort
+%type <str> select_w_o_sort opt_select_limit select_limit_value,
+%type <str> select_offset_value
-%type <str> ECPGWhenever ECPGConnect connection_target ECPGOpen open_opts
-%type <str> indicator ECPGExecute ecpg_expr dotext
+%type <str> ECPGWhenever ECPGConnect connection_target ECPGOpen opt_using
+%type <str> indicator ECPGExecute ecpg_expr dotext ECPGPrepare
%type <str> storage_clause opt_initializer vartext c_anything blockstart
%type <str> blockend variable_list variable var_anything do_anything
%type <str> opt_pointer cvariable ECPGDisconnect dis_name
%type <str> stmt symbol opt_symbol ECPGRelease execstring server_name
-%type <str> connection_object opt_server opt_port c_thing
+%type <str> connection_object opt_server opt_port c_thing opt_reference
%type <str> user_name opt_user char_variable ora_user ident
%type <str> db_prefix server opt_options opt_connection_name
-%type <str> ECPGSetConnection c_line cpp_line s_enum
-%type <str> enum_type
+%type <str> ECPGSetConnection c_line cpp_line s_enum ECPGTypedef
+%type <str> enum_type civariableonly ECPGCursorStmt ECPGDeallocate
+%type <str> ECPGFree ECPGDeclare ECPGVar sql_variable_declarations
+%type <str> sql_declaration sql_variable_list sql_variable
+%type <str> struct_type s_struct declaration variable_declarations
-%type <type_enum> simple_type
+%type <type_enum> simple_type varchar_type
-%type <type> type
+%type <type> type ctype
%type <action> action
-%type <index> opt_array_bounds nest_array_bounds
+%type <index> opt_array_bounds nest_array_bounds opt_type_array_bounds
+%type <index> nest_type_array_bounds
%%
prog: statements;
@@ -769,13 +871,29 @@ stmt: AddAttrStmt { output_statement($1, 0); }
whenever_action(0);
free($1);
}
+ | ECPGCursorStmt {
+ fputs($1, yyout);
+ free($1);
+ }
+ | ECPGDeallocate {
+ fputs($1, yyout);
+ whenever_action(0);
+ free($1);
+ }
+ | ECPGDeclare {
+ fputs($1, yyout);
+ free($1);
+ }
| ECPGDisconnect {
fprintf(yyout, "ECPGdisconnect(__LINE__, \"%s\");", $1);
whenever_action(0);
free($1);
}
| ECPGExecute {
- fprintf(yyout, "ECPGdo(__LINE__, %s, ECPGt_EOIT, ECPGt_EORT);", $1);
+ output_statement($1, 0);
+ }
+ | ECPGFree {
+ fprintf(yyout, "ECPGdeallocate(__LINE__, \"%s\");", $1);
whenever_action(0);
free($1);
}
@@ -797,26 +915,39 @@ stmt: AddAttrStmt { output_statement($1, 0); }
fprintf(yyout, "ECPGdo(__LINE__, \"%s\",", ptr->command);
/* dump variables to C file*/
dump_variables(ptr->argsinsert, 0);
+ dump_variables(argsinsert, 0);
fputs("ECPGt_EOIT, ", yyout);
dump_variables(ptr->argsresult, 0);
fputs("ECPGt_EORT);", yyout);
whenever_action(0);
free($1);
}
+ | ECPGPrepare {
+ fprintf(yyout, "ECPGprepare(__LINE__, %s);", $1);
+ whenever_action(0);
+ free($1);
+ }
| ECPGRelease { /* output already done */ }
| ECPGSetConnection {
fprintf(yyout, "ECPGsetconn(__LINE__, %s);", $1);
whenever_action(0);
free($1);
}
+ | ECPGTypedef {
+ fputs($1, yyout);
+ free($1);
+ }
+ | ECPGVar {
+ fputs($1, yyout);
+ free($1);
+ }
| ECPGWhenever {
fputs($1, yyout);
output_line_number();
free($1);
}
- | ECPGPrepare {
- yyerror("PREPARE is not supported yet.");
- }
+ ;
+
/*
* We start with a lot of stuff that's very similar to the backend's parsing
@@ -1098,7 +1229,7 @@ copy_delimiter: USING DELIMITERS Sconst { $$ = cat2_str(make1_str("using delim
CreateStmt: CREATE OptTemp TABLE relation_name '(' OptTableElementList ')'
OptInherit
{
- $$ = cat5_str(make1_str("create"), $2, make1_str("table"), make3_str(make1_str("("), $6, make1_str(")")), $8);
+ $$ = cat3_str(cat4_str(make1_str("create"), $2, make1_str("table"), $4), make3_str(make1_str("("), $6, make1_str(")")), $8);
}
;
@@ -2127,40 +2258,37 @@ opt_column: COLUMN { $$ = make1_str("colmunn"); }
RuleStmt: CREATE RULE name AS
{ QueryIsRule=1; }
ON event TO event_object where_clause
- DO opt_instead OptStmtList
+ DO opt_instead RuleActionList
{
$$ = cat2_str(cat5_str(cat5_str(make1_str("create rule"), $3, make1_str("as on"), $7, make1_str("to")), $9, $10, make1_str("do"), $12), $13);
}
;
-OptStmtList: NOTHING { $$ = make1_str("nothing"); }
- | OptimizableStmt { $$ = $1; }
- | '[' OptStmtBlock ']' { $$ = cat3_str(make1_str("["), $2, make1_str("]")); }
-/***S*I*D***/
-/* We comment this out because it produces a shift / reduce conflict
- * with the select_w_o_sort rule */
-/* | '(' OptStmtBlock ')' { $$ = cat3_str(make1_str("("), $2, make1_str(")")); }*/
- ;
+RuleActionList: NOTHING { $$ = make1_str("nothing"); }
+ | SelectStmt { $$ = $1; }
+ | RuleActionStmt { $$ = $1; }
+ | '[' RuleActionBlock ']' { $$ = cat3_str(make1_str("["), $2, make1_str("]")); }
+ | '(' RuleActionBlock ')' { $$ = cat3_str(make1_str("("), $2, make1_str(")")); }
+ ;
-OptStmtBlock: OptStmtMulti
- { $$ = $1; }
- | OptimizableStmt
- { $$ = $1; }
+RuleActionBlock: RuleActionMulti { $$ = $1; }
+ | RuleActionStmt { $$ = $1; }
;
-OptStmtMulti: OptStmtMulti OptimizableStmt ';'
+RuleActionMulti: RuleActionMulti RuleActionStmt
+ { $$ = cat2_str($1, $2); }
+ | RuleActionMulti RuleActionStmt ';'
{ $$ = cat3_str($1, $2, make1_str(";")); }
-/***S*I***/
-/* We comment the next rule because it seems to be redundant
- * and produces 16 shift/reduce conflicts with the new SelectStmt rule
- * needed for EXCEPT and INTERSECT. So far I did not notice any
- * violations by removing the rule! */
-/* | OptStmtMulti OptimizableStmt
- { $$ = cat2_str($1, $2); }*/
- | OptimizableStmt ';'
+ | RuleActionStmt ';'
{ $$ = cat2_str($1, make1_str(";")); }
;
+RuleActionStmt: InsertStmt
+ | UpdateStmt
+ | DeleteStmt
+ | NotifyStmt
+ ;
+
event_object: relation_name '.' attr_name
{
$$ = make3_str($1, make1_str("."), $3);
@@ -2588,7 +2716,7 @@ CursorStmt: DECLARE name opt_cursor CURSOR FOR SelectStmt cursor_clause
{
if (strcmp($2, ptr->name) == 0)
{
- /* re-definition is a bug*/
+ /* re-definition is a bug */
sprintf(errortext, "cursor %s already defined", $2);
yyerror(errortext);
}
@@ -2642,13 +2770,13 @@ opt_of: OF columnList { $$ = make2_str(make1_str("of"), $2); }
/* The new 'SelectStmt' rule adapted for the optional use of INTERSECT EXCEPT a nd UNION
* accepts the use of '(' and ')' to select an order of set operations.
*/
-SelectStmt: select_w_o_sort sort_clause for_update_clause
+SelectStmt: select_w_o_sort sort_clause for_update_clause opt_select_limit
{
if (strlen($3) > 0 && ForUpdateNotAllowed != 0)
yyerror("SELECT FOR UPDATE is not allowed in this context");
ForUpdateNotAllowed = 0;
- $$ = cat3_str($1, $2, $3);
+ $$ = cat4_str($1, $2, $3, $4);
}
/***S*I***/
@@ -2736,6 +2864,29 @@ OptUseOp: USING Op { $$ = cat2_str(make1_str("using"), $2); }
| /*EMPTY*/ { $$ = make1_str(""); }
;
+opt_select_limit: LIMIT select_limit_value ',' select_offset_value
+ { $$ = cat4_str(make1_str("limit"), $2, make1_str(","), $4); }
+ | LIMIT select_limit_value OFFSET select_offset_value
+ { $$ = cat4_str(make1_str("limit"), $2, make1_str("offset"), $4); }
+ | LIMIT select_limit_value
+ { $$ = cat2_str(make1_str("limit"), $2);; }
+ | OFFSET select_offset_value LIMIT select_limit_value
+ { $$ = cat4_str(make1_str("offset"), $2, make1_str("limit"), $4); }
+ | OFFSET select_offset_value
+ { $$ = cat2_str(make1_str("offset"), $2); }
+ | /* EMPTY */
+ { $$ = make1_str(""); }
+ ;
+
+select_limit_value: Iconst { $$ = $1; }
+ | ALL { $$ = make1_str("all"); }
+ | PARAM { $$ = make_name(); }
+ ;
+
+select_offset_value: Iconst { $$ = $1; }
+ | PARAM { $$ = make_name(); }
+ ;
+
/*
* jimmy bell-style recursive queries aren't supported in the
* current system.
@@ -2952,6 +3103,36 @@ Generic: generic
generic: ident { $$ = $1; }
| TYPE_P { $$ = make1_str("type"); }
+ | SQL_BOOL { $$ = make1_str("bool"); }
+ | SQL_BREAK { $$ = make1_str("break"); }
+ | SQL_CALL { $$ = make1_str("call"); }
+ | SQL_CONNECT { $$ = make1_str("connect"); }
+ | SQL_CONNECTION { $$ = make1_str("connection"); }
+ | SQL_CONTINUE { $$ = make1_str("continue"); }
+ | SQL_DEALLOCATE { $$ = make1_str("deallocate"); }
+ | SQL_DISCONNECT { $$ = make1_str("disconnect"); }
+ | SQL_FOUND { $$ = make1_str("found"); }
+ | SQL_GO { $$ = make1_str("go"); }
+ | SQL_GOTO { $$ = make1_str("goto"); }
+ | SQL_IDENTIFIED { $$ = make1_str("identified"); }
+ | SQL_IMMEDIATE { $$ = make1_str("immediate"); }
+ | SQL_INDICATOR { $$ = make1_str("indicator"); }
+ | SQL_INT { $$ = make1_str("int"); }
+ | SQL_LONG { $$ = make1_str("long"); }
+ | SQL_OPEN { $$ = make1_str("open"); }
+ | SQL_PREPARE { $$ = make1_str("prepare"); }
+ | SQL_RELEASE { $$ = make1_str("release"); }
+ | SQL_SECTION { $$ = make1_str("section"); }
+ | SQL_SHORT { $$ = make1_str("short"); }
+ | SQL_SIGNED { $$ = make1_str("signed"); }
+ | SQL_SQLERROR { $$ = make1_str("sqlerror"); }
+ | SQL_SQLPRINT { $$ = make1_str("sqlprint"); }
+ | SQL_SQLWARNING { $$ = make1_str("sqlwarning"); }
+ | SQL_STOP { $$ = make1_str("stop"); }
+ | SQL_STRUCT { $$ = make1_str("struct"); }
+ | SQL_UNSIGNED { $$ = make1_str("unsigned"); }
+ | SQL_VAR { $$ = make1_str("var"); }
+ | SQL_WHENEVER { $$ = make1_str("whenever"); }
;
/* SQL92 numeric data types
@@ -3638,7 +3819,7 @@ b_expr: attr opt_indirection
$$ = make3_str(make1_str("trim("), $3, make1_str(")"));
}
| civariableonly
- { $$ = make1_str(";;"); }
+ { $$ = $1; }
;
opt_indirection: '[' ecpg_expr ']' opt_indirection
@@ -4125,6 +4306,36 @@ ColId: ident { $$ = $1; }
| VALID { $$ = make1_str("valid"); }
| VERSION { $$ = make1_str("version"); }
| ZONE { $$ = make1_str("zone"); }
+ | SQL_BOOL { $$ = make1_str("bool"); }
+ | SQL_BREAK { $$ = make1_str("break"); }
+ | SQL_CALL { $$ = make1_str("call"); }
+ | SQL_CONNECT { $$ = make1_str("connect"); }
+ | SQL_CONNECTION { $$ = make1_str("connection"); }
+ | SQL_CONTINUE { $$ = make1_str("continue"); }
+ | SQL_DEALLOCATE { $$ = make1_str("deallocate"); }
+ | SQL_DISCONNECT { $$ = make1_str("disconnect"); }
+ | SQL_FOUND { $$ = make1_str("found"); }
+ | SQL_GO { $$ = make1_str("go"); }
+ | SQL_GOTO { $$ = make1_str("goto"); }
+ | SQL_IDENTIFIED { $$ = make1_str("identified"); }
+ | SQL_IMMEDIATE { $$ = make1_str("immediate"); }
+ | SQL_INDICATOR { $$ = make1_str("indicator"); }
+ | SQL_INT { $$ = make1_str("int"); }
+ | SQL_LONG { $$ = make1_str("long"); }
+ | SQL_OPEN { $$ = make1_str("open"); }
+ | SQL_PREPARE { $$ = make1_str("prepare"); }
+ | SQL_RELEASE { $$ = make1_str("release"); }
+ | SQL_SECTION { $$ = make1_str("section"); }
+ | SQL_SHORT { $$ = make1_str("short"); }
+ | SQL_SIGNED { $$ = make1_str("signed"); }
+ | SQL_SQLERROR { $$ = make1_str("sqlerror"); }
+ | SQL_SQLPRINT { $$ = make1_str("sqlprint"); }
+ | SQL_SQLWARNING { $$ = make1_str("sqlwarning"); }
+ | SQL_STOP { $$ = make1_str("stop"); }
+ | SQL_STRUCT { $$ = make1_str("struct"); }
+ | SQL_UNSIGNED { $$ = make1_str("unsigned"); }
+ | SQL_VAR { $$ = make1_str("var"); }
+ | SQL_WHENEVER { $$ = make1_str("whenever"); }
;
/* Column label
* Allowed labels in "AS" clauses.
@@ -4198,223 +4409,6 @@ SpecialRuleRelation: CURRENT
*/
/*
- * 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 */
- | declaration variable_declarations;
-
-declaration: storage_clause type
- {
- actual_storage[struct_level] = $1;
- actual_type[struct_level] = $2.type_enum;
- if ($2.type_enum != ECPGt_varchar && $2.type_enum != ECPGt_struct)
- fprintf(yyout, "%s %s", $1, $2.type_str);
- free($2.type_str);
- }
- variable_list ';' { fputc(';', yyout); }
-
-storage_clause : S_EXTERN { $$ = "extern"; }
- | S_STATIC { $$ = "static"; }
- | S_SIGNED { $$ = "signed"; }
- | S_CONST { $$ = "const"; }
- | S_REGISTER { $$ = "register"; }
- | S_AUTO { $$ = "auto"; }
- | /* empty */ { $$ = ""; }
-
-type: simple_type
- {
- $$.type_enum = $1;
- $$.type_str = mm_strdup(ECPGtype_name($1));
- }
- | struct_type
- {
- $$.type_enum = ECPGt_struct;
- $$.type_str = make1_str("");
- }
- | enum_type
- {
- $$.type_str = $1;
- $$.type_enum = ECPGt_int;
- }
-
-enum_type: s_enum '{' c_line '}'
- {
- $$ = cat4_str($1, make1_str("{"), $3, make1_str("}"));
- }
-
-s_enum: S_ENUM opt_symbol { $$ = cat2_str(make1_str("enum"), $2); }
-
-struct_type: s_struct '{' variable_declarations '}'
- {
- ECPGfree_struct_member(struct_member_list[struct_level]);
- free(actual_storage[struct_level--]);
- fputs("} ", yyout);
- }
-
-s_struct : S_STRUCT opt_symbol
- {
- struct_member_list[struct_level++] = NULL;
- if (struct_level >= STRUCT_DEPTH)
- yyerror("Too many levels in nested structure definition");
- fprintf(yyout, "struct %s {", $2);
- free($2);
- }
-
-opt_symbol: /* empty */ { $$ = make1_str(""); }
- | symbol { $$ = $1; }
-
-simple_type: S_SHORT { $$ = ECPGt_short; }
- | S_UNSIGNED S_SHORT { $$ = ECPGt_unsigned_short; }
- | S_INT { $$ = ECPGt_int; }
- | S_UNSIGNED S_INT { $$ = ECPGt_unsigned_int; }
- | S_LONG { $$ = ECPGt_long; }
- | S_UNSIGNED S_LONG { $$ = ECPGt_unsigned_long; }
- | S_FLOAT { $$ = ECPGt_float; }
- | S_DOUBLE { $$ = ECPGt_double; }
- | S_BOOL { $$ = ECPGt_bool; };
- | S_CHAR { $$ = ECPGt_char; }
- | S_UNSIGNED S_CHAR { $$ = ECPGt_unsigned_char; }
- | S_VARCHAR { $$ = ECPGt_varchar; }
-
-variable_list: variable
- | variable_list ','
- {
- if (actual_type[struct_level] != ECPGt_varchar)
- fputs(", ", yyout);
- else
- fputs(";\n ", yyout);
- } variable
-
-variable: opt_pointer symbol opt_array_bounds opt_initializer
- {
- struct ECPGtype * type;
- int dimension = $3.index1; /* dimension of array */
- int length = $3.index2; /* lenght of string */
- char dim[14L];
-
- switch (actual_type[struct_level])
- {
- case ECPGt_struct:
- /* pointer has to get dimension 0 */
- if (strlen($1) > 0)
- {
- length = dimension;
- dimension = 0;
- }
-
- if (length >= 0)
- yyerror("No multi-dimensional array support for structures");
-
- if (dimension == 1 || dimension < 0)
- type = ECPGmake_struct_type(struct_member_list[struct_level]);
- else
- type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level]), dimension);
-
- fprintf(yyout, "%s%s%s%s", $1, $2, $3.str, $4);
- break;
- case ECPGt_varchar:
- /* pointer has to get length 0 */
- if (strlen($1) > 0)
- length=0;
-
- /* one index is the string length */
- if (length < 0)
- {
- length = dimension;
- dimension = 1;
- }
-
- if (dimension == 1)
- type = ECPGmake_simple_type(actual_type[struct_level], length);
- else
- type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level], length), dimension);
-
- switch(dimension)
- {
- case 0:
- strcpy(dim, "[]");
- break;
- case 1:
- *dim = '\0';
- break;
- default:
- sprintf(dim, "[%d]", dimension);
- break;
- }
- if (length > 0)
- fprintf(yyout, "%s struct varchar_%s { int len; char arr[%d]; } %s%s", actual_storage[struct_level], $2, length, $2, dim);
- else
- fprintf(yyout, "%s struct varchar_%s { int len; char *arr; } %s%s", actual_storage[struct_level], $2, $2, dim);
- break;
- case ECPGt_char:
- case ECPGt_unsigned_char:
- /* pointer has to get length 0 */
- if (strlen($1) > 0)
- length=0;
-
- /* one index is the string length */
- if (length < 0)
- {
- length = (dimension < 0) ? 1 : dimension;
- dimension = 1;
- }
-
- if (dimension == 1)
- type = ECPGmake_simple_type(actual_type[struct_level], length);
- else
- type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level], length), dimension);
-
- fprintf(yyout, "%s%s%s%s", $1, $2, $3.str, $4);
- break;
- default:
- /* a pointer has dimension = 0 */
- if (strlen($1) > 0) {
- length = dimension;
- dimension = 0;
- }
-
- if (length >= 0)
- yyerror("No multi-dimensional array support for simple data types");
-
- if (dimension == 1 || dimension < 0)
- type = ECPGmake_simple_type(actual_type[struct_level], 1);
- else
- type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level], 1), dimension);
-
- fprintf(yyout, "%s%s%s%s", $1, $2, $3.str, $4);
- break;
- }
-
- if (struct_level == 0)
- new_variable($2, type);
- else
- ECPGmake_struct_member($2, type, &(struct_member_list[struct_level - 1]));
-
- free($1);
- free($2);
- free($3.str);
- free($4);
- }
-
-opt_initializer: /* empty */ { $$ = make1_str(""); }
- | '=' vartext { $$ = make2_str(make1_str("="), $2); }
-
-opt_pointer: /* empty */ { $$ = make1_str(""); }
- | '*' { $$ = make1_str("*"); }
-
-/*
* the exec sql connect statement: connect to the given database
*/
ECPGConnect: SQL_CONNECT TO connection_target opt_connection_name opt_user
@@ -4585,6 +4579,280 @@ opt_options: Op ColId
| /* empty */ { $$ = make1_str(""); }
/*
+ * Declare a prepared cursor. The syntax is different from the standard
+ * declare statement, so we create a new rule.
+ */
+ECPGCursorStmt: DECLARE name opt_cursor CURSOR FOR ident cursor_clause
+ {
+ struct cursor *ptr, *this;
+ struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
+
+ for (ptr = cur; ptr != NULL; ptr = ptr->next)
+ {
+ if (strcmp($2, ptr->name) == 0)
+ {
+ /* re-definition is a bug */
+ sprintf(errortext, "cursor %s already defined", $2);
+ yyerror(errortext);
+ }
+ }
+
+ this = (struct cursor *) mm_alloc(sizeof(struct cursor));
+
+ /* initial definition */
+ this->next = cur;
+ this->name = $2;
+ this->command = cat5_str(make1_str("declare"), mm_strdup($2), $3, make1_str("cursor for ;;"), $7);
+ this->argsresult = NULL;
+
+ thisquery->type = &ecpg_query;
+ thisquery->brace_level = 0;
+ thisquery->next = NULL;
+ thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(\"\")") + strlen($6));
+ sprintf(thisquery->name, "ECPGprepared_statement(\"%s\")", $6);
+
+ this->argsinsert = NULL;
+ add_variable(&(this->argsinsert), thisquery, &no_indicator);
+
+ cur = this;
+
+ $$ = cat3_str(make1_str("/*"), mm_strdup(this->command), make1_str("*/"));
+ }
+ ;
+
+/*
+ * the exec sql deallocate prepare command to deallocate a previously
+ * prepared statement
+ */
+ECPGDeallocate: SQL_DEALLOCATE SQL_PREPARE ident { $$ = make3_str(make1_str("ECPGdeallocate(__LINE__, \""), $3, make1_str("\");")); }
+
+/*
+ * variable declaration inside the exec sql declare block
+ */
+ECPGDeclaration: sql_startdeclare
+ {
+ fputs("/* exec sql begin declare section */", yyout);
+ output_line_number();
+ }
+ variable_declarations sql_enddeclare
+ {
+ fprintf(yyout, "%s/* exec sql end declare section */", $3);
+ free($3);
+ output_line_number();
+ }
+
+sql_startdeclare : ecpgstart BEGIN_TRANS DECLARE SQL_SECTION SQL_SEMI {}
+
+sql_enddeclare: ecpgstart END_TRANS DECLARE SQL_SECTION SQL_SEMI {}
+
+variable_declarations: /* empty */
+ {
+ $$ = make1_str("");
+ }
+ | declaration variable_declarations
+ {
+ $$ = cat2_str($1, $2);
+ }
+
+declaration: storage_clause
+ {
+ actual_storage[struct_level] = mm_strdup($1);
+ }
+ type
+ {
+ actual_type[struct_level].type_enum = $3.type_enum;
+ actual_type[struct_level].type_dimension = $3.type_dimension;
+ actual_type[struct_level].type_index = $3.type_index;
+ }
+ variable_list ';'
+ {
+ $$ = cat4_str($1, $3.type_str, $5, make1_str(";\n"));
+ }
+
+storage_clause : S_EXTERN { $$ = make1_str("extern"); }
+ | S_STATIC { $$ = make1_str("static"); }
+ | S_SIGNED { $$ = make1_str("signed"); }
+ | S_CONST { $$ = make1_str("const"); }
+ | S_REGISTER { $$ = make1_str("register"); }
+ | S_AUTO { $$ = make1_str("auto"); }
+ | /* empty */ { $$ = make1_str(""); }
+
+type: simple_type
+ {
+ $$.type_enum = $1;
+ $$.type_str = mm_strdup(ECPGtype_name($1));
+ $$.type_dimension = -1;
+ $$.type_index = -1;
+ }
+ | varchar_type
+ {
+ $$.type_enum = ECPGt_varchar;
+ $$.type_str = make1_str("");
+ $$.type_dimension = -1;
+ $$.type_index = -1;
+ }
+ | struct_type
+ {
+ $$.type_enum = ECPGt_struct;
+ $$.type_str = $1;
+ $$.type_dimension = -1;
+ $$.type_index = -1;
+ }
+ | enum_type
+ {
+ $$.type_str = $1;
+ $$.type_enum = ECPGt_int;
+ $$.type_dimension = -1;
+ $$.type_index = -1;
+ }
+ | symbol
+ {
+ /* this is for typedef'ed types */
+ struct typedefs *this = get_typedef($1);
+
+ $$.type_str = mm_strdup(this->name);
+ $$.type_enum = this->type->type_enum;
+ $$.type_dimension = this->type->type_dimension;
+ $$.type_index = this->type->type_index;
+ struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
+ }
+
+enum_type: s_enum '{' c_line '}'
+ {
+ $$ = cat4_str($1, make1_str("{"), $3, make1_str("}"));
+ }
+
+s_enum: S_ENUM opt_symbol { $$ = cat2_str(make1_str("enum"), $2); }
+
+struct_type: s_struct '{' variable_declarations '}'
+ {
+ ECPGfree_struct_member(struct_member_list[struct_level]);
+ free(actual_storage[struct_level--]);
+ $$ = cat4_str($1, make1_str("{"), $3, make1_str("}"));
+ }
+
+s_struct : S_STRUCT opt_symbol
+ {
+ struct_member_list[struct_level++] = NULL;
+ if (struct_level >= STRUCT_DEPTH)
+ yyerror("Too many levels in nested structure definition");
+ $$ = cat2_str(make1_str("struct"), $2);
+ }
+
+opt_symbol: /* empty */ { $$ = make1_str(""); }
+ | symbol { $$ = $1; }
+
+simple_type: S_SHORT { $$ = ECPGt_short; }
+ | S_UNSIGNED S_SHORT { $$ = ECPGt_unsigned_short; }
+ | S_INT { $$ = ECPGt_int; }
+ | S_UNSIGNED S_INT { $$ = ECPGt_unsigned_int; }
+ | S_LONG { $$ = ECPGt_long; }
+ | S_UNSIGNED S_LONG { $$ = ECPGt_unsigned_long; }
+ | S_FLOAT { $$ = ECPGt_float; }
+ | S_DOUBLE { $$ = ECPGt_double; }
+ | S_BOOL { $$ = ECPGt_bool; };
+ | S_CHAR { $$ = ECPGt_char; }
+ | S_UNSIGNED S_CHAR { $$ = ECPGt_unsigned_char; }
+
+varchar_type: S_VARCHAR { $$ = ECPGt_varchar; }
+
+variable_list: variable
+ {
+ $$ = $1;
+ }
+ | variable_list ',' variable
+ {
+ $$ = cat3_str($1, make1_str(","), $3);
+ }
+
+variable: opt_pointer symbol opt_array_bounds opt_initializer
+ {
+ struct ECPGtype * type;
+ int dimension = $3.index1; /* dimension of array */
+ int length = $3.index2; /* lenght of string */
+ char dim[14L], ascii_len[12];
+
+ adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension, actual_type[struct_level].type_index, strlen($1));
+
+ switch (actual_type[struct_level].type_enum)
+ {
+ case ECPGt_struct:
+ if (dimension < 0)
+ type = ECPGmake_struct_type(struct_member_list[struct_level]);
+ else
+ type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level]), dimension);
+
+ $$ = make4_str($1, mm_strdup($2), $3.str, $4);
+ break;
+ case ECPGt_varchar:
+ if (dimension == -1)
+ type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length);
+ else
+ type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension);
+
+ switch(dimension)
+ {
+ case 0:
+ strcpy(dim, "[]");
+ break;
+ case -1:
+ case 1:
+ *dim = '\0';
+ break;
+ default:
+ sprintf(dim, "[%d]", dimension);
+ break;
+ }
+ sprintf(ascii_len, "%d", length);
+
+ if (length > 0)
+ $$ = make4_str(make5_str(mm_strdup(actual_storage[struct_level]), make1_str(" struct varchar_"), mm_strdup($2), make1_str(" { int len; char arr["), mm_strdup(ascii_len)), make1_str("]; } "), mm_strdup($2), mm_strdup(dim));
+ else
+ $$ = make4_str(make3_str(mm_strdup(actual_storage[struct_level]), make1_str(" struct varchar_"), mm_strdup($2)), make1_str(" { int len; char *arr; } "), mm_strdup($2), mm_strdup(dim));
+ break;
+ case ECPGt_char:
+ case ECPGt_unsigned_char:
+ if (dimension == -1)
+ type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length);
+ else
+ type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension);
+
+ $$ = make4_str($1, mm_strdup($2), $3.str, $4);
+ break;
+ default:
+ if (dimension < 0)
+ type = ECPGmake_simple_type(actual_type[struct_level].type_enum, 1);
+ else
+ type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, 1), dimension);
+
+ $$ = make4_str($1, mm_strdup($2), $3.str, $4);
+ break;
+ }
+
+ if (struct_level == 0)
+ new_variable($2, type);
+ else
+ ECPGmake_struct_member($2, type, &(struct_member_list[struct_level - 1]));
+
+ free($2);
+ }
+
+opt_initializer: /* empty */ { $$ = make1_str(""); }
+ | '=' vartext { $$ = make2_str(make1_str("="), $2); }
+
+opt_pointer: /* empty */ { $$ = make1_str(""); }
+ | '*' { $$ = make1_str("*"); }
+
+/*
+ * As long as the prepare statement is not supported by the backend, we will
+ * try to simulate it here so we get dynamic SQL
+ */
+ECPGDeclare: DECLARE STATEMENT ident
+ {
+ /* this is only supported for compatibility */
+ $$ = cat3_str(make1_str("/* declare statement"), $3, make1_str("*/"));
+ }
+/*
* the exec sql disconnect statement: disconnect from the given database
*/
ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; }
@@ -4600,23 +4868,68 @@ connection_object: connection_target { $$ = $1; }
/*
* execute a given string as sql command
*/
-ECPGExecute : EXECUTE SQL_IMMEDIATE execstring { $$ = $3; };
+ECPGExecute : EXECUTE SQL_IMMEDIATE execstring
+ {
+ struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
+
+ thisquery->type = &ecpg_query;
+ thisquery->brace_level = 0;
+ thisquery->next = NULL;
+ thisquery->name = $3;
+
+ add_variable(&argsinsert, thisquery, &no_indicator);
+
+ $$ = make1_str(";;");
+ }
+ | EXECUTE ident
+ {
+ struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
-execstring: cvariable |
+ thisquery->type = &ecpg_query;
+ thisquery->brace_level = 0;
+ thisquery->next = NULL;
+ thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(\"\")") + strlen($2));
+ sprintf(thisquery->name, "ECPGprepared_statement(\"%s\")", $2);
+
+ add_variable(&argsinsert, thisquery, &no_indicator);
+ } opt_using
+ {
+ $$ = make1_str(";;");
+ }
+
+execstring: char_variable |
CSTRING { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); };
/*
+ * the exec sql free command to deallocate a previously
+ * prepared statement
+ */
+ECPGFree: SQL_FREE ident { $$ = $2; }
+
+/*
* open is an open cursor, at the moment this has to be removed
*/
-ECPGOpen: SQL_OPEN name open_opts {
+ECPGOpen: SQL_OPEN name opt_using {
$$ = $2;
};
-open_opts: /* empty */ { $$ = make1_str(""); }
- | USING cvariable {
- yyerror ("open cursor with variables not implemented yet");
+opt_using: /* empty */ { $$ = make1_str(""); }
+ | USING variablelist {
+ /* yyerror ("open cursor with variables not implemented yet"); */
+ $$ = make1_str("");
}
+variablelist: cinputvariable | cinputvariable ',' variablelist
+
+/*
+ * As long as the prepare statement is not supported by the backend, we will
+ * try to simulate it here so we get dynamic SQL
+ */
+ECPGPrepare: SQL_PREPARE ident FROM char_variable
+ {
+ $$ = make4_str(make1_str("\""), $2, make1_str("\", "), $4);
+ }
+
/*
* for compatibility with ORACLE we will also allow the keyword RELEASE
* after a transaction statement to disconnect from the database.
@@ -4642,6 +4955,378 @@ ECPGSetConnection: SET SQL_CONNECTION connection_object
{
$$ = $3;
}
+
+/*
+ * define a new type for embedded SQL
+ */
+ECPGTypedef: TYPE_P symbol IS ctype opt_type_array_bounds opt_reference
+ {
+ /* add entry to list */
+ struct typedefs *ptr, *this;
+ int dimension = $5.index1;
+ int length = $5.index2;
+
+ for (ptr = types; ptr != NULL; ptr = ptr->next)
+ {
+ if (strcmp($2, ptr->name) == 0)
+ {
+ /* re-definition is a bug */
+ sprintf(errortext, "type %s already defined", $2);
+ yyerror(errortext);
+ }
+ }
+
+ adjust_array($4.type_enum, &dimension, &length, $4.type_dimension, $4.type_index, strlen($6));
+
+ this = (struct typedefs *) mm_alloc(sizeof(struct typedefs));
+
+ /* initial definition */
+ this->next = types;
+ this->name = $2;
+ this->type = (struct this_type *) mm_alloc(sizeof(struct this_type));
+ this->type->type_enum = $4.type_enum;
+ this->type->type_str = mm_strdup($2);
+ this->type->type_dimension = dimension; /* dimension of array */
+ this->type->type_index = length; /* lenght of string */
+ this->struct_member_list = struct_member_list[struct_level];
+
+ if ($4.type_enum != ECPGt_varchar &&
+ $4.type_enum != ECPGt_char &&
+ $4.type_enum != ECPGt_unsigned_char &&
+ this->type->type_index >= 0)
+ yyerror("No multi-dimensional array support for simple data types");
+
+ types = this;
+
+ $$ = cat5_str(cat3_str(make1_str("/* exec sql type"), mm_strdup($2), make1_str("is")), mm_strdup($4.type_str), mm_strdup($5.str), $6, make1_str("*/"));
+ }
+
+opt_type_array_bounds: '[' ']' nest_type_array_bounds
+ {
+ $$.index1 = 0;
+ $$.index2 = $3.index1;
+ $$.str = cat2_str(make1_str("[]"), $3.str);
+ }
+ | '(' ')' nest_type_array_bounds
+ {
+ $$.index1 = 0;
+ $$.index2 = $3.index1;
+ $$.str = cat2_str(make1_str("[]"), $3.str);
+ }
+ | '[' Iconst ']' nest_type_array_bounds
+ {
+ $$.index1 = atol($2);
+ $$.index2 = $4.index1;
+ $$.str = cat4_str(make1_str("["), $2, make1_str("]"), $4.str);
+ }
+ | '(' Iconst ')' nest_type_array_bounds
+ {
+ $$.index1 = atol($2);
+ $$.index2 = $4.index1;
+ $$.str = cat4_str(make1_str("["), $2, make1_str("]"), $4.str);
+ }
+ | /* EMPTY */
+ {
+ $$.index1 = -1;
+ $$.index2 = -1;
+ $$.str= make1_str("");
+ }
+ ;
+
+nest_type_array_bounds: '[' ']' nest_type_array_bounds
+ {
+ $$.index1 = 0;
+ $$.index2 = $3.index1;
+ $$.str = cat2_str(make1_str("[]"), $3.str);
+ }
+ | '(' ')' nest_type_array_bounds
+ {
+ $$.index1 = 0;
+ $$.index2 = $3.index1;
+ $$.str = cat2_str(make1_str("[]"), $3.str);
+ }
+ | '[' Iconst ']' nest_type_array_bounds
+ {
+ $$.index1 = atol($2);
+ $$.index2 = $4.index1;
+ $$.str = cat4_str(make1_str("["), $2, make1_str("]"), $4.str);
+ }
+ | '(' Iconst ')' nest_type_array_bounds
+ {
+ $$.index1 = atol($2);
+ $$.index2 = $4.index1;
+ $$.str = cat4_str(make1_str("["), $2, make1_str("]"), $4.str);
+ }
+ | /* EMPTY */
+ {
+ $$.index1 = -1;
+ $$.index2 = -1;
+ $$.str= make1_str("");
+ }
+ ;
+opt_reference: SQL_REFERENCE { $$ = make1_str("reference"); }
+ | /* empty */ { $$ = make1_str(""); }
+
+ctype: CHAR
+ {
+ $$.type_str = make1_str("char");
+ $$.type_enum = ECPGt_char;
+ $$.type_index = -1;
+ $$.type_dimension = -1;
+ }
+ | VARCHAR
+ {
+ $$.type_str = make1_str("varchar");
+ $$.type_enum = ECPGt_varchar;
+ $$.type_index = -1;
+ $$.type_dimension = -1;
+ }
+ | FLOAT
+ {
+ $$.type_str = make1_str("float");
+ $$.type_enum = ECPGt_float;
+ $$.type_index = -1;
+ $$.type_dimension = -1;
+ }
+ | DOUBLE
+ {
+ $$.type_str = make1_str("double");
+ $$.type_enum = ECPGt_double;
+ $$.type_index = -1;
+ $$.type_dimension = -1;
+ }
+ | opt_signed SQL_INT
+ {
+ $$.type_str = make1_str("int");
+ $$.type_enum = ECPGt_int;
+ $$.type_index = -1;
+ $$.type_dimension = -1;
+ }
+ | SQL_ENUM
+ {
+ $$.type_str = make1_str("int");
+ $$.type_enum = ECPGt_int;
+ $$.type_index = -1;
+ $$.type_dimension = -1;
+ }
+ | opt_signed SQL_SHORT
+ {
+ $$.type_str = make1_str("short");
+ $$.type_enum = ECPGt_short;
+ $$.type_index = -1;
+ $$.type_dimension = -1;
+ }
+ | opt_signed SQL_LONG
+ {
+ $$.type_str = make1_str("long");
+ $$.type_enum = ECPGt_long;
+ $$.type_index = -1;
+ $$.type_dimension = -1;
+ }
+ | SQL_BOOL
+ {
+ $$.type_str = make1_str("bool");
+ $$.type_enum = ECPGt_bool;
+ $$.type_index = -1;
+ $$.type_dimension = -1;
+ }
+ | SQL_UNSIGNED SQL_INT
+ {
+ $$.type_str = make1_str("unsigned int");
+ $$.type_enum = ECPGt_unsigned_int;
+ $$.type_index = -1;
+ $$.type_dimension = -1;
+ }
+ | SQL_UNSIGNED SQL_SHORT
+ {
+ $$.type_str = make1_str("unsigned short");
+ $$.type_enum = ECPGt_unsigned_short;
+ $$.type_index = -1;
+ $$.type_dimension = -1;
+ }
+ | SQL_UNSIGNED SQL_LONG
+ {
+ $$.type_str = make1_str("unsigned long");
+ $$.type_enum = ECPGt_unsigned_long;
+ $$.type_index = -1;
+ $$.type_dimension = -1;
+ }
+ | SQL_STRUCT
+ {
+ struct_member_list[struct_level++] = NULL;
+ if (struct_level >= STRUCT_DEPTH)
+ yyerror("Too many levels in nested structure definition");
+ } '{' sql_variable_declarations '}'
+ {
+ ECPGfree_struct_member(struct_member_list[struct_level--]);
+ $$.type_str = cat3_str(make1_str("struct {"), $4, make1_str("}"));
+ $$.type_enum = ECPGt_struct;
+ $$.type_index = -1;
+ $$.type_dimension = -1;
+ }
+ | symbol
+ {
+ struct typedefs *this = get_typedef($1);
+
+ $$.type_str = mm_strdup($1);
+ $$.type_enum = this->type->type_enum;
+ $$.type_dimension = this->type->type_dimension;
+ $$.type_index = this->type->type_index;
+ struct_member_list[struct_level] = this->struct_member_list;
+ }
+
+opt_signed: SQL_SIGNED | /* empty */
+
+sql_variable_declarations: /* empty */
+ {
+ $$ = make1_str("");
+ }
+ | sql_declaration sql_variable_declarations
+ {
+ $$ = cat2_str($1, $2);
+ }
+ ;
+
+sql_declaration: ctype
+ {
+ actual_type[struct_level].type_enum = $1.type_enum;
+ actual_type[struct_level].type_dimension = $1.type_dimension;
+ actual_type[struct_level].type_index = $1.type_index;
+ }
+ sql_variable_list SQL_SEMI
+ {
+ $$ = cat3_str($1.type_str, $3, make1_str(";"));
+ }
+
+sql_variable_list: sql_variable
+ {
+ $$ = $1;
+ }
+ | sql_variable_list ',' sql_variable
+ {
+ $$ = make3_str($1, make1_str(","), $3);
+ }
+
+sql_variable: opt_pointer symbol opt_array_bounds
+ {
+ int dimension = $3.index1;
+ int length = $3.index2;
+ struct ECPGtype * type;
+ char dim[14L];
+
+ adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension, actual_type[struct_level].type_index, strlen($1));
+
+ switch (actual_type[struct_level].type_enum)
+ {
+ case ECPGt_struct:
+ if (dimension < 0)
+ type = ECPGmake_struct_type(struct_member_list[struct_level]);
+ else
+ type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level]), dimension);
+
+ break;
+ case ECPGt_varchar:
+ if (dimension == -1)
+ type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length);
+ else
+ type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension);
+
+ switch(dimension)
+ {
+ case 0:
+ strcpy(dim, "[]");
+ break;
+ case -1:
+ case 1:
+ *dim = '\0';
+ break;
+ default:
+ sprintf(dim, "[%d]", dimension);
+ break;
+ }
+
+ break;
+ case ECPGt_char:
+ case ECPGt_unsigned_char:
+ if (dimension == -1)
+ type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length);
+ else
+ type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension);
+
+ break;
+ default:
+ if (length >= 0)
+ yyerror("No multi-dimensional array support for simple data types");
+
+ if (dimension < 0)
+ type = ECPGmake_simple_type(actual_type[struct_level].type_enum, 1);
+ else
+ type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, 1), dimension);
+
+ break;
+ }
+
+ if (struct_level == 0)
+ new_variable($2, type);
+ else
+ ECPGmake_struct_member($2, type, &(struct_member_list[struct_level - 1]));
+
+ $$ = cat3_str($1, $2, $3.str);
+ }
+
+/*
+ * define the type of one variable for embedded SQL
+ */
+ECPGVar: SQL_VAR symbol IS ctype opt_type_array_bounds opt_reference
+ {
+ struct variable *p = find_variable($2);
+ int dimension = $5.index1;
+ int length = $5.index2;
+ struct ECPGtype * type;
+
+ adjust_array($4.type_enum, &dimension, &length, $4.type_dimension, $4.type_index, strlen($6));
+
+ switch ($4.type_enum)
+ {
+ case ECPGt_struct:
+ if (dimension < 0)
+ type = ECPGmake_struct_type(struct_member_list[struct_level]);
+ else
+ type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level]), dimension);
+ break;
+ case ECPGt_varchar:
+ if (dimension == -1)
+ type = ECPGmake_simple_type($4.type_enum, length);
+ else
+ type = ECPGmake_array_type(ECPGmake_simple_type($4.type_enum, length), dimension);
+
+ break;
+ case ECPGt_char:
+ case ECPGt_unsigned_char:
+ if (dimension == -1)
+ type = ECPGmake_simple_type($4.type_enum, length);
+ else
+ type = ECPGmake_array_type(ECPGmake_simple_type($4.type_enum, length), dimension);
+
+ break;
+ default:
+ if (length >= 0)
+ yyerror("No multi-dimensional array support for simple data types");
+
+ if (dimension < 0)
+ type = ECPGmake_simple_type($4.type_enum, 1);
+ else
+ type = ECPGmake_array_type(ECPGmake_simple_type($4.type_enum, 1), dimension);
+
+ break;
+ }
+
+ ECPGfree_type(p->type);
+ p->type = type;
+
+ $$ = cat5_str(cat3_str(make1_str("/* exec sql var"), mm_strdup($2), make1_str("is")), mm_strdup($4.type_str), mm_strdup($5.str), $6, make1_str("*/"));
+ }
+
/*
* whenever statement: decide what to do in case of error/no data found
* according to SQL standards we lack: SQLSTATE, CONSTRAINT and SQLEXCEPTION
@@ -4703,14 +5388,6 @@ action : SQL_CONTINUE {
$<action>$.str = cat2_str(make1_str("call"), mm_strdup($<action>$.command));
}
-/*
- * As long as the prepare statement in not supported by the backend, we will
- * try to simulate it here so we get dynamic SQL
- */
-ECPGPrepare: SQL_PREPARE name FROM name
- {
- }
-
/* some other stuff for ecpg */
ecpg_expr: attr opt_indirection
{
@@ -4987,7 +5664,7 @@ ecpg_expr: attr opt_indirection
| NOT ecpg_expr
{ $$ = cat2_str(make1_str("not"), $2); }
| civariableonly
- { $$ = make1_str(";;"); }
+ { $$ = $1; }
;
into_list : coutputvariable | into_list ',' coutputvariable;
@@ -5010,6 +5687,7 @@ cinputvariable : cvariable indicator {
civariableonly : cvariable {
add_variable(&argsinsert, find_variable($1), &no_indicator);
+ $$ = make1_str(";;");
}
cvariable: CVARIABLE { $$ = $1; }
diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c
index 52cc8f8087..dd3546b50a 100644
--- a/src/interfaces/ecpg/preproc/type.c
+++ b/src/interfaces/ecpg/preproc/type.c
@@ -2,7 +2,6 @@
#include <string.h>
#include <stdlib.h>
-#include "type.h"
#include "extern.h"
/* malloc + error check */
@@ -36,8 +35,8 @@ mm_strdup(const char *string)
}
/* duplicate memberlist */
-static struct ECPGstruct_member *
-struct_member_dup(struct ECPGstruct_member * rm)
+struct ECPGstruct_member *
+ECPGstruct_member_dup(struct ECPGstruct_member * rm)
{
struct ECPGstruct_member *new = NULL;
@@ -71,7 +70,8 @@ void
ECPGmake_struct_member(char *name, struct ECPGtype * type, struct ECPGstruct_member ** start)
{
struct ECPGstruct_member *ptr,
- *ne = (struct ECPGstruct_member *) mm_alloc(sizeof(struct ECPGstruct_member));
+ *ne =
+ (struct ECPGstruct_member *) mm_alloc(sizeof(struct ECPGstruct_member));
ne->name = strdup(name);
ne->typ = type;
@@ -112,7 +112,7 @@ ECPGmake_struct_type(struct ECPGstruct_member * rm)
{
struct ECPGtype *ne = ECPGmake_simple_type(ECPGt_struct, 1);
- ne->u.members = struct_member_dup(rm);
+ ne->u.members = ECPGstruct_member_dup(rm);
return ne;
}
@@ -160,6 +160,9 @@ get_type(enum ECPGttype typ)
case ECPGt_NO_INDICATOR: /* no indicator */
return ("ECPGt_NO_INDICATOR");
break;
+ case ECPGt_char_variable: /* string that should not be quoted */
+ return ("ECPGt_char_variable");
+ break;
default:
abort();
}
@@ -202,23 +205,30 @@ ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *in
{
ECPGdump_a_simple(o, name, typ->u.element->typ,
typ->u.element->size, typ->size, NULL, prefix);
- if (ind_typ == &ecpg_no_indicator)
+ if (ind_typ->typ == ECPGt_NO_INDICATOR)
ECPGdump_a_simple(o, ind_name, ind_typ->typ, ind_typ->size, -1, NULL, ind_prefix);
else
+ {
+ if (ind_typ->typ != ECPGt_array)
+ {
+ fprintf(stderr, "Indicator for an array has to be array too.\n");
+ exit(INDICATOR_NOT_ARRAY);
+ }
ECPGdump_a_simple(o, ind_name, ind_typ->u.element->typ,
ind_typ->u.element->size, ind_typ->size, NULL, prefix);
+ }
}
else if (typ->u.element->typ == ECPGt_array)
{
- yyerror("No nested arrays allowed (except strings)"); /* Array of array, */
+ yyerror("No nested arrays allowed (except strings)"); /* array of array */
}
else if (typ->u.element->typ == ECPGt_struct)
{
- /* Array of structs. */
+ /* Array of structs */
ECPGdump_a_struct(o, name, ind_name, typ->size, typ->u.element, ind_typ->u.element, NULL, prefix, ind_prefix);
}
else
- yyerror("Internal error: unknown datatype, pleqase inform pgsql-bugs@postgresql.org");
+ yyerror("Internal error: unknown datatype, please inform pgsql-bugs@postgresql.org");
break;
case ECPGt_struct:
ECPGdump_a_struct(o, name, ind_name, 1, typ, ind_typ, NULL, prefix, ind_prefix);
@@ -260,6 +270,7 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
break;
case ECPGt_char:
case ECPGt_unsigned_char:
+ case ECPGt_char_variable:
sprintf(offset, "%ld*sizeof(char)", varcharsize);
break;
default:
diff --git a/src/interfaces/ecpg/preproc/type.h b/src/interfaces/ecpg/preproc/type.h
index f5c5941c13..f9642d9276 100644
--- a/src/interfaces/ecpg/preproc/type.h
+++ b/src/interfaces/ecpg/preproc/type.h
@@ -30,6 +30,7 @@ struct ECPGtype *ECPGmake_simple_type(enum ECPGttype, long);
struct ECPGtype *ECPGmake_varchar_type(enum ECPGttype, long);
struct ECPGtype *ECPGmake_array_type(struct ECPGtype *, long);
struct ECPGtype *ECPGmake_struct_type(struct ECPGstruct_member *);
+struct ECPGstruct_member * ECPGstruct_member_dup(struct ECPGstruct_member *);
/* Frees a type. */
void ECPGfree_struct_member(struct ECPGstruct_member *);
@@ -84,6 +85,54 @@ struct index
struct this_type
{
- enum ECPGttype type_enum;
- char *type_str;
+ enum ECPGttype type_enum;
+ char *type_str;
+ int type_dimension;
+ int type_index;
+};
+
+struct _include_path
+{
+ char *path;
+ struct _include_path *next;
+};
+
+struct cursor
+{
+ char *name;
+ char *command;
+ struct arguments *argsinsert;
+ struct arguments *argsresult;
+ struct cursor *next;
+};
+
+struct typedefs
+{
+ char *name;
+ struct this_type *type;
+ struct ECPGstruct_member *struct_member_list;
+ struct typedefs *next;
+};
+
+struct _defines
+{
+ char *old;
+ char *new;
+ struct _defines *next;
+};
+
+/* This is a linked list of the variable names and types. */
+struct variable
+{
+ char *name;
+ struct ECPGtype *type;
+ int brace_level;
+ struct variable *next;
+};
+
+struct arguments
+{
+ struct variable *variable;
+ struct variable *indicator;
+ struct arguments *next;
};