diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog index 1e6c960064a71398b13f5a1be6e79cde468a4ce6..ffe622ef924413c5e96dca4375e8be2d05482430 100644 --- a/src/interfaces/ecpg/ChangeLog +++ b/src/interfaces/ecpg/ChangeLog @@ -1146,5 +1146,9 @@ Sun Oct 21 14:19:42 CEST 2001 Fri Nov 2 16:16:25 CET 2001 - Synced preproc.y with gram.y. + +Wed Nov 14 11:50:27 CET 2001 + + - Added several patches by Christof Petig . - Set ecpg version to 2.9.0. - Set library version to 3.3.0. diff --git a/src/interfaces/ecpg/README.dynSQL b/src/interfaces/ecpg/README.dynSQL index fedcf80402dbbc863d94356443769a2a17f12789..4c606ca3985a9162c8d9482bcf5686413c67fc09 100644 --- a/src/interfaces/ecpg/README.dynSQL +++ b/src/interfaces/ecpg/README.dynSQL @@ -1,20 +1,10 @@ descriptor statements have the following shortcomings -- up to now the only reasonable statement is - FETCH ... INTO SQL DESCRIPTOR - no input variables allowed! +- input descriptors (USING DESCRIPTOR ) are not supported Reason: to fully support dynamic SQL the frontend/backend communication should change to recognize input parameters. Since this is not likely to happen in the near future and you can cover the same functionality with the existing infrastructure - I'll leave the work to someone else. - -- string buffer overflow does not always generate warnings - (beware: terminating 0 may be missing because strncpy is used) - :var=data sets sqlwarn accordingly (but not indicator) - -- char variables pointing to NULL are not allocated on demand - -- string truncation does not show up in indicator + (using s[n]printf), I'll leave the work to someone else. diff --git a/src/interfaces/ecpg/include/ecpglib.h b/src/interfaces/ecpg/include/ecpglib.h index 8c455ec58b0d9d50ff1cd1d881c70513ec5c6a29..5c295d872802cb028c354935100d68c18feb7b33 100644 --- a/src/interfaces/ecpg/include/ecpglib.h +++ b/src/interfaces/ecpg/include/ecpglib.h @@ -67,6 +67,8 @@ void ECPGraise(int line, int code, const char *str); bool ECPGget_desc_header(int, char *, int *); bool ECPGget_desc(int, char *, int,...); +/* dynamic result allocation */ + void ECPGfree_auto_mem(void); #ifdef __cplusplus } diff --git a/src/interfaces/ecpg/lib/connect.c b/src/interfaces/ecpg/lib/connect.c index da4b8a3d7e07b429b6c0ef8db360d765fe218352..2f02e92da377f5f0e7463d0836808add4830d406 100644 --- a/src/interfaces/ecpg/lib/connect.c +++ b/src/interfaces/ecpg/lib/connect.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/connect.c,v 1.14 2001/10/31 04:49:44 momjian Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/connect.c,v 1.15 2001/11/14 11:11:49 meskes Exp $ */ #include "postgres_fe.h" @@ -12,7 +12,7 @@ static struct connection *all_connections = NULL, *actual_connection = NULL; struct connection * -get_connection(const char *connection_name) +ECPGget_connection(const char *connection_name) { struct connection *con = all_connections; @@ -63,10 +63,10 @@ ecpg_finish(struct connection * act) bool ECPGsetcommit(int lineno, const char *mode, const char *connection_name) { - struct connection *con = get_connection(connection_name); + struct connection *con = ECPGget_connection(connection_name); PGresult *results; - if (!ecpg_init(con, connection_name, lineno)) + if (!ECPGinit(con, connection_name, lineno)) return (false); ECPGlog("ECPGsetcommit line %d action = %s connection = %s\n", lineno, mode, con->name); @@ -106,9 +106,9 @@ ECPGsetcommit(int lineno, const char *mode, const char *connection_name) bool ECPGsetconn(int lineno, const char *connection_name) { - struct connection *con = get_connection(connection_name); + struct connection *con = ECPGget_connection(connection_name); - if (!ecpg_init(con, connection_name, lineno)) + if (!ECPGinit(con, connection_name, lineno)) return (false); actual_connection = con; @@ -269,9 +269,9 @@ ECPGconnect(int lineno, const char *name, const char *user, const char *passwd, *realname = NULL, *options = NULL; - init_sqlca(); + ECPGinit_sqlca(); - if ((this = (struct connection *) ecpg_alloc(sizeof(struct connection), lineno)) == NULL) + if ((this = (struct connection *) ECPGalloc(sizeof(struct connection), lineno)) == NULL) return false; if (dbname == NULL && connection_name == NULL) @@ -393,9 +393,9 @@ ECPGconnect(int lineno, const char *name, const char *user, const char *passwd, /* add connection to our list */ if (connection_name != NULL) - this->name = ecpg_strdup(connection_name, lineno); + this->name = ECPGstrdup(connection_name, lineno); else - this->name = ecpg_strdup(realname, lineno); + this->name = ECPGstrdup(realname, lineno); this->cache_head = NULL; @@ -465,7 +465,7 @@ ECPGdisconnect(int lineno, const char *connection_name) if (strcmp(connection_name, "ALL") == 0) { - init_sqlca(); + ECPGinit_sqlca(); for (con = all_connections; con;) { struct connection *f = con; @@ -476,9 +476,9 @@ ECPGdisconnect(int lineno, const char *connection_name) } else { - con = get_connection(connection_name); + con = ECPGget_connection(connection_name); - if (!ecpg_init(con, connection_name, lineno)) + if (!ECPGinit(con, connection_name, lineno)) return (false); else ecpg_finish(con); diff --git a/src/interfaces/ecpg/lib/data.c b/src/interfaces/ecpg/lib/data.c index 0d4ec712b55d2a8e86386ce17aca3d23b9a8f6a9..81bdad751bf112d6aeb3d636b36094c2a59d177b 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.18 2001/11/05 17:46:37 momjian Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/data.c,v 1.19 2001/11/14 11:11:49 meskes Exp $ */ #include "postgres_fe.h" @@ -12,14 +12,14 @@ #include "sqlca.h" bool -get_data(const PGresult *results, int act_tuple, int act_field, int lineno, +ECPGget_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) { char *pval = (char *) PQgetvalue(results, act_tuple, act_field); - ECPGlog("get_data line %d: RESULT: %s\n", lineno, pval ? pval : ""); + ECPGlog("ECPGget_data line %d: RESULT: %s\n", lineno, pval ? pval : ""); /* pval is a pointer to the value */ /* let's check is it really is an array if it should be one */ diff --git a/src/interfaces/ecpg/lib/descriptor.c b/src/interfaces/ecpg/lib/descriptor.c index 95e65d603e4545d7a41eadb6104733fa68ec8af7..533bdcea5a45640a158111e6bbf76371326b5113 100644 --- a/src/interfaces/ecpg/lib/descriptor.c +++ b/src/interfaces/ecpg/lib/descriptor.c @@ -1,9 +1,10 @@ /* dynamic SQL support routines * - * $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/descriptor.c,v 1.18 2001/11/05 17:46:37 momjian Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/descriptor.c,v 1.19 2001/11/14 11:11:49 meskes Exp $ */ #include "postgres_fe.h" +#include "pg_type.h" #include "ecpgtype.h" #include "ecpglib.h" @@ -30,14 +31,16 @@ ECPGDynamicType_DDT(Oid type) { switch (type) { - case 1082: - return SQL3_DDT_DATE; /* date */ - case 1083: - return SQL3_DDT_TIME; /* time */ - case 1184: - return SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE; /* datetime */ - case 1296: - return SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE; /* timestamp */ + case DATEOID: + return SQL3_DDT_DATE; + case TIMEOID: + return SQL3_DDT_TIME; + case TIMESTAMPOID: + return SQL3_DDT_TIMESTAMP; + case TIMESTAMPTZOID: + return SQL3_DDT_TIMESTAMP_WITH_TIME_ZONE; + case TIMETZOID: + return SQL3_DDT_TIME_WITH_TIME_ZONE; default: return SQL3_DDT_ILLEGAL; } @@ -139,11 +142,10 @@ ECPGget_desc(int lineno, char *desc_name, int index,...) va_list args; PGresult *ECPGresult = ECPGresultByDescriptor(lineno, desc_name); enum ECPGdtype type; - bool Indicator_seen = false, - Data_seen = false; int ntuples, act_tuple; - + struct variable data_var; + va_start(args, index); if (!ECPGresult) return (false); @@ -165,7 +167,11 @@ ECPGget_desc(int lineno, char *desc_name, int index,...) --index; type = va_arg(args, enum ECPGdtype); - + + memset (&data_var, 0, sizeof data_var); + data_var.type=ECPGt_EORT; + data_var.ind_type=ECPGt_NO_INDICATOR; + while (type != ECPGd_EODT) { char type_str[20]; @@ -184,26 +190,27 @@ ECPGget_desc(int lineno, char *desc_name, int index,...) switch (type) { case (ECPGd_indicator): + data_var.ind_type=vartype; + data_var.ind_pointer=var; + data_var.ind_varcharsize=varcharsize; + data_var.ind_arrsize=arrsize; + data_var.ind_offset=offset; + if (data_var.ind_arrsize == 0 || data_var.ind_varcharsize == 0) + data_var.ind_value = *((void **) (data_var.ind_pointer)); + else + data_var.ind_value = data_var.ind_pointer; + break; - /* - * this is like ECPGexecute missing : allocate arrays, - * perhaps this should go into a common function !! - */ - if (ntuples > arrsize) - { - ECPGlog("ECPGget_desc line %d: Incorrect number of matches: %d don't fit into array of %d\n", - lineno, ntuples, arrsize); - ECPGraise(lineno, ECPG_TOO_MANY_MATCHES, NULL); - return false; - } - Indicator_seen = true; - for (act_tuple = 0; act_tuple < ntuples; act_tuple++) - { - if (!get_int_item(lineno, var, vartype, -PQgetisnull(ECPGresult, act_tuple, index))) - return (false); - var = (char *) var + offset; - ECPGlog("ECPGget_desc: INDICATOR[%d] = %d\n", act_tuple, -PQgetisnull(ECPGresult, act_tuple, index)); - } + case ECPGd_data: + data_var.type=vartype; + data_var.pointer=var; + data_var.varcharsize=varcharsize; + data_var.arrsize=arrsize; + data_var.offset=offset; + if (data_var.arrsize == 0 || data_var.varcharsize == 0) + data_var.value = *((void **) (data_var.pointer)); + else + data_var.value = data_var.pointer; break; case ECPGd_name: @@ -239,29 +246,6 @@ ECPGget_desc(int lineno, char *desc_name, int index,...) ECPGlog("ECPGget_desc: PRECISION = %d\n", PQfmod(ECPGresult, index) >> 16); break; - case ECPGd_ret_length: - case ECPGd_ret_octet: - - /* - * this is like ECPGexecute missing : allocate arrays, - * perhaps this should go into a common function !! - */ - if (ntuples > arrsize) - { - ECPGlog("ECPGget_desc line %d: Incorrect number of matches: %d don't fit into array of %d\n", - lineno, ntuples, arrsize); - ECPGraise(lineno, ECPG_TOO_MANY_MATCHES, NULL); - return false; - } - for (act_tuple = 0; act_tuple < ntuples; act_tuple++) - { - if (!get_int_item(lineno, var, vartype, PQgetlength(ECPGresult, act_tuple, index))) - return (false); - var = (char *) var + offset; - ECPGlog("ECPGget_desc: RETURNED[%d] = %d\n", act_tuple, PQgetlength(ECPGresult, act_tuple, index)); - } - break; - case ECPGd_octet: if (!get_int_item(lineno, var, vartype, PQfsize(ECPGresult, index))) return (false); @@ -289,38 +273,45 @@ ECPGget_desc(int lineno, char *desc_name, int index,...) ECPGlog("ECPGget_desc: TYPE = %d\n", ECPGDynamicType_DDT(PQftype(ECPGresult, index))); break; - case ECPGd_data: + + case ECPGd_cardinality: + if (!get_int_item(lineno, var, vartype, PQntuples(ECPGresult))) + return (false); + + ECPGlog("ECPGget_desc: CARDINALITY = %d\n", PQntuples(ECPGresult)); + break; + + case ECPGd_ret_length: + case ECPGd_ret_octet: /* - * this is like ECPGexecute missing : allocate arrays, - * perhaps this should go into a common function !! + * this is like ECPGstore_result */ - if (ntuples > arrsize) + if (arrsize > 0 && ntuples > arrsize) { ECPGlog("ECPGget_desc line %d: Incorrect number of matches: %d don't fit into array of %d\n", lineno, ntuples, arrsize); ECPGraise(lineno, ECPG_TOO_MANY_MATCHES, NULL); return false; } - Data_seen = true; + /* allocate storage if needed */ + if (arrsize == 0 && var != NULL && *(void**)var == NULL) + { + void *mem = (void *) ECPGalloc(offset * ntuples, lineno); + *(void **)var = mem; + ECPGadd_mem(mem, lineno); + var = mem; + } + for (act_tuple = 0; act_tuple < ntuples; act_tuple++) { - if (PQgetisnull(ECPGresult, act_tuple, index)) - continue; /* do not touch data on null value */ - if (!get_data(ECPGresult, act_tuple, index, lineno, - vartype, ECPGt_NO_INDICATOR, var, NULL, - varcharsize, offset, false)) + if (!get_int_item(lineno, var, vartype, PQgetlength(ECPGresult, act_tuple, index))) return (false); + var = (char *) var + offset; + ECPGlog("ECPGget_desc: RETURNED[%d] = %d\n", act_tuple, PQgetlength(ECPGresult, act_tuple, index)); } break; - case ECPGd_cardinality: - if (!get_int_item(lineno, var, vartype, PQntuples(ECPGresult))) - return (false); - - ECPGlog("ECPGget_desc: CARDINALITY = %d\n", PQntuples(ECPGresult)); - break; - default: snprintf(type_str, sizeof(type_str), "%d", type); ECPGraise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, type_str); @@ -330,18 +321,45 @@ ECPGget_desc(int lineno, char *desc_name, int index,...) type = va_arg(args, enum ECPGdtype); } - if (Data_seen && !Indicator_seen) + if (data_var.type!=ECPGt_EORT) { + struct statement stmt; + memset (&stmt, 0, sizeof stmt); + stmt.lineno=lineno; + /* desparate try to guess something sensible */ + stmt.connection=ECPGget_connection(NULL); + ECPGstore_result(ECPGresult, index, &stmt, &data_var); + } + else if (data_var.ind_type!=ECPGt_NO_INDICATOR) + { + /* + * this is like ECPGstore_result + * but since we don't have a data variable at hand, we can't call it + */ + if (data_var.ind_arrsize > 0 && ntuples > data_var.ind_arrsize) + { + ECPGlog("ECPGget_desc line %d: Incorrect number of matches (indicator): %d don't fit into array of %d\n", + lineno, ntuples, data_var.ind_arrsize); + ECPGraise(lineno, ECPG_TOO_MANY_MATCHES, NULL); + return false; + } + /* allocate storage if needed */ + if (data_var.ind_arrsize == 0 && data_var.ind_pointer != NULL && data_var.ind_value == NULL) + { + void *mem = (void *) ECPGalloc(data_var.ind_offset * ntuples, lineno); + *(void **)data_var.ind_pointer = mem; + ECPGadd_mem(mem, lineno); + data_var.ind_value = mem; + } for (act_tuple = 0; act_tuple < ntuples; act_tuple++) { - if (PQgetisnull(ECPGresult, act_tuple, index)) - { - ECPGraise(lineno, ECPG_MISSING_INDICATOR, NULL); + if (!get_int_item(lineno, data_var.ind_value, data_var.ind_type, -PQgetisnull(ECPGresult, act_tuple, index))) return (false); - } + data_var.ind_value = (char *) data_var.ind_value + data_var.ind_offset; + ECPGlog("ECPGget_desc: INDICATOR[%d] = %d\n", act_tuple, -PQgetisnull(ECPGresult, act_tuple, index)); } } - + return (true); } @@ -369,10 +387,10 @@ ECPGdeallocate_desc(int line, const char *name) bool ECPGallocate_desc(int line, const char *name) { - struct descriptor *new = (struct descriptor *) ecpg_alloc(sizeof(struct descriptor), line); + struct descriptor *new = (struct descriptor *) ECPGalloc(sizeof(struct descriptor), line); new->next = all_descriptors; - new->name = ecpg_alloc(strlen(name) + 1, line); + new->name = ECPGalloc(strlen(name) + 1, line); new->result = PQmakeEmptyPGresult(NULL, 0); strcpy(new->name, name); all_descriptors = new; diff --git a/src/interfaces/ecpg/lib/error.c b/src/interfaces/ecpg/lib/error.c index e39ee48c11529fcf4a1f31a68daaf96818b96007..56dd42fbed9c942e3d7937814a884e8fe737330c 100644 --- a/src/interfaces/ecpg/lib/error.c +++ b/src/interfaces/ecpg/lib/error.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/error.c,v 1.12 2001/10/18 20:32:58 momjian Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/error.c,v 1.13 2001/11/14 11:11:49 meskes Exp $ */ #include "postgres_fe.h" @@ -154,7 +154,7 @@ ECPGraise(int line, int code, const char *str) ECPGlog("raising sqlcode %d in line %d, '%s'.\n", code, line, sqlca.sqlerrm.sqlerrmc); /* free all memory we have allocated for the user */ - free_auto_mem(); + ECPGfree_auto_mem(); } /* print out an error message */ diff --git a/src/interfaces/ecpg/lib/execute.c b/src/interfaces/ecpg/lib/execute.c index 57fd5c7767640f0ae2483992d88b71695bc8cb0f..4cd13944d2b74ff762bbea4cb8f5775a1c6dec34 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.31 2001/11/05 17:46:37 momjian Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/execute.c,v 1.32 2001/11/14 11:11:49 meskes Exp $ */ /* * The aim is to get a simpler inteface to the database routines. @@ -55,22 +55,6 @@ struct sqlca sqlca = } }; -struct variable -{ - enum ECPGttype type; - void *value; - void *pointer; - 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; -}; - /* keep a list of memory we allocated for the user */ static struct auto_mem { @@ -78,17 +62,17 @@ static struct auto_mem struct auto_mem *next; } *auto_allocs = NULL; -static void -add_mem(void *ptr, int lineno) +void +ECPGadd_mem(void *ptr, int lineno) { - struct auto_mem *am = (struct auto_mem *) ecpg_alloc(sizeof(struct auto_mem), lineno); - + struct auto_mem *am = (struct auto_mem *) ECPGalloc(sizeof(struct auto_mem), lineno); + am->pointer = ptr; am->next = auto_allocs; auto_allocs = am; } void -free_auto_mem(void) +ECPGfree_auto_mem(void) { struct auto_mem *am; @@ -112,7 +96,7 @@ static char * quote_postgres(char *arg, int lineno) { - char *res = (char *) ecpg_alloc(2 * strlen(arg) + 3, lineno); + char *res = (char *) ECPGalloc(2 * strlen(arg) + 3, lineno); int i, ri = 0; @@ -168,7 +152,7 @@ create_statement(int lineno, struct connection * connection, struct statement ** struct variable **list = &((*stmt)->inlist); enum ECPGttype type; - if (!(*stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno))) + if (!(*stmt = (struct statement *) ECPGalloc(sizeof(struct statement), lineno))) return false; (*stmt)->command = query; @@ -188,7 +172,7 @@ create_statement(int lineno, struct connection * connection, struct statement ** struct variable *var, *ptr; - if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno))) + if (!(var = (struct variable *) ECPGalloc(sizeof(struct variable), lineno))) return false; var->type = type; @@ -212,12 +196,18 @@ create_statement(int lineno, struct connection * connection, struct statement ** var->value = var->pointer; var->ind_type = va_arg(ap, enum ECPGttype); - var->ind_value = va_arg(ap, void *); + var->ind_pointer = 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; + if (var->ind_type!=ECPGt_NO_INDICATOR + && (var->ind_arrsize == 0 || var->ind_varcharsize == 0)) + var->ind_value = *((void **) (var->ind_pointer)); + else + var->ind_value = var->ind_pointer; + for (ptr = *list; ptr && ptr->next; ptr = ptr->next); if (ptr == NULL) @@ -285,7 +275,7 @@ 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 *) ecpg_alloc(sizeof(struct ECPGtype_information_cache), lineno); + = (struct ECPGtype_information_cache *) ECPGalloc(sizeof(struct ECPGtype_information_cache), lineno); new_entry->oid = oid; new_entry->isarray = isarray; @@ -347,6 +337,7 @@ ECPGis_type_an_array(int type, const struct statement * stmt, const struct varia 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); @@ -360,7 +351,7 @@ ECPGis_type_an_array(int type, const struct statement * stmt, const struct varia return cache_entry->isarray; } - array_query = (char *) ecpg_alloc(strlen("select typelem from pg_type where oid=") + 11, stmt->lineno); + 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); free(array_query); @@ -430,17 +421,33 @@ ECPGstore_result(const PGresult *results, int act_field, { case ECPGt_char: case ECPGt_unsigned_char: - var->varcharsize = 0; - /* check strlen for each tuple */ - for (act_tuple = 0; act_tuple < ntuples; act_tuple++) + if (!var->varcharsize && !var->arrsize) { - int len = strlen(PQgetvalue(results, act_tuple, act_field)) + 1; + /* special mode for handling char**foo=0 */ + for (act_tuple = 0; act_tuple < ntuples; act_tuple++) + { + len += strlen(PQgetvalue(results, act_tuple, act_field)) + 1; + } + len *= var->offset; /* should be 1, but YMNK */ + len += (ntuples+1) * sizeof(char *); - if (len > var->varcharsize) - var->varcharsize = len; + ECPGlog("ECPGstore_result: line %d: allocating %d bytes for %d tuples (char**=0)", + stmt->lineno,len, ntuples); + } + else + { + 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; } - var->offset *= var->varcharsize; - len = var->offset * ntuples; break; case ECPGt_varchar: len = ntuples * (var->varcharsize + sizeof(int)); @@ -449,17 +456,58 @@ ECPGstore_result(const PGresult *results, int act_field, len = var->offset * ntuples; break; } - var->value = (void *) ecpg_alloc(len, stmt->lineno); + var->value = (void *) ECPGalloc(len, stmt->lineno); *((void **) var->pointer) = var->value; - add_mem(var->value, stmt->lineno); + ECPGadd_mem(var->value, stmt->lineno); + } + /* allocate indicator variable if needed */ + if ((var->ind_arrsize == 0 || var->ind_varcharsize == 0) && var->ind_value == NULL && var->ind_pointer!=NULL) + { + int len = var->ind_offset * ntuples; + var->ind_value = (void *) ECPGalloc(len, stmt->lineno); + *((void **) var->ind_pointer) = var->ind_value; + ECPGadd_mem(var->ind_value, stmt->lineno); } + + /* fill the variable with the tuple(s) */ - for (act_tuple = 0; act_tuple < ntuples && status; act_tuple++) + if (!var->varcharsize && !var->arrsize && + (var->type==ECPGt_char || var->type==ECPGt_unsigned_char)) + { + /* special mode for handling char**foo=0 */ + + /* filling the array of (char*)s */ + char **current_string = (char**) var->value; + /* storing the data (after the last array element) */ + char *current_data_location = (char*) ¤t_string[ntuples+1]; + + for (act_tuple = 0; act_tuple < ntuples && status; act_tuple++) + { + int len = strlen(PQgetvalue(results, act_tuple, act_field)) + 1; + if (!ECPGget_data(results, act_tuple, act_field, stmt->lineno, + var->type, var->ind_type, current_data_location, + var->ind_value, len, 0, isarray)) + status = false; + else + { + *current_string = current_data_location; + current_data_location += len; + current_string++; + } + } + + /* terminate the list */ + *current_string = NULL; + } + else { - 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; + for (act_tuple = 0; act_tuple < ntuples && status; act_tuple++) + { + if (!ECPGget_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; } @@ -515,7 +563,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, int element; case ECPGt_short: - if (!(mallocedval = ecpg_alloc(var->arrsize * 20, stmt->lineno))) + if (!(mallocedval = ECPGalloc(var->arrsize * 20, stmt->lineno))) return false; if (var->arrsize > 1) @@ -535,7 +583,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, break; case ECPGt_int: - if (!(mallocedval = ecpg_alloc(var->arrsize * 20, stmt->lineno))) + if (!(mallocedval = ECPGalloc(var->arrsize * 20, stmt->lineno))) return false; if (var->arrsize > 1) @@ -555,7 +603,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, break; case ECPGt_unsigned_short: - if (!(mallocedval = ecpg_alloc(var->arrsize * 20, stmt->lineno))) + if (!(mallocedval = ECPGalloc(var->arrsize * 20, stmt->lineno))) return false; if (var->arrsize > 1) @@ -575,7 +623,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, break; case ECPGt_unsigned_int: - if (!(mallocedval = ecpg_alloc(var->arrsize * 20, stmt->lineno))) + if (!(mallocedval = ECPGalloc(var->arrsize * 20, stmt->lineno))) return false; if (var->arrsize > 1) @@ -595,7 +643,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, break; case ECPGt_long: - if (!(mallocedval = ecpg_alloc(var->arrsize * 20, stmt->lineno))) + if (!(mallocedval = ECPGalloc(var->arrsize * 20, stmt->lineno))) return false; if (var->arrsize > 1) @@ -615,7 +663,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, break; case ECPGt_unsigned_long: - if (!(mallocedval = ecpg_alloc(var->arrsize * 20, stmt->lineno))) + if (!(mallocedval = ECPGalloc(var->arrsize * 20, stmt->lineno))) return false; if (var->arrsize > 1) @@ -635,7 +683,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, break; #ifdef HAVE_LONG_LONG_INT_64 case ECPGt_long_long: - if (!(mallocedval = ecpg_alloc(var->arrsize * 25, stmt->lineno))) + if (!(mallocedval = ECPGalloc(var->arrsize * 25, stmt->lineno))) return false; if (var->arrsize > 1) @@ -655,7 +703,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, break; case ECPGt_unsigned_long_long: - if (!(mallocedval = ecpg_alloc(var->arrsize * 25, stmt->lineno))) + if (!(mallocedval = ECPGalloc(var->arrsize * 25, stmt->lineno))) return false; if (var->arrsize > 1) @@ -675,7 +723,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, break; #endif /* HAVE_LONG_LONG_INT_64 */ case ECPGt_float: - if (!(mallocedval = ecpg_alloc(var->arrsize * 20, stmt->lineno))) + if (!(mallocedval = ECPGalloc(var->arrsize * 20, stmt->lineno))) return false; if (var->arrsize > 1) @@ -695,7 +743,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, break; case ECPGt_double: - if (!(mallocedval = ecpg_alloc(var->arrsize * 20, stmt->lineno))) + if (!(mallocedval = ECPGalloc(var->arrsize * 20, stmt->lineno))) return false; if (var->arrsize > 1) @@ -715,7 +763,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, break; case ECPGt_bool: - if (!(mallocedval = ecpg_alloc(var->arrsize * 20, stmt->lineno))) + if (!(mallocedval = ECPGalloc(var->arrsize * 20, stmt->lineno))) return false; if (var->arrsize > 1) @@ -758,7 +806,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, /* set slen to string length if type is char * */ int slen = (var->varcharsize == 0) ? strlen((char *) var->value) : var->varcharsize; - if (!(newcopy = ecpg_alloc(slen + 1, stmt->lineno))) + if (!(newcopy = ECPGalloc(slen + 1, stmt->lineno))) return false; strncpy(newcopy, (char *) var->value, slen); @@ -778,7 +826,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, { int slen = strlen((char *) var->value); - if (!(mallocedval = ecpg_alloc(slen + 1, stmt->lineno))) + if (!(mallocedval = ECPGalloc(slen + 1, stmt->lineno))) return false; strncpy(mallocedval, (char *) var->value, slen); @@ -793,7 +841,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, struct ECPGgeneric_varchar *variable = (struct ECPGgeneric_varchar *) (var->value); - if (!(newcopy = (char *) ecpg_alloc(variable->len + 1, stmt->lineno))) + if (!(newcopy = (char *) ECPGalloc(variable->len + 1, stmt->lineno))) return false; strncpy(newcopy, variable->arr, variable->len); @@ -829,7 +877,7 @@ ECPGexecute(struct statement * stmt) PGnotify *notify; struct variable *var; - copiedquery = ecpg_strdup(stmt->command, stmt->lineno); + copiedquery = ECPGstrdup(stmt->command, stmt->lineno); /* * Now, if the type is one of the fill in types then we take the @@ -853,7 +901,7 @@ ECPGexecute(struct statement * stmt) * Now tobeinserted points to an area that is to be inserted at * the first %s */ - if (!(newcopy = (char *) ecpg_alloc(strlen(copiedquery) + strlen(tobeinserted) + 1, stmt->lineno))) + if (!(newcopy = (char *) ECPGalloc(strlen(copiedquery) + strlen(tobeinserted) + 1, stmt->lineno))) return false; strcpy(newcopy, copiedquery); @@ -1054,7 +1102,7 @@ ECPGdo(int lineno, const char *connection_name, char *query,...) { va_list args; struct statement *stmt; - struct connection *con = get_connection(connection_name); + struct connection *con = ECPGget_connection(connection_name); bool status; char *oldlocale; @@ -1063,7 +1111,7 @@ ECPGdo(int lineno, const char *connection_name, char *query,...) oldlocale = strdup(setlocale(LC_NUMERIC, NULL)); setlocale(LC_NUMERIC, "C"); - if (!ecpg_init(con, connection_name, lineno)) + if (!ECPGinit(con, connection_name, lineno)) { setlocale(LC_NUMERIC, oldlocale); free(oldlocale); diff --git a/src/interfaces/ecpg/lib/extern.h b/src/interfaces/ecpg/lib/extern.h index 8e7ba566a36f99dca2e564ed802b56795829d935..3759751555bb27ec6f2cae5dafda1f85849fc0a0 100644 --- a/src/interfaces/ecpg/lib/extern.h +++ b/src/interfaces/ecpg/lib/extern.h @@ -3,14 +3,15 @@ /* 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(const PGresult *, int, int, int, enum ECPGttype type, +void ECPGadd_mem(void *ptr, int lineno); + +bool ECPGget_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); -char *ecpg_alloc(long, int); -bool ecpg_init(const struct connection *, const char *, const int); -char *ecpg_strdup(const char *, int); +struct connection *ECPGget_connection(const char *); +void ECPGinit_sqlca(void); +char *ECPGalloc(long, int); +bool ECPGinit(const struct connection *, const char *, const int); +char *ECPGstrdup(const char *, int); const char *ECPGtype_name(enum ECPGttype); unsigned int ECPGDynamicType(Oid); @@ -62,6 +63,23 @@ struct descriptor struct descriptor *next; }; +struct variable +{ + enum ECPGttype type; + void *value; + void *pointer; + long varcharsize; + long arrsize; + long offset; + enum ECPGttype ind_type; + void *ind_value; + void *ind_pointer; + long ind_varcharsize; + long ind_arrsize; + long ind_offset; + struct variable *next; +}; + PGresult ** ECPGdescriptor_lvalue(int line, const char *descriptor); diff --git a/src/interfaces/ecpg/lib/memory.c b/src/interfaces/ecpg/lib/memory.c index b49289abe5c27c1cad5c37404edf22b93a57a459..e1bc12eef3f8cb493e4b084743e5a28fb09a116e 100644 --- a/src/interfaces/ecpg/lib/memory.c +++ b/src/interfaces/ecpg/lib/memory.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/memory.c,v 1.6 2001/10/05 17:37:07 meskes Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/memory.c,v 1.7 2001/11/14 11:11:49 meskes Exp $ */ #include "postgres_fe.h" @@ -8,7 +8,7 @@ #include "extern.h" char * -ecpg_alloc(long size, int lineno) +ECPGalloc(long size, int lineno) { char *new = (char *) calloc(1L, size); @@ -23,7 +23,7 @@ ecpg_alloc(long size, int lineno) } char * -ecpg_strdup(const char *string, int lineno) +ECPGstrdup(const char *string, int lineno) { char *new = strdup(string); diff --git a/src/interfaces/ecpg/lib/misc.c b/src/interfaces/ecpg/lib/misc.c index 2d3daf7d4fdf06f206a15cceca3fc53a6175a113..1a74cf46d309a88649cba34451b1cc5300188540 100644 --- a/src/interfaces/ecpg/lib/misc.c +++ b/src/interfaces/ecpg/lib/misc.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/misc.c,v 1.9 2001/10/30 05:38:56 momjian Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/misc.c,v 1.10 2001/11/14 11:11:49 meskes Exp $ */ #include "postgres_fe.h" @@ -40,15 +40,15 @@ static int simple_debug = 0; static FILE *debugstream = NULL; void -init_sqlca(void) +ECPGinit_sqlca(void) { memcpy((char *) &sqlca, (char *) &sqlca_init, sizeof(sqlca)); } bool -ecpg_init(const struct connection * con, const char *connection_name, const int lineno) +ECPGinit(const struct connection * con, const char *connection_name, const int lineno) { - init_sqlca(); + ECPGinit_sqlca(); if (con == NULL) { ECPGraise(lineno, ECPG_NO_CONN, connection_name ? connection_name : "NULL"); @@ -61,9 +61,9 @@ ecpg_init(const struct connection * con, const char *connection_name, const int bool ECPGstatus(int lineno, const char *connection_name) { - struct connection *con = get_connection(connection_name); + struct connection *con = ECPGget_connection(connection_name); - if (!ecpg_init(con, connection_name, lineno)) + if (!ECPGinit(con, connection_name, lineno)) return (false); /* are we connected? */ @@ -80,9 +80,9 @@ bool ECPGtrans(int lineno, const char *connection_name, const char *transaction) { PGresult *res; - struct connection *con = get_connection(connection_name); + struct connection *con = ECPGget_connection(connection_name); - if (!ecpg_init(con, connection_name, lineno)) + if (!ECPGinit(con, connection_name, lineno)) return (false); ECPGlog("ECPGtrans line %d action = %s connection = %s\n", lineno, transaction, con->name); diff --git a/src/interfaces/ecpg/lib/pg_type.h b/src/interfaces/ecpg/lib/pg_type.h index 5ebe0faed178309fe3d7efd4aad71654d97c2cbe..da8cebf7ec2c2079472c9999c655cf1749dda6fc 100644 --- a/src/interfaces/ecpg/lib/pg_type.h +++ b/src/interfaces/ecpg/lib/pg_type.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_type.h,v 1.5 2001/11/05 17:46:37 momjian Exp $ + * $Id: pg_type.h,v 1.6 2001/11/14 11:11:49 meskes Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -62,7 +62,8 @@ #define VARCHAROID 1043 #define DATEOID 1082 #define TIMEOID 1083 -#define TIMESTAMPOID 1184 +#define TIMESTAMPOID 1114 +#define TIMESTAMPTZOID 1184 #define INTERVALOID 1186 #define TIMETZOID 1266 #define ZPBITOID 1560 diff --git a/src/interfaces/ecpg/lib/prepare.c b/src/interfaces/ecpg/lib/prepare.c index e0960768799ad53bac6c8d206db7d66bac642322..4117454835e533cdfaea5856fbff5ad375029019 100644 --- a/src/interfaces/ecpg/lib/prepare.c +++ b/src/interfaces/ecpg/lib/prepare.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/prepare.c,v 1.10 2001/11/05 17:46:37 momjian Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/lib/Attic/prepare.c,v 1.11 2001/11/14 11:11:49 meskes Exp $ */ #include "postgres_fe.h" @@ -69,11 +69,11 @@ ECPGprepare(int lineno, char *name, char *variable) return false; } - this = (struct prepared_statement *) ecpg_alloc(sizeof(struct prepared_statement), lineno); + this = (struct prepared_statement *) ECPGalloc(sizeof(struct prepared_statement), lineno); if (!this) return false; - stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno); + stmt = (struct statement *) ECPGalloc(sizeof(struct statement), lineno); if (!stmt) { free(this); @@ -83,14 +83,14 @@ ECPGprepare(int lineno, char *name, char *variable) /* create statement */ stmt->lineno = lineno; stmt->connection = NULL; - stmt->command = ecpg_strdup(variable, lineno); + stmt->command = ECPGstrdup(variable, lineno); stmt->inlist = stmt->outlist = NULL; /* if we have C variables in our statment replace them with '?' */ replace_variables(stmt->command); /* add prepared statement to our list */ - this->name = ecpg_strdup(name, lineno); + this->name = ECPGstrdup(name, lineno); this->stmt = stmt; if (prep_stmts == NULL) diff --git a/src/interfaces/ecpg/test/Makefile b/src/interfaces/ecpg/test/Makefile index 33bd758378cd10532b2f433e0904b6429ec6f1df..5ce77ef9b7fa97d70df332b888fe46bf19ba21ef 100644 --- a/src/interfaces/ecpg/test/Makefile +++ b/src/interfaces/ecpg/test/Makefile @@ -1,4 +1,4 @@ -# $Header: /cvsroot/pgsql/src/interfaces/ecpg/test/Makefile,v 1.31 2001/08/11 10:52:09 petere Exp $ +# $Header: /cvsroot/pgsql/src/interfaces/ecpg/test/Makefile,v 1.32 2001/11/14 11:11:49 meskes Exp $ subdir = src/interfaces/ecpg/test top_builddir = ../../../.. @@ -8,7 +8,7 @@ override CPPFLAGS := -I$(srcdir)/../include $(CPPFLAGS) ECPG = ../preproc/ecpg -I$(srcdir)/../include -TESTS = test1 test2 test3 test4 perftest dyntest dyntest2 test_notice test_code100 test_init +TESTS = test1 test2 test3 test4 perftest dyntest dyntest2 test_notice test_code100 test_init testdynalloc all: $(TESTS) diff --git a/src/interfaces/ecpg/test/dyntest.pgc b/src/interfaces/ecpg/test/dyntest.pgc index b91bcb1d940aad57b0c8a1ad1f5091c260eb6547..2a432d4723b1e58b68258ac57b168bf616c2fe50 100644 --- a/src/interfaces/ecpg/test/dyntest.pgc +++ b/src/interfaces/ecpg/test/dyntest.pgc @@ -2,7 +2,7 @@ * * Copyright (c) 2000, Christof Petig * - * $Header: /cvsroot/pgsql/src/interfaces/ecpg/test/Attic/dyntest.pgc,v 1.8 2001/08/11 10:52:09 petere Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/ecpg/test/Attic/dyntest.pgc,v 1.9 2001/11/14 11:11:49 meskes Exp $ */ #include diff --git a/src/interfaces/ecpg/test/dyntest2.pgc b/src/interfaces/ecpg/test/dyntest2.pgc index 5f9be4007339ed403ec7c9d04f03d0eaa4bafc02..396f6a1730f59ae9456fe69a3f52e2266a20ba42 100644 --- a/src/interfaces/ecpg/test/dyntest2.pgc +++ b/src/interfaces/ecpg/test/dyntest2.pgc @@ -2,7 +2,7 @@ * * Copyright (c) 2000, Christof Petig * - * $Header: /cvsroot/pgsql/src/interfaces/ecpg/test/Attic/dyntest2.pgc,v 1.2 2001/08/11 10:52:09 petere Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/ecpg/test/Attic/dyntest2.pgc,v 1.3 2001/11/14 11:11:49 meskes Exp $ */ #include