|
|
|
|
@ -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 (var == NULL) |
|
|
|
|
{ |
|
|
|
|
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 ((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", |
|
|
|
|
lineno, ntuples, arrsize); |
|
|
|
|
register_error(ECPG_TOO_MANY_MATCHES, "Too many matches line %d.", lineno); |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
|