Upgrade ECPG to 2.0

Michael Meskes <meskes@topsystem.de>
This commit is contained in:
Marc G. Fournier 1998-04-21 13:23:24 +00:00
parent 5e6b0a574b
commit 64e35e1468
20 changed files with 4982 additions and 621 deletions

View File

@ -86,3 +86,43 @@ Fri Mar 13 13:35:13 CET 1998
Mon Mar 16 15:09:10 CET 1998
- fixed parser to print correct filename and line number
Wed Mar 18 14:28:49 CET 1998
- started working on indicator variables
Mon Mar 23 13:49:15 CET 1998
- fixed some bugs in indicator variable handling
- completely rewrote parser for fetch and insert statements
- indicator variables are also allowed in insert statements now
Mon Mar 23 16:09:05 CET 1998
- fixed whenever command goto to only allow valid lables
Thu Mar 26 13:33:02 MEZ 1998
- some minor bugfixes
Mon Apr 20 13:06:09 CEST 1998
- database name no longer has to entered as string constant, i.e.
just remove the '...' around the name
Mon Apr 20 14:38:45 CEST 1998
- both test cases compile cleanly
Mon Apr 20 16:13:25 CEST 1998
- Phew! Finally finished parser rewriting.
Mon Apr 20 16:39:23 CEST 1998
- Cursor is opened when the open command is issued, not at declare time.
Tue Apr 21 12:53:49 CEST 1998
- Set indicator to amount of data really written (truncation).

View File

@ -1,15 +1,6 @@
This list is still from Linus. MM
The variables should be static.
Preprocessor cannot do syntax checking on your SQL statements Whatever you
write is copied more or less exactly to the PostgreSQL and you will not be
able to locate your errors until run-time.
No restriction to strings only The PQ interface, and most of all the PQexec
function, that is used by the ecpg relies on that the request is built up as
a string. In some cases, like when the data contains the null character,
this will be a serious problem.
There should be different error numbers for the different errors instead of
just -1 for them all.
@ -21,12 +12,6 @@ ecpg it is done for compatibility reasons only. For them to improve speed
would require a lot more insight in the postgres internal mechanisms than I
possess.
Oracle has indicator variables that tell if a value is null or if it is
empty. This largely simplifies array operations and provides for a way to
hack around some design flaws in the handling of VARCHAR2 (like that an
empty string isn't distinguishable from a null value). I am not sure if this
is an Oracle extension or part of the ANSI standard.
As well as complex types like records and arrays, typedefs would be a good
thing to take care of.
@ -43,8 +28,6 @@ Now comes my list (MM):
The return code is alway -1 in case of an error. You cannot see which error
occured by examining the return code.
The cursor is opened when the declare statement is issued.
ecpg does not understand enum datatypes.
There is no exec sql prepare statement.
@ -59,7 +42,16 @@ There is no way yet to fill a complete array with one call except arrays of
ecpg cannot use pointer variables except [unsigned] char *
List all commands as sqlcommand, not just S_SYMBOL or even better rewrite
pareser to be equivalent to backend´s parser.
give back the number of tuples affected via sqlca
Set standard include paths.
exec sql disconnect {current|default|all|connectionname|connection_hostvar};
oder <disconnect statement> ::=
DISCONNECT <disconnect object>
<disconnect object> ::=
<connection object>
| ALL
| CURRENT
commit release|commit work release auch disconnect
It is not neccessary to check for sql not found after all commands.

View File

@ -6,13 +6,13 @@ all clean::
@echo Nothing to be done.
install::
$(INSTALL) $(INSTLOPTS) ecpglib.h $(HEADERDIR)
$(INSTALL) $(INSTLOPTS) ecpgtype.h $(HEADERDIR)
$(INSTALL) $(INSTLOPTS) sqlca.h $(HEADERDIR)
$(INSTALL) $(INSTLOPTS) ecpglib.h $(DESTDIR)$(HEADERDIR)
$(INSTALL) $(INSTLOPTS) ecpgtype.h $(DESTDIR)$(HEADERDIR)
$(INSTALL) $(INSTLOPTS) sqlca.h $(DESTDIR)$(HEADERDIR)
uninstall::
rm -f $(HEADERDIR)/ecpglib.h
rm -f $(HEADERDIR)/ecpgtype.h
rm -f $(HEADERDIR)/sqlca.h
rm -f $(DESTDIR)$(HEADERDIR)/ecpglib.h
rm -f $(DESTDIR)$(HEADERDIR)/ecpgtype.h
rm -f $(DESTDIR)$(HEADERDIR)/sqlca.h
dep depend:

View File

@ -13,11 +13,6 @@ bool ECPGstatus(void);
void ECPGlog(const char *format,...);
/* These functions are only kept for compatibility reasons. */
/* Use ECPGtrans instead. */
bool ECPGcommit(int);
bool ECPGrollback(int);
#ifdef LIBPQ_FE_H
bool ECPGsetdb(PGconn *);

View File

@ -43,7 +43,8 @@ enum ECPGttype
ECPGt_array,
ECPGt_record,
ECPGt_EOIT, /* End of insert types. */
ECPGt_EORT /* End of result types. */
ECPGt_EORT, /* End of result types. */
ECPGt_NO_INDICATOR /* no indicator */
};
#define IS_SIMPLE_TYPE(type) ((type) >= ECPGt_char && (type) <= ECPGt_varchar2)

View File

@ -3,8 +3,8 @@ include $(SRCDIR)/Makefile.global
PQ_INCLUDE=-I$(SRCDIR)/interfaces/libpq
SO_MAJOR_VERSION=1
SO_MINOR_VERSION=1
SO_MAJOR_VERSION=2
SO_MINOR_VERSION=0
PORTNAME=@PORTNAME@
@ -16,6 +16,7 @@ endif
shlib :=
install-shlib-dep :=
ifeq ($(PORTNAME), linux)
LINUX_ELF=@LINUX_ELF@
ifdef LINUX_ELF
install-shlib-dep := install-shlib
shlib := libecpg.so.$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION)

View File

@ -96,10 +96,11 @@ ECPGdo(int lineno, char *query,...)
*/
while (type != ECPGt_EOIT)
{
void *value = NULL;
long varcharsize;
long size;
long arrsize;
void *value = NULL, *ind_value;
long varcharsize, ind_varcharsize;
long size, ind_size;
long arrsize, ind_arrsize;
enum ECPGttype ind_type;
char *newcopy;
char *mallocedval = NULL;
@ -117,9 +118,40 @@ ECPGdo(int lineno, char *query,...)
varcharsize = va_arg(ap, long);
size = va_arg(ap, long);
arrsize = va_arg(ap, long);
ind_type = va_arg(ap, enum ECPGttype);
ind_value = va_arg(ap, void *);
ind_varcharsize = va_arg(ap, long);
ind_size = va_arg(ap, long);
ind_arrsize = va_arg(ap, long);
switch (type)
buff[0] = '\0';
/* check for null value and set input buffer accordingly */
switch (ind_type)
{
case ECPGt_short:
case ECPGt_unsigned_short:
if (*(short *) ind_value < 0)
strcpy(buff, "null");
break;
case ECPGt_int:
case ECPGt_unsigned_int:
if (*(int *) ind_value < 0)
strcpy(buff, "null");
break;
case ECPGt_long:
case ECPGt_unsigned_long:
if (*(long *) ind_value < 0L)
strcpy(buff, "null");
break;
default:
break;
}
if (*buff == '\0')
{
switch (type)
{
case ECPGt_short:
case ECPGt_int:
sprintf(buff, "%d", *(int *) value);
@ -205,7 +237,10 @@ ECPGdo(int lineno, char *query,...)
ECPGtype_name(type), lineno);
return false;
break;
}
}
else
tobeinserted = buff;
/*
* Now tobeinserted points to an area that is to be inserted at
@ -266,7 +301,7 @@ ECPGdo(int lineno, char *query,...)
if (committed)
{
if ((results = PQexec(simple_connection, "begin")) == NULL)
if ((results = PQexec(simple_connection, "begin transaction")) == NULL)
{
register_error(-1, "Error starting transaction line %d.", lineno);
return false;
@ -324,10 +359,11 @@ ECPGdo(int lineno, char *query,...)
for (x = 0; x < m && status; x++)
{
void *value = NULL;
long varcharsize;
long size;
long arrsize;
void *value = NULL, *ind_value;
long varcharsize, ind_varcharsize;
long size, ind_size;
long arrsize, ind_arrsize;
enum ECPGttype ind_type;
char *pval = PQgetvalue(results, 0, x);
@ -339,14 +375,38 @@ ECPGdo(int lineno, char *query,...)
ECPGlog("ECPGdo line %d: RESULT: %s\n", lineno, pval ? pval : "");
/* No the pval is a pointer to the value. */
/* Now the pval is a pointer to the value. */
/* We will have to decode the value */
type = va_arg(ap, enum ECPGttype);
value = va_arg(ap, void *);
varcharsize = va_arg(ap, long);
size = va_arg(ap, long);
arrsize = va_arg(ap, long);
ind_type = va_arg(ap, enum ECPGttype);
ind_value = va_arg(ap, void *);
ind_varcharsize = va_arg(ap, long);
ind_size = va_arg(ap, long);
ind_arrsize = va_arg(ap, long);
/* check for null value and set indicator accordingly */
switch (ind_type)
{
case ECPGt_short:
case ECPGt_unsigned_short:
*(short *) ind_value = -PQgetisnull(results, 0, x);
break;
case ECPGt_int:
case ECPGt_unsigned_int:
*(int *) ind_value = -PQgetisnull(results, 0, x);
break;
case ECPGt_long:
case ECPGt_unsigned_long:
*(long *) ind_value = -PQgetisnull(results, 0, x);
break;
default:
break;
}
switch (type)
{
long res;
@ -486,7 +546,30 @@ ECPGdo(int lineno, char *query,...)
((char *) value)[strlen(pval)] = '\0';
}
else
{
strncpy((char *) value, pval, varcharsize);
if (varcharsize < strlen(pval))
{
/* truncation */
switch (ind_type)
{
case ECPGt_short:
case ECPGt_unsigned_short:
*(short *) ind_value = varcharsize;
break;
case ECPGt_int:
case ECPGt_unsigned_int:
*(int *) ind_value = varcharsize;
break;
case ECPGt_long:
case ECPGt_unsigned_long:
*(long *) ind_value = varcharsize;
break;
default:
break;
}
}
}
}
break;
@ -498,7 +581,28 @@ ECPGdo(int lineno, char *query,...)
strncpy(var->arr, pval, varcharsize);
var->len = strlen(pval);
if (var->len > varcharsize)
{
/* truncation */
switch (ind_type)
{
case ECPGt_short:
case ECPGt_unsigned_short:
*(short *) ind_value = varcharsize;
break;
case ECPGt_int:
case ECPGt_unsigned_int:
*(int *) ind_value = varcharsize;
break;
case ECPGt_long:
case ECPGt_unsigned_long:
*(long *) ind_value = varcharsize;
break;
default:
break;
}
var->len = varcharsize;
}
}
break;
@ -587,19 +691,6 @@ ECPGtrans(int lineno, const char * transaction)
return (TRUE);
}
/* include these for compatibility */
bool
ECPGcommit(int lineno)
{
return(ECPGtrans(lineno, "end"));
}
bool
ECPGrollback(int lineno)
{
return(ECPGtrans(lineno, "abort"));
}
bool
ECPGsetdb(PGconn *newcon)
{

View File

@ -1,13 +1,16 @@
SRCDIR= ../../..
include $(SRCDIR)/Makefile.global
MAJOR_VERSION=1
MINOR_VERSION=1
MAJOR_VERSION=2
MINOR_VERSION=0
PATCHLEVEL=0
CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \
-DMINOR_VERSION=$(MINOR_VERSION) -DPATCHLEVEL=$(PATCHLEVEL) \
-DINCLUDE_PATH=\"$(HEADERDIR)\"
-DINCLUDE_PATH=\"$(DESTDIR)$(HEADERDIR)\"
OBJ=y.tab.o pgc.o type.o ecpg.o ecpg_keywords.o ../../../backend/parser/scansup.o \
keywords.o c_keywords.o ../lib/typename.o
all:: ecpg
@ -15,21 +18,22 @@ clean:
rm -f *.o core a.out ecpg y.tab.h y.tab.c pgc.c *~
install: all
$(INSTALL) $(INSTL_EXE_OPTS) ecpg $(BINDIR)
$(INSTALL) $(INSTL_EXE_OPTS) ecpg $(DESTDIR)$(BINDIR)
uninstall:
rm -f $(BINDIR)/ecpg
dep depend:
$(CC) -MM $(CFLAGS) *.c > depend
rm -f $(DESTDIR)$(BINDIR)/ecpg
# Rule that really do something.
ecpg: y.tab.o pgc.o type.o ecpg.o ../lib/typename.o
$(CC) -o ecpg y.tab.o pgc.o type.o ecpg.o ../lib/typename.o $(LEXLIB) $(LDFLAGS)
ecpg: $(OBJ)
$(CC) -o ecpg $(OBJ) $(LEXLIB)
y.tab.h y.tab.c: preproc.y
$(YACC) $(YFLAGS) $<
y.tab.o : y.tab.h ../include/ecpgtype.h
y.tab.o : y.tab.h ../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c
type.o : ../include/ecpgtype.h
pgc.o : ../include/ecpgtype.h
pgc.o : ../include/ecpgtype.h keywords.c c_keywords.c ecpg_keywords.c y.tab.h
keywords.o: ../include/ecpgtype.h y.tab.h
c_keywords.o: ../include/ecpgtype.h y.tab.h
ecpg_keywords.o: ../include/ecpgtype.h y.tab.h

View File

@ -0,0 +1,63 @@
/*-------------------------------------------------------------------------
*
* keywords.c--
* lexical token lookup for reserved words in postgres embedded SQL
*
*-------------------------------------------------------------------------
*/
#include <ctype.h>
#include <string.h>
#include "postgres.h"
#include "type.h"
#include "y.tab.h"
#include "extern.h"
/*
* List of (keyword-name, keyword-token-value) pairs.
*
* !!WARNING!!: This list must be sorted, because binary
* search is used to locate entries.
*/
static ScanKeyword ScanKeywords[] = {
/* name value */
{"auto", S_AUTO},
{"bool", S_BOOL},
{"char", S_CHAR},
{"const", S_CONST},
{"double", S_DOUBLE},
{"extern", S_EXTERN},
{"float", S_FLOAT},
{"int", S_INT},
{"long", S_LONG},
{"register", S_REGISTER},
{"short", S_SHORT},
{"signed", S_SIGNED},
{"static", S_STATIC},
{"struct", S_STRUCT},
{"unsigned", S_UNSIGNED},
{"varchar", S_VARCHAR},
};
ScanKeyword *
ScanCKeywordLookup(char *text)
{
ScanKeyword *low = &ScanKeywords[0];
ScanKeyword *high = endof(ScanKeywords) - 1;
ScanKeyword *middle;
int difference;
while (low <= high)
{
middle = low + (high - low) / 2;
difference = strcmp(middle->name, text);
if (difference == 0)
return (middle);
else if (difference < 0)
low = middle + 1;
else
high = middle - 1;
}
return (NULL);
}

View File

@ -91,7 +91,7 @@ main(int argc, char *const argv[])
/* after the options there must not be anything but filenames */
for (fnr = optind; fnr < argc; fnr++)
{
char *ptr2ext;
char *output_filename = NULL, *ptr2ext;
input_filename = mm_alloc(strlen(argv[fnr]) + 5);
@ -113,7 +113,7 @@ main(int argc, char *const argv[])
if (out_option == 0)/* calculate the output name */
{
char *output_filename = strdup(input_filename);
output_filename = strdup(input_filename);
ptr2ext = strrchr(output_filename, '.');
/* make extension = .c */
@ -128,7 +128,6 @@ main(int argc, char *const argv[])
free(input_filename);
continue;
}
free(output_filename);
}
yyin = fopen(input_filename, "r");
@ -136,9 +135,25 @@ main(int argc, char *const argv[])
perror(argv[fnr]);
else
{
struct cursor *ptr;
/* initialize lex */
lex_init();
/* initialize cursor list */
for (ptr = cur; ptr != NULL;)
{
struct cursor *c;
free(ptr->name);
free(ptr->command);
c = ptr;
ptr = ptr->next;
free(c);
}
cur = NULL;
/* we need two includes */
fprintf(yyout, "/* Processed by ecpg (%d.%d.%d) */\n/*These two include files are added by the preprocessor */\n#include <ecpgtype.h>\n#include <ecpglib.h>\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL);
@ -150,6 +165,10 @@ main(int argc, char *const argv[])
if (out_option == 0)
fclose(yyout);
}
if (output_filename)
free(output_filename);
free(input_filename);
}
}

View File

@ -0,0 +1,60 @@
/*-------------------------------------------------------------------------
*
* keywords.c--
* lexical token lookup for reserved words in postgres embedded SQL
*
*-------------------------------------------------------------------------
*/
#include <ctype.h>
#include <string.h>
#include "postgres.h"
#include "type.h"
#include "y.tab.h"
#include "extern.h"
/*
* List of (keyword-name, keyword-token-value) pairs.
*
* !!WARNING!!: This list must be sorted, because binary
* search is used to locate entries.
*/
static ScanKeyword ScanKeywords[] = {
/* name value */
{"connect", SQL_CONNECT},
{"continue", SQL_CONTINUE},
{"found", SQL_FOUND},
{"go", SQL_GO},
{"goto", SQL_GOTO},
{"immediate", SQL_IMMEDIATE},
{"indicator", SQL_INDICATOR},
{"open", SQL_OPEN},
{"section", SQL_SECTION},
{"sqlerror", SQL_SQLERROR},
{"sqlprint", SQL_SQLPRINT},
{"stop", SQL_STOP},
{"whenever", SQL_WHENEVER},
};
ScanKeyword *
ScanECPGKeywordLookup(char *text)
{
ScanKeyword *low = &ScanKeywords[0];
ScanKeyword *high = endof(ScanKeywords) - 1;
ScanKeyword *middle;
int difference;
while (low <= high)
{
middle = low + (high - low) / 2;
difference = strcmp(middle->name, text);
if (difference == 0)
return (middle);
else if (difference < 0)
low = middle + 1;
else
high = middle - 1;
}
return (NULL);
}

View File

@ -1,3 +1,5 @@
#include "parser/keywords.h"
/* variables */
extern int debugging,
@ -14,9 +16,19 @@ struct _include_path { char * path;
extern struct _include_path *include_paths;
struct cursor { char *name;
char *command;
struct cursor *next;
};
extern struct cursor *cur;
/* functions */
extern void lex_init(void);
extern char *input_filename;
extern int yyparse(void);
extern void *mm_alloc(size_t), *mm_realloc(void *, size_t);
ScanKeyword * ScanECPGKeywordLookup(char *);
ScanKeyword * ScanCKeywordLookup(char *);
extern void yyerror(char *);

View File

@ -0,0 +1,242 @@
/*-------------------------------------------------------------------------
*
* keywords.c--
* lexical token lookup for reserved words in postgres SQL
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.1 1998/04/21 13:23:06 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <ctype.h>
#include <string.h>
#include "postgres.h"
#include "nodes/parsenodes.h"
#include "nodes/pg_list.h"
#include "type.h"
#include "y.tab.h"
#include "parser/keywords.h"
#include "utils/elog.h"
/*
* List of (keyword-name, keyword-token-value) pairs.
*
* !!WARNING!!: This list must be sorted, because binary
* search is used to locate entries.
*/
static ScanKeyword ScanKeywords[] = {
/* name value */
{"abort", ABORT_TRANS},
{"action", ACTION},
{"add", ADD},
{"after", AFTER},
{"aggregate", AGGREGATE},
{"all", ALL},
{"alter", ALTER},
{"analyze", ANALYZE},
{"and", AND},
{"any", ANY},
{"archive", ARCHIVE},
{"as", AS},
{"asc", ASC},
{"backward", BACKWARD},
{"before", BEFORE},
{"begin", BEGIN_TRANS},
{"between", BETWEEN},
{"binary", BINARY},
{"both", BOTH},
{"by", BY},
{"cache", CACHE},
{"cascade", CASCADE},
{"cast", CAST},
{"char", CHAR},
{"character", CHARACTER},
{"check", CHECK},
{"close", CLOSE},
{"cluster", CLUSTER},
{"collate", COLLATE},
{"column", COLUMN},
{"commit", COMMIT},
{"constraint", CONSTRAINT},
{"copy", COPY},
{"create", CREATE},
{"createdb", CREATEDB},
{"createuser", CREATEUSER},
{"cross", CROSS},
{"current", CURRENT},
{"current_date", CURRENT_DATE},
{"current_time", CURRENT_TIME},
{"current_timestamp", CURRENT_TIMESTAMP},
{"current_user", CURRENT_USER},
{"cursor", CURSOR},
{"cycle", CYCLE},
{"database", DATABASE},
{"day", DAY_P},
{"decimal", DECIMAL},
{"declare", DECLARE},
{"default", DEFAULT},
{"delete", DELETE},
{"delimiters", DELIMITERS},
{"desc", DESC},
{"distinct", DISTINCT},
{"do", DO},
{"double", DOUBLE},
{"drop", DROP},
{"each", EACH},
{"end", END_TRANS},
{"execute", EXECUTE},
{"exists", EXISTS},
{"explain", EXPLAIN},
{"extend", EXTEND},
{"extract", EXTRACT},
{"false", FALSE_P},
{"fetch", FETCH},
{"float", FLOAT},
{"for", FOR},
{"foreign", FOREIGN},
{"forward", FORWARD},
{"from", FROM},
{"full", FULL},
{"function", FUNCTION},
{"grant", GRANT},
{"group", GROUP},
{"handler", HANDLER},
{"having", HAVING},
{"hour", HOUR_P},
{"in", IN},
{"increment", INCREMENT},
{"index", INDEX},
{"inherits", INHERITS},
{"inner", INNER_P},
{"insert", INSERT},
{"instead", INSTEAD},
{"interval", INTERVAL},
{"into", INTO},
{"is", IS},
{"isnull", ISNULL},
{"join", JOIN},
{"key", KEY},
{"lancompiler", LANCOMPILER},
{"language", LANGUAGE},
{"leading", LEADING},
{"left", LEFT},
{"like", LIKE},
{"listen", LISTEN},
{"load", LOAD},
{"local", LOCAL},
{"location", LOCATION},
{"lock", LOCK_P},
{"match", MATCH},
{"maxvalue", MAXVALUE},
{"minute", MINUTE_P},
{"minvalue", MINVALUE},
{"month", MONTH_P},
{"move", MOVE},
{"national", NATIONAL},
{"natural", NATURAL},
{"nchar", NCHAR},
{"new", NEW},
{"no", NO},
{"nocreatedb", NOCREATEDB},
{"nocreateuser", NOCREATEUSER},
{"none", NONE},
{"not", NOT},
{"nothing", NOTHING},
{"notify", NOTIFY},
{"notnull", NOTNULL},
{"null", NULL_P},
{"numeric", NUMERIC},
{"oids", OIDS},
{"on", ON},
{"operator", OPERATOR},
{"option", OPTION},
{"or", OR},
{"order", ORDER},
{"outer", OUTER_P},
{"partial", PARTIAL},
{"password", PASSWORD},
{"position", POSITION},
{"precision", PRECISION},
{"primary", PRIMARY},
{"privileges", PRIVILEGES},
{"procedural", PROCEDURAL},
{"procedure", PROCEDURE},
{"public", PUBLIC},
{"recipe", RECIPE},
{"references", REFERENCES},
{"rename", RENAME},
{"reset", RESET},
{"returns", RETURNS},
{"revoke", REVOKE},
{"right", RIGHT},
{"rollback", ROLLBACK},
{"row", ROW},
{"rule", RULE},
{"second", SECOND_P},
{"select", SELECT},
{"sequence", SEQUENCE},
{"set", SET},
{"setof", SETOF},
{"show", SHOW},
{"start", START},
{"statement", STATEMENT},
{"stdin", STDIN},
{"stdout", STDOUT},
{"substring", SUBSTRING},
{"table", TABLE},
{"time", TIME},
{"to", TO},
{"trailing", TRAILING},
{"transaction", TRANSACTION},
{"trigger", TRIGGER},
{"trim", TRIM},
{"true", TRUE_P},
{"trusted", TRUSTED},
{"type", TYPE_P},
{"union", UNION},
{"unique", UNIQUE},
{"until", UNTIL},
{"update", UPDATE},
{"user", USER},
{"using", USING},
{"vacuum", VACUUM},
{"valid", VALID},
{"values", VALUES},
{"varchar", VARCHAR},
{"varying", VARYING},
{"verbose", VERBOSE},
{"version", VERSION},
{"view", VIEW},
{"where", WHERE},
{"with", WITH},
{"work", WORK},
{"year", YEAR_P},
{"zone", ZONE},
};
ScanKeyword *
ScanKeywordLookup(char *text)
{
ScanKeyword *low = &ScanKeywords[0];
ScanKeyword *high = endof(ScanKeywords) - 1;
ScanKeyword *middle;
int difference;
while (low <= high)
{
middle = low + (high - low) / 2;
difference = strcmp(middle->name, text);
if (difference == 0)
return (middle);
else if (difference < 0)
low = middle + 1;
else
high = middle - 1;
}
return (NULL);
}

View File

@ -1,6 +1,8 @@
/* Copyright comment! */
/* This is a modified version of src/backend/parser/scan.l */
%{
#include "config.h"
#include <ctype.h>
#include <sys/types.h>
#include <limits.h>
#if defined(HAVE_STRING_H)
@ -8,101 +10,428 @@
#else
#include <strings.h>
#endif
#include <errno.h>
#include "postgres.h"
#include "miscadmin.h"
#include "nodes/pg_list.h"
#include "nodes/parsenodes.h"
#include "parser/gramparse.h"
#include "parser/scansup.h"
#include "type.h"
#include "y.tab.h"
#include "utils/builtins.h"
#include "extern.h"
/* some versions of lex define this as a macro */
#if defined(yywrap)
#undef yywrap
#endif /* yywrap */
int debugging = 0;
extern YYSTYPE yylval;
int llen;
char literal[MAX_PARSE_BUFFER];
struct _yy_buffer { YY_BUFFER_STATE buffer;
long lineno;
char * filename;
struct _yy_buffer * next;
} *yy_buffer = NULL;
#define dbg(arg) if (debugging) fprintf(stderr, "DEBUG, %d: %s\n", yylineno, #arg);
%}
%option yylineno
%s C SQL incl
ccomment \/\*([^*]|\*[^/]|\*\*[^/])*\*\/
ws ([ \t\n][ \t\n]*|{ccomment})*
letter [A-Za-z_]
digit [0-9]
length {digit}+
symbol {letter}({letter}|{digit})*
label ({letter}|{digit})*
string '[^']*'
/* OK, here is a short description of lex/flex rules behavior.
* The longest pattern which matches an input string is always chosen.
* For equal-length patterns, the first occurring in the rules list is chosen.
* INITIAL is the starting condition, to which all non-conditional rules apply.
* When in an exclusive condition, only those rules defined for that condition apply.
*
* Exclusive states change parsing rules while the state is active.
* There are exclusive states for quoted strings, extended comments,
* and to eliminate parsing troubles for numeric strings.
* Exclusive states:
* <xb> binary numeric string - thomas 1997-11-16
* <xc> extended C-style comments - tgl 1997-07-12
* <xd> delimited identifiers (double-quoted identifiers) - tgl 1997-10-27
* <xh> hexadecimal numeric string - thomas 1997-11-16
* <xm> numeric strings with embedded minus sign - tgl 1997-09-05
* <xq> quoted strings - tgl 1997-07-30
*
* The "extended comment" syntax closely resembles allowable operator syntax.
* So, when in condition <xc>, only strings which would terminate the
* "extended comment" trigger any action other than "ignore".
* Be sure to match _any_ candidate comment, including those with appended
* operator-like symbols. - thomas 1997-07-14
*/
abort [aA][bB][oO][rR][tT]
begin [bB][eE][gG][iI][nN]
commit [cC][oO][mM][mM][iI][tT]
connect [cC][oO][nN][nN][eE][cC][tT]
continue [cC][oO][nN][tT][iI][nN][uU][eE]
declare [dD][eE][cC][lL][aA][rR][eE]
do [dD][oO]
end [eE][nN][dD]
exec [eE][xX][eE][cC]
execute [eE][xX][eE][cC][uU][tT][eE]
fetch [fF][eE][tT][cC][hH]
found [fF][oO][uU][nN][dD]
from [fF][rR][oO][mM]
go [gG][oO]
goto [gG][oO][tT][oO]
immediate [iI][mM][mM][eE][dD][iI][aA][tT][eE]
%x xb
%x xc
%x xd
%x xh
%x xm
%x xq
/* Binary number
*/
xbstart [bB]{quote}
xbstop {quote}
xbinside [^']*
xbcat {quote}{space}*\n{space}*{quote}
/* Hexadecimal number
*/
xhstart [xX]{quote}
xhstop {quote}
xhinside [^']*
xhcat {quote}{space}*\n{space}*{quote}
/* Extended quote
* xqdouble implements SQL92 embedded quote
* xqcat allows strings to cross input lines
*/
quote '
xqstart {quote}
xqstop {quote}
xqdouble {quote}{quote}
xqinside [^\\']*
xqembedded "\\'"
xqliteral [\\](.|\n)
xqcat {quote}{space}*\n{space}*{quote}
/* Delimited quote
* Allows embedded spaces and other special characters into identifiers.
*/
dquote \"
xdstart {dquote}
xdstop {dquote}
xdinside [^"]*
/* Comments
* Ignored by the scanner and parser.
*/
xcline [\/][\*].*[\*][\/]{space}*\n*
xcstart [\/][\*]{op_and_self}*
xcstop {op_and_self}*[\*][\/]({space}*|\n)
xcinside [^*]*
xcstar [^/]
digit [0-9]
number [-+.0-9Ee]
letter [\200-\377_A-Za-z]
letter_or_digit [\200-\377_A-Za-z0-9]
identifier {letter}{letter_or_digit}*
typecast "::"
self [,()\[\].$\:\+\-\*\/\<\>\=\|]
op_and_self [\~\!\@\#\%\^\&\|\`\?\$\:\+\-\*\/\<\>\=]
operator {op_and_self}+
xminteger {integer}/-
xmreal {real}/{space}*-{digit}
xmstop -
integer -?{digit}+
real -?{digit}+\.{digit}+([Ee][-+]?{digit}+)?
param \${integer}
comment ("--"|"//").*\n
space [ \t\n\f]
other .
/* some stuff needed for ecpg */
ccomment \/\*([^*]|\*[^/]|\*\*[^/])*\*\/
exec [eE][xX][eE][cC]
include [iI][nN][cC][lL][uU][dD][eE]
in [iI][nN]
into [iI][nN][tT][oO]
not [nN][oO][tT]
open [oO][pP][eE][nN]
release [rR][eE][lL][eE][aA][sS][eE]
rollback [rR][oO][lL][lL][bB][aA][cC][kK]
section [sS][eE][cC][tT][iI][oO][nN]
sql [sS][qQ][lL]
sqlerror [sS][qQ][lL][eE][rR][rR][oO][rR]
sqlprint [sS][qQ][lL][pP][rR][iI][nN][tT]
stop [sS][tT][oO][pP]
transaction [tT][rR][aA][nN][sS][aA][cC][tT][iI][oO][nN]
to [tT][oO]
varchar [vV][aA][rR][cC][hH][aA][rR]
varchar2 [vV][aA][rR][cC][hH][aA][rR]2
whenever [wW][hH][eE][nN][eE][vV][eE][rR]
work [wW][oO][rR][kK]
vacuum [vV][aA][cC][uU][uU][mM]
sql [sS][qQ][lL]
/* DO NOT PUT ANY COMMENTS IN THE FOLLOWING SECTION.
* AT&T lex does not properly handle C-style comments in this second lex block.
* So, put comments here. tgl - 1997-09-08
*
* Quoted strings must allow some special characters such as single-quote
* and newline.
* Embedded single-quotes are implemented both in the SQL/92-standard
* style of two adjacent single quotes "''" and in the Postgres/Java style
* of escaped-quote "\'".
* Other embedded escaped characters are matched explicitly and the leading
* backslash is dropped from the string. - thomas 1997-09-24
*/
%%
<C>{exec}{ws}{sql} { BEGIN SQL; dbg(SQL_START); return SQL_START; }
<SQL>";" { BEGIN C; dbg(SQL_SEMI); return SQL_SEMI; }
<SQL>{abort} { dbg(SQL_ABORT); return SQL_ABORT; }
<SQL>{begin} { dbg(SQL_BEGIN); return SQL_BEGIN; }
<SQL>{end} { dbg(SQL_END); return SQL_END; }
<SQL>{declare} { dbg(SQL_DECLARE); return SQL_DECLARE; }
<SQL>{execute} { dbg(SQL_EXECUTE); return SQL_EXECUTE; }
<SQL>{immediate} { dbg(SQL_IMMEDIATE); return SQL_IMMEDIATE; }
<SQL>{section} { dbg(SQL_SECTION); return SQL_SECTION; }
<SQL>{connect} { dbg(SQL_CONNECT); return SQL_CONNECT; }
<SQL>{open} { dbg(SQL_OPEN); return SQL_OPEN; }
<SQL>{commit} { dbg(SQL_COMMIT); return SQL_COMMIT; }
<SQL>{release} { dbg(SQL_RELEASE); return SQL_RELEASE; }
<SQL>{work} { dbg(SQL_WORK); return SQL_WORK; }
<SQL>{fetch} { dbg(SQL_FETCH); return SQL_FETCH; }
<SQL>{rollback} { dbg(SQL_ROLLBACK); return SQL_ROLLBACK; }
<SQL>{whenever} { dbg(SQL_WHENEVER); return SQL_WHENEVER; }
<SQL>{sqlerror} { dbg(SQL_SQLERROR); return SQL_SQLERROR; }
<SQL>{sqlprint} { dbg(SQL_SQLPRINT); return SQL_SQLPRINT; }
<SQL>{not}{ws}{found} { dbg(SQL_NOT_FOUND); return SQL_NOT_FOUND; }
<SQL>{continue} { dbg(SQL_CONTINUE); return SQL_CONTINUE; }
<SQL>{into} { dbg(SQL_INTO); return SQL_INTO; }
<SQL>{in} { dbg(SQL_IN); return SQL_IN; }
<SQL>{goto} { dbg(SQL_GOTO); return SQL_GOTO; }
<SQL>{go}{ws}{to} { dbg(SQL_GOTO); return SQL_GOTO; }
<SQL>{stop} { dbg(SQL_STOP); return SQL_STOP; }
<SQL>{do} { dbg(SQL_DO); return SQL_DO; }
<SQL>{from} { dbg(SQL_FROM); return SQL_FROM; }
<SQL>{transaction} { dbg(SQL_TRANSACTION); return SQL_TRANSACTION; }
<SQL>{vacuum} { dbg(SQL_VACUUM); return SQL_VACUUM; }
<SQL>{comment} { /* ignore */ }
<SQL>{xcline} { /* ignore */ }
<xc>{xcstar} |
<SQL>{xcstart} { BEGIN(xc); }
<xc>{xcstop} { BEGIN(SQL); }
<xc>{xcinside} { /* ignore */ }
<SQL>{xbstart} {
BEGIN(xb);
llen = 0;
*literal = '\0';
}
<xb>{xbstop} {
char* endptr;
BEGIN(SQL);
errno = 0;
yylval.ival = strtol((char *)literal,&endptr,2);
if (*endptr != '\0' || errno == ERANGE)
yyerror("ERROR: Bad binary integer input!");
return (ICONST);
}
<xh>{xhinside} |
<xb>{xbinside} {
if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
yyerror("ERROR: quoted string parse buffer exceeded");
memcpy(literal+llen, yytext, yyleng+1);
llen += yyleng;
}
<xh>{xhcat} |
<xb>{xbcat} {
}
<SQL>{xhstart} {
BEGIN(xh);
llen = 0;
*literal = '\0';
}
<xh>{xhstop} {
char* endptr;
BEGIN(SQL);
errno = 0;
yylval.ival = strtol((char *)literal,&endptr,16);
if (*endptr != '\0' || errno == ERANGE)
yyerror("ERROR: Bad hexadecimal integer input");
return (ICONST);
}
<SQL>{xqstart} {
BEGIN(xq);
llen = 0;
*literal = '\0';
}
<xq>{xqstop} {
BEGIN(SQL);
yylval.str = strdup(scanstr(literal));
return (SCONST);
}
<xq>{xqdouble} |
<xq>{xqinside} {
if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
yyerror("ERROR: quoted string parse buffer exceeded");
memcpy(literal+llen, yytext, yyleng+1);
llen += yyleng;
}
<xq>{xqembedded} {
if ((llen+yyleng-1) > (MAX_PARSE_BUFFER - 1))
yyerror("ERROR: quoted string parse buffer exceeded");
memcpy(literal+llen, yytext, yyleng+1);
*(literal+llen) = '\'';
llen += yyleng;
}
<xq>{xqliteral} {
if ((llen+yyleng-1) > (MAX_PARSE_BUFFER - 1))
yyerror("ERROR: quoted string parse buffer exceeded");
memcpy(literal+llen, yytext, yyleng+1);
llen += yyleng;
}
<xq>{xqcat} {
}
<C>{exec}{ws}{sql}{ws}{include} { BEGIN(incl); }
<incl>{ws} /* eat the whitespace */
<SQL>{xdstart} {
BEGIN(xd);
llen = 0;
*literal = '\0';
}
<xd>{xdstop} {
BEGIN(SQL);
yylval.str = strdup(literal);
return (IDENT);
}
<xd>{xdinside} {
if ((llen+yyleng) > (MAX_PARSE_BUFFER - 1))
yyerror("ERROR: quoted string parse buffer exceeded");
memcpy(literal+llen, yytext, yyleng+1);
llen += yyleng;
}
<xm>{space}* { /* ignore */ }
<xm>{xmstop} {
BEGIN(SQL);
return (yytext[0]);
}
<SQL>{typecast} { return TYPECAST; }
<SQL>{self}/-[\.0-9] {
return (yytext[0]);
}
<SQL>{self} { return (yytext[0]); }
<SQL>{operator}/-[\.0-9] {
yylval.str = strdup((char*)yytext);
return (Op);
}
<SQL>{operator} {
if (strcmp((char*)yytext,"!=") == 0)
yylval.str = strdup("<>"); /* compatability */
else
yylval.str = strdup((char*)yytext);
return (Op);
}
<SQL>{param} {
yylval.ival = atoi((char*)&yytext[1]);
return (PARAM);
}
<SQL>{identifier}/{space}*-{number} {
int i;
ScanKeyword *keyword;
BEGIN(xm);
for(i = 0; yytext[i]; i++)
if (isupper(yytext[i]))
yytext[i] = tolower(yytext[i]);
keyword = ScanKeywordLookup((char*)yytext);
if (keyword != NULL) {
return (keyword->value);
}
else
{
keyword = ScanECPGKeywordLookup((char*)yytext);
if (keyword != NULL) {
return (keyword->value);
}
else
{
yylval.str = strdup((char*)yytext);
return (IDENT);
}
}
}
{integer}/{space}*-{number} {
char* endptr;
BEGIN(xm);
errno = 0;
yylval.ival = strtol((char *)yytext,&endptr,10);
if (*endptr != '\0' || errno == ERANGE)
{
errno = 0;
yylval.dval = strtod(((char *)yytext),&endptr);
if (*endptr != '\0' || errno == ERANGE)
yyerror("ERROR: Bad integer input");
yyerror("WARNING: Integer input is out of range; promoted to float");
return (FCONST);
}
return (ICONST);
}
{real}/{space}*-{number} {
char* endptr;
BEGIN(xm);
errno = 0;
yylval.dval = strtod(((char *)yytext),&endptr);
if (*endptr != '\0' || errno == ERANGE)
yyerror("ERROR: Bad float8 input");
return (FCONST);
}
{integer} {
char* endptr;
errno = 0;
yylval.ival = strtol((char *)yytext,&endptr,10);
if (*endptr != '\0' || errno == ERANGE)
{
errno = 0;
yylval.dval = strtod(((char *)yytext),&endptr);
if (*endptr != '\0' || errno == ERANGE)
yyerror("ERROR: Bad integer input");
yyerror("WARNING: Integer input is out of range; promoted to float");
return (FCONST);
}
return (ICONST);
}
{real} {
char* endptr;
errno = 0;
yylval.dval = strtod((char *)yytext,&endptr);
if (*endptr != '\0' || errno == ERANGE)
yyerror("ERROR: Bad float input");
return (FCONST);
}
<SQL>{identifier} {
int i;
ScanKeyword *keyword;
for(i = 0; yytext[i]; i++)
if (isupper(yytext[i]))
yytext[i] = tolower(yytext[i]);
keyword = ScanKeywordLookup((char*)yytext);
if (keyword != NULL) {
return (keyword->value);
}
else
{
keyword = ScanECPGKeywordLookup((char*)yytext);
if (keyword != NULL) {
return (keyword->value);
}
else
{
yylval.str = strdup((char*)yytext);
return (IDENT);
}
}
}
<SQL>{space} { /* ignore */ }
<SQL>";" { BEGIN C; return SQL_SEMI; }
<SQL>{other} { return (yytext[0]); }
<C>{exec}{space}{sql} { BEGIN SQL; return SQL_START; }
<C>{identifier} {
ScanKeyword *keyword;
keyword = ScanCKeywordLookup((char*)yytext);
if (keyword != NULL) {
return (keyword->value);
}
else
{
yylval.str = strdup((char*)yytext);
return (IDENT);
}
}
<C>";" { return(';'); }
<C>{space} { ECHO; }
\{ { return('{'); }
\} { return('}'); }
\[ { return('['); }
\] { return(']'); }
\= { return('='); }
<C>{other} { return (S_ANYTHING); }
<C>{exec}{space}{sql}{space}{include} { BEGIN(incl); }
<incl>{space} /* eat the whitespace */
<incl>[^ \t\n]+ { /* got the include file name */
struct _yy_buffer *yb;
struct _include_path *ip;
@ -125,7 +454,7 @@ vacuum [vV][aA][cC][uU][uU][mM]
{
if (strlen(ip->path) + strlen(yytext) + 3 > PATH_MAX)
{
fprintf(stderr, "Path %s/%s is too long, skipping.\n", ip->path, yytext);
fprintf(stderr, "Error: Path %s/%s is too long in line %d, skipping.\n", ip->path, yytext, yylineno);
continue;
}
sprintf (inc_file, "%s/%s", ip->path, yytext);
@ -142,7 +471,7 @@ vacuum [vV][aA][cC][uU][uU][mM]
}
if (!yyin)
{
fprintf(stderr, "Cannot open include file %s\n", yytext);
fprintf(stderr, "Error: Cannot open include file %s in line %d\n", yytext, yylineno);
exit(1);
}
@ -153,79 +482,6 @@ vacuum [vV][aA][cC][uU][uU][mM]
BEGIN C;
}
<incl>";" { BEGIN C; }
{length} { dbg(S_LENGTH); return S_LENGTH; }
{varchar} { dbg(S_VARCHAR); return S_VARCHAR; }
{varchar2} { dbg(S_VARCHAR2); return S_VARCHAR2; }
long { dbg(S_LONG); return S_LONG; }
short { dbg(S_SHORT); return S_SHORT; }
int { dbg(S_INT); return S_INT; }
char { dbg(S_CHAR); return S_CHAR; }
float { dbg(S_FLOAT); return S_FLOAT; }
double { dbg(S_DOUBLE); return S_DOUBLE; }
bool { dbg(S_BOOL); return S_BOOL; }
static { dbg(S_STATIC); return S_STATIC; }
signed { dbg(S_SIGNED); return S_SIGNED; }
extern { dbg(S_EXTERN); return S_EXTERN; }
auto { dbg(S_AUTO); return S_AUTO; }
const { dbg(S_CONST); return S_CONST; }
register { dbg(S_REGISTER); return S_REGISTER; }
struct { dbg(S_STRUCT); return S_STRUCT; }
{string} { dbg(SQL_STRING); return SQL_STRING; }
<SQL>{ws} ;
{symbol} { dbg(S_SYMBOL); return S_SYMBOL; }
{label} { dbg(S_LABEL); return S_LABEL; }
<SQL>"!<" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"!>" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"!^" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"!|" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"!~" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"!~*" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"#<" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"#<=" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"#<>" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"#=" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"#>" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"#>=" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"&&" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"&<" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"&>" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"<<" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"<=" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"<===>" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"<>" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"<?>" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"===>" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"===`" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"=|=" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>">=" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>">>" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"@@" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"|/" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"||/" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"~*" { dbg(S_SYMBOL); return S_SYMBOL; }
<SQL>"~=" { dbg(S_SYMBOL); return S_SYMBOL; }
"[" { dbg([); return '['; }
"]" { dbg(]); return ']'; }
";" { dbg(;); return ';'; }
"=" { dbg(=); return '='; }
"," { dbg(komma); return ','; }
\( { dbg(braceopen); return '('; }
\) { dbg(braceclose); return ')'; }
\{ { dbg(blockstart); return '{'; }
\} { dbg(blockend); return '}'; }
\* { dbg(*); return('*'); }
<SQL>":" { dbg(:); return ':'; }
<SQL>"::" { dbg(SQL_CONV); return SQL_CONV; }
{ws} { ECHO; }
. { dbg(.); return S_ANYTHING; }
<<EOF>> { if (yy_buffer == NULL)
yyterminate();
else
@ -260,4 +516,3 @@ int yywrap(void)
{
return 1;
}

File diff suppressed because it is too large Load Diff

View File

@ -123,22 +123,27 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
long varcharsize,
long arrsiz, const char *siz, const char *prefix);
void
ECPGdump_a_record(FILE *o, const char *name, long arrsiz,
struct ECPGtype * typ, const char *offset, const char *prefix);
ECPGdump_a_record(FILE *o, const char *name, const char *ind_name, long arrsiz,
struct ECPGtype * typ, struct ECPGtype * ind_typ, const char *offset, const char *prefix, const char * ind_prefix);
void
ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *prefix)
ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *ind_name, struct ECPGtype * ind_typ, const char *prefix, const char *ind_prefix)
{
if (IS_SIMPLE_TYPE(typ->typ))
{
ECPGdump_a_simple(o, name, typ->typ, typ->size, 0, 0, prefix);
ECPGdump_a_simple(o, ind_name, ind_typ->typ, ind_typ->size, 0, 0, ind_prefix);
}
else if (typ->typ == ECPGt_array)
{
if (IS_SIMPLE_TYPE(typ->u.element->typ))
{
ECPGdump_a_simple(o, name, typ->u.element->typ,
typ->u.element->size, typ->size, 0, prefix);
ECPGdump_a_simple(o, ind_name, ind_typ->u.element->typ,
ind_typ->u.element->size, ind_typ->size, 0, prefix);
}
else if (typ->u.element->typ == ECPGt_array)
{
abort(); /* Array of array, */
@ -146,7 +151,7 @@ ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *pr
else if (typ->u.element->typ == ECPGt_record)
{
/* Array of records. */
ECPGdump_a_record(o, name, typ->size, typ->u.element, 0, prefix);
ECPGdump_a_record(o, name, ind_name, typ->size, typ->u.element, ind_typ->u.element, 0, prefix, ind_prefix);
}
else
{
@ -155,7 +160,7 @@ ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *pr
}
else if (typ->typ == ECPGt_record)
{
ECPGdump_a_record(o, name, 0, typ, 0, prefix);
ECPGdump_a_record(o, name, ind_name, 0, typ, ind_typ, 0, prefix, ind_prefix);
}
else
{
@ -171,7 +176,8 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
long varcharsize,
long arrsiz,
const char *siz,
const char *prefix)
const char *prefix
)
{
switch (typ)
{
@ -241,15 +247,19 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
varcharsize,
arrsiz, siz);
break;
case ECPGt_NO_INDICATOR: /* no indicator */
fprintf(o, "\n\tECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ");
break;
default:
abort();
}
}
/* Penetrate a record and dump the contents. */
void
ECPGdump_a_record(FILE *o, const char *name, long arrsiz, struct ECPGtype * typ, const char *offsetarg, const char *prefix)
ECPGdump_a_record(FILE *o, const char *name, const char * ind_name, long arrsiz, struct ECPGtype * typ, struct ECPGtype * ind_typ, const char *offsetarg, const char *prefix, const char *ind_prefix)
{
/*
@ -257,9 +267,9 @@ ECPGdump_a_record(FILE *o, const char *name, long arrsiz, struct ECPGtype * typ,
* then we are in a record in a record and the offset is used as
* offset.
*/
struct ECPGrecord_member *p;
struct ECPGrecord_member *p, *ind_p;
char obuf[BUFSIZ];
char pbuf[BUFSIZ];
char pbuf[BUFSIZ], ind_pbuf[BUFSIZ];
const char *offset;
if (offsetarg == NULL)
@ -274,63 +284,13 @@ ECPGdump_a_record(FILE *o, const char *name, long arrsiz, struct ECPGtype * typ,
sprintf(pbuf, "%s%s.", prefix ? prefix : "", name);
prefix = pbuf;
sprintf(ind_pbuf, "%s%s.", ind_prefix ? ind_prefix : "", ind_name);
ind_prefix = ind_pbuf;
for (p = typ->u.members; p; p = p->next)
for (p = typ->u.members, ind_p = ind_typ->u.members; p; p = p->next, ind_p = ind_p->next)
{
#if 0
if (IS_SIMPLE_TYPE(p->typ->typ))
{
sprintf(buf, "%s.%s", name, p->name);
ECPGdump_a_simple(o, buf, p->typ->typ, p->typ->size,
arrsiz, offset);
}
else if (p->typ->typ == ECPGt_array)
{
int i;
for (i = 0; i < p->typ->size; i++)
{
if (IS_SIMPLE_TYPE(p->typ->u.element->typ))
{
/* sprintf(buf, "%s.%s[%d]", name, p->name, i); */
sprintf(buf, "%s.%s", name, p->name);
ECPGdump_a_simple(o, buf, p->typ->u.element->typ, p->typ->u.element->size,
p->typ->u.element->size, offset);
}
else if (p->typ->u.element->typ == ECPGt_array)
{
/* Array within an array. NOT implemented. */
abort();
}
else if (p->typ->u.element->typ == ECPGt_record)
{
/*
* Record within array within record. NOT implemented
* yet.
*/
abort();
}
else
{
/* Unknown type */
abort();
}
}
}
else if (p->typ->typ == ECPGt_record)
{
/* Record within a record */
sprintf(buf, "%s.%s", name, p->name);
ECPGdump_a_record(o, buf, arrsiz, p->typ, offset);
}
else
{
/* Unknown type */
abort();
}
#endif
ECPGdump_a_type(o, p->name, p->typ, prefix);
ECPGdump_a_type(o, p->name, p->typ, ind_p->name, ind_p->typ, prefix, ind_prefix);
}
}

View File

@ -45,7 +45,7 @@ void ECPGfree_type(struct ECPGtype *);
size is the maxsize in case it is a varchar. Otherwise it is the size of
the variable (required to do array fetches of records).
*/
void ECPGdump_a_type(FILE *, const char *name, struct ECPGtype *, const char *);
void ECPGdump_a_type(FILE *, const char *, struct ECPGtype *, const char *, struct ECPGtype *, const char *, const char *);
/* A simple struct to keep a variable and its type. */
struct ECPGtemp_type
@ -71,5 +71,6 @@ enum WHEN
struct when
{
enum WHEN code;
char *str;
char *command;
char *str;
};

View File

@ -1,16 +1,14 @@
all: test2 perftest
test2: test2.c
gcc -g -I ../include -I ../../libpq -o test2 test2.c -L../lib -lecpg -L../../libpq -lpq -lcrypt
gcc -g -I ../include -I ../../libpq -o test2 test2.c -L../lib -lecpg -L../../libpq -lpq -lcrypt --static
test2.c: test2.pgc
ecpg test2.pgc
../preproc/ecpg test2.pgc
perftest: perftest.c
gcc -g -I ../include -I ../../libpq -o perftest perftest.c -L../lib -lecpg -L../../libpq -lpq -lcrypt
gcc -g -I ../include -I ../../libpq -o perftest perftest.c -L../lib -lecpg -L../../libpq -lpq -lcrypt --static
perftest.c: perftest.pgc
ecpg perftest.pgc
../preproc/ecpg perftest.pgc
clean:
/bin/rm test2 test2.c perftest perftest.c log
dep depend:

View File

@ -16,7 +16,8 @@ print_result(long sec, long usec, char *text)
usec+=1000000;
}
printf("I needed %ld seconds and %ld microseconds for the %s test.\n", sec, usec, text);
exec sql vacuum analyze;
exec sql vacuum;
sleep(1);
}
int
@ -27,9 +28,9 @@ exec sql begin declare section;
exec sql end declare section;
struct timeval tvs, tve;
exec sql connect 'mm';
exec sql connect mm;
exec sql create table perftest1(number int4, ascii char16);
exec sql create table perftest1(number int4, ascii char(16));
exec sql create unique index number1 on perftest1(number);
@ -100,6 +101,16 @@ exec sql end declare section;
print_result(tve.tv_sec - tvs.tv_sec, tve.tv_usec - tvs.tv_usec, "update");
gettimeofday(&tvs, NULL);
exec sql delete from perftest2;
exec sql commit;
gettimeofday(&tve, NULL);
print_result(tve.tv_sec - tvs.tv_sec, tve.tv_usec - tvs.tv_usec, "delete");
exec sql drop index number2;
exec sql drop table perftest2;

View File

@ -2,8 +2,6 @@
exec sql include header_test;
extern void ECPGdebug(int n, FILE *dbgs);
static int not_found = 0;
static void
set_not_found(void)
@ -18,39 +16,53 @@ exec sql begin declare section;
struct personal_struct { varchar name[8];
struct birth_struct { long born;
short age;
} birth;
} birth;
} personal;
struct personal_indicator { short name;
struct birth_indicator { short born;
int age;
} ind_birth;
} ind_personal;
long ind_married;
char married[9]="a";
exec sql end declare section;
char msg[128];
char msg[128], command[128];
FILE *dbgs;
if ((dbgs = fopen("log", "w")) != NULL)
ECPGdebug(1, dbgs);
ECPGdebug(1, dbgs);
strcpy(msg, "connect");
exec sql connect 'mm';
exec sql connect mm;
strcpy(msg, "create");
exec sql create table meskes(name char8, born int4, age int2);
exec sql create table meskes(name char(8), born integer, age smallint, married char(8));
strcpy(msg, "insert");
exec sql insert into meskes(name, born, age) values ('Petra', 19661202, 31);
exec sql insert into meskes(name, born, age) values ('Michael', 19660117, 32);
exec sql insert into meskes(name, born, age, married) values ('Petra', 19661202, 31, '19900404');
exec sql insert into meskes(name, born, age, married) values ('Michael', 19660117, 32, '19900404');
exec sql insert into meskes(name, born, age) values ('Carsten', 19910103, 7);
exec sql insert into meskes(name, born, age) values ('Marc', 19930907, 4);
exec sql insert into meskes(name, born, age) values ('Chris', 19970923, 0);
sprintf(command, "insert into meskes(name, born, age) values ('Chris', 19970923, 0)");
strcpy(msg, "execute");
exec sql execute immediate :command;
strcpy(msg, "commit");
exec sql commit;
strcpy(msg, "declare");
exec sql declare cur cursor for
select name, born, age from meskes;
select name, born, age, married from meskes;
strcpy(msg, "open");
exec sql open cur;
while (not_found == 0) {
strcpy(msg, "fetch");
exec sql fetch cur into :personal;
exec sql fetch cur into :personal:ind_personal, :married:ind_married;
if (not_found == 0)
printf ("%8.8s was born %d (age = %d)\n", personal.name.arr, personal.birth.born, personal.birth.age);
printf ("%8.8s was born %d (age = %d) %s%s\n", personal.name.arr, personal.birth.born, personal.birth.age, ind_married ? "" : "and married ", ind_married ? "" : married);
}
strcpy(msg, "close");
@ -63,7 +75,7 @@ exec sql end declare section;
exec sql commit;
if (dbgs != NULL)
fclose(dbgs);
fclose(dbgs);
return (0);
}