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
- Set version to 2.3.5
- 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
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
has to be 100.

View File

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

View File

@ -4,7 +4,7 @@ include $(SRCDIR)/Makefile.global
PQ_INCLUDE=-I$(SRCDIR)/interfaces/libpq
SO_MAJOR_VERSION=2
SO_MINOR_VERSION=4
SO_MINOR_VERSION=5
PORTNAME=@PORTNAME@

View File

@ -33,6 +33,29 @@ static struct connection
struct connection *next;
} *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 FILE *debugstream = NULL;
static int committed = true;
@ -116,27 +139,87 @@ ECPGfinish(struct connection *act)
ECPGlog("ECPGfinish: called an extra time.\n");
}
bool
ECPGdo(int lineno, char *query,...)
/* create a list of variables */
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;
char *copiedquery;
PGresult *results;
PGnotify *notify;
enum ECPGttype type;
void *value = NULL, *ind_value;
long varcharsize, ind_varcharsize;
long arrsize, ind_arrsize;
long offset, ind_offset;
enum ECPGttype ind_type;
struct variable *var;
memset((char *) &sqlca, 0, sizeof (sqlca));
va_start(ap, query);
copiedquery = strdup(query);
type = va_arg(ap, enum ECPGttype);
copiedquery = strdup(stmt->command);
/*
* 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
* so on.
*/
while (type != ECPGt_EOIT)
var = stmt->inlist;
while (var)
{
char *newcopy;
char *mallocedval = NULL;
@ -158,34 +242,24 @@ ECPGdo(int lineno, char *query,...)
* 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';
/* check for null value and set input buffer accordingly */
switch (ind_type)
switch (var->ind_type)
{
case ECPGt_short:
case ECPGt_unsigned_short:
if (*(short *) ind_value < 0)
if (*(short *) var->ind_value < 0)
strcpy(buff, "null");
break;
case ECPGt_int:
case ECPGt_unsigned_int:
if (*(int *) ind_value < 0)
if (*(int *) var->ind_value < 0)
strcpy(buff, "null");
break;
case ECPGt_long:
case ECPGt_unsigned_long:
if (*(long *) ind_value < 0L)
if (*(long *) var->ind_value < 0L)
strcpy(buff, "null");
break;
default:
@ -194,42 +268,42 @@ ECPGdo(int lineno, char *query,...)
if (*buff == '\0')
{
switch (type)
switch (var->type)
{
case ECPGt_short:
case ECPGt_int:
sprintf(buff, "%d", *(int *) value);
sprintf(buff, "%d", *(int *) var->value);
tobeinserted = buff;
break;
case ECPGt_unsigned_short:
case ECPGt_unsigned_int:
sprintf(buff, "%d", *(unsigned int *) value);
sprintf(buff, "%d", *(unsigned int *) var->value);
tobeinserted = buff;
break;
case ECPGt_long:
sprintf(buff, "%ld", *(long *) value);
sprintf(buff, "%ld", *(long *) var->value);
tobeinserted = buff;
break;
case ECPGt_unsigned_long:
sprintf(buff, "%ld", *(unsigned long *) value);
sprintf(buff, "%ld", *(unsigned long *) var->value);
tobeinserted = buff;
break;
case ECPGt_float:
sprintf(buff, "%.14g", *(float *) value);
sprintf(buff, "%.14g", *(float *) var->value);
tobeinserted = buff;
break;
case ECPGt_double:
sprintf(buff, "%.14g", *(double *) value);
sprintf(buff, "%.14g", *(double *) var->value);
tobeinserted = buff;
break;
case ECPGt_bool:
sprintf(buff, "'%c'", (*(char *) value ? 't' : 'f'));
sprintf(buff, "'%c'", (*(char *) var->value ? 't' : 'f'));
tobeinserted = buff;
break;
@ -237,7 +311,7 @@ ECPGdo(int lineno, char *query,...)
case ECPGt_unsigned_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;
newcopy = (char *) malloc(slen + 1);
@ -245,11 +319,11 @@ ECPGdo(int lineno, char *query,...)
{
ECPGfinish(actual_connection);
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;
}
strncpy(newcopy, (char *) value, slen);
strncpy(newcopy, (char *) var->value, slen);
newcopy[slen] = '\0';
mallocedval = (char *) malloc(2 * strlen(newcopy) + 3);
@ -257,7 +331,7 @@ ECPGdo(int lineno, char *query,...)
{
ECPGfinish(actual_connection);
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;
}
@ -267,7 +341,7 @@ ECPGdo(int lineno, char *query,...)
{
ECPGfinish(actual_connection);
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;
}
@ -282,28 +356,28 @@ ECPGdo(int lineno, char *query,...)
case ECPGt_varchar:
{
struct ECPGgeneric_varchar *var =
(struct ECPGgeneric_varchar *) value;
struct ECPGgeneric_varchar *variable =
(struct ECPGgeneric_varchar *) (var->value);
char *tmp;
newcopy = (char *) malloc(var->len + 1);
newcopy = (char *) malloc(variable->len + 1);
if (!newcopy)
{
ECPGfinish(actual_connection);
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;
}
strncpy(newcopy, var->arr, var->len);
newcopy[var->len] = '\0';
strncpy(newcopy, variable->arr, variable->len);
newcopy[variable->len] = '\0';
mallocedval = (char *) malloc(2 * strlen(newcopy) + 3);
if (!mallocedval)
{
ECPGfinish(actual_connection);
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;
}
@ -313,7 +387,7 @@ ECPGdo(int lineno, char *query,...)
{
ECPGfinish(actual_connection);
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;
}
@ -329,7 +403,7 @@ ECPGdo(int lineno, char *query,...)
default:
/* Not implemented yet */
register_error(ECPG_UNSUPPORTED, "Unsupported type %s on line %d.",
ECPGtype_name(type), lineno);
ECPGtype_name(var->type), stmt->lineno);
return false;
break;
}
@ -348,7 +422,7 @@ ECPGdo(int lineno, char *query,...)
{
ECPGfinish(actual_connection);
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;
}
@ -360,7 +434,7 @@ ECPGdo(int lineno, char *query,...)
* We have an argument but we dont have the matched up 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;
}
else
@ -379,7 +453,7 @@ ECPGdo(int lineno, char *query,...)
/*
* 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)
{
@ -390,13 +464,13 @@ ECPGdo(int lineno, char *query,...)
free(copiedquery);
copiedquery = newcopy;
type = va_arg(ap, enum ECPGttype);
var = var->next;
}
/* Check if there are unmatched things left. */
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;
}
@ -406,27 +480,28 @@ ECPGdo(int lineno, char *query,...)
{
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;
}
PQclear(results);
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);
free(copiedquery);
if (results == NULL)
{
ECPGlog("ECPGdo line %d: error: %s", lineno,
ECPGlog("ECPGexecute line %d: error: %s", stmt->lineno,
PQerrorMessage(actual_connection->connection));
register_error(ECPG_PGSQL, "Postgres error: %s line %d.",
PQerrorMessage(actual_connection->connection), lineno);
PQerrorMessage(actual_connection->connection), stmt->lineno);
}
else
{
sqlca.sqlerrd[2] = 0;
var = stmt->outlist;
switch (PQresultStatus(results))
{
int nfields, ntuples, act_tuple, act_field;
@ -445,9 +520,9 @@ ECPGdo(int lineno, char *query,...)
if (ntuples < 1)
{
ECPGlog("ECPGdo line %d: Incorrect number of matches: %d\n",
lineno, ntuples);
register_error(ECPG_NOT_FOUND, "Data not found line %d.", lineno);
ECPGlog("ECPGexecute line %d: Incorrect number of matches: %d\n",
stmt->lineno, ntuples);
register_error(ECPG_NOT_FOUND, "Data not found line %d.", stmt->lineno);
status = false;
break;
}
@ -457,23 +532,19 @@ ECPGdo(int lineno, char *query,...)
char *pval;
char *scan_length;
type = va_arg(ap, enum ECPGttype);
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))
if (var == NULL)
{
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);
ECPGlog("ECPGexecute line %d: Too few arguments.\n", stmt->lineno);
register_error(ECPG_TOO_FEW_ARGUMENTS, "Too few arguments line %d.", stmt->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;
break;
}
@ -481,31 +552,31 @@ ECPGdo(int lineno, char *query,...)
{
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. */
/* We will have to decode the value */
/* Now the pval is a pointer to the var->value. */
/* We will have to decode the var->value */
/* check for null value and set indicator accordingly */
switch (ind_type)
/* check for null var->value and set indicator accordingly */
switch (var->ind_type)
{
case ECPGt_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;
case ECPGt_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;
case ECPGt_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;
default:
break;
}
switch (type)
switch (var->type)
{
long res;
unsigned long ures;
@ -520,7 +591,7 @@ ECPGdo(int lineno, char *query,...)
if (*scan_length != '\0') /* Garbage left */
{
register_error(ECPG_INT_FORMAT, "Not correctly formatted int type: %s line %d.",
pval, lineno);
pval, stmt->lineno);
status = false;
res = 0L;
}
@ -529,16 +600,16 @@ ECPGdo(int lineno, char *query,...)
res = 0L;
/* Again?! Yes */
switch (type)
switch (var->type)
{
case ECPGt_short:
((short *) value)[act_tuple] = (short) res;
((short *) var->value)[act_tuple] = (short) res;
break;
case ECPGt_int:
((int *) value)[act_tuple] = (int) res;
((int *) var->value)[act_tuple] = (int) res;
break;
case ECPGt_long:
((long *) value)[act_tuple] = res;
((long *) var->value)[act_tuple] = res;
break;
default:
/* Cannot happen */
@ -555,7 +626,7 @@ ECPGdo(int lineno, char *query,...)
if (*scan_length != '\0') /* Garbage left */
{
register_error(ECPG_UINT_FORMAT, "Not correctly formatted unsigned type: %s line %d.",
pval, lineno);
pval, stmt->lineno);
status = false;
ures = 0L;
}
@ -564,16 +635,16 @@ ECPGdo(int lineno, char *query,...)
ures = 0L;
/* Again?! Yes */
switch (type)
switch (var->type)
{
case ECPGt_unsigned_short:
((unsigned short *) value)[act_tuple] = (unsigned short) ures;
((unsigned short *) var->value)[act_tuple] = (unsigned short) ures;
break;
case ECPGt_unsigned_int:
((unsigned int *) value)[act_tuple] = (unsigned int) ures;
((unsigned int *) var->value)[act_tuple] = (unsigned int) ures;
break;
case ECPGt_unsigned_long:
((unsigned long *) value)[act_tuple] = ures;
((unsigned long *) var->value)[act_tuple] = ures;
break;
default:
/* Cannot happen */
@ -590,7 +661,7 @@ ECPGdo(int lineno, char *query,...)
if (*scan_length != '\0') /* Garbage left */
{
register_error(ECPG_FLOAT_FORMAT, "Not correctly formatted floating point type: %s line %d.",
pval, lineno);
pval, stmt->lineno);
status = false;
dres = 0.0;
}
@ -599,13 +670,13 @@ ECPGdo(int lineno, char *query,...)
dres = 0.0;
/* Again?! Yes */
switch (type)
switch (var->type)
{
case ECPGt_float:
((float *) value)[act_tuple] = dres;
((float *) var->value)[act_tuple] = dres;
break;
case ECPGt_double:
((double *) value)[act_tuple] = dres;
((double *) var->value)[act_tuple] = dres;
break;
default:
/* Cannot happen */
@ -618,50 +689,50 @@ ECPGdo(int lineno, char *query,...)
{
if (pval[0] == 'f' && pval[1] == '\0')
{
((char *) value)[act_tuple] = false;
((char *) var->value)[act_tuple] = false;
break;
}
else if (pval[0] == 't' && pval[1] == '\0')
{
((char *) value)[act_tuple] = true;
((char *) var->value)[act_tuple] = true;
break;
}
}
register_error(ECPG_CONVERT_BOOL, "Unable to convert %s to bool on line %d.",
(pval ? pval : "NULL"),
lineno);
stmt->lineno);
status = false;
break;
case ECPGt_char:
case ECPGt_unsigned_char:
{
if (varcharsize == 0)
if (var->varcharsize == 0)
{
/* char* */
strncpy(((char **) value)[act_tuple], pval, strlen(pval));
(((char **) value)[act_tuple])[strlen(pval)] = '\0';
strncpy(((char **) var->value)[act_tuple], pval, strlen(pval));
(((char **) var->value)[act_tuple])[strlen(pval)] = '\0';
}
else
{
strncpy((char *) (value + offset * act_tuple), pval, varcharsize);
if (varcharsize < strlen(pval))
strncpy((char *) (var->value + var->offset * act_tuple), pval, var->varcharsize);
if (var->varcharsize < strlen(pval))
{
/* truncation */
switch (ind_type)
switch (var->ind_type)
{
case ECPGt_short:
case ECPGt_unsigned_short:
((short *) ind_value)[act_tuple] = varcharsize;
((short *) var->ind_value)[act_tuple] = var->varcharsize;
break;
case ECPGt_int:
case ECPGt_unsigned_int:
((int *) ind_value)[act_tuple] = varcharsize;
((int *) var->ind_value)[act_tuple] = var->varcharsize;
break;
case ECPGt_long:
case ECPGt_unsigned_long:
((long *) ind_value)[act_tuple] = varcharsize;
((long *) var->ind_value)[act_tuple] = var->varcharsize;
break;
default:
break;
@ -674,62 +745,55 @@ ECPGdo(int lineno, char *query,...)
case ECPGt_varchar:
{
struct ECPGgeneric_varchar *var =
(struct ECPGgeneric_varchar *) (value + offset * act_tuple);
struct ECPGgeneric_varchar *variable =
(struct ECPGgeneric_varchar *) (var->value + var->offset * act_tuple);
if (varcharsize == 0)
strncpy(var->arr, pval, strlen(pval));
if (var->varcharsize == 0)
strncpy(variable->arr, pval, strlen(pval));
else
strncpy(var->arr, pval, varcharsize);
strncpy(variable->arr, pval, var->varcharsize);
var->len = strlen(pval);
if (varcharsize > 0 && var->len > varcharsize)
variable->len = strlen(pval);
if (var->varcharsize > 0 && variable->len > var->varcharsize)
{
/* truncation */
switch (ind_type)
switch (var->ind_type)
{
case ECPGt_short:
case ECPGt_unsigned_short:
((short *) ind_value)[act_tuple] = varcharsize;
((short *) var->ind_value)[act_tuple] = var->varcharsize;
break;
case ECPGt_int:
case ECPGt_unsigned_int:
((int *) ind_value)[act_tuple] = varcharsize;
((int *) var->ind_value)[act_tuple] = var->varcharsize;
break;
case ECPGt_long:
case ECPGt_unsigned_long:
((long *) ind_value)[act_tuple] = varcharsize;
((long *) var->ind_value)[act_tuple] = var->varcharsize;
break;
default:
break;
}
sqlca.sqlwarn[0] = sqlca.sqlwarn[1] = 'W';
var->len = varcharsize;
variable->len = var->varcharsize;
}
}
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:
register_error(ECPG_UNSUPPORTED, "Unsupported type %s on line %d.",
ECPGtype_name(type), lineno);
ECPGtype_name(var->type), stmt->lineno);
status = false;
break;
}
}
var = var->next;
}
type = va_arg(ap, enum ECPGttype);
if (status && type != ECPGt_EORT)
if (status && var != NULL)
{
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;
}
@ -737,35 +801,34 @@ ECPGdo(int lineno, char *query,...)
break;
case PGRES_EMPTY_QUERY:
/* do nothing */
register_error(ECPG_EMPTY, "Empty query line %d.", lineno);
register_error(ECPG_EMPTY, "Empty query line %d.", stmt->lineno);
break;
case PGRES_COMMAND_OK:
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("ECPGexecute line %d Ok: %s\n", stmt->lineno, PQcmdStatus(results));
break;
case PGRES_NONFATAL_ERROR:
case PGRES_FATAL_ERROR:
case PGRES_BAD_RESPONSE:
ECPGlog("ECPGdo line %d: Error: %s",
lineno, PQerrorMessage(actual_connection->connection));
ECPGlog("ECPGexecute line %d: Error: %s",
stmt->lineno, PQerrorMessage(actual_connection->connection));
register_error(ECPG_PGSQL, "Error: %s line %d.",
PQerrorMessage(actual_connection->connection), lineno);
PQerrorMessage(actual_connection->connection), stmt->lineno);
status = false;
break;
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);
break;
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);
break;
default:
ECPGlog("ECPGdo line %d: Got something else, postgres error.\n",
lineno);
register_error(ECPG_PGSQL, "Postgres error line %d.", lineno);
ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n",
stmt->lineno);
register_error(ECPG_PGSQL, "Postgres error line %d.", stmt->lineno);
status = false;
break;
}
@ -775,8 +838,8 @@ ECPGdo(int lineno, char *query,...)
notify = PQnotifies(actual_connection->connection);
if (notify)
{
ECPGlog("ECPGdo line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
lineno, notify->relname, notify->be_pid);
ECPGlog("ECPGexecute line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
stmt->lineno, notify->relname, notify->be_pid);
free(notify);
}
@ -784,6 +847,20 @@ ECPGdo(int lineno, char *query,...)
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
ECPGtrans(int lineno, const char * transaction)
@ -940,56 +1017,3 @@ sqlprint(void)
sqlca.sqlerrm.sqlerrmc[sqlca.sqlerrm.sqlerrml] = '\0';
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;
static int no_auto_trans = 0;
struct cursor *cur = NULL;
static void
usage(char *progname)
@ -138,6 +139,24 @@ main(int argc, char *const argv[])
{
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 */
lex_init();

View File

@ -16,6 +16,15 @@ struct _include_path { char * path;
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. */
struct variable
{
@ -28,6 +37,15 @@ struct variable
extern struct ECPGtype ecpg_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 */
extern void lex_init(void);

View File

@ -245,14 +245,9 @@ remove_variables(int brace_level)
* These are of two kinds: input and output.
* I will make two lists for them.
*/
struct arguments {
struct variable * variable;
struct variable * indicator;
struct arguments * next;
};
static struct arguments * argsinsert = NULL;
static struct arguments * argsresult = NULL;
struct arguments * argsinsert = NULL;
struct arguments * argsresult = NULL;
static 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.
*/
static void
dump_variables(struct arguments * list)
dump_variables(struct arguments * list, int mode)
{
if (list == NULL)
{
@ -290,7 +285,7 @@ dump_variables(struct arguments * list)
end of the list:
*/
dump_variables(list->next);
dump_variables(list->next, mode);
/* Then the current element and its indicator */
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);
/* Then release the list element. */
free(list);
if (mode != 0)
free(list);
}
static void
@ -494,9 +490,9 @@ output_statement(char * stmt, int mode)
fputs("\", ", yyout);
/* dump variables to C file*/
dump_variables(argsinsert);
dump_variables(argsinsert, 1);
fputs("ECPGt_EOIT, ", yyout);
dump_variables(argsresult);
dump_variables(argsresult, 1);
fputs("ECPGt_EORT);", yyout);
whenever_action(mode);
free(stmt);
@ -737,10 +733,9 @@ stmt: AddAttrStmt { output_statement($1, 0); }
| RenameStmt { output_statement($1, 0); }
| RevokeStmt { output_statement($1, 0); }
| OptimizableStmt {
if (strncmp($1, "ECPGdeclare" , sizeof("ECPGdeclare")-1) == 0)
if (strncmp($1, "/* " , sizeof("/* ")-1) == 0)
{
fputs($1, yyout);
whenever_action(0);
free($1);
}
else
@ -775,7 +770,27 @@ stmt: AddAttrStmt { output_statement($1, 0); }
whenever_action(0);
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);
free($1);
}
@ -2359,7 +2374,31 @@ CursorStmt: DECLARE name opt_binary CURSOR FOR
group_clause having_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
*/
ECPGOpen: SQL_OPEN name open_opts {
$$ = make3_str(make1_str("\""), $2, make1_str("\""));
$$ = $2;
};
open_opts: /* empty */ { $$ = make1_str(""); }

View File

@ -1,6 +1,6 @@
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.c: test1.pgc

View File

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