Commit 6bccf64d authored by Marc G. Fournier's avatar Marc G. Fournier

From: Michael Meskes <meskes@topsystem.de>

Tue Apr 28 14:48:41 CEST 1998

      - Put operator "->" back into parser. Note that :foo->bar means the
        C term, but :foo ->bar means the operator "->".

Tue Apr 28 15:49:07 CEST 1998

      - Added exec sql disconnect command.
      - Allow varchar in C to be written in uppercase too.
      - Added whenever option "do break;"

Wed Apr 29 09:17:53 CEST 1998

      - Corrected parsing of C comments.
      - Also allow C++ style comments.
      - Make sure not found is only checked after commands that could
          return it.
      - Added error codes, see ecpgerror.h for details.
      - Added "exec sql <TransactionStmt> release" as disconnect statement
        for compatibility issues.

Thu Apr 30 10:42:10 CEST 1998

      - Added a -t option to disable automatic transaction start.
      - Added sqlerrd[] to sqlca struct.
      - Give back number of tuples affect in sqlca.sqlerrd[2].

Thu Apr 30 13:36:02 CEST 1998

      - Make the return code different in case of different errors.

Wed May  6 11:42:48 CEST 1998

      - Free memory if possible
      - Some bugfixes for bugs I found while changing the memory
          allocation code
      - Now able to fill complete array with one call (see test1.pgc for
          an example)
      - Set version to 2.3.0
      - Set library version to 2.1
parent f9322c66
...@@ -149,3 +149,43 @@ Mon Apr 27 14:26:55 CEST 1998 ...@@ -149,3 +149,43 @@ Mon Apr 27 14:26:55 CEST 1998
and :foo.bar as variables. and :foo.bar as variables.
- Set version to 2.2.0 - Set version to 2.2.0
Tue Apr 28 14:48:41 CEST 1998
- Put operator "->" back into parser. Note that :foo->bar means the
C term, but :foo ->bar means the operator "->".
Tue Apr 28 15:49:07 CEST 1998
- Added exec sql disconnect command.
- Allow varchar in C to be written in uppercase too.
- Added whenever option "do break;"
Wed Apr 29 09:17:53 CEST 1998
- Corrected parsing of C comments.
- Also allow C++ style comments.
- Make sure not found is only checked after commands that could
return it.
- Added error codes, see ecpgerror.h for details.
- Added "exec sql <TransactionStmt> release" as disconnect statement
for compatibility issues.
Thu Apr 30 10:42:10 CEST 1998
- Added a -t option to disable automatic transaction start.
- Added sqlerrd[] to sqlca struct.
- Give back number of tuples affect in sqlca.sqlerrd[2].
Thu Apr 30 13:36:02 CEST 1998
- Make the return code different in case of different errors.
Wed May 6 11:42:48 CEST 1998
- Free memory if possible
- Some bugfixes for bugs I found while changing the memory
allocation code
- Now able to fill complete array with one call (see test1.pgc for
an example)
- Set version to 2.3.0
- Set library version to 2.1
This list is still from Linus. MM
The variables should be static.
There should be different error numbers for the different errors instead of
just -1 for them all.
Missing library functions to_date et al.
Oracle has array operations that enhances speed. When implementing it in
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.
As well as complex types like records and arrays, typedefs would be a good
thing to take care of.
To set up a database you need a few scripts with table definitions and other
configuration parameters. If you have these scripts for an old database you
would like to just apply them to get a postgres database that works in the
same way. The functionality could be accomplished with some conversion
scripts. Speed will never be accomplished in this way. To do this you need a
bigger insight in the database construction and the use of the database than
could be realised in a script.
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.
ecpg does not understand enum datatypes. ecpg does not understand enum datatypes.
There is no exec sql prepare statement.
The complete structure definition has to be listed inside the declare The complete structure definition has to be listed inside the declare
section for ecpg to be able to understand it. section of the structure variable for ecpg to be able to understand it.
There is no way yet to fill a complete array with one call except arrays of Variable type bool has to be checked. I never used it so far.
[unsigned] char which are considered strings.
ecpg cannot use pointer variables except [unsigned] char * ecpg cannot use pointer variables except [unsigned] char *
give back the number of tuples affected via sqlca There is no exec sql type statement which is the SQL version of a typedef.
exec sql disconnect {current|default|all|connectionname|connection_hostvar};
oder <disconnect statement> ::=
DISCONNECT <disconnect object>
<disconnect object> ::= There is no exec sql prepare statement.
<connection object>
| ALL
| CURRENT
commit release|commit work release auch disconnect
It is not neccessary to check for "not found" after all commands. There is no SQLSTATE
...@@ -6,11 +6,13 @@ all clean:: ...@@ -6,11 +6,13 @@ all clean::
@echo Nothing to be done. @echo Nothing to be done.
install:: install::
$(INSTALL) $(INSTLOPTS) ecpgerrno.h $(DESTDIR)$(HEADERDIR)
$(INSTALL) $(INSTLOPTS) ecpglib.h $(DESTDIR)$(HEADERDIR) $(INSTALL) $(INSTLOPTS) ecpglib.h $(DESTDIR)$(HEADERDIR)
$(INSTALL) $(INSTLOPTS) ecpgtype.h $(DESTDIR)$(HEADERDIR) $(INSTALL) $(INSTLOPTS) ecpgtype.h $(DESTDIR)$(HEADERDIR)
$(INSTALL) $(INSTLOPTS) sqlca.h $(DESTDIR)$(HEADERDIR) $(INSTALL) $(INSTLOPTS) sqlca.h $(DESTDIR)$(HEADERDIR)
uninstall:: uninstall::
rm -f $(DESTDIR)$(HEADERDIR)/ecpgerrno.h
rm -f $(DESTDIR)$(HEADERDIR)/ecpglib.h rm -f $(DESTDIR)$(HEADERDIR)/ecpglib.h
rm -f $(DESTDIR)$(HEADERDIR)/ecpgtype.h rm -f $(DESTDIR)$(HEADERDIR)/ecpgtype.h
rm -f $(DESTDIR)$(HEADERDIR)/sqlca.h rm -f $(DESTDIR)$(HEADERDIR)/sqlca.h
......
#ifndef _ECPG_ERROR_H
#define _ECPG_ERROR_H
/* This is a list of all error codes the embedded SQL program can return */
#define ECPG_NO_ERROR 0
#define ECPG_NOT_FOUND 100
#define ECPG_PGSQL -1
#define ECPG_UNSUPPORTED -2
#define ECPG_TOO_MANY_ARGUMENTS -3
#define ECPG_TOO_FEW_ARGUMENTS -4
#define ECPG_TRANS -5
#define ECPG_TOO_MANY_MATCHES -6
#define ECPG_INT_FORMAT -7
#define ECPG_UINT_FORMAT -8
#define ECPG_FLOAT_FORMAT -9
#define ECPG_CONVERT_BOOL -10
#define ECPG_EMPTY -11
#define ECPG_CONNECT -12
#define ECPG_DISCONNECT -13
#endif /* !_ECPG_ERROR_H */
...@@ -5,11 +5,11 @@ extern "C" { ...@@ -5,11 +5,11 @@ extern "C" {
#endif #endif
void ECPGdebug(int, FILE *); void ECPGdebug(int, FILE *);
bool ECPGconnect(const char *dbname); bool ECPGconnect(const char *);
bool ECPGdo(int, char *,...); bool ECPGdo(int, char *,...);
bool ECPGtrans(int, const char *); bool ECPGtrans(int, const char *);
bool ECPGfinish(void); bool ECPGfinish(void);
bool ECPGstatus(void); bool ECPGdisconnect(const char *);
void ECPGlog(const char *format,...); void ECPGlog(const char *format,...);
...@@ -39,3 +39,5 @@ void sqlprint(void); ...@@ -39,3 +39,5 @@ void sqlprint(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#include <ecpgerrno.h>
...@@ -13,6 +13,7 @@ struct sqlca ...@@ -13,6 +13,7 @@ struct sqlca
int sqlerrml; int sqlerrml;
char sqlerrmc[1000]; char sqlerrmc[1000];
} sqlerrm; } sqlerrm;
long sqlerrd[6];
} sqlca; } sqlca;
#endif #endif
......
...@@ -4,7 +4,7 @@ include $(SRCDIR)/Makefile.global ...@@ -4,7 +4,7 @@ include $(SRCDIR)/Makefile.global
PQ_INCLUDE=-I$(SRCDIR)/interfaces/libpq PQ_INCLUDE=-I$(SRCDIR)/interfaces/libpq
SO_MAJOR_VERSION=2 SO_MAJOR_VERSION=2
SO_MINOR_VERSION=0 SO_MINOR_VERSION=1
PORTNAME=@PORTNAME@ PORTNAME=@PORTNAME@
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#include <ecpglib.h> #include <ecpglib.h>
#include <sqlca.h> #include <sqlca.h>
extern int no_auto_trans;
static PGconn *simple_connection = NULL; static PGconn *simple_connection = NULL;
static int simple_debug = 0; static int simple_debug = 0;
static FILE *debugstream = NULL; static FILE *debugstream = NULL;
...@@ -80,6 +82,11 @@ ECPGdo(int lineno, char *query,...) ...@@ -80,6 +82,11 @@ ECPGdo(int lineno, char *query,...)
PGresult *results; PGresult *results;
PGnotify *notify; PGnotify *notify;
enum ECPGttype type; enum ECPGttype type;
void *value = NULL, *ind_value;
long varcharsize, ind_varcharsize;
long arrsize, ind_arrsize;
long offset, ind_offset;
enum ECPGttype ind_type;
va_start(ap, query); va_start(ap, query);
...@@ -96,12 +103,6 @@ ECPGdo(int lineno, char *query,...) ...@@ -96,12 +103,6 @@ ECPGdo(int lineno, char *query,...)
*/ */
while (type != ECPGt_EOIT) while (type != ECPGt_EOIT)
{ {
void *value = NULL, *ind_value;
long varcharsize, ind_varcharsize;
long size, ind_size;
long arrsize, ind_arrsize;
enum ECPGttype ind_type;
char *newcopy; char *newcopy;
char *mallocedval = NULL; char *mallocedval = NULL;
char *tobeinserted = NULL; char *tobeinserted = NULL;
...@@ -116,13 +117,13 @@ ECPGdo(int lineno, char *query,...) ...@@ -116,13 +117,13 @@ ECPGdo(int lineno, char *query,...)
value = va_arg(ap, void *); value = va_arg(ap, void *);
varcharsize = va_arg(ap, long); varcharsize = va_arg(ap, long);
size = va_arg(ap, long);
arrsize = va_arg(ap, long); arrsize = va_arg(ap, long);
offset = va_arg(ap, long);
ind_type = va_arg(ap, enum ECPGttype); ind_type = va_arg(ap, enum ECPGttype);
ind_value = va_arg(ap, void *); ind_value = va_arg(ap, void *);
ind_varcharsize = va_arg(ap, long); ind_varcharsize = va_arg(ap, long);
ind_size = va_arg(ap, long);
ind_arrsize = va_arg(ap, long); ind_arrsize = va_arg(ap, long);
ind_offset = va_arg(ap, long);
buff[0] = '\0'; buff[0] = '\0';
...@@ -211,7 +212,6 @@ ECPGdo(int lineno, char *query,...) ...@@ -211,7 +212,6 @@ ECPGdo(int lineno, char *query,...)
break; break;
case ECPGt_varchar: case ECPGt_varchar:
case ECPGt_varchar2:
{ {
struct ECPGgeneric_varchar *var = struct ECPGgeneric_varchar *var =
(struct ECPGgeneric_varchar *) value; (struct ECPGgeneric_varchar *) value;
...@@ -233,7 +233,7 @@ ECPGdo(int lineno, char *query,...) ...@@ -233,7 +233,7 @@ ECPGdo(int lineno, char *query,...)
default: default:
/* Not implemented yet */ /* Not implemented yet */
register_error(-1, "Unsupported type %s on line %d.", register_error(ECPG_UNSUPPORTED, "Unsupported type %s on line %d.",
ECPGtype_name(type), lineno); ECPGtype_name(type), lineno);
return false; return false;
break; break;
...@@ -257,7 +257,7 @@ ECPGdo(int lineno, char *query,...) ...@@ -257,7 +257,7 @@ ECPGdo(int lineno, char *query,...)
* We have an argument but we dont have the matched up string * We have an argument but we dont have the matched up string
* in the string * in the string
*/ */
register_error(-1, "Too many arguments line %d.", lineno); register_error(ECPG_TOO_MANY_ARGUMENTS, "Too many arguments line %d.", lineno);
return false; return false;
} }
else else
...@@ -293,17 +293,17 @@ ECPGdo(int lineno, char *query,...) ...@@ -293,17 +293,17 @@ ECPGdo(int lineno, char *query,...)
/* Check if there are unmatched things left. */ /* Check if there are unmatched things left. */
if (strstr(copiedquery, ";;") != NULL) if (strstr(copiedquery, ";;") != NULL)
{ {
register_error(-1, "Too few arguments line %d.", lineno); register_error(ECPG_TOO_FEW_ARGUMENTS, "Too few arguments line %d.", lineno);
return false; return false;
} }
/* Now the request is built. */ /* Now the request is built. */
if (committed) if (committed && !no_auto_trans)
{ {
if ((results = PQexec(simple_connection, "begin transaction")) == NULL) if ((results = PQexec(simple_connection, "begin transaction")) == NULL)
{ {
register_error(-1, "Error starting transaction line %d.", lineno); register_error(ECPG_TRANS, "Error starting transaction line %d.", lineno);
return false; return false;
} }
PQclear(results); PQclear(results);
...@@ -318,15 +318,15 @@ ECPGdo(int lineno, char *query,...) ...@@ -318,15 +318,15 @@ ECPGdo(int lineno, char *query,...)
{ {
ECPGlog("ECPGdo line %d: error: %s", lineno, ECPGlog("ECPGdo line %d: error: %s", lineno,
PQerrorMessage(simple_connection)); PQerrorMessage(simple_connection));
register_error(-1, "Postgres error: %s line %d.", register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
PQerrorMessage(simple_connection), lineno); PQerrorMessage(simple_connection), lineno);
} }
else else
{
sqlca.sqlerrd[2] = 0;
switch (PQresultStatus(results)) switch (PQresultStatus(results))
{ {
int m, int nfields, ntuples, act_tuple, act_field;
n,
x;
case PGRES_TUPLES_OK: case PGRES_TUPLES_OK:
...@@ -336,72 +336,67 @@ ECPGdo(int lineno, char *query,...) ...@@ -336,72 +336,67 @@ ECPGdo(int lineno, char *query,...)
* !! * !!
*/ */
m = PQnfields(results); nfields = PQnfields(results);
n = PQntuples(results); sqlca.sqlerrd[2] = ntuples = PQntuples(results);
status = true;
if (n < 1)
{
ECPGlog("ECPGdo line %d: Incorrect number of matches: %d\n",
lineno, n);
register_error(1, "Data not found line %d.", lineno);
break;
}
if (n > 1) if (ntuples < 1)
{ {
ECPGlog("ECPGdo line %d: Incorrect number of matches: %d\n", ECPGlog("ECPGdo line %d: Incorrect number of matches: %d\n",
lineno, n); lineno, ntuples);
register_error(-1, "To many matches line %d.", lineno); register_error(ECPG_NOT_FOUND, "Data not found line %d.", lineno);
status = false;
break; break;
} }
status = true; for (act_field = 0; act_field < nfields && status; act_field++)
for (x = 0; x < m && status; x++)
{ {
void *value = NULL, *ind_value; char *pval;
long varcharsize, ind_varcharsize;
long size, ind_size;
long arrsize, ind_arrsize;
enum ECPGttype ind_type;
char *pval = PQgetvalue(results, 0, x);
/*
* long int * res_int; char ** res_charstar; char *
* res_char; int res_len;
*/
char *scan_length; char *scan_length;
ECPGlog("ECPGdo line %d: RESULT: %s\n", lineno, pval ? pval : "");
/* Now the pval is a pointer to the value. */
/* We will have to decode the value */
type = va_arg(ap, enum ECPGttype); type = va_arg(ap, enum ECPGttype);
value = va_arg(ap, void *); value = va_arg(ap, void *);
varcharsize = va_arg(ap, long); varcharsize = va_arg(ap, long);
size = va_arg(ap, long);
arrsize = va_arg(ap, long); arrsize = va_arg(ap, long);
offset = va_arg(ap, long);
ind_type = va_arg(ap, enum ECPGttype); ind_type = va_arg(ap, enum ECPGttype);
ind_value = va_arg(ap, void *); ind_value = va_arg(ap, void *);
ind_varcharsize = va_arg(ap, long); ind_varcharsize = va_arg(ap, long);
ind_size = va_arg(ap, long);
ind_arrsize = va_arg(ap, long); ind_arrsize = va_arg(ap, long);
ind_offset = va_arg(ap, long);
/* if we don't have enough space, we cannot read all tuples */
if ((arrsize > 0 && ntuples > arrsize) || (ind_arrsize > 0 && ntuples > ind_arrsize))
{
ECPGlog("ECPGdo line %d: Incorrect number of matches: %d don't fit into array of %d\n",
lineno, ntuples, arrsize);
register_error(ECPG_TOO_MANY_MATCHES, "Too many matches line %d.", lineno);
status = false;
break;
}
for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
{
pval = PQgetvalue(results, act_tuple, act_field);
ECPGlog("ECPGdo line %d: RESULT: %s\n", lineno, pval ? pval : "");
/* Now the pval is a pointer to the value. */
/* We will have to decode the value */
/* check for null value and set indicator accordingly */ /* check for null value and set indicator accordingly */
switch (ind_type) switch (ind_type)
{ {
case ECPGt_short: case ECPGt_short:
case ECPGt_unsigned_short: case ECPGt_unsigned_short:
*(short *) ind_value = -PQgetisnull(results, 0, x); ((short *) ind_value)[act_tuple] = -PQgetisnull(results, act_tuple, act_field);
break; break;
case ECPGt_int: case ECPGt_int:
case ECPGt_unsigned_int: case ECPGt_unsigned_int:
*(int *) ind_value = -PQgetisnull(results, 0, x); ((int *) ind_value)[act_tuple] = -PQgetisnull(results, act_tuple, act_field);
break; break;
case ECPGt_long: case ECPGt_long:
case ECPGt_unsigned_long: case ECPGt_unsigned_long:
*(long *) ind_value = -PQgetisnull(results, 0, x); ((long *) ind_value)[act_tuple] = -PQgetisnull(results, act_tuple, act_field);
break; break;
default: default:
break; break;
...@@ -421,7 +416,7 @@ ECPGdo(int lineno, char *query,...) ...@@ -421,7 +416,7 @@ ECPGdo(int lineno, char *query,...)
res = strtol(pval, &scan_length, 10); res = strtol(pval, &scan_length, 10);
if (*scan_length != '\0') /* Garbage left */ if (*scan_length != '\0') /* Garbage left */
{ {
register_error(-1, "Not correctly formatted int type: %s line %d.", register_error(ECPG_INT_FORMAT, "Not correctly formatted int type: %s line %d.",
pval, lineno); pval, lineno);
status = false; status = false;
res = 0L; res = 0L;
...@@ -434,13 +429,13 @@ ECPGdo(int lineno, char *query,...) ...@@ -434,13 +429,13 @@ ECPGdo(int lineno, char *query,...)
switch (type) switch (type)
{ {
case ECPGt_short: case ECPGt_short:
*(short *) value = (short) res; ((short *) value)[act_tuple] = (short) res;
break; break;
case ECPGt_int: case ECPGt_int:
*(int *) value = (int) res; ((int *) value)[act_tuple] = (int) res;
break; break;
case ECPGt_long: case ECPGt_long:
*(long *) value = res; ((long *) value)[act_tuple] = res;
break; break;
default: default:
/* Cannot happen */ /* Cannot happen */
...@@ -456,7 +451,7 @@ ECPGdo(int lineno, char *query,...) ...@@ -456,7 +451,7 @@ ECPGdo(int lineno, char *query,...)
ures = strtoul(pval, &scan_length, 10); ures = strtoul(pval, &scan_length, 10);
if (*scan_length != '\0') /* Garbage left */ if (*scan_length != '\0') /* Garbage left */
{ {
register_error(-1, "Not correctly formatted unsigned type: %s line %d.", register_error(ECPG_UINT_FORMAT, "Not correctly formatted unsigned type: %s line %d.",
pval, lineno); pval, lineno);
status = false; status = false;
ures = 0L; ures = 0L;
...@@ -469,13 +464,13 @@ ECPGdo(int lineno, char *query,...) ...@@ -469,13 +464,13 @@ ECPGdo(int lineno, char *query,...)
switch (type) switch (type)
{ {
case ECPGt_unsigned_short: case ECPGt_unsigned_short:
*(unsigned short *) value = (unsigned short) ures; ((unsigned short *) value)[act_tuple] = (unsigned short) ures;
break; break;
case ECPGt_unsigned_int: case ECPGt_unsigned_int:
*(unsigned int *) value = (unsigned int) ures; ((unsigned int *) value)[act_tuple] = (unsigned int) ures;
break; break;
case ECPGt_unsigned_long: case ECPGt_unsigned_long:
*(unsigned long *) value = ures; ((unsigned long *) value)[act_tuple] = ures;
break; break;
default: default:
/* Cannot happen */ /* Cannot happen */
...@@ -491,7 +486,7 @@ ECPGdo(int lineno, char *query,...) ...@@ -491,7 +486,7 @@ ECPGdo(int lineno, char *query,...)
dres = strtod(pval, &scan_length); dres = strtod(pval, &scan_length);
if (*scan_length != '\0') /* Garbage left */ if (*scan_length != '\0') /* Garbage left */
{ {
register_error(-1, "Not correctly formatted floating point type: %s line %d.", register_error(ECPG_FLOAT_FORMAT, "Not correctly formatted floating point type: %s line %d.",
pval, lineno); pval, lineno);
status = false; status = false;
dres = 0.0; dres = 0.0;
...@@ -504,10 +499,10 @@ ECPGdo(int lineno, char *query,...) ...@@ -504,10 +499,10 @@ ECPGdo(int lineno, char *query,...)
switch (type) switch (type)
{ {
case ECPGt_float: case ECPGt_float:
*(float *) value = dres; ((float *) value)[act_tuple] = dres;
break; break;
case ECPGt_double: case ECPGt_double:
*(double *) value = dres; ((double *) value)[act_tuple] = dres;
break; break;
default: default:
/* Cannot happen */ /* Cannot happen */
...@@ -520,20 +515,20 @@ ECPGdo(int lineno, char *query,...) ...@@ -520,20 +515,20 @@ ECPGdo(int lineno, char *query,...)
{ {
if (pval[0] == 'f' && pval[1] == '\0') if (pval[0] == 'f' && pval[1] == '\0')
{ {
*(char *) value = false; ((char *) value)[act_tuple] = false;
break; break;
} }
else if (pval[0] == 't' && pval[1] == '\0') else if (pval[0] == 't' && pval[1] == '\0')
{ {
*(char *) value = true; ((char *) value)[act_tuple] = true;
break; break;
} }
} }
register_error(-1, "Unable to convert %s to bool on line %d.", register_error(ECPG_CONVERT_BOOL, "Unable to convert %s to bool on line %d.",
(pval ? pval : "NULL"), (pval ? pval : "NULL"),
lineno); lineno);
return false; status = false;
break; break;
case ECPGt_char: case ECPGt_char:
...@@ -542,12 +537,12 @@ ECPGdo(int lineno, char *query,...) ...@@ -542,12 +537,12 @@ ECPGdo(int lineno, char *query,...)
if (varcharsize == 0) if (varcharsize == 0)
{ {
/* char* */ /* char* */
strncpy((char *) value, pval, strlen(pval)); strncpy(((char **) value)[act_tuple], pval, strlen(pval));
((char *) value)[strlen(pval)] = '\0'; (((char **) value)[act_tuple])[strlen(pval)] = '\0';
} }
else else
{ {
strncpy((char *) value, pval, varcharsize); strncpy((char *) (value + offset * act_tuple), pval, varcharsize);
if (varcharsize < strlen(pval)) if (varcharsize < strlen(pval))
{ {
/* truncation */ /* truncation */
...@@ -555,15 +550,15 @@ ECPGdo(int lineno, char *query,...) ...@@ -555,15 +550,15 @@ ECPGdo(int lineno, char *query,...)
{ {
case ECPGt_short: case ECPGt_short:
case ECPGt_unsigned_short: case ECPGt_unsigned_short:
*(short *) ind_value = varcharsize; ((short *) ind_value)[act_tuple] = varcharsize;
break; break;
case ECPGt_int: case ECPGt_int:
case ECPGt_unsigned_int: case ECPGt_unsigned_int:
*(int *) ind_value = varcharsize; ((int *) ind_value)[act_tuple] = varcharsize;
break; break;
case ECPGt_long: case ECPGt_long:
case ECPGt_unsigned_long: case ECPGt_unsigned_long:
*(long *) ind_value = varcharsize; ((long *) ind_value)[act_tuple] = varcharsize;
break; break;
default: default:
break; break;
...@@ -576,26 +571,30 @@ ECPGdo(int lineno, char *query,...) ...@@ -576,26 +571,30 @@ ECPGdo(int lineno, char *query,...)
case ECPGt_varchar: case ECPGt_varchar:
{ {
struct ECPGgeneric_varchar *var = struct ECPGgeneric_varchar *var =
(struct ECPGgeneric_varchar *) value; (struct ECPGgeneric_varchar *) (value + offset * act_tuple);
if (varcharsize == 0)
strncpy(var->arr, pval, strlen(pval));
else
strncpy(var->arr, pval, varcharsize); strncpy(var->arr, pval, varcharsize);
var->len = strlen(pval); var->len = strlen(pval);
if (var->len > varcharsize) if (varcharsize > 0 && var->len > varcharsize)
{ {
/* truncation */ /* truncation */
switch (ind_type) switch (ind_type)
{ {
case ECPGt_short: case ECPGt_short:
case ECPGt_unsigned_short: case ECPGt_unsigned_short:
*(short *) ind_value = varcharsize; ((short *) ind_value)[act_tuple] = varcharsize;
break; break;
case ECPGt_int: case ECPGt_int:
case ECPGt_unsigned_int: case ECPGt_unsigned_int:
*(int *) ind_value = varcharsize; ((int *) ind_value)[act_tuple] = varcharsize;
break; break;
case ECPGt_long: case ECPGt_long:
case ECPGt_unsigned_long: case ECPGt_unsigned_long:
*(long *) ind_value = varcharsize; ((long *) ind_value)[act_tuple] = varcharsize;
break; break;
default: default:
break; break;
...@@ -608,34 +607,37 @@ ECPGdo(int lineno, char *query,...) ...@@ -608,34 +607,37 @@ ECPGdo(int lineno, char *query,...)
case ECPGt_EORT: case ECPGt_EORT:
ECPGlog("ECPGdo line %d: Too few arguments.\n", lineno); ECPGlog("ECPGdo line %d: Too few arguments.\n", lineno);
register_error(-1, "Too few arguments line %d.", lineno); register_error(ECPG_TOO_FEW_ARGUMENTS, "Too few arguments line %d.", lineno);
status = false; status = false;
break; break;
default: default:
register_error(-1, "Unsupported type %s on line %d.", register_error(ECPG_UNSUPPORTED, "Unsupported type %s on line %d.",
ECPGtype_name(type), lineno); ECPGtype_name(type), lineno);
return false; status = false;
break; break;
} }
} }
}
type = va_arg(ap, enum ECPGttype); type = va_arg(ap, enum ECPGttype);
if (status && type != ECPGt_EORT) if (status && type != ECPGt_EORT)
{ {
register_error(-1, "Too many arguments line %d.", lineno); register_error(ECPG_TOO_MANY_ARGUMENTS, "Too many arguments line %d.", lineno);
return false; status = false;
} }
PQclear(results); PQclear(results);
break; break;
case PGRES_EMPTY_QUERY: case PGRES_EMPTY_QUERY:
/* do nothing */ /* do nothing */
register_error(-1, "Empty query line %d.", lineno); register_error(ECPG_EMPTY, "Empty query line %d.", lineno);
break; break;
case PGRES_COMMAND_OK: case PGRES_COMMAND_OK:
status = true; status = true;
sqlca.sqlerrd[2] = atol(PQcmdTuples(results));
ECPGlog("TEST: %s\n", PQcmdTuples(results));
ECPGlog("ECPGdo line %d Ok: %s\n", lineno, PQcmdStatus(results)); ECPGlog("ECPGdo line %d Ok: %s\n", lineno, PQcmdStatus(results));
break; break;
case PGRES_NONFATAL_ERROR: case PGRES_NONFATAL_ERROR:
...@@ -643,8 +645,9 @@ ECPGdo(int lineno, char *query,...) ...@@ -643,8 +645,9 @@ ECPGdo(int lineno, char *query,...)
case PGRES_BAD_RESPONSE: case PGRES_BAD_RESPONSE:
ECPGlog("ECPGdo line %d: Error: %s", ECPGlog("ECPGdo line %d: Error: %s",
lineno, PQerrorMessage(simple_connection)); lineno, PQerrorMessage(simple_connection));
register_error(-1, "Error: %s line %d.", register_error(ECPG_PGSQL, "Error: %s line %d.",
PQerrorMessage(simple_connection), lineno); PQerrorMessage(simple_connection), lineno);
status = false;
break; break;
case PGRES_COPY_OUT: case PGRES_COPY_OUT:
ECPGlog("ECPGdo line %d: Got PGRES_COPY_OUT ... tossing.\n", lineno); ECPGlog("ECPGdo line %d: Got PGRES_COPY_OUT ... tossing.\n", lineno);
...@@ -657,9 +660,11 @@ ECPGdo(int lineno, char *query,...) ...@@ -657,9 +660,11 @@ ECPGdo(int lineno, char *query,...)
default: default:
ECPGlog("ECPGdo line %d: Got something else, postgres error.\n", ECPGlog("ECPGdo line %d: Got something else, postgres error.\n",
lineno); lineno);
register_error(-1, "Postgres error line %d.", lineno); register_error(ECPG_PGSQL, "Postgres error line %d.", lineno);
status = false;
break; break;
} }
}
/* check for asynchronous returns */ /* check for asynchronous returns */
notify = PQnotifies(simple_connection); notify = PQnotifies(simple_connection);
...@@ -683,10 +688,11 @@ ECPGtrans(int lineno, const char * transaction) ...@@ -683,10 +688,11 @@ ECPGtrans(int lineno, const char * transaction)
ECPGlog("ECPGtrans line %d action = %s\n", lineno, transaction); ECPGlog("ECPGtrans line %d action = %s\n", lineno, transaction);
if ((res = PQexec(simple_connection, transaction)) == NULL) if ((res = PQexec(simple_connection, transaction)) == NULL)
{ {
register_error(-1, "Error in transaction processing line %d.", lineno); register_error(ECPG_TRANS, "Error in transaction processing line %d.", lineno);
return (FALSE); return (FALSE);
} }
PQclear(res); PQclear(res);
if (strcmp(transaction, "commit") == 0 || strcmp(transaction, "rollback") == 0)
committed = 1; committed = 1;
return (TRUE); return (TRUE);
} }
...@@ -716,21 +722,25 @@ ECPGconnect(const char *dbname) ...@@ -716,21 +722,25 @@ ECPGconnect(const char *dbname)
if (PQstatus(simple_connection) == CONNECTION_BAD) if (PQstatus(simple_connection) == CONNECTION_BAD)
{ {
ECPGfinish(); ECPGfinish();
ECPGlog("ECPGconnect: could not open database %s\n", dbname); ECPGlog("connect: could not open database %s\n", dbname);
register_error(-1, "ECPGconnect: could not open database %s.", dbname); register_error(ECPG_CONNECT, "connect: could not open database %s.", dbname);
return false; return false;
} }
return true; return true;
} }
bool bool
ECPGstatus(void) ECPGdisconnect(const char *dbname)
{ {
return PQstatus(simple_connection) != CONNECTION_BAD; if (strlen(dbname) > 0 && strcmp(PQdb(simple_connection), dbname) != 0)
{
ECPGlog("disconnect: not connected to database %s\n", dbname);
register_error(ECPG_DISCONNECT, "disconnect: not connected to database %s.", dbname);
return false;
}
return ECPGfinish();
} }
bool bool
ECPGfinish(void) ECPGfinish(void)
{ {
......
...@@ -2,7 +2,7 @@ SRCDIR= ../../.. ...@@ -2,7 +2,7 @@ SRCDIR= ../../..
include $(SRCDIR)/Makefile.global include $(SRCDIR)/Makefile.global
MAJOR_VERSION=2 MAJOR_VERSION=2
MINOR_VERSION=2 MINOR_VERSION=3
PATCHLEVEL=0 PATCHLEVEL=0
CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \ CFLAGS+=-I../include -DMAJOR_VERSION=$(MAJOR_VERSION) \
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
*/ */
static ScanKeyword ScanKeywords[] = { static ScanKeyword ScanKeywords[] = {
/* name value */ /* name value */
{"VARCHAR", S_VARCHAR},
{"auto", S_AUTO}, {"auto", S_AUTO},
{"bool", S_BOOL}, {"bool", S_BOOL},
{"char", S_CHAR}, {"char", S_CHAR},
......
...@@ -22,12 +22,13 @@ extern char *optarg; ...@@ -22,12 +22,13 @@ extern char *optarg;
#include "extern.h" #include "extern.h"
struct _include_path *include_paths; struct _include_path *include_paths;
static int no_auto_trans = 0;
static void static void
usage(char *progname) usage(char *progname)
{ {
fprintf(stderr, "ecpg - the postgresql preprocessor, version: %d.%d.%d\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL); fprintf(stderr, "ecpg - the postgresql preprocessor, version: %d.%d.%d\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL);
fprintf(stderr, "Usage: %s: [-v] [-I include path] [ -o output file name] file1 [file2] ...\n", progname); fprintf(stderr, "Usage: %s: [-v] [-t] [-I include path] [ -o output file name] file1 [file2] ...\n", progname);
} }
static void static void
...@@ -51,7 +52,7 @@ main(int argc, char *const argv[]) ...@@ -51,7 +52,7 @@ main(int argc, char *const argv[])
add_include_path("/usr/local/include"); add_include_path("/usr/local/include");
add_include_path("."); add_include_path(".");
while ((c = getopt(argc, argv, "vo:I:")) != EOF) while ((c = getopt(argc, argv, "vo:I:t")) != EOF)
{ {
switch (c) switch (c)
{ {
...@@ -65,23 +66,26 @@ main(int argc, char *const argv[]) ...@@ -65,23 +66,26 @@ main(int argc, char *const argv[])
case 'I': case 'I':
add_include_path(optarg); add_include_path(optarg);
break; break;
case 't':
no_auto_trans = 1;
break;
case 'v': case 'v':
fprintf(stderr, "ecpg - the postgresql preprocessor, version: %d.%d.%d\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL); fprintf(stderr, "ecpg - the postgresql preprocessor, version: %d.%d.%d\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL);
fprintf(stderr, "exec sql include ... search starts here:\n"); fprintf(stderr, "exec sql include ... search starts here:\n");
for (ip = include_paths; ip != NULL; ip = ip->next) for (ip = include_paths; ip != NULL; ip = ip->next)
fprintf(stderr, " %s\n", ip->path); fprintf(stderr, " %s\n", ip->path);
fprintf(stderr, "End of search list.\n"); fprintf(stderr, "End of search list.\n");
return (0); return (OK);
default: default:
usage(argv[0]); usage(argv[0]);
return (1); return (ILLEGAL_OPTION);
} }
} }
if (optind >= argc) /* no files specified */ if (optind >= argc) /* no files specified */
{ {
usage(argv[0]); usage(argv[0]);
return(1); return(ILLEGAL_OPTION);
} }
else else
{ {
...@@ -151,8 +155,8 @@ main(int argc, char *const argv[]) ...@@ -151,8 +155,8 @@ main(int argc, char *const argv[])
cur = NULL; cur = NULL;
/* we need two includes */ /* we need two includes and a constant */
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); 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\nconst int no_auto_trans = %d;\n\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL, no_auto_trans);
/* and parse the source */ /* and parse the source */
yyparse(); yyparse();
...@@ -169,5 +173,5 @@ main(int argc, char *const argv[]) ...@@ -169,5 +173,5 @@ main(int argc, char *const argv[])
free(input_filename); free(input_filename);
} }
} }
return (0); return (OK);
} }
...@@ -21,15 +21,18 @@ ...@@ -21,15 +21,18 @@
*/ */
static ScanKeyword ScanKeywords[] = { static ScanKeyword ScanKeywords[] = {
/* name value */ /* name value */
{"break", SQL_BREAK},
{"call", SQL_CALL}, {"call", SQL_CALL},
{"connect", SQL_CONNECT}, {"connect", SQL_CONNECT},
{"continue", SQL_CONTINUE}, {"continue", SQL_CONTINUE},
{"disconnect", SQL_DISCONNECT},
{"found", SQL_FOUND}, {"found", SQL_FOUND},
{"go", SQL_GO}, {"go", SQL_GO},
{"goto", SQL_GOTO}, {"goto", SQL_GOTO},
{"immediate", SQL_IMMEDIATE}, {"immediate", SQL_IMMEDIATE},
{"indicator", SQL_INDICATOR}, {"indicator", SQL_INDICATOR},
{"open", SQL_OPEN}, {"open", SQL_OPEN},
{"release", SQL_RELEASE},
{"section", SQL_SECTION}, {"section", SQL_SECTION},
{"sqlerror", SQL_SQLERROR}, {"sqlerror", SQL_SQLERROR},
{"sqlprint", SQL_SQLPRINT}, {"sqlprint", SQL_SQLPRINT},
......
...@@ -43,3 +43,11 @@ extern void *mm_alloc(size_t), *mm_realloc(void *, size_t); ...@@ -43,3 +43,11 @@ extern void *mm_alloc(size_t), *mm_realloc(void *, size_t);
ScanKeyword * ScanECPGKeywordLookup(char *); ScanKeyword * ScanECPGKeywordLookup(char *);
ScanKeyword * ScanCKeywordLookup(char *); ScanKeyword * ScanCKeywordLookup(char *);
extern void yyerror(char *); extern void yyerror(char *);
/* return codes */
#define OK 0
#define NO_INCLUDE_FILE 1
#define PARSE_ERROR 2
#define OUT_OF_MEMORY 3
#define ILLEGAL_OPTION 4
...@@ -39,6 +39,7 @@ int debugging = 0; ...@@ -39,6 +39,7 @@ int debugging = 0;
extern YYSTYPE yylval; extern YYSTYPE yylval;
int llen; int llen;
char literal[MAX_PARSE_BUFFER]; char literal[MAX_PARSE_BUFFER];
int before_comment;
struct _yy_buffer { YY_BUFFER_STATE buffer; struct _yy_buffer { YY_BUFFER_STATE buffer;
long lineno; long lineno;
...@@ -153,7 +154,7 @@ space [ \t\n\f] ...@@ -153,7 +154,7 @@ space [ \t\n\f]
other . other .
/* some stuff needed for ecpg */ /* some stuff needed for ecpg */
ccomment \/\*([^*]|\*[^/]|\*\*[^/])*\*\/ ccomment "//".*\n
exec [eE][xX][eE][cC] exec [eE][xX][eE][cC]
include [iI][nN][cC][lL][uU][dD][eE] include [iI][nN][cC][lL][uU][dD][eE]
sql [sS][qQ][lL] sql [sS][qQ][lL]
...@@ -174,12 +175,18 @@ sql [sS][qQ][lL] ...@@ -174,12 +175,18 @@ sql [sS][qQ][lL]
%% %%
<SQL>{comment} { /* ignore */ } <SQL>{comment} { /* ignore */ }
<SQL>{xcline} { /* ignore */ } {xcline} { /* ignore */ }
<xc>{xcstar} | <xc>{xcstar} { /* ignore */ }
<SQL>{xcstart} { BEGIN(xc); } {xcstart} {
fprintf(stderr,"ys = %d %d\n", YYSTATE, before_comment);
before_comment = YYSTATE;
BEGIN(xc);
fprintf(stderr,"ys = %d %d\n", YYSTATE,
before_comment);
}
<xc>{xcstop} { BEGIN(SQL); } <xc>{xcstop} { fprintf(stderr,"ys = %d %d\n", YYSTATE, before_comment);BEGIN(before_comment); }
<xc>{xcinside} { /* ignore */ } <xc>{xcinside} { /* ignore */ }
...@@ -306,7 +313,6 @@ sql [sS][qQ][lL] ...@@ -306,7 +313,6 @@ sql [sS][qQ][lL]
return (yytext[0]); return (yytext[0]);
} }
<SQL>{self} { return (yytext[0]); } <SQL>{self} { return (yytext[0]); }
<SQL>"->" { return S_STRUCTPOINTER; }
<SQL>{operator}/-[\.0-9] { <SQL>{operator}/-[\.0-9] {
yylval.str = strdup((char*)yytext); yylval.str = strdup((char*)yytext);
return (Op); return (Op);
...@@ -402,7 +408,7 @@ sql [sS][qQ][lL] ...@@ -402,7 +408,7 @@ sql [sS][qQ][lL]
return (FCONST); return (FCONST);
} }
<SQL>:{identifier} { <SQL>:{identifier}(("->"|\.){identifier})* {
yylval.str = strdup((char*)yytext+1); yylval.str = strdup((char*)yytext+1);
return(CVARIABLE); return(CVARIABLE);
} }
...@@ -436,6 +442,7 @@ sql [sS][qQ][lL] ...@@ -436,6 +442,7 @@ sql [sS][qQ][lL]
<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>{identifier} { <C>{identifier} {
ScanKeyword *keyword; ScanKeyword *keyword;
...@@ -501,7 +508,7 @@ sql [sS][qQ][lL] ...@@ -501,7 +508,7 @@ sql [sS][qQ][lL]
if (!yyin) if (!yyin)
{ {
fprintf(stderr, "Error: Cannot open include file %s in line %d\n", yytext, yylineno); fprintf(stderr, "Error: Cannot open include file %s in line %d\n", yytext, yylineno);
exit(1); exit(NO_INCLUDE_FILE);
} }
input_filename = strdup(inc_file); input_filename = strdup(inc_file);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -14,7 +14,7 @@ mm_alloc(size_t size) ...@@ -14,7 +14,7 @@ mm_alloc(size_t size)
if (ptr == NULL) if (ptr == NULL)
{ {
fprintf(stderr, "Out of memory\n"); fprintf(stderr, "Out of memory\n");
exit(1); exit(OUT_OF_MEMORY);
} }
return (ptr); return (ptr);
...@@ -29,15 +29,27 @@ mm_realloc(void *ptr, size_t size) ...@@ -29,15 +29,27 @@ mm_realloc(void *ptr, size_t size)
if (ptr == NULL) if (ptr == NULL)
{ {
fprintf(stderr, "Out of memory\n"); fprintf(stderr, "Out of memory\n");
exit(1); exit(OUT_OF_MEMORY);
} }
return (ptr); return (ptr);
} }
/* Constructors /* duplicate memberlist */
Yes, I mostly write c++-code static struct ECPGstruct_member *
*/ struct_member_dup(struct ECPGstruct_member * rm)
{
struct ECPGstruct_member *new = NULL;
while (rm)
{
ECPGmake_struct_member(rm->name, rm->typ, &new);
rm = rm->next;
}
return(new);
}
/* The NAME argument is copied. The type argument is preserved as a pointer. */ /* The NAME argument is copied. The type argument is preserved as a pointer. */
struct ECPGstruct_member * struct ECPGstruct_member *
...@@ -72,22 +84,11 @@ ECPGmake_simple_type(enum ECPGttype typ, long siz) ...@@ -72,22 +84,11 @@ ECPGmake_simple_type(enum ECPGttype typ, long siz)
return ne; return ne;
} }
struct ECPGtype *
ECPGmake_varchar_type(enum ECPGttype typ, long siz)
{
struct ECPGtype *ne = ECPGmake_simple_type(typ, 1);
ne->size = siz;
return ne;
}
struct ECPGtype * struct ECPGtype *
ECPGmake_array_type(struct ECPGtype * typ, long siz) ECPGmake_array_type(struct ECPGtype * typ, long siz)
{ {
struct ECPGtype *ne = ECPGmake_simple_type(ECPGt_array, siz); struct ECPGtype *ne = ECPGmake_simple_type(ECPGt_array, siz);
ne->size = siz;
ne->u.element = typ; ne->u.element = typ;
return ne; return ne;
...@@ -98,11 +99,57 @@ ECPGmake_struct_type(struct ECPGstruct_member * rm) ...@@ -98,11 +99,57 @@ 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 = rm; ne->u.members = struct_member_dup(rm);
return ne; return ne;
} }
static const char *get_type(enum ECPGttype typ)
{
switch (typ)
{
case ECPGt_char:
return("ECPGt_char");
break;
case ECPGt_unsigned_char:
return("ECPGt_unsigned_char");
break;
case ECPGt_short:
return("ECPGt_short");
break;
case ECPGt_unsigned_short:
return("ECPGt_unsigned_short");
break;
case ECPGt_int:
return("ECPGt_int");
break;
case ECPGt_unsigned_int:
return("ECPGt_unsigned_int");
break;
case ECPGt_long:
return("ECPGt_long");
break;
case ECPGt_unsigned_long:
return("ECPGt_unsigned_int");
break;
case ECPGt_float:
return("ECPGt_float");
break;
case ECPGt_double:
return("ECPGt_double");
break;
case ECPGt_bool:
return("ECPGt_bool");
break;
case ECPGt_varchar:
return("ECPGt_varchar");
case ECPGt_NO_INDICATOR: /* no indicator */
return("ECPGt_NO_INDICATOR");
break;
default:
abort();
}
}
/* Dump a type. /* Dump a type.
The type is dumped as: The type is dumped as:
...@@ -136,41 +183,40 @@ ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *in ...@@ -136,41 +183,40 @@ ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *in
ind_name = "no_indicator"; ind_name = "no_indicator";
} }
if (IS_SIMPLE_TYPE(typ->typ)) switch(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)
{ {
case ECPGt_array:
if (IS_SIMPLE_TYPE(typ->u.element->typ)) if (IS_SIMPLE_TYPE(typ->u.element->typ))
{ {
ECPGdump_a_simple(o, name, typ->u.element->typ, ECPGdump_a_simple(o, name, typ->u.element->typ,
typ->u.element->size, typ->size, 0, prefix); typ->u.element->size, typ->size, NULL, prefix);
if (ind_typ == &ecpg_no_indicator)
ECPGdump_a_simple(o, ind_name, ind_typ->typ, ind_typ->size, -1, NULL, ind_prefix);
else
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, 0, 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)
{ {
abort(); /* 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, 0, 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
{ {
abort(); yyerror("Internal error: unknown datatype, pleqase inform pgsql-bugs@postgresql.org");
}
}
else if (typ->typ == ECPGt_struct)
{
ECPGdump_a_struct(o, name, ind_name, 0, typ, ind_typ, 0, prefix, ind_prefix);
} }
else break;
{ case ECPGt_struct:
abort(); ECPGdump_a_struct(o, name, ind_name, 1, typ, ind_typ, NULL, prefix, ind_prefix);
break;
default:
ECPGdump_a_simple(o, name, typ->typ, typ->size, -1, NULL, prefix);
ECPGdump_a_simple(o, ind_name, ind_typ->typ, ind_typ->size, -1, NULL, ind_prefix);
break;
} }
} }
...@@ -180,86 +226,48 @@ ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *in ...@@ -180,86 +226,48 @@ ECPGdump_a_type(FILE *o, const char *name, struct ECPGtype * typ, const char *in
void void
ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ, ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype typ,
long varcharsize, long varcharsize,
long arrsiz, long arrsize,
const char *siz, const char *siz,
const char *prefix const char *prefix
) )
{ {
switch (typ) if (typ == ECPGt_NO_INDICATOR)
fprintf(o, "\n\tECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ");
else
{ {
case ECPGt_char: char *variable = (char *)mm_alloc(strlen(name) + ((prefix == NULL) ? 0 : strlen(prefix)) + 4);
if (varcharsize == 0) /* pointer */ char *offset = (char *)mm_alloc(strlen(name) + strlen("sizeof(struct varchar_)") + 1);
fprintf(o, "\n\tECPGt_char,(%s%s),%ldL,%ldL,%s, ", prefix ? prefix : "", name, varcharsize, arrsiz,
siz == NULL ? "sizeof(char)" : siz); if (varcharsize == 0 || arrsize >= 0)
sprintf(variable, "(%s%s)", prefix ? prefix : "", name);
else else
fprintf(o, "\n\tECPGt_char,&(%s%s),%ldL,%ldL,%s, ", prefix ? prefix : "", name, varcharsize, arrsiz, sprintf(variable, "&(%s%s)", prefix ? prefix : "", name);
siz == NULL ? "sizeof(char)" : siz);
switch (typ)
{
case ECPGt_varchar:
sprintf(offset, "sizeof(struct varchar_%s)", name);
break; break;
case ECPGt_char:
case ECPGt_unsigned_char: case ECPGt_unsigned_char:
if (varcharsize == 0) /* pointer */ sprintf(offset, "%ld*sizeof(char)", varcharsize);
fprintf(o, "\n\tECPGt_unsigned_char,(%s%s),%ldL,%ldL,%s, ", prefix ? prefix : "", name, varcharsize, arrsiz,
siz == NULL ? "sizeof(char)" : siz);
else
fprintf(o, "\n\tECPGt_unsigned_char,&(%s%s),%ldL,%ldL,%s, ", prefix ? prefix : "", name, varcharsize, arrsiz,
siz == NULL ? "sizeof(unsigned char)" : siz);
break;
case ECPGt_short:
fprintf(o, "\n\tECPGt_short,&(%s%s),0L,%ldL,%s, ", prefix ? prefix : "", name, arrsiz,
siz == NULL ? "sizeof(short)" : siz);
break;
case ECPGt_unsigned_short:
fprintf(o,
"\n\tECPGt_unsigned_short,&(%s%s),0L,%ldL,%s, ", prefix ? prefix : "", name, arrsiz,
siz == NULL ? "sizeof(unsigned short)" : siz);
break;
case ECPGt_int:
fprintf(o, "\n\tECPGt_int,&(%s%s),0L,%ldL,%s, ", prefix ? prefix : "", name, arrsiz,
siz == NULL ? "sizeof(int)" : siz);
break;
case ECPGt_unsigned_int:
fprintf(o, "\n\tECPGt_unsigned_int,&(%s%s),0L,%ldL,%s, ", prefix ? prefix : "", name, arrsiz,
siz == NULL ? "sizeof(unsigned int)" : siz);
break; break;
case ECPGt_long: default:
fprintf(o, "\n\tECPGt_long,&(%s%s),0L,%ldL,%s, ", prefix ? prefix : "", name, arrsiz, sprintf(offset, "sizeof(%s)", ECPGtype_name(typ));
siz == NULL ? "sizeof(long)" : siz);
break;
case ECPGt_unsigned_long:
fprintf(o, "\n\tECPGt_unsigned_int,&(%s%s),0L,%ldL,%s, ", prefix ? prefix : "", name, arrsiz,
siz == NULL ? "sizeof(unsigned int)" : siz);
break;
case ECPGt_float:
fprintf(o, "\n\tECPGt_float,&(%s%s),0L,%ldL,%s, ", prefix ? prefix : "", name, arrsiz,
siz == NULL ? "sizeof(float)" : siz);
break;
case ECPGt_double:
fprintf(o, "\n\tECPGt_double,&(%s%s),0L,%ldL,%s, ", prefix ? prefix : "", name, arrsiz,
siz == NULL ? "sizeof(double)" : siz);
break;
case ECPGt_bool:
fprintf(o, "\n\tECPGt_bool,&(%s%s),0L,%ldL,%s, ", prefix ? prefix : "", name, arrsiz,
siz == NULL ? "sizeof(bool)" : siz);
break; break;
case ECPGt_varchar: }
case ECPGt_varchar2:
if (arrsize < 0)
arrsize = 1;
if (siz == NULL) if (siz == NULL)
fprintf(o, "\n\tECPGt_varchar,&(%s%s),%ldL,%ldL,sizeof(struct varchar_%s), ", fprintf(o, "\n\t%s,%s,%ldL,%ldL,%s, ", get_type(typ), variable, varcharsize, arrsize, offset);
prefix ? prefix : "", name,
varcharsize,
arrsiz, name);
else else
fprintf(o, "\n\tECPGt_varchar,&(%s%s),%ldL,%ldL,%s, ", fprintf(o, "\n\t%s,%s,%ldL,%ldL,%s, ", get_type(typ), variable, varcharsize, arrsize, siz);
prefix ? prefix : "", name,
varcharsize,
arrsiz, siz);
break;
case ECPGt_NO_INDICATOR: /* no indicator */
fprintf(o, "\n\tECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ");
break;
default:
abort();
}
free(variable);
free(offset);
}
} }
...@@ -302,12 +310,7 @@ ECPGdump_a_struct(FILE *o, const char *name, const char * ind_name, long arrsiz, ...@@ -302,12 +310,7 @@ ECPGdump_a_struct(FILE *o, const char *name, const char * ind_name, long arrsiz,
} }
} }
void
/* Freeing is not really that important. Since we throw away the process
anyway. Lets implement that last! */
/* won't work anymore because a list of members may appear in several locations */
/*void
ECPGfree_struct_member(struct ECPGstruct_member * rm) ECPGfree_struct_member(struct ECPGstruct_member * rm)
{ {
while (rm) while (rm)
...@@ -318,7 +321,7 @@ ECPGfree_struct_member(struct ECPGstruct_member * rm) ...@@ -318,7 +321,7 @@ ECPGfree_struct_member(struct ECPGstruct_member * rm)
free(p->name); free(p->name);
free(p); free(p);
} }
}*/ }
void void
ECPGfree_type(struct ECPGtype * typ) ECPGfree_type(struct ECPGtype * typ)
...@@ -332,16 +335,18 @@ ECPGfree_type(struct ECPGtype * typ) ...@@ -332,16 +335,18 @@ ECPGfree_type(struct ECPGtype * typ)
else if (typ->u.element->typ == ECPGt_array) else if (typ->u.element->typ == ECPGt_array)
abort(); /* Array of array, */ abort(); /* 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. */
ECPGfree_struct_member(typ->u.members);
free(typ->u.members); free(typ->u.members);
/* ECPGfree_struct_member(typ->u.members);*/ }
else else
abort(); abort();
} }
else if (typ->typ == ECPGt_struct) else if (typ->typ == ECPGt_struct)
{ {
ECPGfree_struct_member(typ->u.members);
free(typ->u.members); free(typ->u.members);
/* ECPGfree_struct_member(typ->u.members);*/
} }
else else
{ {
......
...@@ -77,6 +77,7 @@ struct when ...@@ -77,6 +77,7 @@ struct when
struct index struct index
{ {
int ival; int index1;
int index2;
char *str; char *str;
}; };
all: test2 perftest all: test1 test2 perftest
LDFLAGS=-g -I ../include -I ../../libpq -L../lib -lecpg -L../../libpq -lpq -lcrypt --static
test1: test1.c
test1.c: test1.pgc
../preproc/ecpg $?
test2: test2.c test2: test2.c
gcc -g -I ../include -I ../../libpq -o test2 test2.c -L../lib -lecpg -L../../libpq -lpq -lcrypt --static
test2.c: test2.pgc test2.c: test2.pgc
../preproc/ecpg test2.pgc ../preproc/ecpg $?
perftest: perftest.c perftest: perftest.c
gcc -g -I ../include -I ../../libpq -o perftest perftest.c -L../lib -lecpg -L../../libpq -lpq -lcrypt --static perftest.c:perftest.pgc
perftest.c: perftest.pgc ../preproc/ecpg $?
../preproc/ecpg perftest.pgc
clean: clean:
/bin/rm test2 test2.c perftest perftest.c log /bin/rm test1 test2 perftest *.c log
/* These two include files are added by the preprocessor */
#include <ecpgtype.h>
#include <ecpglib.h>
/* exec sql begin declare section */
/* VARSIZE */ struct varchar_uid
{
int len;
char arr[200];
} uid;
struct varchar_name
{
int len;
char arr[200];
} name;
short value;
/* exec sql end declare section */
#include "sqlca.h"
#define DBCP(x,y) strcpy(x.arr,y);x.len = strlen(x.arr)
#define LENFIX(x) x.len=strlen(x.arr)
#define STRFIX(x) x.arr[x.len]='\0'
#define SQLCODE sqlca.sqlcode
void
db_error(char *msg)
{
sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml] = '\0';
printf("%s: db error %s\n", msg, sqlca.sqlerrm.sqlerrmc);
exit(1);
}
int
main()
{
strcpy(uid.arr, "test/test");
LENFIX(uid);
ECPGconnect("kom");
if (SQLCODE)
db_error("connect");
strcpy(name.arr, "opt1");
LENFIX(name);
ECPGdo(__LINE__, "declare cur cursor for select name , value from pace_test ", ECPGt_EOIT, ECPGt_EORT);
if (SQLCODE)
db_error("declare");
if (SQLCODE)
db_error("open");
while (1)
{
ECPGdo(__LINE__, "fetch in cur ", ECPGt_EOIT, ECPGt_varchar, &name, 200, 0, sizeof(struct varchar_name), ECPGt_short, &value, 0, 0, sizeof(short), ECPGt_EORT);
if (SQLCODE)
break;
STRFIX(name);
printf("%s\t%d\n", name.arr, value);
}
if (SQLCODE < 0)
db_error("fetch");
ECPGdo(__LINE__, "close cur ", ECPGt_EOIT, ECPGt_EORT);
if (SQLCODE)
db_error("close");
ECPGcommit(__LINE__);
if (SQLCODE)
db_error("commit");
return (0);
}
exec sql include sqlca; exec sql include sqlca;
exec sql whenever not found do set_not_found(); exec sql whenever not found do break;
exec sql whenever sqlerror sqlprint; exec sql whenever sqlerror sqlprint;
...@@ -121,5 +121,7 @@ exec sql end declare section; ...@@ -121,5 +121,7 @@ exec sql end declare section;
exec sql commit; exec sql commit;
exec sql disconnect;
return (0); return (0);
} }
exec sql begin declare section;
VARCHAR uid[200 /* VARSIZE */ ];
varchar name[200];
short value;
exec sql end declare section;
exec sql include sqlca;
#define DBCP(x,y) strcpy(x.arr,y);x.len = strlen(x.arr)
#define LENFIX(x) x.len=strlen(x.arr)
#define STRFIX(x) x.arr[x.len]='\0'
#define SQLCODE sqlca.sqlcode
void
db_error(char *msg)
{
sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml] = '\0';
printf("%s: db error %s\n", msg, sqlca.sqlerrm.sqlerrmc);
exit(1);
}
int
main()
{
strcpy(uid.arr, "test/test");
LENFIX(uid);
exec sql connect 'kom';
if (SQLCODE)
db_error("connect");
strcpy(name.arr, "opt1");
LENFIX(name);
exec sql declare cur cursor for
select name,
value from pace_test;
if (SQLCODE)
db_error("declare");
exec sql open cur;
if (SQLCODE)
db_error("open");
while (1)
{
exec sql fetch in cur into:name,
: value;
if (SQLCODE)
break;
STRFIX(name);
printf("%s\t%d\n", name.arr, value);
}
if (SQLCODE < 0)
db_error("fetch");
exec sql close cur;
if (SQLCODE)
db_error("close");
exec sql commit;
if (SQLCODE)
db_error("commit");
return (0);
}
#include <stdio.h>
exec sql whenever sqlerror sqlprint;
exec sql include sqlca;
int
main ()
{
exec sql begin declare section;
int amount[5];
char name[5][8];
exec sql end declare section;
char msg[128], command[128];
FILE *dbgs;
int i,j;
if ((dbgs = fopen("log", "w")) != NULL)
ECPGdebug(1, dbgs);
strcpy(msg, "connect");
exec sql connect mm;
strcpy(msg, "create");
exec sql create table test(name char(8), amount int);
strcpy(msg, "execute insert 1");
sprintf(command, "insert into test(name, amount) values ('foobar', 1)");
exec sql execute immediate :command;
strcpy(msg, "excute insert 2");
sprintf(command, "insert into test(name, amount) select name, amount+1 from test");
exec sql execute immediate :command;
strcpy(msg, "excute insert 3");
sprintf(command, "insert into test(name, amount) select name, amount+10 from test");
exec sql execute immediate :command;
printf("Inserted %d tuples via execute immediate\n", sqlca.sqlerrd[2]);
strcpy(msg, "commit");
exec sql commit;
strcpy(msg, "select");
exec sql select name, amount into :name, :amount from test;
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]);
strcpy(msg, "drop");
exec sql drop table test;
strcpy(msg, "commit");
exec sql commit;
strcpy(msg, "disconnect");
exec sql disconnect;
if (dbgs != NULL)
fclose(dbgs);
return (0);
}
...@@ -2,13 +2,6 @@ ...@@ -2,13 +2,6 @@
exec sql include header_test; exec sql include header_test;
static int not_found = 0;
static void
set_not_found(void)
{
not_found = 1;
}
int int
main () main ()
{ {
...@@ -43,10 +36,7 @@ exec sql end declare section; ...@@ -43,10 +36,7 @@ exec sql end declare section;
exec sql insert into meskes(name, born, age, married) values ('Michael', 19660117, 32, '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 ('Carsten', 19910103, 7);
exec sql insert into meskes(name, born, age) values ('Marc', 19930907, 4); 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"); strcpy(msg, "commit");
exec sql commit; exec sql commit;
...@@ -58,10 +48,9 @@ exec sql end declare section; ...@@ -58,10 +48,9 @@ exec sql end declare section;
strcpy(msg, "open"); strcpy(msg, "open");
exec sql open cur; exec sql open cur;
while (not_found == 0) { while (1) {
strcpy(msg, "fetch"); strcpy(msg, "fetch");
exec sql fetch cur into :personal:ind_personal, :married:ind_married; exec sql fetch cur into :personal:ind_personal, :married:ind_married;
if (not_found == 0)
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 was born %d (age = %d) %s%s\n", personal.name.arr, personal.birth.born, personal.birth.age, ind_married ? "" : "and married ", ind_married ? "" : married);
} }
...@@ -74,6 +63,9 @@ exec sql end declare section; ...@@ -74,6 +63,9 @@ exec sql end declare section;
strcpy(msg, "commit"); strcpy(msg, "commit");
exec sql commit; exec sql commit;
strcpy(msg, "disconnect");
exec sql disconnect;
if (dbgs != NULL) if (dbgs != NULL)
fclose(dbgs); fclose(dbgs);
......
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