Commit 64e35e14 authored by Marc G. Fournier's avatar Marc G. Fournier

Upgrade ECPG to 2.0

Michael Meskes <meskes@topsystem.de>
parent 5e6b0a57
......@@ -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).
This list is still from Linus. MM
The variables should be static.
Preprocessor cannot do syntax checking on your SQL statements Whatever you
write is copied more or less exactly to the PostgreSQL and you will not be
able to locate your errors until run-time.
No restriction to strings only The PQ interface, and most of all the PQexec
function, that is used by the ecpg relies on that the request is built up as
a string. In some cases, like when the data contains the null character,
this will be a serious problem.
There should be different error numbers for the different errors instead of
just -1 for them all.
......@@ -21,12 +12,6 @@ ecpg it is done for compatibility reasons only. For them to improve speed
would require a lot more insight in the postgres internal mechanisms than I
possess.
Oracle has indicator variables that tell if a value is null or if it is
empty. This largely simplifies array operations and provides for a way to
hack around some design flaws in the handling of VARCHAR2 (like that an
empty string isn't distinguishable from a null value). I am not sure if this
is an Oracle extension or part of the ANSI standard.
As well as complex types like records and arrays, typedefs would be a good
thing to take care of.
......@@ -43,8 +28,6 @@ Now comes my list (MM):
The return code is alway -1 in case of an error. You cannot see which error
occured by examining the return code.
The cursor is opened when the declare statement is issued.
ecpg does not understand enum datatypes.
There is no exec sql prepare statement.
......@@ -59,7 +42,16 @@ There is no way yet to fill a complete array with one call except arrays of
ecpg cannot use pointer variables except [unsigned] char *
List all commands as sqlcommand, not just S_SYMBOL or even better rewrite
pareser to be equivalent to backend´s parser.
give back the number of tuples affected via sqlca
exec sql disconnect {current|default|all|connectionname|connection_hostvar};
oder <disconnect statement> ::=
DISCONNECT <disconnect object>
<disconnect object> ::=
<connection object>
| ALL
| CURRENT
commit release|commit work release auch disconnect
Set standard include paths.
It is not neccessary to check for sql not found after all commands.
......@@ -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:
......@@ -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 *);
......
......@@ -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)
......
......@@ -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)
......
......@@ -96,10 +96,11 @@ ECPGdo(int lineno, char *query,...)
*/
while (type != ECPGt_EOIT)
{
void *value = NULL;
long varcharsize;
long size;
long arrsize;
void *value = NULL, *ind_value;
long varcharsize, ind_varcharsize;
long size, ind_size;
long arrsize, ind_arrsize;
enum ECPGttype ind_type;
char *newcopy;
char *mallocedval = NULL;
......@@ -117,9 +118,40 @@ ECPGdo(int lineno, char *query,...)
varcharsize = va_arg(ap, long);
size = va_arg(ap, long);
arrsize = va_arg(ap, long);
switch (type)
ind_type = va_arg(ap, enum ECPGttype);
ind_value = va_arg(ap, void *);
ind_varcharsize = va_arg(ap, long);
ind_size = va_arg(ap, long);
ind_arrsize = va_arg(ap, long);
buff[0] = '\0';
/* check for null value and set input buffer accordingly */
switch (ind_type)
{
case ECPGt_short:
case ECPGt_unsigned_short:
if (*(short *) ind_value < 0)
strcpy(buff, "null");
break;
case ECPGt_int:
case ECPGt_unsigned_int:
if (*(int *) ind_value < 0)
strcpy(buff, "null");
break;
case ECPGt_long:
case ECPGt_unsigned_long:
if (*(long *) ind_value < 0L)
strcpy(buff, "null");
break;
default:
break;
}
if (*buff == '\0')
{
switch (type)
{
case ECPGt_short:
case ECPGt_int:
sprintf(buff, "%d", *(int *) value);
......@@ -205,7 +237,10 @@ ECPGdo(int lineno, char *query,...)
ECPGtype_name(type), lineno);
return false;
break;
}
}
else
tobeinserted = buff;
/*
* Now tobeinserted points to an area that is to be inserted at
......@@ -266,7 +301,7 @@ ECPGdo(int lineno, char *query,...)
if (committed)
{
if ((results = PQexec(simple_connection, "begin")) == NULL)
if ((results = PQexec(simple_connection, "begin transaction")) == NULL)
{
register_error(-1, "Error starting transaction line %d.", lineno);
return false;
......@@ -324,10 +359,11 @@ ECPGdo(int lineno, char *query,...)
for (x = 0; x < m && status; x++)
{
void *value = NULL;
long varcharsize;
long size;
long arrsize;
void *value = NULL, *ind_value;
long varcharsize, ind_varcharsize;
long size, ind_size;
long arrsize, ind_arrsize;
enum ECPGttype ind_type;
char *pval = PQgetvalue(results, 0, x);
......@@ -339,14 +375,38 @@ ECPGdo(int lineno, char *query,...)
ECPGlog("ECPGdo line %d: RESULT: %s\n", lineno, pval ? pval : "");
/* No the pval is a pointer to the value. */
/* Now the pval is a pointer to the value. */
/* We will have to decode the value */
type = va_arg(ap, enum ECPGttype);
value = va_arg(ap, void *);
varcharsize = va_arg(ap, long);
size = va_arg(ap, long);
arrsize = va_arg(ap, long);
ind_type = va_arg(ap, enum ECPGttype);
ind_value = va_arg(ap, void *);
ind_varcharsize = va_arg(ap, long);
ind_size = va_arg(ap, long);
ind_arrsize = va_arg(ap, long);
/* check for null value and set indicator accordingly */
switch (ind_type)
{
case ECPGt_short:
case ECPGt_unsigned_short:
*(short *) ind_value = -PQgetisnull(results, 0, x);
break;
case ECPGt_int:
case ECPGt_unsigned_int:
*(int *) ind_value = -PQgetisnull(results, 0, x);
break;
case ECPGt_long:
case ECPGt_unsigned_long:
*(long *) ind_value = -PQgetisnull(results, 0, x);
break;
default:
break;
}
switch (type)
{
long res;
......@@ -486,7 +546,30 @@ ECPGdo(int lineno, char *query,...)
((char *) value)[strlen(pval)] = '\0';
}
else
{
strncpy((char *) value, pval, varcharsize);
if (varcharsize < strlen(pval))
{
/* truncation */
switch (ind_type)
{
case ECPGt_short:
case ECPGt_unsigned_short:
*(short *) ind_value = varcharsize;
break;
case ECPGt_int:
case ECPGt_unsigned_int:
*(int *) ind_value = varcharsize;
break;
case ECPGt_long:
case ECPGt_unsigned_long:
*(long *) ind_value = varcharsize;
break;
default:
break;
}
}
}
}
break;
......@@ -498,7 +581,28 @@ ECPGdo(int lineno, char *query,...)
strncpy(var->arr, pval, varcharsize);
var->len = strlen(pval);
if (var->len > varcharsize)
{
/* truncation */
switch (ind_type)
{
case ECPGt_short:
case ECPGt_unsigned_short:
*(short *) ind_value = varcharsize;
break;
case ECPGt_int:
case ECPGt_unsigned_int:
*(int *) ind_value = varcharsize;
break;
case ECPGt_long:
case ECPGt_unsigned_long:
*(long *) ind_value = varcharsize;
break;
default:
break;
}
var->len = varcharsize;
}
}
break;
......@@ -587,19 +691,6 @@ ECPGtrans(int lineno, const char * transaction)
return (TRUE);
}
/* include these for compatibility */
bool
ECPGcommit(int lineno)
{
return(ECPGtrans(lineno, "end"));
}
bool
ECPGrollback(int lineno)
{
return(ECPGtrans(lineno, "abort"));
}
bool
ECPGsetdb(PGconn *newcon)
{
......
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
/*-------------------------------------------------------------------------
*
* 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);
}
......@@ -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);
}
}
......
/*-------------------------------------------------------------------------
*
* 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);
}
#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 *);
/*-------------------------------------------------------------------------
*
* 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);
}
This diff is collapsed.
This diff is collapsed.
......@@ -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);
}
}
......
......@@ -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;
};
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:
......@@ -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;
......
......@@ -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);
}
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