Commit c6dd1e63 authored by Bruce Momjian's avatar Bruce Momjian

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

to understand cursors with variables.

Michael
parent 79c8d2e3
...@@ -270,3 +270,10 @@ Mon Aug 3 17:23:18 CEST 1998 ...@@ -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
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.
......
...@@ -13,9 +13,6 @@ bool ECPGdisconnect(int, const char *); ...@@ -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 *);
......
...@@ -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=4 SO_MINOR_VERSION=5
PORTNAME=@PORTNAME@ PORTNAME=@PORTNAME@
......
...@@ -33,6 +33,29 @@ static struct connection ...@@ -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) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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); ECPGlog("ECPGexecute line %d: Too few arguments.\n", stmt->lineno);
arrsize = va_arg(ap, long); register_error(ECPG_TOO_FEW_ARGUMENTS, "Too few arguments line %d.", stmt->lineno);
offset = va_arg(ap, long); return(false);
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 we don't have enough space, we cannot read all tuples */
if ((arrsize > 0 && ntuples > arrsize) || (ind_arrsize > 0 && ntuples > ind_arrsize)) if ((var->arrsize > 0 && ntuples > var->arrsize) || (var->ind_arrsize > 0 && ntuples > var->ind_arrsize))
{ {
ECPGlog("ECPGdo line %d: Incorrect number of matches: %d don't fit into array of %d\n", ECPGlog("ECPGexecute line %d: Incorrect number of matches: %d don't fit into array of %d\n",
lineno, ntuples, arrsize); stmt->lineno, ntuples, var->arrsize);
register_error(ECPG_TOO_MANY_MATCHES, "Too many matches line %d.", lineno); 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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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,...) ...@@ -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) ...@@ -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);
}
...@@ -23,6 +23,7 @@ extern char *optarg; ...@@ -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[]) ...@@ -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();
......
...@@ -16,6 +16,15 @@ struct _include_path { char * path; ...@@ -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 ...@@ -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);
......
...@@ -245,14 +245,9 @@ remove_variables(int brace_level) ...@@ -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 * ...@@ -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) ...@@ -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,6 +293,7 @@ dump_variables(struct arguments * list) ...@@ -298,6 +293,7 @@ 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. */
if (mode != 0)
free(list); free(list);
} }
...@@ -494,9 +490,9 @@ output_statement(char * stmt, int mode) ...@@ -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); } ...@@ -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); } ...@@ -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 ...@@ -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 | ...@@ -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(""); }
......
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
......
...@@ -19,6 +19,10 @@ exec sql begin declare section; ...@@ -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;
...@@ -41,10 +45,6 @@ exec sql end declare section; ...@@ -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;
......
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