diff --git a/src/interfaces/ecpg/ecpglib/data.c b/src/interfaces/ecpg/ecpglib/data.c index e1cfc3d2e7..a6d99c74db 100644 --- a/src/interfaces/ecpg/ecpglib/data.c +++ b/src/interfaces/ecpg/ecpglib/data.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/data.c,v 1.20 2003/09/20 09:10:09 meskes Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/data.c,v 1.21 2003/11/08 19:46:27 meskes Exp $ */ #define POSTGRES_ECPG_INTERNAL #include "postgres_fe.h" @@ -16,21 +16,39 @@ #include "pgtypes_timestamp.h" #include "pgtypes_interval.h" +static bool garbage_left(enum ARRAY_TYPE isarray, char *scan_length, enum COMPAT_MODE compat) +{ + /* INFORMIX allows for selecting a numeric into an int, the result is truncated */ + if (isarray == ECPG_ARRAY_NONE && INFORMIX_MODE(compat) && *scan_length == '.') + return false; + + if (isarray == ECPG_ARRAY_ARRAY && *scan_length != ',' && *scan_length != '}') + return true; + + if (isarray == ECPG_ARRAY_VECTOR && *scan_length != ' ' && *scan_length != '\0') + return true; + + if (isarray == ECPG_ARRAY_NONE && *scan_length != ' ' && *scan_length != '\0') + return true; + + return false; +} + bool ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, enum ECPGttype type, enum ECPGttype ind_type, char *var, char *ind, long varcharsize, long offset, - long ind_offset, bool isarray, enum COMPAT_MODE compat, bool force_indicator) + long ind_offset, enum ARRAY_TYPE isarray, enum COMPAT_MODE compat, bool force_indicator) { struct sqlca_t *sqlca = ECPGget_sqlca(); char *pval = (char *) PQgetvalue(results, act_tuple, act_field); int value_for_indicator = 0; - ECPGlog("ECPGget_data line %d: RESULT: %s offset: %ld\n", lineno, pval ? pval : "", offset); + ECPGlog("ECPGget_data line %d: RESULT: %s offset: %ld array: %d\n", lineno, pval ? pval : "", offset, isarray); /* pval is a pointer to the value */ - /* let's check is it really is an array if it should be one */ - if (isarray) + /* let's check if it really is an array if it should be one */ + if (isarray == ECPG_ARRAY_ARRAY) { if (*pval != '{') { @@ -126,9 +144,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, if (pval) { res = strtol(pval, &scan_length, 10); - /* INFORMIX allows for selecting a numeric into an int, the result is truncated */ - if ((isarray && *scan_length != ',' && *scan_length != '}') - || (!isarray && !(INFORMIX_MODE(compat) && *scan_length == '.') && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */ + if (garbage_left(isarray, scan_length, compat)) { ECPGraise(lineno, ECPG_INT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); return (false); @@ -160,8 +176,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, if (pval) { ures = strtoul(pval, &scan_length, 10); - if ((isarray && *scan_length != ',' && *scan_length != '}') - || (!isarray && !(INFORMIX_MODE(compat) && *scan_length == '.') && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */ + if (garbage_left(isarray, scan_length, compat)) { ECPGraise(lineno, ECPG_UINT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); return (false); @@ -193,8 +208,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, if (pval) { *((long long int *) (var + offset * act_tuple)) = strtoll(pval, &scan_length, 10); - if ((isarray && *scan_length != ',' && *scan_length != '}') - || (!isarray && !(INFORMIX_MODE(compat) && *scan_length == '.') && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */ + if (garbage_left(isarray, scan_length, compat)) { ECPGraise(lineno, ECPG_INT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); return (false); @@ -236,8 +250,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, if (isarray && *scan_length == '"') scan_length++; - if ((isarray && *scan_length != ',' && *scan_length != '}') - || (!isarray && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */ + if (garbage_left(isarray, scan_length, compat)) { ECPGraise(lineno, ECPG_FLOAT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); return (false); @@ -411,8 +424,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, if (isarray && *scan_length == '"') scan_length++; - if ((isarray && *scan_length != ',' && *scan_length != '}') - || (!isarray && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */ + if (garbage_left(isarray, scan_length, compat)) { ECPGraise(lineno, ECPG_NUMERIC_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); return (false); @@ -455,8 +467,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, if (isarray && *scan_length == '"') scan_length++; - if ((isarray && *scan_length != ',' && *scan_length != '}') - || (!isarray && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */ + if (garbage_left(isarray, scan_length, compat)) { ECPGraise(lineno, ECPG_INTERVAL_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); return (false); @@ -495,8 +506,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, if (isarray && *scan_length == '"') scan_length++; - if ((isarray && *scan_length != ',' && *scan_length != '}') - || (!isarray && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */ + if (garbage_left(isarray, scan_length, compat)) { ECPGraise(lineno, ECPG_DATE_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); return (false); @@ -534,8 +544,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, if (isarray && *scan_length == '"') scan_length++; - if ((isarray && *scan_length != ',' && *scan_length != '}') - || (!isarray && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */ + if (garbage_left(isarray, scan_length, compat)) { ECPGraise(lineno, ECPG_TIMESTAMP_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); return (false); @@ -551,7 +560,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, return (false); break; } - if (isarray) + if (isarray == ECPG_ARRAY_ARRAY) { bool string = false; @@ -566,7 +575,22 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno, if (*pval == ',') ++pval; } - } while (isarray && *pval != '}'); + else if (isarray == ECPG_ARRAY_VECTOR) + { + bool string = false; + + /* set array to next entry */ + ++act_tuple; + + /* set pval to the next entry */ + for (; string || (*pval != ' ' && *pval != '\0'); ++pval) + if (*pval == '"') + string = string ? false : true; + + if (*pval == ' ') + ++pval; + } + } while ((isarray == ECPG_ARRAY_ARRAY && *pval != '}') || (isarray == ECPG_ARRAY_VECTOR && *pval != '\0')); return (true); } diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c index 5bb87e12f6..2da9de7b69 100644 --- a/src/interfaces/ecpg/ecpglib/execute.c +++ b/src/interfaces/ecpg/ecpglib/execute.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.26 2003/10/26 09:50:47 meskes Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.27 2003/11/08 19:46:27 meskes Exp $ */ /* * The aim is to get a simpler inteface to the database routines. @@ -230,29 +230,12 @@ next_insert(char *text) return (*ptr == '\0') ? NULL : ptr; } -/* - * push a value on the cache - */ - -static void -ECPGtypeinfocache_push(struct ECPGtype_information_cache ** cache, int oid, bool isarray, int lineno) -{ - struct ECPGtype_information_cache *new_entry - = (struct ECPGtype_information_cache *) ECPGalloc(sizeof(struct ECPGtype_information_cache), lineno); - - new_entry->oid = oid; - new_entry->isarray = isarray; - new_entry->next = *cache; - *cache = new_entry; -} - -static bool +static enum ARRAY_TYPE ECPGis_type_an_array(int type, const struct statement * stmt, const struct variable * var) { - char *array_query; - int isarray = 0; - PGresult *query; - struct ECPGtype_information_cache *cache_entry; + char *array_query; + enum ARRAY_TYPE isarray = ECPG_ARRAY_NOT_SET; + PGresult *query; if ((stmt->connection->cache_head) == NULL) { @@ -261,78 +244,119 @@ ECPGis_type_an_array(int type, const struct statement * stmt, const struct varia * them as an array. This define reminds you to not 'correct' * these values. */ -#define not_an_array_in_ecpg false - - /* populate cache with well known types to speed things up */ - ECPGtypeinfocache_push(&(stmt->connection->cache_head), BOOLOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), BYTEAOID, not_an_array_in_ecpg, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), CHAROID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), NAMEOID, not_an_array_in_ecpg, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), INT8OID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), INT2OID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), INT2VECTOROID, true, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), INT4OID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), REGPROCOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), TEXTOID, not_an_array_in_ecpg, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), OIDOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), TIDOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), XIDOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), CIDOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), OIDVECTOROID, true, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), POINTOID, true, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), LSEGOID, true, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), PATHOID, not_an_array_in_ecpg, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), BOXOID, true, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), POLYGONOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), LINEOID, true, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), FLOAT4OID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), FLOAT8OID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), ABSTIMEOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), RELTIMEOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), TINTERVALOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), UNKNOWNOID, not_an_array_in_ecpg, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), CIRCLEOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), CASHOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), INETOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), CIDROID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), BPCHAROID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), VARCHAROID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), DATEOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), TIMEOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), TIMESTAMPOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), TIMESTAMPTZOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), INTERVALOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), TIMETZOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), ZPBITOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), VARBITOID, false, stmt->lineno); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), NUMERICOID, false, stmt->lineno); - } - - for (cache_entry = (stmt->connection->cache_head); cache_entry != NULL; cache_entry = cache_entry->next) - { - if (cache_entry->oid == type) - return cache_entry->isarray; - } - - array_query = (char *) ECPGalloc(strlen("select typelem from pg_type where oid=") + 11, stmt->lineno); - sprintf(array_query, "select typelem from pg_type where oid=%d", type); - query = PQexec(stmt->connection->connection, array_query); - ECPGfree(array_query); - if (PQresultStatus(query) == PGRES_TUPLES_OK) - { - isarray = atol((char *) PQgetvalue(query, 0, 0)); - if (ECPGDynamicType(type) == SQL3_CHARACTER || - ECPGDynamicType(type) == SQL3_CHARACTER_VARYING) +#define not_an_array_in_ecpg ECPG_ARRAY_NONE + + switch (type) { - /* - * arrays of character strings are not yet implemented - */ - isarray = false; + case BOOLOID: isarray = ECPG_ARRAY_NONE; + break; + case BYTEAOID: isarray = ECPG_ARRAY_NONE; + break; + case CHAROID: isarray = ECPG_ARRAY_NONE; + break; + case NAMEOID: isarray = not_an_array_in_ecpg; + break; + case INT8OID: isarray = ECPG_ARRAY_NONE; + break; + case INT2OID: isarray = ECPG_ARRAY_NONE; + break; + case INT2VECTOROID: isarray = ECPG_ARRAY_VECTOR; + break; + case INT4OID: isarray = ECPG_ARRAY_NONE; + break; + case REGPROCOID: isarray = ECPG_ARRAY_NONE; + break; + case TEXTOID: isarray = ECPG_ARRAY_NONE; + break; + case OIDOID: isarray = ECPG_ARRAY_NONE; + break; + case TIDOID: isarray = ECPG_ARRAY_NONE; + break; + case XIDOID: isarray = ECPG_ARRAY_NONE; + break; + case CIDOID: isarray = ECPG_ARRAY_NONE; + break; + case OIDVECTOROID: isarray = ECPG_ARRAY_VECTOR; + break; + case POINTOID: isarray = ECPG_ARRAY_VECTOR; + break; + case LSEGOID: isarray = ECPG_ARRAY_VECTOR; + break; + case PATHOID: isarray = ECPG_ARRAY_NONE; + break; + case BOXOID: isarray = ECPG_ARRAY_VECTOR; + break; + case POLYGONOID: isarray = ECPG_ARRAY_NONE; + break; + case LINEOID: isarray = ECPG_ARRAY_VECTOR; + break; + case FLOAT4OID: isarray = ECPG_ARRAY_NONE; + break; + case FLOAT8OID: isarray = ECPG_ARRAY_NONE; + break; + case ABSTIMEOID: isarray = ECPG_ARRAY_NONE; + break; + case RELTIMEOID: isarray = ECPG_ARRAY_NONE; + break; + case TINTERVALOID: isarray = ECPG_ARRAY_NONE; + break; + case UNKNOWNOID: isarray = ECPG_ARRAY_NONE; + break; + case CIRCLEOID: isarray = ECPG_ARRAY_NONE; + break; + case CASHOID: isarray = ECPG_ARRAY_NONE; + break; + case INETOID: isarray = ECPG_ARRAY_NONE; + break; + case CIDROID: isarray = ECPG_ARRAY_NONE; + break; + case BPCHAROID: isarray = ECPG_ARRAY_NONE; + break; + case VARCHAROID: isarray = ECPG_ARRAY_NONE; + break; + case DATEOID: isarray = ECPG_ARRAY_NONE; + break; + case TIMEOID: isarray = ECPG_ARRAY_NONE; + break; + case TIMESTAMPOID: isarray = ECPG_ARRAY_NONE; + break; + case TIMESTAMPTZOID: isarray = ECPG_ARRAY_NONE; + break; + case INTERVALOID: isarray = ECPG_ARRAY_NONE; + break; + case TIMETZOID: isarray = ECPG_ARRAY_NONE; + break; + case ZPBITOID: isarray = ECPG_ARRAY_NONE; + break; + case VARBITOID: isarray = ECPG_ARRAY_NONE; + break; + case NUMERICOID: isarray = ECPG_ARRAY_NONE; + break; + default: break; } - ECPGlog("ECPGexecute line %d: TYPE database: %d C: %d array: %s\n", stmt->lineno, type, var->type, isarray ? "yes" : "no"); - ECPGtypeinfocache_push(&(stmt->connection->cache_head), type, isarray, stmt->lineno); } - PQclear(query); + + if (isarray == ECPG_ARRAY_NOT_SET) + { + array_query = (char *) ECPGalloc(strlen("select typlen from pg_type where oid= and typelem<>0") + 11, stmt->lineno); + sprintf(array_query, "select typlen from pg_type where oid=%d and typelem<>0", type); + query = PQexec(stmt->connection->connection, array_query); + ECPGfree(array_query); + if (PQresultStatus(query) == PGRES_TUPLES_OK) + { + isarray = (atol((char *) PQgetvalue(query, 0, 0)) == -1) ? ECPG_ARRAY_ARRAY : ECPG_ARRAY_VECTOR; + if (ECPGDynamicType(type) == SQL3_CHARACTER || + ECPGDynamicType(type) == SQL3_CHARACTER_VARYING) + { + /* + * arrays of character strings are not yet implemented + */ + isarray = ECPG_ARRAY_NONE; + } + } + PQclear(query); + } + ECPGlog("ECPGexecute line %d: TYPE database: %d C: %d array: %d\n", stmt->lineno, type, var->type, isarray); return isarray; } @@ -341,14 +365,14 @@ bool ECPGstore_result(const PGresult *results, int act_field, const struct statement * stmt, struct variable * var) { - int isarray, - act_tuple, + enum ARRAY_TYPE isarray; + int act_tuple, ntuples = PQntuples(results); bool status = true; isarray = ECPGis_type_an_array(PQftype(results, act_field), stmt, var); - if (!isarray) + if (isarray == ECPG_ARRAY_NONE) { /* * if we don't have enough space, we cannot read all tuples @@ -1164,6 +1188,7 @@ ECPGexecute(struct statement * stmt) case PGRES_TUPLES_OK: nfields = PQnfields(results); sqlca->sqlerrd[2] = ntuples = PQntuples(results); + ECPGlog("ECPGexecute line %d: Correctly got %d tuples with %d fields\n", stmt->lineno, ntuples, nfields); status = true; if (ntuples < 1) diff --git a/src/interfaces/ecpg/ecpglib/extern.h b/src/interfaces/ecpg/ecpglib/extern.h index 3976d5b24d..b265247f38 100644 --- a/src/interfaces/ecpg/ecpglib/extern.h +++ b/src/interfaces/ecpg/ecpglib/extern.h @@ -12,13 +12,18 @@ enum COMPAT_MODE #define INFORMIX_MODE(X) ((X) == ECPG_COMPAT_INFORMIX || (X) == ECPG_COMPAT_INFORMIX_SE) +enum ARRAY_TYPE +{ + ECPG_ARRAY_NOT_SET, ECPG_ARRAY_ARRAY, ECPG_ARRAY_VECTOR, ECPG_ARRAY_NONE +}; + /* Here are some methods used by the lib. */ /* Returns a pointer to a string containing a simple type name. */ void ECPGadd_mem(void *ptr, int lineno); bool ECPGget_data(const PGresult *, int, int, int, enum ECPGttype type, - enum ECPGttype, char *, char *, long, long, long, bool, enum COMPAT_MODE, bool); + enum ECPGttype, char *, char *, long, long, long, enum ARRAY_TYPE, enum COMPAT_MODE, bool); struct connection *ECPGget_connection(const char *); char *ECPGalloc(long, int); char *ECPGrealloc(void *, long, int); diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y index 408c3b8605..86e9afbe7b 100644 --- a/src/interfaces/ecpg/preproc/preproc.y +++ b/src/interfaces/ecpg/preproc/preproc.y @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/Attic/preproc.y,v 1.263 2003/10/22 16:43:42 tgl Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/Attic/preproc.y,v 1.264 2003/11/08 19:46:27 meskes Exp $ */ /* Copyright comment */ %{ @@ -2056,7 +2056,7 @@ access_method_clause: USING access_method ; index_params: index_elem { $$ = $1; } - | index_params ',' index_elem { $$ = $1; } + | index_params ',' index_elem { $$ = cat_str(3, $1, make_str(","), $3); } ; index_elem: attr_name opt_class