Commit bf6636ba authored by Marc G. Fournier's avatar Marc G. Fournier

From: Michael Meskes <Michael_Meskes@topmail.de>

See Changes file...
parent 3eb22085
...@@ -400,3 +400,60 @@ Tue Feb 2 07:40:52 CET 1999 ...@@ -400,3 +400,60 @@ Tue Feb 2 07:40:52 CET 1999
- Brought preproc.y in sync again with gram.y. - Brought preproc.y in sync again with gram.y.
- Set ecpg version to 2.4.9 - Set ecpg version to 2.4.9
Wed Feb 3 18:28:46 CET 1999
- Started working on PREPARE statement.
- Fixed typo in preproc that cause CREATE statement to not work
anymore.
Thu Feb 4 19:43:39 CET 1999
- Some parts of the PREPARE statement work now.
- Added EXECUTE command
- Added DEALLOCATE PREPARE command
Fri Feb 5 18:25:07 CET 1999
- PREPARE seems to be working okay now.
- Fixed some minor bugs.
- Renamed y.tab.* to preproc.*
Mon Feb 8 07:57:29 CET 1999
- Synced preproc.y with gram.y again.
- Allow ':<name>' as positional variable in prepare statement also.
You can still specify ';;' instead of course.
- Added TYPE statement.
- Set library version to 2.7.0
Tue Feb 9 07:07:11 CET 1999
- Synced preproc.y with gram.y.
Tue Feb 9 20:21:44 CET 1999
- Added FREE statement.
Wed Feb 10 07:51:09 CET 1999
- Synced keyword.c.
Sat Feb 13 10:44:43 CET 1999
- Added DECLARE STATEMENT for compatibility with Oracle. De facto
this statement does nothing.
- Added VAR statement.
Son Feb 14 11:36:04 CET 1999
- Added type 'enum' to TYPE and VAR statement.
- Allow ecpg keywords as datatypes.
Thu Feb 18 08:35:35 CET 1999
- Make sure indicator for array is array too.
Fri Feb 19 18:38:45 CET 1999
- Finished type aliasing for structures.
- Set ecpg version to 2.5.0
...@@ -11,10 +11,10 @@ DESCRIPTOR statement will be ignored. ...@@ -11,10 +11,10 @@ DESCRIPTOR statement will be ignored.
it would be nice to be able to use :var[:index] as cvariable it would be nice to be able to use :var[:index] as cvariable
'at DB connection' is missing for several commands (is this standard?)
support for unions
Missing statements: Missing statements:
- exec sql type
- exec sql prepare
- exec sql allocate - exec sql allocate
- exqc sql free
- SQLSTATE - SQLSTATE
- exec sql whenever sqlwarning
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#define ECPG_NO_CONN -220 #define ECPG_NO_CONN -220
#define ECPG_NOT_CONN -221 #define ECPG_NOT_CONN -221
#define ECPG_INVALID_STMT -230
/* finally the backend error messages, they start at 400 */ /* finally the backend error messages, they start at 400 */
#define ECPG_PGSQL -400 #define ECPG_PGSQL -400
#define ECPG_TRANS -401 #define ECPG_TRANS -401
......
...@@ -11,7 +11,10 @@ extern "C" ...@@ -11,7 +11,10 @@ extern "C"
bool ECPGdo(int, char *,...); bool ECPGdo(int, char *,...);
bool ECPGtrans(int, const char *); bool ECPGtrans(int, const char *);
bool ECPGdisconnect(int, const char *); bool ECPGdisconnect(int, const char *);
bool ECPGprepare(int, char *, char *);
bool ECPGdeallocate(int, char *);
char *ECPGprepared_statement(char *);
void ECPGlog(const char *format,...); void ECPGlog(const char *format,...);
#ifdef LIBPQ_FE_H #ifdef LIBPQ_FE_H
......
...@@ -45,7 +45,8 @@ extern "C" ...@@ -45,7 +45,8 @@ extern "C"
ECPGt_struct, ECPGt_struct,
ECPGt_EOIT, /* End of insert types. */ ECPGt_EOIT, /* End of insert types. */
ECPGt_EORT, /* End of result types. */ ECPGt_EORT, /* End of result types. */
ECPGt_NO_INDICATOR /* no indicator */ ECPGt_NO_INDICATOR, /* no indicator */
ECPGt_char_variable
}; };
#define IS_SIMPLE_TYPE(type) ((type) >= ECPGt_char && (type) <= ECPGt_varchar2) #define IS_SIMPLE_TYPE(type) ((type) >= ECPGt_char && (type) <= ECPGt_varchar2)
......
...@@ -6,13 +6,13 @@ ...@@ -6,13 +6,13 @@
# Copyright (c) 1994, Regents of the University of California # Copyright (c) 1994, Regents of the University of California
# #
# IDENTIFICATION # IDENTIFICATION
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.40 1999/01/21 20:01:32 scrappy Exp $ # $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/Makefile.in,v 1.41 1999/02/20 07:00:53 scrappy Exp $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
NAME= ecpg NAME= ecpg
SO_MAJOR_VERSION= 2 SO_MAJOR_VERSION= 2
SO_MINOR_VERSION= 6.3 SO_MINOR_VERSION= 7.0
SRCDIR= @top_srcdir@ SRCDIR= @top_srcdir@
include $(SRCDIR)/Makefile.global include $(SRCDIR)/Makefile.global
......
...@@ -75,12 +75,19 @@ struct variable ...@@ -75,12 +75,19 @@ struct variable
struct statement struct statement
{ {
int lineno; int lineno;
char *command; char *command;
struct variable *inlist; struct variable *inlist;
struct variable *outlist; struct variable *outlist;
}; };
struct prepared_statement
{
char *name;
struct statement *stmt;
struct prepared_statement *next;
} *prep_stmts = NULL;
static int simple_debug = 0; static int simple_debug = 0;
static FILE *debugstream = NULL; static FILE *debugstream = NULL;
static int committed = true; static int committed = true;
...@@ -196,6 +203,41 @@ quote_postgres(char *arg, int lineno) ...@@ -196,6 +203,41 @@ quote_postgres(char *arg, int lineno)
return res; return res;
} }
/* This function returns a newly malloced string that has the \
in the strings inside the argument quoted with another \.
*/
static
char *
quote_strings(char *arg, int lineno)
{
char *res = (char *) ecpg_alloc(2 * strlen(arg) + 1, lineno);
int i,
ri;
bool string = false;
if (!res)
return (res);
for (i = 0, ri = 0; arg[i]; i++, ri++)
{
switch (arg[i])
{
case '\'':
string = string ? false : true;
break;
case '\\':
res[ri++] = '\\';
default:
;
}
res[ri] = arg[i];
}
res[ri] = '\0';
return res;
}
/* create a list of variables */ /* create a list of variables */
static bool static bool
create_statement(int lineno, struct statement ** stmt, char *query, va_list ap) create_statement(int lineno, struct statement ** stmt, char *query, va_list ap)
...@@ -236,6 +278,14 @@ create_statement(int lineno, struct statement ** stmt, char *query, va_list ap) ...@@ -236,6 +278,14 @@ create_statement(int lineno, struct statement ** stmt, char *query, va_list ap)
var->ind_arrsize = va_arg(ap, long); var->ind_arrsize = va_arg(ap, long);
var->ind_offset = va_arg(ap, long); var->ind_offset = va_arg(ap, long);
var->next = NULL; var->next = NULL;
if (var->value == NULL)
{
ECPGlog("create_statement: invalid statement name\n");
register_error(ECPG_INVALID_STMT, "Invalid statement name in line %d", lineno);
free(var);
return false;
}
for (ptr = *list; ptr && ptr->next; ptr = ptr->next); for (ptr = *list; ptr && ptr->next; ptr = ptr->next);
...@@ -251,6 +301,19 @@ create_statement(int lineno, struct statement ** stmt, char *query, va_list ap) ...@@ -251,6 +301,19 @@ create_statement(int lineno, struct statement ** stmt, char *query, va_list ap)
return (true); return (true);
} }
static char *
next_insert(char *text)
{
char *ptr = text;
bool string = false;
for (; ptr[1] != '\0' && (ptr[0] != ';' || ptr[1] != ';' || string); ptr++)
if (ptr[0] == '\'')
string = string ? false : true;
return (ptr[1] == '\0') ? NULL : ptr;
}
static bool static bool
ECPGexecute(struct statement * stmt) ECPGexecute(struct statement * stmt)
{ {
...@@ -379,7 +442,30 @@ ECPGexecute(struct statement * stmt) ...@@ -379,7 +442,30 @@ ECPGexecute(struct statement * stmt)
tobeinserted = mallocedval; tobeinserted = mallocedval;
} }
break; break;
case ECPGt_char_variable:
{
/* set slen to string length if type is char * */
int slen = (var->varcharsize == 0) ? strlen((char *) var->value) : var->varcharsize;
char *tmp;
if (!(newcopy = ecpg_alloc(slen + 1, stmt->lineno)))
return false;
strncpy(newcopy, (char *) var->value, slen);
newcopy[slen] = '\0';
if (!(mallocedval = (char *) ecpg_alloc(2 * strlen(newcopy) + 1, stmt->lineno)))
return false;
tmp = quote_strings(newcopy, stmt->lineno);
if (!tmp)
return false;
strcat(mallocedval, tmp);
free(newcopy);
tobeinserted = mallocedval;
}
break;
case ECPGt_varchar: case ECPGt_varchar:
{ {
struct ECPGgeneric_varchar *variable = struct ECPGgeneric_varchar *variable =
...@@ -428,7 +514,7 @@ ECPGexecute(struct statement * stmt) ...@@ -428,7 +514,7 @@ ECPGexecute(struct statement * stmt)
return false; return false;
strcpy(newcopy, copiedquery); strcpy(newcopy, copiedquery);
if ((p = strstr(newcopy, ";;")) == NULL) if ((p = next_insert(newcopy)) == NULL)
{ {
/* /*
...@@ -449,7 +535,7 @@ ECPGexecute(struct statement * stmt) ...@@ -449,7 +535,7 @@ ECPGexecute(struct statement * stmt)
strcat(newcopy, strcat(newcopy,
copiedquery copiedquery
+ (p - newcopy) + (p - newcopy)
+ 2 /* Length of ;; */ ); + sizeof(";;") - 1 /* don't count the '\0' */);
} }
/* /*
...@@ -470,7 +556,7 @@ ECPGexecute(struct statement * stmt) ...@@ -470,7 +556,7 @@ ECPGexecute(struct statement * stmt)
} }
/* Check if there are unmatched things left. */ /* Check if there are unmatched things left. */
if (strstr(copiedquery, ";;") != NULL) if (next_insert(copiedquery) != NULL)
{ {
register_error(ECPG_TOO_FEW_ARGUMENTS, "Too few arguments line %d.", stmt->lineno); register_error(ECPG_TOO_FEW_ARGUMENTS, "Too few arguments line %d.", stmt->lineno);
return false; return false;
...@@ -898,7 +984,21 @@ ECPGtrans(int lineno, const char *transaction) ...@@ -898,7 +984,21 @@ ECPGtrans(int lineno, const char *transaction)
PQclear(res); PQclear(res);
} }
if (strcmp(transaction, "commit") == 0 || strcmp(transaction, "rollback") == 0) if (strcmp(transaction, "commit") == 0 || strcmp(transaction, "rollback") == 0)
{
struct prepared_statement *this;
committed = 1; committed = 1;
/* deallocate all prepared statements */
for (this = prep_stmts; this != NULL; this = this->next)
{
bool b = ECPGdeallocate(lineno, this->name);
if (!b)
return false;
}
}
return TRUE; return TRUE;
} }
...@@ -1033,3 +1133,109 @@ sqlprint(void) ...@@ -1033,3 +1133,109 @@ sqlprint(void)
sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml] = '\0'; sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml] = '\0';
printf("sql error %s\n", sqlca.sqlerrm.sqlerrmc); printf("sql error %s\n", sqlca.sqlerrm.sqlerrmc);
} }
static void
replace_variables(char *text)
{
char *ptr = text;
bool string = false;
for (; *ptr != '\0'; ptr++)
{
if (*ptr == '\'')
string = string ? false : true;
if (!string && *ptr == ':')
{
ptr[0] = ptr[1] = ';';
for (ptr += 2; *ptr && *ptr != ' '; ptr++)
*ptr = ' ';
}
}
}
/* handle the EXEC SQL PREPARE statement */
bool
ECPGprepare(int lineno, char *name, char *variable)
{
struct statement *stmt;
struct prepared_statement *this;
/* check if we already have prepared this statement */
for (this = prep_stmts; this != NULL && strcmp(this->name, name) != 0; this = this->next);
if (this)
{
bool b = ECPGdeallocate(lineno, name);
if (!b)
return false;
}
this = (struct prepared_statement *) ecpg_alloc(sizeof(struct prepared_statement), lineno);
if (!this)
return false;
stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno);
if (!stmt)
{
free(this);
return false;
}
/* create statement */
stmt->lineno = lineno;
stmt->command = ecpg_strdup(variable, lineno);
stmt->inlist = stmt->outlist = NULL;
/* if we have C variables in our statment replace them with ';;' */
replace_variables(stmt->command);
/* add prepared statement to our list */
this->name = ecpg_strdup(name, lineno);
this->stmt = stmt;
if (prep_stmts == NULL)
this->next = NULL;
else
this->next = prep_stmts;
prep_stmts = this;
return true;
}
/* handle the EXEC SQL DEALLOCATE PREPARE statement */
bool
ECPGdeallocate(int lineno, char *name)
{
struct prepared_statement *this, *prev;
/* check if we really have prepared this statement */
for (this = prep_stmts, prev = NULL; this != NULL && strcmp(this->name, name) != 0; prev = this, this = this->next);
if (this)
{
/* okay, free all the resources */
free(this->name);
free(this->stmt->command);
free(this->stmt);
if (prev != NULL)
prev->next = this->next;
else
prep_stmts = this->next;
return true;
}
ECPGlog("deallocate_prepare: invalid statement name %s\n", name);
register_error(ECPG_INVALID_STMT, "Invalid statement name %s in line %d", name, lineno);
return false;
}
/* return the prepared statement */
char *
ECPGprepared_statement(char *name)
{
struct prepared_statement *this;
for (this = prep_stmts; this != NULL && strcmp(this->name, name) != 0; this = this->next);
return (this) ? this->stmt->command : NULL;
}
...@@ -8,7 +8,7 @@ ECPGtype_name(enum ECPGttype typ) ...@@ -8,7 +8,7 @@ ECPGtype_name(enum ECPGttype typ)
{ {
switch (typ) switch (typ)
{ {
case ECPGt_char: case ECPGt_char:
return "char"; return "char";
case ECPGt_unsigned_char: case ECPGt_unsigned_char:
return "unsigned char"; return "unsigned char";
...@@ -32,6 +32,8 @@ ECPGtype_name(enum ECPGttype typ) ...@@ -32,6 +32,8 @@ ECPGtype_name(enum ECPGttype typ)
return "bool"; return "bool";
case ECPGt_varchar: case ECPGt_varchar:
return "varchar"; return "varchar";
case ECPGt_char_variable:
return "char";
default: default:
abort(); abort();
} }
......
...@@ -2,20 +2,25 @@ SRCDIR= ../../.. ...@@ -2,20 +2,25 @@ SRCDIR= ../../..
include $(SRCDIR)/Makefile.global include $(SRCDIR)/Makefile.global
MAJOR_VERSION=2 MAJOR_VERSION=2
MINOR_VERSION=4 MINOR_VERSION=5
PATCHLEVEL=9 PATCHLEVEL=0
CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \ CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \
-DMINOR_VERSION=$(MINOR_VERSION) -DPATCHLEVEL=$(PATCHLEVEL) \ -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 keywords.o c_keywords.o ../lib/typename.o
all:: ecpg all:: ecpg
preproc.c preproc.h: preproc.y
$(YACC) $(YFLAGS) $<
mv y.tab.c preproc.c
mv y.tab.h preproc.h
clean: 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: all
$(INSTALL) $(INSTL_EXE_OPTS) ecpg$(X) $(DESTDIR)$(BINDIR) $(INSTALL) $(INSTL_EXE_OPTS) ecpg$(X) $(DESTDIR)$(BINDIR)
...@@ -31,13 +36,10 @@ pgc.c: pgc.l ...@@ -31,13 +36,10 @@ pgc.c: pgc.l
$(LEX) $< $(LEX) $<
mv lex.yy.c pgc.c mv lex.yy.c pgc.c
y.tab.h y.tab.c: preproc.y preproc.o : preproc.h ../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c
$(YACC) $(YFLAGS) $<
y.tab.o : y.tab.h ../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c
type.o : ../include/ecpgtype.h type.o : ../include/ecpgtype.h
pgc.o : ../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c y.tab.h pgc.o : ../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c preproc.h
keywords.o: ../include/ecpgtype.h y.tab.h keywords.o: ../include/ecpgtype.h preproc.h
c_keywords.o: ../include/ecpgtype.h y.tab.h c_keywords.o: ../include/ecpgtype.h preproc.h
ecpg_keywords.o: ../include/ecpgtype.h y.tab.h ecpg_keywords.o: ../include/ecpgtype.h preproc.h
...@@ -9,9 +9,8 @@ ...@@ -9,9 +9,8 @@
#include <string.h> #include <string.h>
#include "postgres.h" #include "postgres.h"
#include "type.h"
#include "y.tab.h"
#include "extern.h" #include "extern.h"
#include "preproc.h"
/* /*
* List of (keyword-name, keyword-token-value) pairs. * List of (keyword-name, keyword-token-value) pairs.
......
...@@ -25,6 +25,7 @@ extern char *optarg; ...@@ -25,6 +25,7 @@ extern char *optarg;
struct _include_path *include_paths; struct _include_path *include_paths;
int no_auto_trans = 0; int no_auto_trans = 0;
struct cursor *cur = NULL; struct cursor *cur = NULL;
struct typedefs *types = NULL;
static void static void
usage(char *progname) usage(char *progname)
...@@ -155,22 +156,22 @@ main(int argc, char *const argv[]) ...@@ -155,22 +156,22 @@ main(int argc, char *const argv[])
{ {
struct cursor *ptr; struct cursor *ptr;
struct _defines *defptr; struct _defines *defptr;
struct typedefs *typeptr;
/* remove old cursor definitions if any are still there */ /* remove old cursor definitions if any are still there */
for (ptr = cur; ptr != NULL;) for (ptr = cur; ptr != NULL;)
{ {
struct cursor *this = ptr; struct cursor *this = ptr;
struct arguments *l1, struct arguments *l1, *l2;
*l2;
free(ptr->command); free(ptr->command);
free(ptr->name); free(ptr->name);
for (l1 = argsinsert; l1; l1 = l2) for (l1 = ptr->argsinsert; l1; l1 = l2)
{ {
l2 = l1->next; l2 = l1->next;
free(l1); free(l1);
} }
for (l1 = argsresult; l1; l1 = l2) for (l1 = ptr->argsresult; l1; l1 = l2)
{ {
l2 = l1->next; l2 = l1->next;
free(l1); free(l1);
...@@ -189,7 +190,19 @@ main(int argc, char *const argv[]) ...@@ -189,7 +190,19 @@ main(int argc, char *const argv[])
defptr = defptr->next; defptr = defptr->next;
free(this); 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 */ /* initialize lex */
lex_init(); lex_init();
......
...@@ -9,9 +9,8 @@ ...@@ -9,9 +9,8 @@
#include <string.h> #include <string.h>
#include "postgres.h" #include "postgres.h"
#include "type.h"
#include "extern.h" #include "extern.h"
#include "y.tab.h" #include "preproc.h"
/* /*
* List of (keyword-name, keyword-token-value) pairs. * List of (keyword-name, keyword-token-value) pairs.
...@@ -21,25 +20,38 @@ ...@@ -21,25 +20,38 @@
*/ */
static ScanKeyword ScanKeywords[] = { static ScanKeyword ScanKeywords[] = {
/* name value */ /* name value */
{"bool", SQL_BOOL},
{"break", SQL_BREAK}, {"break", SQL_BREAK},
{"call", SQL_CALL}, {"call", SQL_CALL},
{"connect", SQL_CONNECT}, {"connect", SQL_CONNECT},
{"connection", SQL_CONNECTION}, {"connection", SQL_CONNECTION},
{"continue", SQL_CONTINUE}, {"continue", SQL_CONTINUE},
{"deallocate", SQL_DEALLOCATE},
{"disconnect", SQL_DISCONNECT}, {"disconnect", SQL_DISCONNECT},
{"enum", SQL_ENUM},
{"found", SQL_FOUND}, {"found", SQL_FOUND},
{"free", SQL_FREE},
{"go", SQL_GO}, {"go", SQL_GO},
{"goto", SQL_GOTO}, {"goto", SQL_GOTO},
{"identified", SQL_IDENTIFIED}, {"identified", SQL_IDENTIFIED},
{"immediate", SQL_IMMEDIATE}, {"immediate", SQL_IMMEDIATE},
{"indicator", SQL_INDICATOR}, {"indicator", SQL_INDICATOR},
{"int", SQL_INT},
{"long", SQL_LONG},
{"open", SQL_OPEN}, {"open", SQL_OPEN},
{"prepare", SQL_PREPARE},
{"reference", SQL_REFERENCE},
{"release", SQL_RELEASE}, {"release", SQL_RELEASE},
{"section", SQL_SECTION}, {"section", SQL_SECTION},
{"short", SQL_SHORT},
{"signed", SQL_SIGNED},
{"sqlerror", SQL_SQLERROR}, {"sqlerror", SQL_SQLERROR},
{"sqlprint", SQL_SQLPRINT}, {"sqlprint", SQL_SQLPRINT},
{"sqlwarning", SQL_SQLWARNING}, {"sqlwarning", SQL_SQLWARNING},
{"stop", SQL_STOP}, {"stop", SQL_STOP},
{"struct", SQL_STRUCT},
{"unsigned", SQL_UNSIGNED},
{"var", SQL_VAR},
{"whenever", SQL_WHENEVER}, {"whenever", SQL_WHENEVER},
}; };
......
#include "parser/keywords.h" #include "parser/keywords.h"
#include "type.h"
#include <errno.h> #include <errno.h>
/* variables */ /* variables */
extern int braces_open, extern int braces_open,
no_auto_trans; no_auto_trans, struct_level;
extern char *yytext; extern char *yytext;
extern int yylineno, extern int yylineno,
yyleng; yyleng;
extern FILE *yyin, extern FILE *yyin,
*yyout; *yyout;
struct _include_path
{
char *path;
struct _include_path *next;
};
extern struct _include_path *include_paths; 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; extern struct cursor *cur;
extern struct typedefs *types;
struct _defines
{
char *old;
char *new;
struct _defines *next;
};
extern struct _defines *defines; 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 ECPGtype ecpg_no_indicator;
extern struct variable 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 *argsinsert;
extern struct arguments *argsresult; extern struct arguments *argsresult;
...@@ -74,9 +34,10 @@ extern void yyerror(char *); ...@@ -74,9 +34,10 @@ extern void yyerror(char *);
/* return codes */ /* return codes */
#define OK 0 #define OK 0
#define PARSE_ERROR -1 #define PARSE_ERROR -1
#define ILLEGAL_OPTION -2 #define ILLEGAL_OPTION -2
#define INDICATOR_NOT_ARRAY -3
#define NO_INCLUDE_FILE ENOENT #define NO_INCLUDE_FILE ENOENT
#define OUT_OF_MEMORY ENOMEM #define OUT_OF_MEMORY ENOMEM
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -18,7 +18,7 @@
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
#include "type.h" #include "type.h"
#include "y.tab.h" #include "preproc.h"
#include "parser/keywords.h" #include "parser/keywords.h"
#include "utils/elog.h" #include "utils/elog.h"
...@@ -69,9 +69,6 @@ static ScanKeyword ScanKeywords[] = { ...@@ -69,9 +69,6 @@ static ScanKeyword ScanKeywords[] = {
{"createdb", CREATEDB}, {"createdb", CREATEDB},
{"createuser", CREATEUSER}, {"createuser", CREATEUSER},
{"cross", CROSS}, {"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_date", CURRENT_DATE},
{"current_time", CURRENT_TIME}, {"current_time", CURRENT_TIME},
{"current_timestamp", CURRENT_TIMESTAMP}, {"current_timestamp", CURRENT_TIMESTAMP},
...@@ -96,6 +93,7 @@ static ScanKeyword ScanKeywords[] = { ...@@ -96,6 +93,7 @@ static ScanKeyword ScanKeywords[] = {
{"end", END_TRANS}, {"end", END_TRANS},
/***S*I***/ /***S*I***/
{"except", EXCEPT}, {"except", EXCEPT},
{"execute", EXECUTE}, {"execute", EXECUTE},
{"exists", EXISTS}, {"exists", EXISTS},
{"explain", EXPLAIN}, {"explain", EXPLAIN},
...@@ -125,6 +123,7 @@ static ScanKeyword ScanKeywords[] = { ...@@ -125,6 +123,7 @@ static ScanKeyword ScanKeywords[] = {
{"instead", INSTEAD}, {"instead", INSTEAD},
/***S*I***/ /***S*I***/
{"intersect", INTERSECT}, {"intersect", INTERSECT},
{"interval", INTERVAL}, {"interval", INTERVAL},
{"into", INTO}, {"into", INTO},
{"is", IS}, {"is", IS},
...@@ -138,6 +137,7 @@ static ScanKeyword ScanKeywords[] = { ...@@ -138,6 +137,7 @@ static ScanKeyword ScanKeywords[] = {
{"left", LEFT}, {"left", LEFT},
{"level", LEVEL}, {"level", LEVEL},
{"like", LIKE}, {"like", LIKE},
{"limit", LIMIT},
{"listen", LISTEN}, {"listen", LISTEN},
{"load", LOAD}, {"load", LOAD},
{"local", LOCAL}, {"local", LOCAL},
...@@ -167,6 +167,7 @@ static ScanKeyword ScanKeywords[] = { ...@@ -167,6 +167,7 @@ static ScanKeyword ScanKeywords[] = {
{"nullif", NULLIF}, {"nullif", NULLIF},
{"numeric", NUMERIC}, {"numeric", NUMERIC},
{"of", OF}, {"of", OF},
{"offset", OFFSET},
{"oids", OIDS}, {"oids", OIDS},
{"old", CURRENT}, {"old", CURRENT},
{"on", ON}, {"on", ON},
......
...@@ -24,9 +24,8 @@ ...@@ -24,9 +24,8 @@
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
#include "parser/gramparse.h" #include "parser/gramparse.h"
#include "parser/scansup.h" #include "parser/scansup.h"
#include "type.h"
#include "extern.h" #include "extern.h"
#include "y.tab.h" #include "preproc.h"
#include "utils/builtins.h" #include "utils/builtins.h"
/* some versions of lex define this as a macro */ /* some versions of lex define this as a macro */
...@@ -241,7 +240,7 @@ cppline {space}*#.*(\\{space}*\n)*\n* ...@@ -241,7 +240,7 @@ cppline {space}*#.*(\\{space}*\n)*\n*
} }
<xq>{xqstop} { <xq>{xqstop} {
BEGIN(SQL); BEGIN(SQL);
yylval.str = strdup(scanstr(literal)); yylval.str = mm_strdup(scanstr(literal));
return SCONST; return SCONST;
} }
<xq>{xqdouble} | <xq>{xqdouble} |
...@@ -276,7 +275,7 @@ cppline {space}*#.*(\\{space}*\n)*\n* ...@@ -276,7 +275,7 @@ cppline {space}*#.*(\\{space}*\n)*\n*
} }
<xd>{xdstop} { <xd>{xdstop} {
BEGIN(SQL); BEGIN(SQL);
yylval.str = strdup(literal); yylval.str = mm_strdup(literal);
return CSTRING; return CSTRING;
} }
<xd>{xdinside} { <xd>{xdinside} {
...@@ -292,7 +291,7 @@ cppline {space}*#.*(\\{space}*\n)*\n* ...@@ -292,7 +291,7 @@ cppline {space}*#.*(\\{space}*\n)*\n*
} }
<xdc>{xdstop} { <xdc>{xdstop} {
BEGIN(C); BEGIN(C);
yylval.str = strdup(literal); yylval.str = mm_strdup(literal);
return CSTRING; return CSTRING;
} }
<xdc>{xdinside} { <xdc>{xdinside} {
...@@ -316,14 +315,14 @@ cppline {space}*#.*(\\{space}*\n)*\n* ...@@ -316,14 +315,14 @@ cppline {space}*#.*(\\{space}*\n)*\n*
} }
<SQL>{self} { return yytext[0]; } <SQL>{self} { return yytext[0]; }
<SQL>{operator}/-[\.0-9] { <SQL>{operator}/-[\.0-9] {
yylval.str = strdup((char*)yytext); yylval.str = mm_strdup((char*)yytext);
return Op; return Op;
} }
<SQL>{operator} { <SQL>{operator} {
if (strcmp((char*)yytext,"!=") == 0) if (strcmp((char*)yytext,"!=") == 0)
yylval.str = strdup("<>"); /* compatability */ yylval.str = mm_strdup("<>"); /* compatability */
else else
yylval.str = strdup((char*)yytext); yylval.str = mm_strdup((char*)yytext);
return Op; return Op;
} }
<SQL>{param} { <SQL>{param} {
...@@ -342,7 +341,6 @@ cppline {space}*#.*(\\{space}*\n)*\n* ...@@ -342,7 +341,6 @@ cppline {space}*#.*(\\{space}*\n)*\n*
if (isascii((unsigned char)lower_text[i]) && isupper(lower_text[i])) if (isascii((unsigned char)lower_text[i]) && isupper(lower_text[i]))
lower_text[i] = tolower(lower_text[i]); lower_text[i] = tolower(lower_text[i]);
printf("yyt= %s, lt = %s\n", yytext, lower_text);
keyword = ScanKeywordLookup((char*)lower_text); keyword = ScanKeywordLookup((char*)lower_text);
if (keyword != NULL) { if (keyword != NULL) {
return keyword->value; return keyword->value;
...@@ -367,7 +365,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text); ...@@ -367,7 +365,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
yb->buffer = YY_CURRENT_BUFFER; yb->buffer = YY_CURRENT_BUFFER;
yb->lineno = yylineno; yb->lineno = yylineno;
yb->filename = strdup(input_filename); yb->filename = mm_strdup(input_filename);
yb->next = yy_buffer; yb->next = yy_buffer;
yy_buffer = yb; yy_buffer = yb;
...@@ -378,7 +376,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text); ...@@ -378,7 +376,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
} }
if (ptr == NULL) if (ptr == NULL)
{ {
yylval.str = strdup((char*)yytext); yylval.str = mm_strdup((char*)yytext);
return IDENT; return IDENT;
} }
} }
...@@ -470,7 +468,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text); ...@@ -470,7 +468,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
return ICONST; return ICONST;
} }
<SQL>:{identifier}(("->"|\.){identifier})* { <SQL>:{identifier}(("->"|\.){identifier})* {
yylval.str = strdup((char*)yytext+1); yylval.str = mm_strdup((char*)yytext+1);
return(CVARIABLE); return(CVARIABLE);
} }
<SQL>{identifier} { <SQL>{identifier} {
...@@ -484,7 +482,6 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text); ...@@ -484,7 +482,6 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
if (isascii((unsigned char)lower_text[i]) && isupper(lower_text[i])) if (isascii((unsigned char)lower_text[i]) && isupper(lower_text[i]))
lower_text[i] = tolower(lower_text[i]); lower_text[i] = tolower(lower_text[i]);
printf("yyt= %s, lt = %s\n", yytext, lower_text);
keyword = ScanKeywordLookup((char*)lower_text); keyword = ScanKeywordLookup((char*)lower_text);
if (keyword != NULL) { if (keyword != NULL) {
return keyword->value; return keyword->value;
...@@ -509,7 +506,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text); ...@@ -509,7 +506,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
yb->buffer = YY_CURRENT_BUFFER; yb->buffer = YY_CURRENT_BUFFER;
yb->lineno = yylineno; yb->lineno = yylineno;
yb->filename = strdup(input_filename); yb->filename = mm_strdup(input_filename);
yb->next = yy_buffer; yb->next = yy_buffer;
yy_buffer = yb; yy_buffer = yb;
...@@ -520,19 +517,26 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text); ...@@ -520,19 +517,26 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
} }
if (ptr == NULL) if (ptr == NULL)
{ {
yylval.str = strdup((char*)yytext); yylval.str = mm_strdup((char*)yytext);
return IDENT; return IDENT;
} }
} }
} }
} }
<SQL>{space} { /* ignore */ } <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]; } <SQL>{other} { return yytext[0]; }
<C>{exec}{space}{sql} { BEGIN SQL; return SQL_START; } <C>{exec}{space}{sql} { BEGIN SQL; return SQL_START; }
<C>{ccomment} { /* ignore */ } <C>{ccomment} { /* ignore */ }
<C>{cppline} { <C>{cppline} {
yylval.str = strdup((char*)yytext); yylval.str = mm_strdup((char*)yytext);
return(CPP_LINE); return(CPP_LINE);
} }
<C>{identifier} { <C>{identifier} {
...@@ -556,7 +560,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text); ...@@ -556,7 +560,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
yb->buffer = YY_CURRENT_BUFFER; yb->buffer = YY_CURRENT_BUFFER;
yb->lineno = yylineno; yb->lineno = yylineno;
yb->filename = strdup(input_filename); yb->filename = mm_strdup(input_filename);
yb->next = yy_buffer; yb->next = yy_buffer;
yy_buffer = yb; yy_buffer = yb;
...@@ -567,7 +571,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text); ...@@ -567,7 +571,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
} }
if (ptr == NULL) if (ptr == NULL)
{ {
yylval.str = strdup((char*)yytext); yylval.str = mm_strdup((char*)yytext);
return IDENT; return IDENT;
} }
} }
...@@ -585,7 +589,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text); ...@@ -585,7 +589,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
<C>{exec}{space}{sql}{space}{define} {BEGIN(def_ident);} <C>{exec}{space}{sql}{space}{define} {BEGIN(def_ident);}
<def_ident>{space} {} <def_ident>{space} {}
<def_ident>{identifier} { <def_ident>{identifier} {
old = strdup(yytext); old = mm_strdup(yytext);
BEGIN(def); BEGIN(def);
llen = 0; llen = 0;
*literal = '\0'; *literal = '\0';
...@@ -599,7 +603,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text); ...@@ -599,7 +603,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
if (strcmp(old, ptr->old) == 0) if (strcmp(old, ptr->old) == 0)
{ {
free(ptr->new); free(ptr->new);
ptr->new = strdup(scanstr(literal)); ptr->new = mm_strdup(scanstr(literal));
} }
} }
if (ptr == NULL) if (ptr == NULL)
...@@ -608,7 +612,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text); ...@@ -608,7 +612,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
/* initial definition */ /* initial definition */
this->old = old; this->old = old;
this->new = strdup(scanstr(literal)); this->new = mm_strdup(scanstr(literal));
this->next = defines; this->next = defines;
defines = this; defines = this;
} }
...@@ -666,7 +670,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text); ...@@ -666,7 +670,7 @@ printf("yyt= %s, lt = %s\n", yytext, lower_text);
exit(NO_INCLUDE_FILE); 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 )); yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
yylineno = 0; yylineno = 0;
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
#include "catalog/catname.h" #include "catalog/catname.h"
#include "utils/numeric.h" #include "utils/numeric.h"
#include "type.h"
#include "extern.h" #include "extern.h"
#ifdef MULTIBYTE #ifdef MULTIBYTE
...@@ -18,10 +17,10 @@ ...@@ -18,10 +17,10 @@
/* /*
* Variables containing simple states. * Variables containing simple states.
*/ */
static int struct_level = 0; int struct_level = 0;
static char errortext[128]; static char errortext[128];
static int QueryIsRule = 0, ForUpdateNotAllowed = 0; 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]; static char *actual_storage[STRUCT_DEPTH];
/* temporarily store struct members while creating the data structure */ /* temporarily store struct members while creating the data structure */
...@@ -30,6 +29,8 @@ struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = { NULL }; ...@@ -30,6 +29,8 @@ struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = { NULL };
struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, 0L, {NULL}}; struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, 0L, {NULL}};
struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, 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. * Handle the filename and line numbering.
*/ */
...@@ -505,6 +506,98 @@ output_statement(char * stmt, int mode) ...@@ -505,6 +506,98 @@ output_statement(char * stmt, int mode)
free(stmt); 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 { %union {
...@@ -519,12 +612,15 @@ output_statement(char * stmt, int mode) ...@@ -519,12 +612,15 @@ output_statement(char * stmt, int mode)
} }
/* special embedded SQL token */ /* special embedded SQL token */
%token SQL_BREAK SQL_CALL SQL_CONNECT SQL_CONNECTION SQL_CONTINUE %token SQL_BOOL SQL_BREAK
%token SQL_DISCONNECT SQL_FOUND SQL_GO SQL_GOTO %token SQL_CALL SQL_CONNECT SQL_CONNECTION SQL_CONTINUE
%token SQL_IDENTIFIED SQL_IMMEDIATE SQL_INDICATOR SQL_OPEN %token SQL_DEALLOCATE SQL_DISCONNECT SQL_ENUM
%token SQL_PREPARE SQL_RELEASE %token SQL_FOUND SQL_FREE SQL_GO SQL_GOTO
%token SQL_SECTION SQL_SEMI SQL_SQLERROR SQL_SQLPRINT SQL_START %token SQL_IDENTIFIED SQL_IMMEDIATE SQL_INDICATOR SQL_INT SQL_LONG
%token SQL_STOP SQL_WHENEVER SQL_SQLWARNING %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 */ /* C token */
%token S_ANYTHING S_AUTO S_BOOL S_CHAR S_CONST S_DOUBLE S_ENUM S_EXTERN %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) ...@@ -577,9 +673,9 @@ output_statement(char * stmt, int mode)
DATABASE, DELIMITERS, DO, EACH, ENCODING, EXPLAIN, EXTEND, DATABASE, DELIMITERS, DO, EACH, ENCODING, EXPLAIN, EXTEND,
FORWARD, FUNCTION, HANDLER, FORWARD, FUNCTION, HANDLER,
INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL, 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, NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL,
OIDS, OPERATOR, PASSWORD, PROCEDURAL, OFFSET, OIDS, OPERATOR, PASSWORD, PROCEDURAL,
RECIPE, RENAME, RESET, RETURNS, ROW, RULE, RECIPE, RENAME, RESET, RETURNS, ROW, RULE,
SERIAL, SEQUENCE, SETOF, SHOW, START, STATEMENT, STDIN, STDOUT, TRUSTED, SERIAL, SEQUENCE, SETOF, SHOW, START, STATEMENT, STDIN, STDOUT, TRUSTED,
UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION
...@@ -654,8 +750,9 @@ output_statement(char * stmt, int mode) ...@@ -654,8 +750,9 @@ output_statement(char * stmt, int mode)
%type <str> index_opt_unique IndexStmt set_opt func_return def_rest %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> func_args_list func_args opt_with ProcedureStmt def_arg
%type <str> def_elem def_list definition def_name def_type DefineStmt %type <str> def_elem def_list definition def_name def_type DefineStmt
%type <str> opt_instead event event_object OptStmtMulti OptStmtBlock %type <str> opt_instead event event_object RuleActionList,
%type <str> OptStmtList RuleStmt opt_column opt_name oper_argtypes %type <str> RuleActionBlock RuleActionMulti
%type <str> RuleStmt opt_column opt_name oper_argtypes
%type <str> MathOp RemoveFuncStmt aggr_argtype for_update_clause %type <str> MathOp RemoveFuncStmt aggr_argtype for_update_clause
%type <str> RemoveAggrStmt remove_type RemoveStmt ExtendStmt RecipeStmt %type <str> RemoveAggrStmt remove_type RemoveStmt ExtendStmt RecipeStmt
%type <str> RemoveOperStmt RenameStmt all_Op user_valid_clause %type <str> RemoveOperStmt RenameStmt all_Op user_valid_clause
...@@ -665,7 +762,7 @@ output_statement(char * stmt, int mode) ...@@ -665,7 +762,7 @@ output_statement(char * stmt, int mode)
%type <str> user_createuser_clause user_group_list user_group_clause %type <str> user_createuser_clause user_group_list user_group_clause
%type <str> CreateUserStmt AlterUserStmt CreateSeqStmt OptSeqList %type <str> CreateUserStmt AlterUserStmt CreateSeqStmt OptSeqList
%type <str> OptSeqElem TriggerForSpec TriggerForOpt TriggerForType %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> TriggerActionTime CreateTrigStmt DropPLangStmt PLangTrusted
%type <str> CreatePLangStmt IntegerOnly TriggerFuncArgs TriggerFuncArg %type <str> CreatePLangStmt IntegerOnly TriggerFuncArgs TriggerFuncArg
%type <str> ViewStmt LoadStmt CreatedbStmt opt_database1 opt_database2 location %type <str> ViewStmt LoadStmt CreatedbStmt opt_database1 opt_database2 location
...@@ -673,27 +770,32 @@ output_statement(char * stmt, int mode) ...@@ -673,27 +770,32 @@ output_statement(char * stmt, int mode)
%type <str> GrantStmt privileges operation_commalist operation %type <str> GrantStmt privileges operation_commalist operation
%type <str> cursor_clause opt_cursor opt_readonly opt_of opt_lmode %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> 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> ECPGWhenever ECPGConnect connection_target ECPGOpen opt_using
%type <str> indicator ECPGExecute ecpg_expr dotext %type <str> indicator ECPGExecute ecpg_expr dotext ECPGPrepare
%type <str> storage_clause opt_initializer vartext c_anything blockstart %type <str> storage_clause opt_initializer vartext c_anything blockstart
%type <str> blockend variable_list variable var_anything do_anything %type <str> blockend variable_list variable var_anything do_anything
%type <str> opt_pointer cvariable ECPGDisconnect dis_name %type <str> opt_pointer cvariable ECPGDisconnect dis_name
%type <str> stmt symbol opt_symbol ECPGRelease execstring server_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> user_name opt_user char_variable ora_user ident
%type <str> db_prefix server opt_options opt_connection_name %type <str> db_prefix server opt_options opt_connection_name
%type <str> ECPGSetConnection c_line cpp_line s_enum %type <str> ECPGSetConnection c_line cpp_line s_enum ECPGTypedef
%type <str> enum_type %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 <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; prog: statements;
...@@ -769,13 +871,29 @@ stmt: AddAttrStmt { output_statement($1, 0); } ...@@ -769,13 +871,29 @@ stmt: AddAttrStmt { output_statement($1, 0); }
whenever_action(0); whenever_action(0);
free($1); free($1);
} }
| ECPGCursorStmt {
fputs($1, yyout);
free($1);
}
| ECPGDeallocate {
fputs($1, yyout);
whenever_action(0);
free($1);
}
| ECPGDeclare {
fputs($1, yyout);
free($1);
}
| ECPGDisconnect { | ECPGDisconnect {
fprintf(yyout, "ECPGdisconnect(__LINE__, \"%s\");", $1); fprintf(yyout, "ECPGdisconnect(__LINE__, \"%s\");", $1);
whenever_action(0); whenever_action(0);
free($1); free($1);
} }
| ECPGExecute { | 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); whenever_action(0);
free($1); free($1);
} }
...@@ -797,26 +915,39 @@ stmt: AddAttrStmt { output_statement($1, 0); } ...@@ -797,26 +915,39 @@ stmt: AddAttrStmt { output_statement($1, 0); }
fprintf(yyout, "ECPGdo(__LINE__, \"%s\",", ptr->command); fprintf(yyout, "ECPGdo(__LINE__, \"%s\",", ptr->command);
/* dump variables to C file*/ /* dump variables to C file*/
dump_variables(ptr->argsinsert, 0); dump_variables(ptr->argsinsert, 0);
dump_variables(argsinsert, 0);
fputs("ECPGt_EOIT, ", yyout); fputs("ECPGt_EOIT, ", yyout);
dump_variables(ptr->argsresult, 0); dump_variables(ptr->argsresult, 0);
fputs("ECPGt_EORT);", yyout); fputs("ECPGt_EORT);", yyout);
whenever_action(0); whenever_action(0);
free($1); free($1);
} }
| ECPGPrepare {
fprintf(yyout, "ECPGprepare(__LINE__, %s);", $1);
whenever_action(0);
free($1);
}
| ECPGRelease { /* output already done */ } | ECPGRelease { /* output already done */ }
| ECPGSetConnection { | ECPGSetConnection {
fprintf(yyout, "ECPGsetconn(__LINE__, %s);", $1); fprintf(yyout, "ECPGsetconn(__LINE__, %s);", $1);
whenever_action(0); whenever_action(0);
free($1); free($1);
} }
| ECPGTypedef {
fputs($1, yyout);
free($1);
}
| ECPGVar {
fputs($1, yyout);
free($1);
}
| ECPGWhenever { | ECPGWhenever {
fputs($1, yyout); fputs($1, yyout);
output_line_number(); output_line_number();
free($1); 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 * 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 ...@@ -1098,7 +1229,7 @@ copy_delimiter: USING DELIMITERS Sconst { $$ = cat2_str(make1_str("using delim
CreateStmt: CREATE OptTemp TABLE relation_name '(' OptTableElementList ')' CreateStmt: CREATE OptTemp TABLE relation_name '(' OptTableElementList ')'
OptInherit 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"); } ...@@ -2127,40 +2258,37 @@ opt_column: COLUMN { $$ = make1_str("colmunn"); }
RuleStmt: CREATE RULE name AS RuleStmt: CREATE RULE name AS
{ QueryIsRule=1; } { QueryIsRule=1; }
ON event TO event_object where_clause 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); $$ = 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"); } RuleActionList: NOTHING { $$ = make1_str("nothing"); }
| OptimizableStmt { $$ = $1; } | SelectStmt { $$ = $1; }
| '[' OptStmtBlock ']' { $$ = cat3_str(make1_str("["), $2, make1_str("]")); } | RuleActionStmt { $$ = $1; }
/***S*I*D***/ | '[' RuleActionBlock ']' { $$ = cat3_str(make1_str("["), $2, make1_str("]")); }
/* We comment this out because it produces a shift / reduce conflict | '(' RuleActionBlock ')' { $$ = cat3_str(make1_str("("), $2, make1_str(")")); }
* with the select_w_o_sort rule */ ;
/* | '(' OptStmtBlock ')' { $$ = cat3_str(make1_str("("), $2, make1_str(")")); }*/
;
OptStmtBlock: OptStmtMulti RuleActionBlock: RuleActionMulti { $$ = $1; }
{ $$ = $1; } | RuleActionStmt { $$ = $1; }
| OptimizableStmt
{ $$ = $1; }
; ;
OptStmtMulti: OptStmtMulti OptimizableStmt ';' RuleActionMulti: RuleActionMulti RuleActionStmt
{ $$ = cat2_str($1, $2); }
| RuleActionMulti RuleActionStmt ';'
{ $$ = cat3_str($1, $2, make1_str(";")); } { $$ = cat3_str($1, $2, make1_str(";")); }
/***S*I***/ | RuleActionStmt ';'
/* 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 ';'
{ $$ = cat2_str($1, make1_str(";")); } { $$ = cat2_str($1, make1_str(";")); }
; ;
RuleActionStmt: InsertStmt
| UpdateStmt
| DeleteStmt
| NotifyStmt
;
event_object: relation_name '.' attr_name event_object: relation_name '.' attr_name
{ {
$$ = make3_str($1, make1_str("."), $3); $$ = make3_str($1, make1_str("."), $3);
...@@ -2588,7 +2716,7 @@ CursorStmt: DECLARE name opt_cursor CURSOR FOR SelectStmt cursor_clause ...@@ -2588,7 +2716,7 @@ CursorStmt: DECLARE name opt_cursor CURSOR FOR SelectStmt cursor_clause
{ {
if (strcmp($2, ptr->name) == 0) if (strcmp($2, ptr->name) == 0)
{ {
/* re-definition is a bug*/ /* re-definition is a bug */
sprintf(errortext, "cursor %s already defined", $2); sprintf(errortext, "cursor %s already defined", $2);
yyerror(errortext); yyerror(errortext);
} }
...@@ -2642,13 +2770,13 @@ opt_of: OF columnList { $$ = make2_str(make1_str("of"), $2); } ...@@ -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 /* 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. * 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) if (strlen($3) > 0 && ForUpdateNotAllowed != 0)
yyerror("SELECT FOR UPDATE is not allowed in this context"); yyerror("SELECT FOR UPDATE is not allowed in this context");
ForUpdateNotAllowed = 0; ForUpdateNotAllowed = 0;
$$ = cat3_str($1, $2, $3); $$ = cat4_str($1, $2, $3, $4);
} }
/***S*I***/ /***S*I***/
...@@ -2736,6 +2864,29 @@ OptUseOp: USING Op { $$ = cat2_str(make1_str("using"), $2); } ...@@ -2736,6 +2864,29 @@ OptUseOp: USING Op { $$ = cat2_str(make1_str("using"), $2); }
| /*EMPTY*/ { $$ = make1_str(""); } | /*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 * jimmy bell-style recursive queries aren't supported in the
* current system. * current system.
...@@ -2952,6 +3103,36 @@ Generic: generic ...@@ -2952,6 +3103,36 @@ Generic: generic
generic: ident { $$ = $1; } generic: ident { $$ = $1; }
| TYPE_P { $$ = make1_str("type"); } | 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 /* SQL92 numeric data types
...@@ -3638,7 +3819,7 @@ b_expr: attr opt_indirection ...@@ -3638,7 +3819,7 @@ b_expr: attr opt_indirection
$$ = make3_str(make1_str("trim("), $3, make1_str(")")); $$ = make3_str(make1_str("trim("), $3, make1_str(")"));
} }
| civariableonly | civariableonly
{ $$ = make1_str(";;"); } { $$ = $1; }
; ;
opt_indirection: '[' ecpg_expr ']' opt_indirection opt_indirection: '[' ecpg_expr ']' opt_indirection
...@@ -4125,6 +4306,36 @@ ColId: ident { $$ = $1; } ...@@ -4125,6 +4306,36 @@ ColId: ident { $$ = $1; }
| VALID { $$ = make1_str("valid"); } | VALID { $$ = make1_str("valid"); }
| VERSION { $$ = make1_str("version"); } | VERSION { $$ = make1_str("version"); }
| ZONE { $$ = make1_str("zone"); } | 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 /* Column label
* Allowed labels in "AS" clauses. * Allowed labels in "AS" clauses.
...@@ -4197,223 +4408,6 @@ SpecialRuleRelation: CURRENT ...@@ -4197,223 +4408,6 @@ SpecialRuleRelation: CURRENT
* and now special embedded SQL stuff * 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 */
| 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 * the exec sql connect statement: connect to the given database
*/ */
...@@ -4585,49 +4579,368 @@ opt_options: Op ColId ...@@ -4585,49 +4579,368 @@ opt_options: Op ColId
| /* empty */ { $$ = make1_str(""); } | /* empty */ { $$ = make1_str(""); }
/* /*
* the exec sql disconnect statement: disconnect from the given database * Declare a prepared cursor. The syntax is different from the standard
* declare statement, so we create a new rule.
*/ */
ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; } ECPGCursorStmt: DECLARE name opt_cursor CURSOR FOR ident cursor_clause
{
struct cursor *ptr, *this;
struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
dis_name: connection_object { $$ = $1; } for (ptr = cur; ptr != NULL; ptr = ptr->next)
| CURRENT { $$ = make1_str("CURRENT"); } {
| ALL { $$ = make1_str("ALL"); } if (strcmp($2, ptr->name) == 0)
| /* empty */ { $$ = make1_str("CURRENT"); } {
/* re-definition is a bug */
sprintf(errortext, "cursor %s already defined", $2);
yyerror(errortext);
}
}
connection_object: connection_target { $$ = $1; } this = (struct cursor *) mm_alloc(sizeof(struct cursor));
| DEFAULT { $$ = make1_str("DEFAULT"); }
/* /* initial definition */
* execute a given string as sql command this->next = cur;
*/ this->name = $2;
ECPGExecute : EXECUTE SQL_IMMEDIATE execstring { $$ = $3; }; this->command = cat5_str(make1_str("declare"), mm_strdup($2), $3, make1_str("cursor for ;;"), $7);
this->argsresult = NULL;
execstring: cvariable | thisquery->type = &ecpg_query;
CSTRING { $$ = make3_str(make1_str("\""), $1, make1_str("\"")); }; 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;
* open is an open cursor, at the moment this has to be removed add_variable(&(this->argsinsert), thisquery, &no_indicator);
*/
ECPGOpen: SQL_OPEN name open_opts {
$$ = $2;
};
open_opts: /* empty */ { $$ = make1_str(""); } cur = this;
| USING cvariable {
yyerror ("open cursor with variables not implemented yet"); $$ = cat3_str(make1_str("/*"), mm_strdup(this->command), make1_str("*/"));
} }
;
/* /*
* for compatibility with ORACLE we will also allow the keyword RELEASE * the exec sql deallocate prepare command to deallocate a previously
* after a transaction statement to disconnect from the database. * prepared statement
*/ */
ECPGDeallocate: SQL_DEALLOCATE SQL_PREPARE ident { $$ = make3_str(make1_str("ECPGdeallocate(__LINE__, \""), $3, make1_str("\");")); }
ECPGRelease: TransactionStmt SQL_RELEASE /*
* variable declaration inside the exec sql declare block
*/
ECPGDeclaration: sql_startdeclare
{ {
if (strncmp($1, "begin", 5) == 0) fputs("/* exec sql begin declare section */", yyout);
yyerror("RELEASE does not make sense when beginning a transaction"); output_line_number();
}
fprintf(yyout, "ECPGtrans(__LINE__, \"%s\");", $1); 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; }
dis_name: connection_object { $$ = $1; }
| CURRENT { $$ = make1_str("CURRENT"); }
| ALL { $$ = make1_str("ALL"); }
| /* empty */ { $$ = make1_str("CURRENT"); }
connection_object: connection_target { $$ = $1; }
| DEFAULT { $$ = make1_str("DEFAULT"); }
/*
* execute a given string as sql command
*/
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));
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 opt_using {
$$ = $2;
};
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.
*/
ECPGRelease: TransactionStmt SQL_RELEASE
{
if (strncmp($1, "begin", 5) == 0)
yyerror("RELEASE does not make sense when beginning a transaction");
fprintf(yyout, "ECPGtrans(__LINE__, \"%s\");", $1);
whenever_action(0); whenever_action(0);
fprintf(yyout, "ECPGdisconnect(\"\");"); fprintf(yyout, "ECPGdisconnect(\"\");");
whenever_action(0); whenever_action(0);
...@@ -4642,6 +4955,378 @@ ECPGSetConnection: SET SQL_CONNECTION connection_object ...@@ -4642,6 +4955,378 @@ ECPGSetConnection: SET SQL_CONNECTION connection_object
{ {
$$ = $3; $$ = $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 * whenever statement: decide what to do in case of error/no data found
* according to SQL standards we lack: SQLSTATE, CONSTRAINT and SQLEXCEPTION * according to SQL standards we lack: SQLSTATE, CONSTRAINT and SQLEXCEPTION
...@@ -4703,14 +5388,6 @@ action : SQL_CONTINUE { ...@@ -4703,14 +5388,6 @@ action : SQL_CONTINUE {
$<action>$.str = cat2_str(make1_str("call"), mm_strdup($<action>$.command)); $<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 */ /* some other stuff for ecpg */
ecpg_expr: attr opt_indirection ecpg_expr: attr opt_indirection
{ {
...@@ -4987,7 +5664,7 @@ ecpg_expr: attr opt_indirection ...@@ -4987,7 +5664,7 @@ ecpg_expr: attr opt_indirection
| NOT ecpg_expr | NOT ecpg_expr
{ $$ = cat2_str(make1_str("not"), $2); } { $$ = cat2_str(make1_str("not"), $2); }
| civariableonly | civariableonly
{ $$ = make1_str(";;"); } { $$ = $1; }
; ;
into_list : coutputvariable | into_list ',' coutputvariable; into_list : coutputvariable | into_list ',' coutputvariable;
...@@ -5010,6 +5687,7 @@ cinputvariable : cvariable indicator { ...@@ -5010,6 +5687,7 @@ cinputvariable : cvariable indicator {
civariableonly : cvariable { civariableonly : cvariable {
add_variable(&argsinsert, find_variable($1), &no_indicator); add_variable(&argsinsert, find_variable($1), &no_indicator);
$$ = make1_str(";;");
} }
cvariable: CVARIABLE { $$ = $1; } cvariable: CVARIABLE { $$ = $1; }
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include "type.h"
#include "extern.h" #include "extern.h"
/* malloc + error check */ /* malloc + error check */
...@@ -36,8 +35,8 @@ mm_strdup(const char *string) ...@@ -36,8 +35,8 @@ mm_strdup(const char *string)
} }
/* duplicate memberlist */ /* duplicate memberlist */
static struct ECPGstruct_member * struct ECPGstruct_member *
struct_member_dup(struct ECPGstruct_member * rm) ECPGstruct_member_dup(struct ECPGstruct_member * rm)
{ {
struct ECPGstruct_member *new = NULL; struct ECPGstruct_member *new = NULL;
...@@ -71,7 +70,8 @@ void ...@@ -71,7 +70,8 @@ void
ECPGmake_struct_member(char *name, struct ECPGtype * type, struct ECPGstruct_member ** start) ECPGmake_struct_member(char *name, struct ECPGtype * type, struct ECPGstruct_member ** start)
{ {
struct ECPGstruct_member *ptr, 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->name = strdup(name);
ne->typ = type; ne->typ = type;
...@@ -112,7 +112,7 @@ ECPGmake_struct_type(struct ECPGstruct_member * rm) ...@@ -112,7 +112,7 @@ ECPGmake_struct_type(struct ECPGstruct_member * rm)
{ {
struct ECPGtype *ne = ECPGmake_simple_type(ECPGt_struct, 1); 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; return ne;
} }
...@@ -160,6 +160,9 @@ get_type(enum ECPGttype typ) ...@@ -160,6 +160,9 @@ get_type(enum ECPGttype typ)
case ECPGt_NO_INDICATOR: /* no indicator */ case ECPGt_NO_INDICATOR: /* no indicator */
return ("ECPGt_NO_INDICATOR"); return ("ECPGt_NO_INDICATOR");
break; break;
case ECPGt_char_variable: /* string that should not be quoted */
return ("ECPGt_char_variable");
break;
default: default:
abort(); abort();
} }
...@@ -202,23 +205,30 @@ ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *in ...@@ -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, ECPGdump_a_simple(o, name, typ->u.element->typ,
typ->u.element->size, typ->size, NULL, prefix); 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); ECPGdump_a_simple(o, ind_name, ind_typ->typ, ind_typ->size, -1, NULL, ind_prefix);
else 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, ECPGdump_a_simple(o, ind_name, ind_typ->u.element->typ,
ind_typ->u.element->size, ind_typ->size, NULL, prefix); ind_typ->u.element->size, ind_typ->size, NULL, prefix);
}
} }
else if (typ->u.element->typ == ECPGt_array) 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) 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); ECPGdump_a_struct(o, name, ind_name, typ->size, typ->u.element, ind_typ->u.element, NULL, prefix, ind_prefix);
} }
else else
yyerror("Internal error: unknown datatype, pleqase inform pgsql-bugs@postgresql.org"); yyerror("Internal error: unknown datatype, please inform pgsql-bugs@postgresql.org");
break; break;
case ECPGt_struct: case ECPGt_struct:
ECPGdump_a_struct(o, name, ind_name, 1, typ, ind_typ, NULL, prefix, ind_prefix); 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, ...@@ -260,6 +270,7 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
break; break;
case ECPGt_char: case ECPGt_char:
case ECPGt_unsigned_char: case ECPGt_unsigned_char:
case ECPGt_char_variable:
sprintf(offset, "%ld*sizeof(char)", varcharsize); sprintf(offset, "%ld*sizeof(char)", varcharsize);
break; break;
default: default:
......
...@@ -30,6 +30,7 @@ struct ECPGtype *ECPGmake_simple_type(enum ECPGttype, long); ...@@ -30,6 +30,7 @@ struct ECPGtype *ECPGmake_simple_type(enum ECPGttype, long);
struct ECPGtype *ECPGmake_varchar_type(enum ECPGttype, long); struct ECPGtype *ECPGmake_varchar_type(enum ECPGttype, long);
struct ECPGtype *ECPGmake_array_type(struct ECPGtype *, long); struct ECPGtype *ECPGmake_array_type(struct ECPGtype *, long);
struct ECPGtype *ECPGmake_struct_type(struct ECPGstruct_member *); struct ECPGtype *ECPGmake_struct_type(struct ECPGstruct_member *);
struct ECPGstruct_member * ECPGstruct_member_dup(struct ECPGstruct_member *);
/* Frees a type. */ /* Frees a type. */
void ECPGfree_struct_member(struct ECPGstruct_member *); void ECPGfree_struct_member(struct ECPGstruct_member *);
...@@ -84,6 +85,54 @@ struct index ...@@ -84,6 +85,54 @@ struct index
struct this_type struct this_type
{ {
enum ECPGttype type_enum; enum ECPGttype type_enum;
char *type_str; 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;
}; };
...@@ -4,16 +4,25 @@ exec sql whenever sqlerror sqlprint; ...@@ -4,16 +4,25 @@ exec sql whenever sqlerror sqlprint;
exec sql include sqlca; exec sql include sqlca;
exec sql define AMOUNT 5; exec sql define AMOUNT 8;
exec sql type intarray is int[AMOUNT];
exec sql type string is char(6);
typedef int intarray[AMOUNT];
int int
main () main ()
{ {
exec sql begin declare section; exec sql begin declare section;
int amount[AMOUNT]; intarray amount;
char name[AMOUNT][8]; int increment=100;
char name[AMOUNT][6];
char letter[AMOUNT][1];
char command[128];
exec sql end declare section; exec sql end declare section;
char msg[128], command[128]; exec sql var name is string(AMOUNT);
char msg[128];
FILE *dbgs; FILE *dbgs;
int i,j; int i,j;
...@@ -24,30 +33,40 @@ exec sql end declare section; ...@@ -24,30 +33,40 @@ exec sql end declare section;
exec sql connect to mm; exec sql connect to mm;
strcpy(msg, "create"); strcpy(msg, "create");
exec sql create table test(name char(8), amount int); exec sql create table test(name char(6), amount int, letter char(1));
strcpy(msg, "commit");
exec sql commit;
strcpy(msg, "execute insert 1"); strcpy(msg, "execute insert 1");
sprintf(command, "insert into test(name, amount) values ('foobar', 1)"); sprintf(command, "insert into test(name, amount, letter) values ('foobar', 1, 'f')");
exec sql execute immediate :command; exec sql execute immediate :command;
strcpy(msg, "excute insert 2"); strcpy(msg, "execute insert 2");
sprintf(command, "insert into test(name, amount) select name, amount+1 from test"); sprintf(command, "insert into test(name, amount, letter) select name, amount+1, letter from test");
exec sql execute immediate :command; exec sql execute immediate :command;
strcpy(msg, "excute insert 3"); strcpy(msg, "execute insert 3");
sprintf(command, "insert into test(name, amount) select name, amount+10 from test"); sprintf(command, "insert into test(name, amount, letter) select name, amount+10, letter from test");
exec sql execute immediate :command; exec sql execute immediate :command;
printf("Inserted %d tuples via execute immediate\n", sqlca.sqlerrd[2]); printf("Inserted %d tuples via execute immediate\n", sqlca.sqlerrd[2]);
strcpy(msg, "execute insert 4");
sprintf(command, "insert into test(name, amount, letter) select name, amount+;;, letter from test");
exec sql prepare I from :command;
exec sql execute I using :increment;
printf("Inserted %d tuples via prepared execute\n", sqlca.sqlerrd[2]);
strcpy(msg, "commit"); strcpy(msg, "commit");
exec sql commit; exec sql commit;
strcpy(msg, "select"); strcpy(msg, "select");
exec sql select name, amount into :name, :amount from test; exec sql select name, amount, letter into :name, :amount, :letter from test;
for (i=0, j=sqlca.sqlerrd[2]; i<j; i++) for (i=0, j=sqlca.sqlerrd[2]; i<j; i++)
printf("name[%d]=%8.8s, amount[%d]=%d\n", i, name[i], i, amount[i]); printf("name[%d]=%6.6s\tamount[%d]=%d\tletter[%d]=%c\n", i, name[i], i, amount[i],i, letter[i][0]);
strcpy(msg, "drop"); strcpy(msg, "drop");
exec sql drop table test; exec sql drop table test;
......
...@@ -2,26 +2,31 @@ ...@@ -2,26 +2,31 @@
exec sql include header_test; exec sql include header_test;
exec sql type c is char reference;
typedef char* c;
int int
main () main ()
{ {
typedef struct { long born; short age; } birthinfo;
exec sql type birthinfo is struct { long born; short age; };
exec sql begin declare section; exec sql begin declare section;
struct personal_struct { varchar name[8]; struct personal_struct { varchar name[8];
struct birth_struct { long born; birthinfo birth;
short age;
} birth;
} personal; } personal;
struct personal_indicator { short ind_name; struct personal_indicator { int ind_name;
struct birth_indicator { short ind_born; birthinfo ind_birth;
int ind_age;
} ind_birth;
} ind_personal; } ind_personal;
long ind_married; int ind_married;
char married[9]; char married[9];
c testname="Petra";
char *query="select name, born, age, married from meskes where name = :var1";
exec sql end declare section; exec sql end declare section;
exec sql declare cur cursor for exec sql var ind_married is long;
select name, born, age, married from meskes;
exec sql declare cur cursor for
select name, born, age, married from meskes;
char msg[128], command[128]; char msg[128], command[128];
FILE *dbgs; FILE *dbgs;
...@@ -36,11 +41,11 @@ exec sql declare cur cursor for ...@@ -36,11 +41,11 @@ exec sql declare cur cursor for
exec sql create table meskes(name char(8), born integer, age smallint, married char(8)); exec sql create table meskes(name char(8), born integer, age smallint, married char(8));
strcpy(msg, "insert"); strcpy(msg, "insert");
exec sql insert into meskes(name, born, age, married) values ('Petra', 19661202, 32, '19900404'); exec sql insert into meskes(name, married) values ('Petra', '19900404');
exec sql insert into meskes(name, born, age, married) values ('Michael', 19660117, 33, '19900404'); exec sql insert into meskes(name, born, age, married) values ('Michael', 19660117, 33, '19900404');
exec sql insert into meskes(name, born, age) values ('Carsten', 19910103, 7); exec sql insert into meskes(name, born, age) values ('Carsten', 19910103, 8);
exec sql insert into meskes(name, born, age) values ('Marc', 19930907, 4); exec sql insert into meskes(name, born, age) values ('Marc', 19930907, 5);
exec sql insert into meskes(name, born, age) values ('Chris', 19970923, 0); exec sql insert into meskes(name, born, age) values ('Chris', 19970923, 1);
strcpy(msg, "commit"); strcpy(msg, "commit");
exec sql commit; exec sql commit;
...@@ -53,12 +58,44 @@ exec sql declare cur cursor for ...@@ -53,12 +58,44 @@ exec sql declare cur cursor for
while (1) { while (1) {
strcpy(msg, "fetch"); strcpy(msg, "fetch");
exec sql fetch in cur into :personal:ind_personal, :married:ind_married; exec sql fetch in cur into :personal:ind_personal, :married:ind_married;
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); printf("%8.8s", personal.name.arr);
if (!ind_personal.ind_birth.born)
printf(", born %d", personal.birth.born);
if (!ind_personal.ind_birth.age)
printf(", age = %d", personal.birth.age);
if (!ind_married)
printf(", married %s", married);
putchar('\n');
} }
strcpy(msg, "close"); strcpy(msg, "close");
exec sql close cur; exec sql close cur;
/* and now the same query with prepare */
exec sql prepare MM from :query;
exec sql declare prep cursor for MM;
strcpy(msg, "open");
exec sql open prep using :testname;
exec sql whenever not found do break;
while (1) {
strcpy(msg, "fetch");
exec sql fetch in prep into :personal:ind_personal, :married:ind_married;
printf("%8.8s", personal.name.arr);
if (!ind_personal.ind_birth.born)
printf(", born %d", personal.birth.born);
if (!ind_personal.ind_birth.age)
printf(", age = %d", personal.birth.age);
if (!ind_married)
printf(", married %s", married);
putchar('\n');
}
strcpy(msg, "close");
exec sql close prep;
strcpy(msg, "drop"); strcpy(msg, "drop");
exec sql drop table meskes; exec sql drop table meskes;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment