1
0
mirror of https://github.com/postgres/postgres.git synced 2025-05-11 05:41:32 +03:00

This one cleans the cursor problems ecpg had so far. It is now able

to understand cursors with variables.

Michael
This commit is contained in:
Bruce Momjian 1998-08-11 18:33:37 +00:00
parent 79c8d2e3a0
commit c6dd1e63a9
10 changed files with 334 additions and 232 deletions

View File

@ -270,3 +270,10 @@ Mon Aug 3 17:23:18 CEST 1998
- Fixed cursor handling - Fixed cursor handling
- Set version to 2.3.5 - Set version to 2.3.5
- Set library version to 2.4 - Set library version to 2.4
Fri Aug 7 12:38:50 CEST 1998
- Fixed cursor handling once again
- Added support for variables in cursor
- Set version to 2.3.6
- Set library version to 2.5

View File

@ -1,9 +1,7 @@
What happens to a cursor declaration with variables?
The complete structure definition has to be listed inside the declare The complete structure definition has to be listed inside the declare
section of the structure variable for ecpg to be able to understand it. section of the structure variable for ecpg to be able to understand it.
Variable type bool has to be checked. I never used it so far. Variable type bool has to be tested. I never used it so far.
The error message for "no data" in an exec sql insert select from statement The error message for "no data" in an exec sql insert select from statement
has to be 100. has to be 100.

View File

@ -13,9 +13,6 @@ bool ECPGdisconnect(int, const char *);
void ECPGlog(const char *format,...); void ECPGlog(const char *format,...);
bool ECPGdeclare(int, const char *, char *);
bool ECPGopen(int, const char *);
#ifdef LIBPQ_FE_H #ifdef LIBPQ_FE_H
bool ECPGsetdb(PGconn *); bool ECPGsetdb(PGconn *);

View File

@ -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=4 SO_MINOR_VERSION=5
PORTNAME=@PORTNAME@ PORTNAME=@PORTNAME@

View File

@ -33,6 +33,29 @@ static struct connection
struct connection *next; struct connection *next;
} *all_connections = NULL, *actual_connection = NULL; } *all_connections = NULL, *actual_connection = NULL;
struct variable
{
enum ECPGttype type;
void *value;
long varcharsize;
long arrsize;
long offset;
enum ECPGttype ind_type;
void *ind_value;
long ind_varcharsize;
long ind_arrsize;
long ind_offset;
struct variable *next;
};
struct statement
{
int lineno;
char *command;
struct variable *inlist;
struct variable *outlist;
};
static int simple_debug = 0; static int simple_debug = 0;
static FILE *debugstream = NULL; static FILE *debugstream = NULL;
static int committed = true; static int committed = true;
@ -116,27 +139,87 @@ ECPGfinish(struct connection *act)
ECPGlog("ECPGfinish: called an extra time.\n"); ECPGlog("ECPGfinish: called an extra time.\n");
} }
bool /* create a list of variables */
ECPGdo(int lineno, char *query,...) static bool
create_statement(int lineno, struct statement **stmt, char *query, va_list ap)
{
struct variable **list = &((*stmt)->inlist);
enum ECPGttype type;
*stmt = calloc(sizeof(struct statement), 1);
if (!*stmt)
{
ECPGfinish(actual_connection);
ECPGlog("out of memory\n");
register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
return false;
}
(*stmt)->command = query;
(*stmt)->lineno = lineno;
list = &((*stmt)->inlist);
type = va_arg(ap, enum ECPGttype);
while (type != ECPGt_EORT)
{
if (type == ECPGt_EOIT)
{
list = &((*stmt)->outlist);
}
else
{
struct variable *var, *ptr;
var = malloc(sizeof(struct variable));
if (!var)
{
ECPGfinish(actual_connection);
ECPGlog("out of memory\n");
register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
return false;
}
var->type = type;
var->value = va_arg(ap, void *);
var->varcharsize = va_arg(ap, long);
var->arrsize = va_arg(ap, long);
var->offset = va_arg(ap, long);
var->ind_type = va_arg(ap, enum ECPGttype);
var->ind_value = va_arg(ap, void *);
var->ind_varcharsize = va_arg(ap, long);
var->ind_arrsize = va_arg(ap, long);
var->ind_offset = va_arg(ap, long);
var->next = NULL;
for (ptr = *list; ptr && ptr->next; ptr=ptr->next);
if (ptr == NULL)
*list = var;
else
ptr->next = var;
}
type = va_arg(ap, enum ECPGttype);
}
return(true);
}
static bool
ECPGexecute(struct statement *stmt)
{ {
va_list ap;
bool status = false; bool status = false;
char *copiedquery; char *copiedquery;
PGresult *results; PGresult *results;
PGnotify *notify; PGnotify *notify;
enum ECPGttype type; struct variable *var;
void *value = NULL, *ind_value;
long varcharsize, ind_varcharsize;
long arrsize, ind_arrsize;
long offset, ind_offset;
enum ECPGttype ind_type;
memset((char *) &sqlca, 0, sizeof (sqlca)); memset((char *) &sqlca, 0, sizeof (sqlca));
va_start(ap, query);
copiedquery = strdup(query); copiedquery = strdup(stmt->command);
type = va_arg(ap, enum ECPGttype);
/* /*
* Now, if the type is one of the fill in types then we take the * Now, if the type is one of the fill in types then we take the
@ -144,7 +227,8 @@ ECPGdo(int lineno, char *query,...)
* Then if there are any more fill in types we fill in at the next and * Then if there are any more fill in types we fill in at the next and
* so on. * so on.
*/ */
while (type != ECPGt_EOIT) var = stmt->inlist;
while (var)
{ {
char *newcopy; char *newcopy;
char *mallocedval = NULL; char *mallocedval = NULL;
@ -158,34 +242,24 @@ ECPGdo(int lineno, char *query,...)
* think). * think).
*/ */
value = va_arg(ap, void *);
varcharsize = va_arg(ap, long);
arrsize = va_arg(ap, long);
offset = va_arg(ap, long);
ind_type = va_arg(ap, enum ECPGttype);
ind_value = va_arg(ap, void *);
ind_varcharsize = va_arg(ap, long);
ind_arrsize = va_arg(ap, long);
ind_offset = va_arg(ap, long);
buff[0] = '\0'; buff[0] = '\0';
/* check for null value and set input buffer accordingly */ /* check for null value and set input buffer accordingly */
switch (ind_type) switch (var->ind_type)
{ {
case ECPGt_short: case ECPGt_short:
case ECPGt_unsigned_short: case ECPGt_unsigned_short:
if (*(short *) ind_value < 0) if (*(short *) var->ind_value < 0)
strcpy(buff, "null"); strcpy(buff, "null");
break; break;
case ECPGt_int: case ECPGt_int:
case ECPGt_unsigned_int: case ECPGt_unsigned_int:
if (*(int *) ind_value < 0) if (*(int *) var->ind_value < 0)
strcpy(buff, "null"); strcpy(buff, "null");
break; break;
case ECPGt_long: case ECPGt_long:
case ECPGt_unsigned_long: case ECPGt_unsigned_long:
if (*(long *) ind_value < 0L) if (*(long *) var->ind_value < 0L)
strcpy(buff, "null"); strcpy(buff, "null");
break; break;
default: default:
@ -194,42 +268,42 @@ ECPGdo(int lineno, char *query,...)
if (*buff == '\0') if (*buff == '\0')
{ {
switch (type) switch (var->type)
{ {
case ECPGt_short: case ECPGt_short:
case ECPGt_int: case ECPGt_int:
sprintf(buff, "%d", *(int *) value); sprintf(buff, "%d", *(int *) var->value);
tobeinserted = buff; tobeinserted = buff;
break; break;
case ECPGt_unsigned_short: case ECPGt_unsigned_short:
case ECPGt_unsigned_int: case ECPGt_unsigned_int:
sprintf(buff, "%d", *(unsigned int *) value); sprintf(buff, "%d", *(unsigned int *) var->value);
tobeinserted = buff; tobeinserted = buff;
break; break;
case ECPGt_long: case ECPGt_long:
sprintf(buff, "%ld", *(long *) value); sprintf(buff, "%ld", *(long *) var->value);
tobeinserted = buff; tobeinserted = buff;
break; break;
case ECPGt_unsigned_long: case ECPGt_unsigned_long:
sprintf(buff, "%ld", *(unsigned long *) value); sprintf(buff, "%ld", *(unsigned long *) var->value);
tobeinserted = buff; tobeinserted = buff;
break; break;
case ECPGt_float: case ECPGt_float:
sprintf(buff, "%.14g", *(float *) value); sprintf(buff, "%.14g", *(float *) var->value);
tobeinserted = buff; tobeinserted = buff;
break; break;
case ECPGt_double: case ECPGt_double:
sprintf(buff, "%.14g", *(double *) value); sprintf(buff, "%.14g", *(double *) var->value);
tobeinserted = buff; tobeinserted = buff;
break; break;
case ECPGt_bool: case ECPGt_bool:
sprintf(buff, "'%c'", (*(char *) value ? 't' : 'f')); sprintf(buff, "'%c'", (*(char *) var->value ? 't' : 'f'));
tobeinserted = buff; tobeinserted = buff;
break; break;
@ -237,7 +311,7 @@ ECPGdo(int lineno, char *query,...)
case ECPGt_unsigned_char: case ECPGt_unsigned_char:
{ {
/* set slen to string length if type is char * */ /* set slen to string length if type is char * */
int slen = (varcharsize == 0) ? strlen((char *) value) : varcharsize; int slen = (var->varcharsize == 0) ? strlen((char *) var->value) : var->varcharsize;
char * tmp; char * tmp;
newcopy = (char *) malloc(slen + 1); newcopy = (char *) malloc(slen + 1);
@ -245,11 +319,11 @@ ECPGdo(int lineno, char *query,...)
{ {
ECPGfinish(actual_connection); ECPGfinish(actual_connection);
ECPGlog("out of memory\n"); ECPGlog("out of memory\n");
register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno); register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno);
return false; return false;
} }
strncpy(newcopy, (char *) value, slen); strncpy(newcopy, (char *) var->value, slen);
newcopy[slen] = '\0'; newcopy[slen] = '\0';
mallocedval = (char *) malloc(2 * strlen(newcopy) + 3); mallocedval = (char *) malloc(2 * strlen(newcopy) + 3);
@ -257,7 +331,7 @@ ECPGdo(int lineno, char *query,...)
{ {
ECPGfinish(actual_connection); ECPGfinish(actual_connection);
ECPGlog("out of memory\n"); ECPGlog("out of memory\n");
register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno); register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno);
return false; return false;
} }
@ -267,7 +341,7 @@ ECPGdo(int lineno, char *query,...)
{ {
ECPGfinish(actual_connection); ECPGfinish(actual_connection);
ECPGlog("out of memory\n"); ECPGlog("out of memory\n");
register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno); register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno);
return false; return false;
} }
@ -282,28 +356,28 @@ ECPGdo(int lineno, char *query,...)
case ECPGt_varchar: case ECPGt_varchar:
{ {
struct ECPGgeneric_varchar *var = struct ECPGgeneric_varchar *variable =
(struct ECPGgeneric_varchar *) value; (struct ECPGgeneric_varchar *) (var->value);
char *tmp; char *tmp;
newcopy = (char *) malloc(var->len + 1); newcopy = (char *) malloc(variable->len + 1);
if (!newcopy) if (!newcopy)
{ {
ECPGfinish(actual_connection); ECPGfinish(actual_connection);
ECPGlog("out of memory\n"); ECPGlog("out of memory\n");
register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno); register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno);
return false; return false;
} }
strncpy(newcopy, var->arr, var->len); strncpy(newcopy, variable->arr, variable->len);
newcopy[var->len] = '\0'; newcopy[variable->len] = '\0';
mallocedval = (char *) malloc(2 * strlen(newcopy) + 3); mallocedval = (char *) malloc(2 * strlen(newcopy) + 3);
if (!mallocedval) if (!mallocedval)
{ {
ECPGfinish(actual_connection); ECPGfinish(actual_connection);
ECPGlog("out of memory\n"); ECPGlog("out of memory\n");
register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno); register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno);
return false; return false;
} }
@ -313,7 +387,7 @@ ECPGdo(int lineno, char *query,...)
{ {
ECPGfinish(actual_connection); ECPGfinish(actual_connection);
ECPGlog("out of memory\n"); ECPGlog("out of memory\n");
register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno); register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno);
return false; return false;
} }
@ -329,7 +403,7 @@ ECPGdo(int lineno, char *query,...)
default: default:
/* Not implemented yet */ /* Not implemented yet */
register_error(ECPG_UNSUPPORTED, "Unsupported type %s on line %d.", register_error(ECPG_UNSUPPORTED, "Unsupported type %s on line %d.",
ECPGtype_name(type), lineno); ECPGtype_name(var->type), stmt->lineno);
return false; return false;
break; break;
} }
@ -348,7 +422,7 @@ ECPGdo(int lineno, char *query,...)
{ {
ECPGfinish(actual_connection); ECPGfinish(actual_connection);
ECPGlog("out of memory\n"); ECPGlog("out of memory\n");
register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno); register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", stmt->lineno);
return false; return false;
} }
@ -360,7 +434,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(ECPG_TOO_MANY_ARGUMENTS, "Too many arguments line %d.", lineno); register_error(ECPG_TOO_MANY_ARGUMENTS, "Too many arguments line %d.", stmt->lineno);
return false; return false;
} }
else else
@ -379,7 +453,7 @@ ECPGdo(int lineno, char *query,...)
/* /*
* Now everything is safely copied to the newcopy. Lets free the * Now everything is safely copied to the newcopy. Lets free the
* oldcopy and let the copiedquery get the value from the newcopy. * oldcopy and let the copiedquery get the var->value from the newcopy.
*/ */
if (mallocedval != NULL) if (mallocedval != NULL)
{ {
@ -390,13 +464,13 @@ ECPGdo(int lineno, char *query,...)
free(copiedquery); free(copiedquery);
copiedquery = newcopy; copiedquery = newcopy;
type = va_arg(ap, enum ECPGttype); var = var->next;
} }
/* Check if there are unmatched things left. */ /* Check if there are unmatched things left. */
if (strstr(copiedquery, ";;") != NULL) if (strstr(copiedquery, ";;") != NULL)
{ {
register_error(ECPG_TOO_FEW_ARGUMENTS, "Too few arguments line %d.", lineno); register_error(ECPG_TOO_FEW_ARGUMENTS, "Too few arguments line %d.", stmt->lineno);
return false; return false;
} }
@ -406,27 +480,28 @@ ECPGdo(int lineno, char *query,...)
{ {
if ((results = PQexec(actual_connection->connection, "begin transaction")) == NULL) if ((results = PQexec(actual_connection->connection, "begin transaction")) == NULL)
{ {
register_error(ECPG_TRANS, "Error starting transaction line %d.", lineno); register_error(ECPG_TRANS, "Error starting transaction line %d.", stmt->lineno);
return false; return false;
} }
PQclear(results); PQclear(results);
committed = 0; committed = 0;
} }
ECPGlog("ECPGdo line %d: QUERY: %s\n", lineno, copiedquery); ECPGlog("ECPGexecute line %d: QUERY: %s\n", stmt->lineno, copiedquery);
results = PQexec(actual_connection->connection, copiedquery); results = PQexec(actual_connection->connection, copiedquery);
free(copiedquery); free(copiedquery);
if (results == NULL) if (results == NULL)
{ {
ECPGlog("ECPGdo line %d: error: %s", lineno, ECPGlog("ECPGexecute line %d: error: %s", stmt->lineno,
PQerrorMessage(actual_connection->connection)); PQerrorMessage(actual_connection->connection));
register_error(ECPG_PGSQL, "Postgres error: %s line %d.", register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
PQerrorMessage(actual_connection->connection), lineno); PQerrorMessage(actual_connection->connection), stmt->lineno);
} }
else else
{ {
sqlca.sqlerrd[2] = 0; sqlca.sqlerrd[2] = 0;
var = stmt->outlist;
switch (PQresultStatus(results)) switch (PQresultStatus(results))
{ {
int nfields, ntuples, act_tuple, act_field; int nfields, ntuples, act_tuple, act_field;
@ -445,9 +520,9 @@ ECPGdo(int lineno, char *query,...)
if (ntuples < 1) if (ntuples < 1)
{ {
ECPGlog("ECPGdo line %d: Incorrect number of matches: %d\n", ECPGlog("ECPGexecute line %d: Incorrect number of matches: %d\n",
lineno, ntuples); stmt->lineno, ntuples);
register_error(ECPG_NOT_FOUND, "Data not found line %d.", lineno); register_error(ECPG_NOT_FOUND, "Data not found line %d.", stmt->lineno);
status = false; status = false;
break; break;
} }
@ -457,23 +532,19 @@ ECPGdo(int lineno, char *query,...)
char *pval; char *pval;
char *scan_length; char *scan_length;
type = va_arg(ap, enum ECPGttype); if (var == NULL)
value = va_arg(ap, void *);
varcharsize = va_arg(ap, long);
arrsize = va_arg(ap, long);
offset = va_arg(ap, long);
ind_type = va_arg(ap, enum ECPGttype);
ind_value = va_arg(ap, void *);
ind_varcharsize = 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", ECPGlog("ECPGexecute line %d: Too few arguments.\n", stmt->lineno);
lineno, ntuples, arrsize); register_error(ECPG_TOO_FEW_ARGUMENTS, "Too few arguments line %d.", stmt->lineno);
register_error(ECPG_TOO_MANY_MATCHES, "Too many matches line %d.", lineno); return(false);
}
/* if we don't have enough space, we cannot read all tuples */
if ((var->arrsize > 0 && ntuples > var->arrsize) || (var->ind_arrsize > 0 && ntuples > var->ind_arrsize))
{
ECPGlog("ECPGexecute line %d: Incorrect number of matches: %d don't fit into array of %d\n",
stmt->lineno, ntuples, var->arrsize);
register_error(ECPG_TOO_MANY_MATCHES, "Too many matches line %d.", stmt->lineno);
status = false; status = false;
break; break;
} }
@ -481,31 +552,31 @@ ECPGdo(int lineno, char *query,...)
{ {
pval = PQgetvalue(results, act_tuple, act_field); pval = PQgetvalue(results, act_tuple, act_field);
ECPGlog("ECPGdo line %d: RESULT: %s\n", lineno, pval ? pval : ""); ECPGlog("ECPGexecute line %d: RESULT: %s\n", stmt->lineno, pval ? pval : "");
/* Now the pval is a pointer to the value. */ /* Now the pval is a pointer to the var->value. */
/* We will have to decode the value */ /* We will have to decode the var->value */
/* check for null value and set indicator accordingly */ /* check for null var->value and set indicator accordingly */
switch (ind_type) switch (var->ind_type)
{ {
case ECPGt_short: case ECPGt_short:
case ECPGt_unsigned_short: case ECPGt_unsigned_short:
((short *) ind_value)[act_tuple] = -PQgetisnull(results, act_tuple, act_field); ((short *) var->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)[act_tuple] = -PQgetisnull(results, act_tuple, act_field); ((int *) var->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)[act_tuple] = -PQgetisnull(results, act_tuple, act_field); ((long *) var->ind_value)[act_tuple] = -PQgetisnull(results, act_tuple, act_field);
break; break;
default: default:
break; break;
} }
switch (type) switch (var->type)
{ {
long res; long res;
unsigned long ures; unsigned long ures;
@ -520,7 +591,7 @@ ECPGdo(int lineno, char *query,...)
if (*scan_length != '\0') /* Garbage left */ if (*scan_length != '\0') /* Garbage left */
{ {
register_error(ECPG_INT_FORMAT, "Not correctly formatted int type: %s line %d.", register_error(ECPG_INT_FORMAT, "Not correctly formatted int type: %s line %d.",
pval, lineno); pval, stmt->lineno);
status = false; status = false;
res = 0L; res = 0L;
} }
@ -529,16 +600,16 @@ ECPGdo(int lineno, char *query,...)
res = 0L; res = 0L;
/* Again?! Yes */ /* Again?! Yes */
switch (type) switch (var->type)
{ {
case ECPGt_short: case ECPGt_short:
((short *) value)[act_tuple] = (short) res; ((short *) var->value)[act_tuple] = (short) res;
break; break;
case ECPGt_int: case ECPGt_int:
((int *) value)[act_tuple] = (int) res; ((int *) var->value)[act_tuple] = (int) res;
break; break;
case ECPGt_long: case ECPGt_long:
((long *) value)[act_tuple] = res; ((long *) var->value)[act_tuple] = res;
break; break;
default: default:
/* Cannot happen */ /* Cannot happen */
@ -555,7 +626,7 @@ ECPGdo(int lineno, char *query,...)
if (*scan_length != '\0') /* Garbage left */ if (*scan_length != '\0') /* Garbage left */
{ {
register_error(ECPG_UINT_FORMAT, "Not correctly formatted unsigned type: %s line %d.", register_error(ECPG_UINT_FORMAT, "Not correctly formatted unsigned type: %s line %d.",
pval, lineno); pval, stmt->lineno);
status = false; status = false;
ures = 0L; ures = 0L;
} }
@ -564,16 +635,16 @@ ECPGdo(int lineno, char *query,...)
ures = 0L; ures = 0L;
/* Again?! Yes */ /* Again?! Yes */
switch (type) switch (var->type)
{ {
case ECPGt_unsigned_short: case ECPGt_unsigned_short:
((unsigned short *) value)[act_tuple] = (unsigned short) ures; ((unsigned short *) var->value)[act_tuple] = (unsigned short) ures;
break; break;
case ECPGt_unsigned_int: case ECPGt_unsigned_int:
((unsigned int *) value)[act_tuple] = (unsigned int) ures; ((unsigned int *) var->value)[act_tuple] = (unsigned int) ures;
break; break;
case ECPGt_unsigned_long: case ECPGt_unsigned_long:
((unsigned long *) value)[act_tuple] = ures; ((unsigned long *) var->value)[act_tuple] = ures;
break; break;
default: default:
/* Cannot happen */ /* Cannot happen */
@ -590,7 +661,7 @@ ECPGdo(int lineno, char *query,...)
if (*scan_length != '\0') /* Garbage left */ if (*scan_length != '\0') /* Garbage left */
{ {
register_error(ECPG_FLOAT_FORMAT, "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, stmt->lineno);
status = false; status = false;
dres = 0.0; dres = 0.0;
} }
@ -599,13 +670,13 @@ ECPGdo(int lineno, char *query,...)
dres = 0.0; dres = 0.0;
/* Again?! Yes */ /* Again?! Yes */
switch (type) switch (var->type)
{ {
case ECPGt_float: case ECPGt_float:
((float *) value)[act_tuple] = dres; ((float *) var->value)[act_tuple] = dres;
break; break;
case ECPGt_double: case ECPGt_double:
((double *) value)[act_tuple] = dres; ((double *) var->value)[act_tuple] = dres;
break; break;
default: default:
/* Cannot happen */ /* Cannot happen */
@ -618,50 +689,50 @@ ECPGdo(int lineno, char *query,...)
{ {
if (pval[0] == 'f' && pval[1] == '\0') if (pval[0] == 'f' && pval[1] == '\0')
{ {
((char *) value)[act_tuple] = false; ((char *) var->value)[act_tuple] = false;
break; break;
} }
else if (pval[0] == 't' && pval[1] == '\0') else if (pval[0] == 't' && pval[1] == '\0')
{ {
((char *) value)[act_tuple] = true; ((char *) var->value)[act_tuple] = true;
break; break;
} }
} }
register_error(ECPG_CONVERT_BOOL, "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); stmt->lineno);
status = false; status = false;
break; break;
case ECPGt_char: case ECPGt_char:
case ECPGt_unsigned_char: case ECPGt_unsigned_char:
{ {
if (varcharsize == 0) if (var->varcharsize == 0)
{ {
/* char* */ /* char* */
strncpy(((char **) value)[act_tuple], pval, strlen(pval)); strncpy(((char **) var->value)[act_tuple], pval, strlen(pval));
(((char **) value)[act_tuple])[strlen(pval)] = '\0'; (((char **) var->value)[act_tuple])[strlen(pval)] = '\0';
} }
else else
{ {
strncpy((char *) (value + offset * act_tuple), pval, varcharsize); strncpy((char *) (var->value + var->offset * act_tuple), pval, var->varcharsize);
if (varcharsize < strlen(pval)) if (var->varcharsize < strlen(pval))
{ {
/* truncation */ /* truncation */
switch (ind_type) switch (var->ind_type)
{ {
case ECPGt_short: case ECPGt_short:
case ECPGt_unsigned_short: case ECPGt_unsigned_short:
((short *) ind_value)[act_tuple] = varcharsize; ((short *) var->ind_value)[act_tuple] = var->varcharsize;
break; break;
case ECPGt_int: case ECPGt_int:
case ECPGt_unsigned_int: case ECPGt_unsigned_int:
((int *) ind_value)[act_tuple] = varcharsize; ((int *) var->ind_value)[act_tuple] = var->varcharsize;
break; break;
case ECPGt_long: case ECPGt_long:
case ECPGt_unsigned_long: case ECPGt_unsigned_long:
((long *) ind_value)[act_tuple] = varcharsize; ((long *) var->ind_value)[act_tuple] = var->varcharsize;
break; break;
default: default:
break; break;
@ -674,62 +745,55 @@ ECPGdo(int lineno, char *query,...)
case ECPGt_varchar: case ECPGt_varchar:
{ {
struct ECPGgeneric_varchar *var = struct ECPGgeneric_varchar *variable =
(struct ECPGgeneric_varchar *) (value + offset * act_tuple); (struct ECPGgeneric_varchar *) (var->value + var->offset * act_tuple);
if (varcharsize == 0) if (var->varcharsize == 0)
strncpy(var->arr, pval, strlen(pval)); strncpy(variable->arr, pval, strlen(pval));
else else
strncpy(var->arr, pval, varcharsize); strncpy(variable->arr, pval, var->varcharsize);
var->len = strlen(pval); variable->len = strlen(pval);
if (varcharsize > 0 && var->len > varcharsize) if (var->varcharsize > 0 && variable->len > var->varcharsize)
{ {
/* truncation */ /* truncation */
switch (ind_type) switch (var->ind_type)
{ {
case ECPGt_short: case ECPGt_short:
case ECPGt_unsigned_short: case ECPGt_unsigned_short:
((short *) ind_value)[act_tuple] = varcharsize; ((short *) var->ind_value)[act_tuple] = var->varcharsize;
break; break;
case ECPGt_int: case ECPGt_int:
case ECPGt_unsigned_int: case ECPGt_unsigned_int:
((int *) ind_value)[act_tuple] = varcharsize; ((int *) var->ind_value)[act_tuple] = var->varcharsize;
break; break;
case ECPGt_long: case ECPGt_long:
case ECPGt_unsigned_long: case ECPGt_unsigned_long:
((long *) ind_value)[act_tuple] = varcharsize; ((long *) var->ind_value)[act_tuple] = var->varcharsize;
break; break;
default: default:
break; break;
} }
sqlca.sqlwarn[0] = sqlca.sqlwarn[1] = 'W'; sqlca.sqlwarn[0] = sqlca.sqlwarn[1] = 'W';
var->len = varcharsize; variable->len = var->varcharsize;
} }
} }
break; break;
case ECPGt_EORT:
ECPGlog("ECPGdo line %d: Too few arguments.\n", lineno);
register_error(ECPG_TOO_FEW_ARGUMENTS, "Too few arguments line %d.", lineno);
status = false;
break;
default: default:
register_error(ECPG_UNSUPPORTED, "Unsupported type %s on line %d.", register_error(ECPG_UNSUPPORTED, "Unsupported type %s on line %d.",
ECPGtype_name(type), lineno); ECPGtype_name(var->type), stmt->lineno);
status = false; status = false;
break; break;
} }
} }
var = var->next;
} }
type = va_arg(ap, enum ECPGttype); if (status && var != NULL)
if (status && type != ECPGt_EORT)
{ {
register_error(ECPG_TOO_MANY_ARGUMENTS, "Too many arguments line %d.", lineno); register_error(ECPG_TOO_MANY_ARGUMENTS, "Too many arguments line %d.", stmt->lineno);
status = false; status = false;
} }
@ -737,35 +801,34 @@ ECPGdo(int lineno, char *query,...)
break; break;
case PGRES_EMPTY_QUERY: case PGRES_EMPTY_QUERY:
/* do nothing */ /* do nothing */
register_error(ECPG_EMPTY, "Empty query line %d.", lineno); register_error(ECPG_EMPTY, "Empty query line %d.", stmt->lineno);
break; break;
case PGRES_COMMAND_OK: case PGRES_COMMAND_OK:
status = true; status = true;
sqlca.sqlerrd[2] = atol(PQcmdTuples(results)); sqlca.sqlerrd[2] = atol(PQcmdTuples(results));
ECPGlog("TEST: %s\n", PQcmdTuples(results)); ECPGlog("ECPGexecute line %d Ok: %s\n", stmt->lineno, PQcmdStatus(results));
ECPGlog("ECPGdo line %d Ok: %s\n", lineno, PQcmdStatus(results));
break; break;
case PGRES_NONFATAL_ERROR: case PGRES_NONFATAL_ERROR:
case PGRES_FATAL_ERROR: case PGRES_FATAL_ERROR:
case PGRES_BAD_RESPONSE: case PGRES_BAD_RESPONSE:
ECPGlog("ECPGdo line %d: Error: %s", ECPGlog("ECPGexecute line %d: Error: %s",
lineno, PQerrorMessage(actual_connection->connection)); stmt->lineno, PQerrorMessage(actual_connection->connection));
register_error(ECPG_PGSQL, "Error: %s line %d.", register_error(ECPG_PGSQL, "Error: %s line %d.",
PQerrorMessage(actual_connection->connection), lineno); PQerrorMessage(actual_connection->connection), stmt->lineno);
status = false; status = false;
break; break;
case PGRES_COPY_OUT: case PGRES_COPY_OUT:
ECPGlog("ECPGdo line %d: Got PGRES_COPY_OUT ... tossing.\n", lineno); ECPGlog("ECPGexecute line %d: Got PGRES_COPY_OUT ... tossing.\n", stmt->lineno);
PQendcopy(results->conn); PQendcopy(results->conn);
break; break;
case PGRES_COPY_IN: case PGRES_COPY_IN:
ECPGlog("ECPGdo line %d: Got PGRES_COPY_IN ... tossing.\n", lineno); ECPGlog("ECPGexecute line %d: Got PGRES_COPY_IN ... tossing.\n", stmt->lineno);
PQendcopy(results->conn); PQendcopy(results->conn);
break; break;
default: default:
ECPGlog("ECPGdo line %d: Got something else, postgres error.\n", ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n",
lineno); stmt->lineno);
register_error(ECPG_PGSQL, "Postgres error line %d.", lineno); register_error(ECPG_PGSQL, "Postgres error line %d.", stmt->lineno);
status = false; status = false;
break; break;
} }
@ -775,8 +838,8 @@ ECPGdo(int lineno, char *query,...)
notify = PQnotifies(actual_connection->connection); notify = PQnotifies(actual_connection->connection);
if (notify) if (notify)
{ {
ECPGlog("ECPGdo line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n", ECPGlog("ECPGexecute line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
lineno, notify->relname, notify->be_pid); stmt->lineno, notify->relname, notify->be_pid);
free(notify); free(notify);
} }
@ -784,6 +847,20 @@ ECPGdo(int lineno, char *query,...)
return status; return status;
} }
bool
ECPGdo(int lineno, char *query, ...)
{
va_list args;
struct statement *stmt;
va_start(args, query);
if (create_statement(lineno, &stmt, query, args) == false)
return(false);
va_end(args);
return(ECPGexecute(stmt));
}
bool bool
ECPGtrans(int lineno, const char * transaction) ECPGtrans(int lineno, const char * transaction)
@ -940,56 +1017,3 @@ sqlprint(void)
sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml] = '\0'; sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml] = '\0';
printf("sql error %s\n", sqlca.sqlerrm.sqlerrmc); printf("sql error %s\n", sqlca.sqlerrm.sqlerrmc);
} }
/* keep a list of cursors */
struct cursor *cur = NULL;
bool ECPGdeclare(int lineno, const char *name, char *command)
{
struct cursor *ptr;
for (ptr = cur; ptr != NULL; ptr = ptr->next)
{
if (strcmp(name, ptr->name) == 0)
{
/* re-definition */
free(ptr->command);
ptr->command = command;
break;
}
}
if (ptr == NULL)
{
struct cursor *this = (struct cursor *) malloc(sizeof(struct cursor));
if (!this)
{
ECPGlog("out of memory\n");
register_error(ECPG_OUT_OF_MEMORY, "out of memory in line %d", lineno);
return false;
}
/* initial definition */
this->next = cur;
this->name = name;
this->command = command;
cur = this;
}
return(true);
}
bool ECPGopen(int lineno, const char *name)
{
struct cursor *ptr;
for (ptr = cur; ptr != NULL; ptr=ptr->next)
{
if (strcmp(ptr->name, name) == 0)
return(ECPGdo(lineno, ptr->command, ECPGt_EOIT, ECPGt_EORT));
}
ECPGlog("trying to open undeclared cursor %s\n", name);
register_error(ECPG_UNDECLARED_CURSOR, "trying to open undeclared cursor %s in line %d", name, lineno);
return(false);
}

View File

@ -23,6 +23,7 @@ extern char *optarg;
struct _include_path *include_paths; struct _include_path *include_paths;
static int no_auto_trans = 0; static int no_auto_trans = 0;
struct cursor *cur = NULL;
static void static void
usage(char *progname) usage(char *progname)
@ -138,6 +139,24 @@ main(int argc, char *const argv[])
{ {
struct cursor *ptr; struct cursor *ptr;
/* remove old cursor definitions if any are still there */
for (ptr = cur; ptr != NULL; ptr=ptr->next)
{
struct arguments *l1, *l2;
free(ptr->command);
free(ptr->name);
for (l1 = argsinsert; l1; l1 = l2)
{
l2 = l1->next;
free(l1);
}
for (l1 = argsresult; l1; l1 = l2)
{
l2 = l1->next;
free(l1);
}
}
/* initialize lex */ /* initialize lex */
lex_init(); lex_init();

View File

@ -16,6 +16,15 @@ struct _include_path { char * path;
extern struct _include_path *include_paths; extern struct _include_path *include_paths;
struct cursor { char *name;
char *command;
struct arguments * argsinsert;
struct arguments * argsresult;
struct cursor *next;
};
extern struct cursor *cur;
/* This is a linked list of the variable names and types. */ /* This is a linked list of the variable names and types. */
struct variable struct variable
{ {
@ -28,6 +37,15 @@ struct variable
extern struct ECPGtype ecpg_no_indicator; extern struct ECPGtype ecpg_no_indicator;
extern struct variable no_indicator; extern struct variable no_indicator;
struct arguments {
struct variable * variable;
struct variable * indicator;
struct arguments * next;
};
extern struct arguments * argsinsert;
extern struct arguments * argsresult;
/* functions */ /* functions */
extern void lex_init(void); extern void lex_init(void);

View File

@ -245,14 +245,9 @@ remove_variables(int brace_level)
* These are of two kinds: input and output. * These are of two kinds: input and output.
* I will make two lists for them. * I will make two lists for them.
*/ */
struct arguments {
struct variable * variable;
struct variable * indicator;
struct arguments * next;
};
static struct arguments * argsinsert = NULL; struct arguments * argsinsert = NULL;
static struct arguments * argsresult = NULL; struct arguments * argsresult = NULL;
static void static void
reset_variables(void) reset_variables(void)
@ -279,7 +274,7 @@ add_variable(struct arguments ** list, struct variable * var, struct variable *
deletes the list as we go on. deletes the list as we go on.
*/ */
static void static void
dump_variables(struct arguments * list) dump_variables(struct arguments * list, int mode)
{ {
if (list == NULL) if (list == NULL)
{ {
@ -290,7 +285,7 @@ dump_variables(struct arguments * list)
end of the list: end of the list:
*/ */
dump_variables(list->next); dump_variables(list->next, mode);
/* Then the current element and its indicator */ /* Then the current element and its indicator */
ECPGdump_a_type(yyout, list->variable->name, list->variable->type, ECPGdump_a_type(yyout, list->variable->name, list->variable->type,
@ -298,7 +293,8 @@ dump_variables(struct arguments * list)
(list->indicator->type->typ != ECPGt_NO_INDICATOR) ? list->indicator->type : NULL, NULL, NULL); (list->indicator->type->typ != ECPGt_NO_INDICATOR) ? list->indicator->type : NULL, NULL, NULL);
/* Then release the list element. */ /* Then release the list element. */
free(list); if (mode != 0)
free(list);
} }
static void static void
@ -494,9 +490,9 @@ output_statement(char * stmt, int mode)
fputs("\", ", yyout); fputs("\", ", yyout);
/* dump variables to C file*/ /* dump variables to C file*/
dump_variables(argsinsert); dump_variables(argsinsert, 1);
fputs("ECPGt_EOIT, ", yyout); fputs("ECPGt_EOIT, ", yyout);
dump_variables(argsresult); dump_variables(argsresult, 1);
fputs("ECPGt_EORT);", yyout); fputs("ECPGt_EORT);", yyout);
whenever_action(mode); whenever_action(mode);
free(stmt); free(stmt);
@ -737,10 +733,9 @@ stmt: AddAttrStmt { output_statement($1, 0); }
| RenameStmt { output_statement($1, 0); } | RenameStmt { output_statement($1, 0); }
| RevokeStmt { output_statement($1, 0); } | RevokeStmt { output_statement($1, 0); }
| OptimizableStmt { | OptimizableStmt {
if (strncmp($1, "ECPGdeclare" , sizeof("ECPGdeclare")-1) == 0) if (strncmp($1, "/* " , sizeof("/* ")-1) == 0)
{ {
fputs($1, yyout); fputs($1, yyout);
whenever_action(0);
free($1); free($1);
} }
else else
@ -775,7 +770,27 @@ stmt: AddAttrStmt { output_statement($1, 0); }
whenever_action(0); whenever_action(0);
free($1); free($1);
} }
| ECPGOpen { fprintf(yyout, "ECPGopen(__LINE__, %s);", $1); | ECPGOpen {
struct cursor *ptr;
for (ptr = cur; ptr != NULL; ptr=ptr->next)
{
if (strcmp(ptr->name, $1) == 0)
break;
}
if (ptr == NULL)
{
sprintf(errortext, "trying to open undeclared cursor %s\n", $1);
yyerror(errortext);
}
fprintf(yyout, "ECPGdo(__LINE__, \"%s\",", ptr->command);
/* dump variables to C file*/
dump_variables(ptr->argsinsert, 0);
fputs("ECPGt_EOIT, ", yyout);
dump_variables(ptr->argsresult, 0);
fputs("ECPGt_EORT);", yyout);
whenever_action(0); whenever_action(0);
free($1); free($1);
} }
@ -2359,7 +2374,31 @@ CursorStmt: DECLARE name opt_binary CURSOR FOR
group_clause having_clause group_clause having_clause
union_clause sort_clause union_clause sort_clause
{ {
$$ = make5_str(make1_str("ECPGdeclare(__LINE__, \""), $2, make1_str("\", \""), cat4_str(cat5_str(cat5_str(make1_str("declare"), strdup($2), $3, make1_str("cursor for select"), $7), $8, $9, $10, $11), $12, $13, $14), make1_str("\");")); struct cursor *ptr, *this;
for (ptr = cur; ptr != NULL; ptr = ptr->next)
{
if (strcmp($2, ptr->name) == 0)
{
/* re-definition is a bug*/
sprintf(errortext, "cursor %s already defined", $2);
yyerror(errortext);
}
}
this = (struct cursor *) mm_alloc(sizeof(struct cursor));
/* initial definition */
this->next = cur;
this->name = $2;
this->command = cat4_str(cat5_str(cat5_str(make1_str("declare"), strdup($2), $3, make1_str("cursor for select"), $7), $8, $9, $10, $11), $12, $13, $14);
this->argsinsert = argsinsert;
this->argsresult = argsresult;
argsinsert = argsresult = NULL;
cur = this;
$$ = cat3_str(make1_str("/*"), strdup(this->command), make1_str("*/"));
} }
; ;
@ -4221,7 +4260,7 @@ execstring: cvariable |
* open is an open cursor, at the moment this has to be removed * open is an open cursor, at the moment this has to be removed
*/ */
ECPGOpen: SQL_OPEN name open_opts { ECPGOpen: SQL_OPEN name open_opts {
$$ = make3_str(make1_str("\""), $2, make1_str("\"")); $$ = $2;
}; };
open_opts: /* empty */ { $$ = make1_str(""); } open_opts: /* empty */ { $$ = make1_str(""); }

View File

@ -1,6 +1,6 @@
all: test1 test2 perftest all: test1 test2 perftest
LDFLAGS=-g -I ../include -I ../../libpq -L../lib -lecpg -L../../libpq -lpq -lcrypt --static LDFLAGS=-g -I ../include -I ../../libpq -L../lib -lecpg -L../../libpq -lpq -lcrypt
test1: test1.c test1: test1.c
test1.c: test1.pgc test1.c: test1.pgc

View File

@ -19,6 +19,10 @@ exec sql begin declare section;
long ind_married; long ind_married;
char married[9]; char married[9];
exec sql end declare section; exec sql end declare section;
exec sql declare cur cursor for
select name, born, age, married from meskes;
char msg[128], command[128]; char msg[128], command[128];
FILE *dbgs; FILE *dbgs;
@ -26,7 +30,7 @@ exec sql end declare section;
ECPGdebug(1, dbgs); ECPGdebug(1, dbgs);
strcpy(msg, "connect"); strcpy(msg, "connect");
exec sql connect to tcp:postgresql://localhost:5432/mm; exec sql connect to tcp:postgresql://localhost:5432/mm;
strcpy(msg, "create"); strcpy(msg, "create");
exec sql create table meskes(name char(8), born integer, age smallint, married char(8)); exec sql create table meskes(name char(8), born integer, age smallint, married char(8));
@ -41,10 +45,6 @@ exec sql end declare section;
strcpy(msg, "commit"); strcpy(msg, "commit");
exec sql commit; exec sql commit;
strcpy(msg, "declare");
exec sql declare cur cursor for
select name, born, age, married from meskes;
strcpy(msg, "open"); strcpy(msg, "open");
exec sql open cur; exec sql open cur;