From 9f09e8362b701730f5c3ab2c387bf603f8ee7cba Mon Sep 17 00:00:00 2001 From: Michael Meskes Date: Mon, 1 Oct 2001 12:02:28 +0000 Subject: [PATCH] - Fixed truncate bug. - Added patch by Christof Petig to clean up ecpglib. --- src/interfaces/ecpg/ChangeLog | 6 + src/interfaces/ecpg/lib/data.c | 4 +- src/interfaces/ecpg/lib/execute.c | 312 ++++++++++++++------------ src/interfaces/ecpg/lib/extern.h | 7 +- src/interfaces/ecpg/preproc/preproc.y | 2 +- 5 files changed, 185 insertions(+), 146 deletions(-) diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog index 18708efae1..668bc986a8 100644 --- a/src/interfaces/ecpg/ChangeLog +++ b/src/interfaces/ecpg/ChangeLog @@ -1101,5 +1101,11 @@ Tue Sep 25 20:10:03 CEST 2001 - Synced preproc.y with gram.y. - Changed locale handling. + +Mon Okt 1 13:49:40 CEST 2001 + + - Fixed truncate bug. + - Added patch by Christof Petig to clean up + ecpglib. - Set ecpg version to 2.9.0. - Set library version to 3.3.0. diff --git a/src/interfaces/ecpg/lib/data.c b/src/interfaces/ecpg/lib/data.c index 8bed8f711e..5d53381314 100644 --- a/src/interfaces/ecpg/lib/data.c +++ b/src/interfaces/ecpg/lib/data.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/data.c,v 1.15 2001/09/19 14:09:32 meskes Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/data.c,v 1.16 2001/10/01 12:02:28 meskes Exp $ */ #include "postgres_fe.h" @@ -12,7 +12,7 @@ #include "sqlca.h" bool -get_data(PGresult *results, int act_tuple, int act_field, int lineno, +get_data(const PGresult *results, int act_tuple, int act_field, int lineno, enum ECPGttype type, enum ECPGttype ind_type, void *var, void *ind, long varcharsize, long offset, bool isarray) diff --git a/src/interfaces/ecpg/lib/execute.c b/src/interfaces/ecpg/lib/execute.c index 87e690eaa8..c696afe54b 100644 --- a/src/interfaces/ecpg/lib/execute.c +++ b/src/interfaces/ecpg/lib/execute.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/execute.c,v 1.25 2001/09/29 20:12:07 tgl Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/execute.c,v 1.26 2001/10/01 12:02:28 meskes Exp $ */ /* * The aim is to get a simpler inteface to the database routines. @@ -370,40 +370,107 @@ ECPGis_type_an_array(int type, const struct statement * stmt, const struct varia return isarray; } -static bool -ECPGexecute(struct statement * stmt) -{ - bool status = false; - char *copiedquery; - PGresult *results; - PGnotify *notify; - struct variable *var; - copiedquery = ecpg_strdup(stmt->command, stmt->lineno); +bool +ECPGstore_result(const PGresult *results, int act_field, + const struct statement * stmt, struct variable *var) +{ int isarray, + act_tuple, + ntuples = PQntuples(results); + bool status = true; + + isarray = ECPGis_type_an_array(PQftype(results, act_field), stmt, var); - /* - * Now, if the type is one of the fill in types then we take the - * argument and enter that in the string at the first %s position. - * Then if there are any more fill in types we fill in at the next and - * so on. - */ - var = stmt->inlist; - while (var) - { - char *newcopy; + if (!isarray) + { + + /* + * 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); + ECPGraise(stmt->lineno, ECPG_TOO_MANY_MATCHES, NULL); + return false; + } + } + else + { + + /* + * since we read an array, the variable has to be + * an array too + */ + if (var->arrsize == 0) + { + ECPGlog("ECPGexecute line %d: variable is not an array\n"); + ECPGraise(stmt->lineno, ECPG_NO_ARRAY, NULL); + return false; + } + } + + /* + * allocate memory for NULL pointers + */ + if ((var->arrsize == 0 || var->varcharsize == 0) && var->value == NULL) + { + int len = 0; + + switch (var->type) + { + case ECPGt_char: + case ECPGt_unsigned_char: + var->varcharsize = 0; + /* check strlen for each tuple */ + for (act_tuple = 0; act_tuple < ntuples; act_tuple++) + { + int len = strlen(PQgetvalue(results, act_tuple, act_field)) + 1; + + if (len > var->varcharsize) + var->varcharsize = len; + } + var->offset *= var->varcharsize; + len = var->offset * ntuples; + break; + case ECPGt_varchar: + len = ntuples * (var->varcharsize + sizeof(int)); + break; + default: + len = var->offset * ntuples; + break; + } + var->value = (void *) ecpg_alloc(len, stmt->lineno); + *((void **) var->pointer) = var->value; + add_mem(var->value, stmt->lineno); + } + + for (act_tuple = 0; act_tuple < ntuples && status; act_tuple++) + { + if (!get_data(results, act_tuple, act_field, stmt->lineno, + var->type, var->ind_type, var->value, + var->ind_value, var->varcharsize, var->offset, isarray)) + status = false; + } + return status; +} + +static bool +ECPGstore_input(const struct statement * stmt, const struct variable *var, + const char **tobeinserted_p, bool *malloced_p) +{ char *mallocedval = NULL; - char *tobeinserted = NULL; - char *p; - char buff[20]; - int hostvarl = 0; + char *newcopy = NULL; /* * Some special treatment is needed for records since we want * their contents to arrive in a comma-separated list on insert (I * think). */ - - buff[0] = '\0'; + + *malloced_p=false; + *tobeinserted_p=""; /* check for null value and set input buffer accordingly */ switch (var->ind_type) @@ -411,30 +478,30 @@ ECPGexecute(struct statement * stmt) case ECPGt_short: case ECPGt_unsigned_short: if (*(short *) var->ind_value < 0) - strcpy(buff, "null"); + *tobeinserted_p="null"; break; case ECPGt_int: case ECPGt_unsigned_int: if (*(int *) var->ind_value < 0) - strcpy(buff, "null"); + *tobeinserted_p="null"; break; case ECPGt_long: case ECPGt_unsigned_long: if (*(long *) var->ind_value < 0L) - strcpy(buff, "null"); + *tobeinserted_p="null"; break; #ifdef HAVE_LONG_LONG_INT_64 case ECPGt_long_long: case ECPGt_unsigned_long_long: if (*(long long int *) var->ind_value < (long long) 0) - strcpy(buff, "null"); + *tobeinserted_p="null"; break; #endif /* HAVE_LONG_LONG_INT_64 */ default: break; } - if (*buff == '\0') + if (**tobeinserted_p == '\0') { switch (var->type) { @@ -456,7 +523,8 @@ ECPGexecute(struct statement * stmt) else sprintf(mallocedval, "%hd", *((short *) var->value)); - tobeinserted = mallocedval; + *tobeinserted_p = mallocedval; + *malloced_p = true; break; case ECPGt_int: @@ -475,7 +543,8 @@ ECPGexecute(struct statement * stmt) else sprintf(mallocedval, "%d", *((int *) var->value)); - tobeinserted = mallocedval; + *tobeinserted_p = mallocedval; + *malloced_p = true; break; case ECPGt_unsigned_short: @@ -494,7 +563,8 @@ ECPGexecute(struct statement * stmt) else sprintf(mallocedval, "%hu", *((unsigned short *) var->value)); - tobeinserted = mallocedval; + *tobeinserted_p = mallocedval; + *malloced_p = true; break; case ECPGt_unsigned_int: @@ -513,7 +583,8 @@ ECPGexecute(struct statement * stmt) else sprintf(mallocedval, "%u", *((unsigned int *) var->value)); - tobeinserted = mallocedval; + *tobeinserted_p = mallocedval; + *malloced_p = true; break; case ECPGt_long: @@ -532,7 +603,8 @@ ECPGexecute(struct statement * stmt) else sprintf(mallocedval, "%ld", *((long *) var->value)); - tobeinserted = mallocedval; + *tobeinserted_p = mallocedval; + *malloced_p = true; break; case ECPGt_unsigned_long: @@ -551,7 +623,8 @@ ECPGexecute(struct statement * stmt) else sprintf(mallocedval, "%lu", *((unsigned long *) var->value)); - tobeinserted = mallocedval; + *tobeinserted_p = mallocedval; + *malloced_p = true; break; #ifdef HAVE_LONG_LONG_INT_64 case ECPGt_long_long: @@ -570,7 +643,8 @@ ECPGexecute(struct statement * stmt) else sprintf(mallocedval, "%lld", *((long long *) var->value)); - tobeinserted = mallocedval; + *tobeinserted_p = mallocedval; + *malloced_p = true; break; case ECPGt_unsigned_long_long: @@ -589,7 +663,8 @@ ECPGexecute(struct statement * stmt) else sprintf(mallocedval, "%llu", *((unsigned long long *) var->value)); - tobeinserted = mallocedval; + *tobeinserted_p = mallocedval; + *malloced_p = true; break; #endif /* HAVE_LONG_LONG_INT_64 */ case ECPGt_float: @@ -608,7 +683,8 @@ ECPGexecute(struct statement * stmt) else sprintf(mallocedval, "%.14g", *((float *) var->value)); - tobeinserted = mallocedval; + *tobeinserted_p = mallocedval; + *malloced_p = true; break; case ECPGt_double: @@ -627,7 +703,8 @@ ECPGexecute(struct statement * stmt) else sprintf(mallocedval, "%.14g", *((double *) var->value)); - tobeinserted = mallocedval; + *tobeinserted_p = mallocedval; + *malloced_p = true; break; case ECPGt_bool: @@ -664,7 +741,8 @@ ECPGexecute(struct statement * stmt) ECPGraise(stmt->lineno, ECPG_CONVERT_BOOL, "different size"); } - tobeinserted = mallocedval; + *tobeinserted_p = mallocedval; + *malloced_p = true; break; case ECPGt_char: @@ -685,7 +763,8 @@ ECPGexecute(struct statement * stmt) free(newcopy); - tobeinserted = mallocedval; + *tobeinserted_p = mallocedval; + *malloced_p = true; } break; case ECPGt_char_variable: @@ -698,7 +777,8 @@ ECPGexecute(struct statement * stmt) strncpy(mallocedval, (char *) var->value, slen); mallocedval[slen] = '\0'; - tobeinserted = mallocedval; + *tobeinserted_p = mallocedval; + *malloced_p = true; } break; case ECPGt_varchar: @@ -718,7 +798,8 @@ ECPGexecute(struct statement * stmt) free(newcopy); - tobeinserted = mallocedval; + *tobeinserted_p = mallocedval; + *malloced_p = true; } break; @@ -729,9 +810,38 @@ ECPGexecute(struct statement * stmt) break; } } - else - tobeinserted = buff; + return true; +} +static bool +ECPGexecute(struct statement * stmt) +{ + bool status = false; + char *copiedquery; + PGresult *results; + PGnotify *notify; + struct variable *var; + + copiedquery = ecpg_strdup(stmt->command, stmt->lineno); + + /* + * Now, if the type is one of the fill in types then we take the + * argument and enter that in the string at the first %s position. + * Then if there are any more fill in types we fill in at the next and + * so on. + */ + var = stmt->inlist; + while (var) + { + char *newcopy = NULL; + const char *tobeinserted = NULL; + char *p; + bool malloced=FALSE; + int hostvarl = 0; + + if (!ECPGstore_input(stmt, var, &tobeinserted, &malloced)) + return false; + /* * Now tobeinserted points to an area that is to be inserted at * the first %s @@ -770,10 +880,10 @@ ECPGexecute(struct statement * stmt) * oldcopy and let the copiedquery get the var->value from the * newcopy. */ - if (mallocedval != NULL) + if (malloced) { - free(mallocedval); - mallocedval = NULL; + free((char*)tobeinserted); + tobeinserted = NULL; } free(copiedquery); @@ -823,9 +933,7 @@ ECPGexecute(struct statement * stmt) { int nfields, ntuples, - act_tuple, - act_field, - isarray; + act_field; case PGRES_TUPLES_OK: nfields = PQnfields(results); @@ -861,83 +969,9 @@ ECPGexecute(struct statement * stmt) ECPGraise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS, NULL); return (false); } + + status = ECPGstore_result(results, act_field, stmt, var); - isarray = ECPGis_type_an_array(PQftype(results, act_field), stmt, var); - - if (!isarray) - { - - /* - * 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); - ECPGraise(stmt->lineno, ECPG_TOO_MANY_MATCHES, NULL); - status = false; - break; - } - } - else - { - - /* - * since we read an array, the variable has to be - * an array too - */ - if (var->arrsize == 0) - { - ECPGlog("ECPGexecute line %d: variable is not an array\n"); - ECPGraise(stmt->lineno, ECPG_NO_ARRAY, NULL); - status = false; - break; - } - } - - /* - * allocate memory for NULL pointers - */ - if ((var->arrsize == 0 || var->varcharsize == 0) && var->value == NULL) - { - int len = 0; - - switch (var->type) - { - case ECPGt_char: - case ECPGt_unsigned_char: - var->varcharsize = 0; - /* check strlen for each tuple */ - for (act_tuple = 0; act_tuple < ntuples; act_tuple++) - { - int len = strlen(PQgetvalue(results, act_tuple, act_field)) + 1; - - if (len > var->varcharsize) - var->varcharsize = len; - } - var->offset *= var->varcharsize; - len = var->offset * ntuples; - break; - case ECPGt_varchar: - len = ntuples * (var->varcharsize + sizeof(int)); - break; - default: - len = var->offset * ntuples; - break; - } - var->value = (void *) ecpg_alloc(len, stmt->lineno); - *((void **) var->pointer) = var->value; - add_mem(var->value, stmt->lineno); - } - - for (act_tuple = 0; act_tuple < ntuples && status; act_tuple++) - { - if (!get_data(results, act_tuple, act_field, stmt->lineno, - var->type, var->ind_type, var->value, - var->ind_value, var->varcharsize, var->offset, isarray)) - status = false; - } var = var->next; } @@ -1006,26 +1040,23 @@ ECPGdo(int lineno, const char *connection_name, char *query,...) va_list args; struct statement *stmt; struct connection *con = get_connection(connection_name); - bool status; - char *oldlocale; + bool status = true; + char *locale; /* Make sure we do NOT honor the locale for numeric input/output */ /* since the database wants the standard decimal point */ - oldlocale = strdup(setlocale(LC_NUMERIC, NULL)); - setlocale(LC_NUMERIC, "C"); + locale = setlocale(LC_NUMERIC, "C"); if (!ecpg_init(con, connection_name, lineno)) { - setlocale(LC_NUMERIC, oldlocale); - free(oldlocale); + setlocale(LC_NUMERIC, locale); return (false); } va_start(args, query); if (create_statement(lineno, con, &stmt, query, args) == false) { - setlocale(LC_NUMERIC, oldlocale); - free(oldlocale); + setlocale(LC_NUMERIC, locale); return (false); } va_end(args); @@ -1036,8 +1067,7 @@ ECPGdo(int lineno, const char *connection_name, char *query,...) free_statement(stmt); ECPGlog("ECPGdo: not connected to %s\n", con->name); ECPGraise(lineno, ECPG_NOT_CONN, NULL); - setlocale(LC_NUMERIC, oldlocale); - free(oldlocale); + setlocale(LC_NUMERIC, locale); return false; } @@ -1045,9 +1075,7 @@ ECPGdo(int lineno, const char *connection_name, char *query,...) free_statement(stmt); /* and reset locale value so our application is not affected */ - setlocale(LC_NUMERIC, oldlocale); - free(oldlocale); - + setlocale(LC_NUMERIC, locale); return (status); } diff --git a/src/interfaces/ecpg/lib/extern.h b/src/interfaces/ecpg/lib/extern.h index 3186b5b110..971924e708 100644 --- a/src/interfaces/ecpg/lib/extern.h +++ b/src/interfaces/ecpg/lib/extern.h @@ -4,7 +4,7 @@ /* Here are some methods used by the lib. */ /* Returns a pointer to a string containing a simple type name. */ void free_auto_mem(void); -bool get_data(PGresult *, int, int, int, enum ECPGttype type, +bool get_data(const PGresult *, int, int, int, enum ECPGttype type, enum ECPGttype, void *, void *, long, long, bool); struct connection *get_connection(const char *); void init_sqlca(void); @@ -14,6 +14,7 @@ char *ecpg_strdup(const char *, int); const char *ECPGtype_name(enum ECPGttype); unsigned int ECPGDynamicType(Oid); + /* A generic varchar type. */ struct ECPGgeneric_varchar { @@ -63,3 +64,7 @@ struct descriptor PGresult ** ECPGdescriptor_lvalue(int line, const char *descriptor); + +bool +ECPGstore_result(const PGresult *results, int act_field, + const struct statement * stmt, struct variable *var); diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y index 31a1cb42d4..e348f773c7 100644 --- a/src/interfaces/ecpg/preproc/preproc.y +++ b/src/interfaces/ecpg/preproc/preproc.y @@ -1552,7 +1552,7 @@ drop_type: TABLE { $$ = make_str("table"); } *****************************************************************************/ TruncateStmt: TRUNCATE opt_table relation_name { - $$ = cat2_str(make_str("drop table"), $3); + $$ = cat2_str(make_str("truncate table"), $3); } ; -- 2.40.0