Обсуждение: Review of "SQLDA support for ECPG"
I took a look at 2-pg85-sqlda-10-ctxdiff.patch. Starting from CVS HEAD of roughly 2009-10-03 05:00 UTC, prerequisite patches 1a-1h applied cleanly. 2-pg85-sqlda hit a trivial whitespace reject in ecpg.trailer along with a more substantive reject at ecpg.addons:407 (FetchStmtMOVEfetch_args). Fixing it up by hand leads to my first question - why did the transition from `opt_ecpg_into' to `opt_ecpg_fetch_into' affect FETCH FORWARD and not FETCH BACKWARD? The main test suite acquired no regressions, but I get failures in two tests of the ecpg test suite (make -C src/interfaces/ecpg/test check). I attach regression.{out,diff} and postmaster.log from the test run. The abort in sqlda.pgc looks like the interesting failure, but I exhausted time with which to dig into it further. preproc/cursor.pgc creates (and ideally drops) the same table `t1' as compat_informix/{sqlda,cursor}.pgc, so a crash in either of the others makes it fail too. Could they all use temp tables, use different table names, or `DROP TABLE IF EXISTS t1' first? Do those logs suggest the cause of the sqlda.pgc failure? If not, I will look into it further. Otherwise, I'm happy to review a future iteration of the patch. As a side note, with patch 1* but not patch 2, test_informix entered an infinite loop with this error: ERROR: syntax error at or near "c" at character 15 STATEMENT: fetch forward c Thank you, nm
Вложения
Hi, thank you very much for the review. Noah Misch írta: > I took a look at 2-pg85-sqlda-10-ctxdiff.patch. Starting from CVS HEAD of > roughly 2009-10-03 05:00 UTC, prerequisite patches 1a-1h applied cleanly. > 2-pg85-sqlda hit a trivial whitespace reject in ecpg.trailer along with a more > substantive reject at ecpg.addons:407 (FetchStmtMOVEfetch_args). Fixing it up > by hand leads to my first question - why did the transition from `opt_ecpg_into' > to `opt_ecpg_fetch_into' affect FETCH FORWARD and not FETCH BACKWARD? > This was a total oversight coming from the previous dynamic cursorname patch. *That* was buggy as it didn't have the two de-factorized rules for FETCH BACKWARD. When I did the fine-grained split-up, I fixed that but I didn't test my SQLDA patch after the new dynamic cursorname patches. I will post a new patch for SQLDA and for all others that need updating. > The main test suite acquired no regressions, but I get failures in two tests of > the ecpg test suite (make -C src/interfaces/ecpg/test check). I attach > regression.{out,diff} and postmaster.log from the test run. The abort in > sqlda.pgc looks like the interesting failure, but I exhausted time with which to > dig into it further. preproc/cursor.pgc creates (and ideally drops) the same > table `t1' as compat_informix/{sqlda,cursor}.pgc, so a crash in either of the > others makes it fail too. Could they all use temp tables, use different table > names, or `DROP TABLE IF EXISTS t1' first? > > Do those logs suggest the cause of the sqlda.pgc failure? If not, I will look > into it further. Otherwise, I'm happy to review a future iteration of the > patch. > No, this is not a real error. I have run into this as well, which is quickly solved if you execute "make install" before running "make check" under the ecpg directory. I guess you already have an installed PG tree at the same prefix as where you have pointed the new one with the SQLDA patch applied. Another solution may be to use a different prefix for the SQLDA source tree. I start to think that the same remedy would be needed here as the contrib subdirectory: "make installcheck" is a mental note the you test the installed libraries, not the freshly compiled ones under the source directory. > As a side note, with patch 1* but not patch 2, test_informix entered an infinite > loop with this error: > ERROR: syntax error at or near "c" at character 15 > STATEMENT: fetch forward c > Do you mean that you applied all the split-up patches posted for the dynamic cursorname extension? I didn't get this error. What did you do exactly? Best regards, Zoltán Böszörményi -- Bible has answers for everything. Proof: "But let your communication be, Yea, yea; Nay, nay: for whatsoever is more than these cometh of evil." (Matthew 5:37) - basics of digital technology. "May your kingdom come" - superficial description of plate tectonics ---------------------------------- Zoltán Böszörményi Cybertec Schönig & Schönig GmbH http://www.postgresql.at/
Hi, Boszormenyi Zoltan írta: > I will post a new patch for SQLDA and for all others that need > updating. > Here it is. Added the changes for the FETCH BACKWARD rules and fixed the other reject as well. Best regards, Zoltán Böszörményi -- Bible has answers for everything. Proof: "But let your communication be, Yea, yea; Nay, nay: for whatsoever is more than these cometh of evil." (Matthew 5:37) - basics of digital technology. "May your kingdom come" - superficial description of plate tectonics ---------------------------------- Zoltán Böszörményi Cybertec Schönig & Schönig GmbH http://www.postgresql.at/ diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/execute.c pgsql.sqlda/src/interfaces/ecpg/ecpglib/execute.c *** pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/execute.c 2009-09-03 14:37:34.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/ecpglib/execute.c 2009-10-05 13:30:08.000000000 +0200 *************** *** 25,30 **** --- 25,31 ---- #include "ecpgerrno.h" #include "extern.h" #include "sqlca.h" + #include "sqlda.h" #include "sql3types.h" #include "pgtypes_numeric.h" #include "pgtypes_date.h" *************** ecpg_store_input(const int lineno, const *** 1033,1038 **** --- 1034,1040 ---- break; case ECPGt_descriptor: + case ECPGt_sqlda: break; default: *************** ecpg_execute(struct statement * stmt) *** 1172,1177 **** --- 1174,1235 ---- if (desc->count == desc_counter) desc_counter = 0; } + else if (var->type == ECPGt_sqlda) + { + pg_sqlda_t **_sqlda = (pg_sqlda_t **)var->pointer; + pg_sqlda_t *sqlda = *_sqlda; + struct variable desc_inlist; + int i; + + if (sqlda == NULL) + return false; + + desc_counter++; + for (i = 0; i < sqlda->sqld; i++) + { + if (i + 1 == desc_counter) + { + desc_inlist.type = ecpg_sqlda_type(sqlda->sqlvar[i].sqltype); + desc_inlist.value = sqlda->sqlvar[i].sqldata; + desc_inlist.pointer = &(sqlda->sqlvar[i].sqldata); + switch (desc_inlist.type) + { + case ECPGt_char: + case ECPGt_varchar: + desc_inlist.varcharsize = strlen(sqlda->sqlvar[i].sqldata); + break; + default: + desc_inlist.varcharsize = 0; + break; + } + desc_inlist.arrsize = 1; + desc_inlist.offset = 0; + if (sqlda->sqlvar[i].sqlind) + { + desc_inlist.ind_type = ECPGt_short; + /* ECPG expects indicator value < 0 */ + if (*(sqlda->sqlvar[i].sqlind)) + *(sqlda->sqlvar[i].sqlind) = -1; + desc_inlist.ind_value = sqlda->sqlvar[i].sqlind; + desc_inlist.ind_pointer = &(sqlda->sqlvar[i].sqlind); + desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = 1; + desc_inlist.ind_offset = 0; + } + else + { + desc_inlist.ind_type = ECPGt_NO_INDICATOR; + desc_inlist.ind_value = desc_inlist.ind_pointer = NULL; + desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = desc_inlist.ind_offset = 0; + } + if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, &desc_inlist, &tobeinserted, false)) + return false; + + break; + } + } + if (sqlda->sqld == desc_counter) + desc_counter = 0; + } else { if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, var, &tobeinserted, false)) *************** ecpg_execute(struct statement * stmt) *** 1353,1358 **** --- 1411,1452 ---- } var = var->next; } + else if (var != NULL && var->type == ECPGt_sqlda) + { + pg_sqlda_t **_sqlda = (pg_sqlda_t **)var->pointer; + pg_sqlda_t *sqlda = *_sqlda; + pg_sqlda_t *sqlda_new; + + /* Build a new sqlda structure. Note that only fetching 1 record is supported */ + sqlda_new = ecpg_build_sqlda_for_PGresult(stmt->lineno, results, 0); + + if (!sqlda_new) + { + ecpg_log("ecpg_execute on line %d: out of memory allocating a new sqlda\n", stmt->lineno); + status = false; + } + else + { + ecpg_log("ecpg_execute on line %d: new sqlda was built\n", stmt->lineno); + + /* If we are passed in a previously existing sqlda then free it. */ + if (sqlda) + { + if (sqlda->sqlvar != (pg_sqlvar_t *)(sqlda + 1)) + free(sqlda->sqlvar); + free(sqlda); + sqlda = NULL; + } + + *_sqlda = sqlda_new; + + ecpg_set_sqlda_from_PGresult(stmt->lineno, _sqlda, results, 0); + ecpg_log("ecpg_execute on line %d: putting result (1 tuple %d fields) into sqlda descriptor\n", + stmt->lineno, PQnfields(results)); + } + + var = var->next; + } else for (act_field = 0; act_field < nfields && status; act_field++) { diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/extern.h pgsql.sqlda/src/interfaces/ecpg/ecpglib/extern.h *** pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/extern.h 2009-05-25 12:08:48.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/ecpglib/extern.h 2009-10-05 13:30:08.000000000 +0200 *************** *** 6,11 **** --- 6,12 ---- #include "postgres_fe.h" #include "libpq-fe.h" #include "sqlca.h" + #include "sqlda.h" #include "ecpg_config.h" #ifndef CHAR_BIT #include <limits.h> *************** bool ecpg_init(const struct connection *** 129,134 **** --- 130,137 ---- char *ecpg_strdup(const char *, int); const char *ecpg_type_name(enum ECPGttype); int ecpg_dynamic_type(Oid); + int ecpg_sqlda_type(int); + int ecpg_to_sqlda_type(Oid); void ecpg_free_auto_mem(void); void ecpg_clear_auto_mem(void); *************** void ecpg_log(const char *format,...); *** 149,154 **** --- 152,160 ---- bool ecpg_auto_prepare(int, const char *, const int, char **, const char *); void ecpg_init_sqlca(struct sqlca_t * sqlca); + pg_sqlda_t *ecpg_build_sqlda_for_PGresult(int, PGresult *, int); + void ecpg_set_sqlda_from_PGresult(int, pg_sqlda_t **, const PGresult *, int); + /* SQLSTATE values generated or processed by ecpglib (intentionally * not exported -- users should refer to the codes directly) */ diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/Makefile pgsql.sqlda/src/interfaces/ecpg/ecpglib/Makefile *** pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/Makefile 2009-07-13 11:16:41.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/ecpglib/Makefile 2009-10-05 13:30:08.000000000 +0200 *************** override CFLAGS += $(PTHREAD_CFLAGS) *** 24,30 **** # Need to recompile any libpgport object files LIBS := $(filter-out -lpgport, $(LIBS)) ! OBJS= execute.o typename.o descriptor.o data.o error.o prepare.o memory.o \ connect.o misc.o path.o pgstrcasecmp.o \ $(filter snprintf.o strlcpy.o, $(LIBOBJS)) --- 24,30 ---- # Need to recompile any libpgport object files LIBS := $(filter-out -lpgport, $(LIBS)) ! OBJS= execute.o typename.o descriptor.o sqlda.o data.o error.o prepare.o memory.o \ connect.o misc.o path.o pgstrcasecmp.o \ $(filter snprintf.o strlcpy.o, $(LIBOBJS)) diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/sqlda.c pgsql.sqlda/src/interfaces/ecpg/ecpglib/sqlda.c *** pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/sqlda.c 1970-01-01 01:00:00.000000000 +0100 --- pgsql.sqlda/src/interfaces/ecpg/ecpglib/sqlda.c 2009-10-05 13:30:08.000000000 +0200 *************** *** 0 **** --- 1,276 ---- + /* + * Crude SQLDA support routines + * Only supports fetching 1 record at a time + * + * The allocated memory area pointed by an sqlda pointer + * contains both the metadata and the data, so freeing up + * is a simple free(sqlda) as expected by the ESQL/C examples. + */ + + #define POSTGRES_ECPG_INTERNAL + #include "postgres_fe.h" + #include "pg_type.h" + + #include <inttypes.h> + #include <dlfcn.h> + + #include "ecpg-pthread-win32.h" + #include "decimal.h" + #include "ecpgtype.h" + #include "ecpglib.h" + #include "ecpgerrno.h" + #include "extern.h" + #include "sqlca.h" + #include "sqlda.h" + #include "sqltypes.h" + + /* + * Compute the next variable's offset with + * the current variable's size and alignment. + */ + static long + ecpg_sqlda_size_round_align(long offset, int alignment, int size) + { + if (offset % alignment) + offset += alignment - (offset % alignment); + offset += size; + return offset; + } + + /* + * Compute the current variable's offset with alignment. + */ + static long + ecpg_sqlda_size_align(long offset, int alignment) + { + if (offset % alignment) + offset += alignment - (offset % alignment); + return offset; + } + + static long + ecpg_sqlda_empty_size(const PGresult *res) + { + long size; + int i; + int sqld = PQnfields(res); + + /* Initial size to store main structure and field structures */ + size = sizeof(pg_sqlda_t) + sqld * sizeof(pg_sqlvar_t); + + /* Add space for field names */ + for (i = 0; i < sqld; i++) + size += strlen(PQfname(res, i)) + 1; + + /* Add padding to the first field value */ + size = ecpg_sqlda_size_align(size, sizeof(int)); + + return size; + } + + static long + ecpg_sqlda_total_size(const PGresult *res, int row) + { + int i; + int sqld = PQnfields(res); + long size; + + size = ecpg_sqlda_empty_size(res); + + if (row < 0) + return size; + + /* Add space for the field values */ + for (i = 0; i < sqld; i++) + { + switch (ecpg_to_sqlda_type(PQftype(res, i))) + { + case SQLSMINT: + size = ecpg_sqlda_size_round_align(size, sizeof(short), sizeof(short)); + break; + case SQLINT: + case SQLSERIAL: + size = ecpg_sqlda_size_round_align(size, sizeof(int), sizeof(int)); + break; + case SQLFLOAT: + size = ecpg_sqlda_size_round_align(size, sizeof(double), sizeof(double)); + break; + case SQLSMFLOAT: + size = ecpg_sqlda_size_round_align(size, sizeof(float), sizeof(float)); + break; + case SQLDECIMAL: + size = ecpg_sqlda_size_round_align(size, sizeof(int), sizeof(decimal)); + break; + case SQLINT8: + case SQLSERIAL8: + size = ecpg_sqlda_size_round_align(size, sizeof(int64_t), sizeof(int64_t)); + break; + + /* + * These types will be passed as character strings + * copied as is from the PGresult until we know + * what to do with them. + */ + case SQLCHAR: + case SQLTEXT: + case SQLVCHAR: + case SQLNCHAR: + case SQLNVCHAR: + case SQLMONEY: + case SQLDATE: + case SQLDTIME: + case SQLINTERVAL: + default: + size += strlen(PQgetvalue(res, row, i)) + 1; + break; + } + } + return size; + } + + /* + * Build pg_sqlda_t (metadata only) from PGresult + * leaving enough space for the field values in + * the given row number + */ + pg_sqlda_t * + ecpg_build_sqlda_for_PGresult(int line, PGresult *res, int row) + { + pg_sqlda_t *sqlda; + pg_sqlvar_t*sqlvar; + char *fname; + long size; + int sqld; + int i; + + size = ecpg_sqlda_total_size(res, row); + sqlda = (pg_sqlda_t *)ecpg_alloc(size, line); + if (!sqlda) + return NULL; + + memset(sqlda, 0, size); + sqlvar = (pg_sqlvar_t *)(sqlda + 1); + sqld = PQnfields(res); + fname = (char *)(sqlvar + sqld); + + sqlda->sqld = sqld; + sqlda->desc_occ = size; /* cheat here, keep the full allocated size */ + sqlda->sqlvar = sqlvar; + + for (i = 0; i < sqlda->sqld; i++) + { + sqlda->sqlvar[i].sqltype = ecpg_to_sqlda_type(PQftype(res, i)); + strcpy(fname, PQfname(res, i)); + sqlda->sqlvar[i].sqlname = fname; + fname += strlen(sqlda->sqlvar[i].sqlname) + 1; + sqlda->sqlvar[i].sqlformat = (char *)(long)PQfformat(res, i); + sqlda->sqlvar[i].sqlxid = PQftype(res, i); + sqlda->sqlvar[i].sqltypelen = PQfsize(res, i); + } + + return sqlda; + } + + /* + * Sets values from PGresult. + */ + void + ecpg_set_sqlda_from_PGresult(int lineno, pg_sqlda_t **_sqlda, const PGresult *res, int row) + { + pg_sqlda_t *sqlda = (*_sqlda); + int i; + long size; + static int2 value_is_null = -1; + static int2 value_is_not_null = 0; + + /* Offset for the first field value */ + size = ecpg_sqlda_empty_size(res); + + /* + * Set sqlvar[i]->sqldata pointers and convert values to correct format + */ + for (i = 0; i < sqlda->sqld; i++) + { + int type = -1, isnull; + int use_getdata = true; + + switch (sqlda->sqlvar[i].sqltype) + { + case SQLSMINT: + size = ecpg_sqlda_size_align(size, sizeof(short)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + size += sizeof(short); + type = ECPGt_short; + break; + case SQLINT: + case SQLSERIAL: + size = ecpg_sqlda_size_align(size, sizeof(int)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + size += sizeof(int); + type = ECPGt_int; + break; + case SQLFLOAT: + size = ecpg_sqlda_size_align(size, sizeof(double)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + size += sizeof(double); + type = ECPGt_double; + break; + case SQLSMFLOAT: + size = ecpg_sqlda_size_align(size, sizeof(float)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + size += sizeof(float); + type = ECPGt_float; + break; + case SQLDECIMAL: + { + size = ecpg_sqlda_size_align(size, sizeof(int)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + size += sizeof(decimal); + type = ECPGt_decimal; + break; + } + case SQLINT8: + case SQLSERIAL8: + size = ecpg_sqlda_size_align(size, sizeof(int64_t)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + size += sizeof(int64_t); + type = ECPGt_long_long; + break; + + /* + * These types will be passed as character strings until + * it's known what to do with them. We use sqlvar->sqldata + * in all cases regardless of length, don't care about + * sqlvar->sqlilongdata. + */ + case SQLCHAR: + case SQLTEXT: + case SQLVCHAR: + case SQLNCHAR: + case SQLNVCHAR: + case SQLMONEY: + case SQLDATE: + case SQLDTIME: + case SQLINTERVAL: + default: + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + size += strlen(PQgetvalue(res, row, i)) + 1; + use_getdata = false; + break; + } + + isnull = PQgetisnull(res, 0, i); + sqlda->sqlvar[i].sqlind = isnull ? &value_is_null : &value_is_not_null; + if (!isnull) + { + if (use_getdata) + ecpg_get_data(res, row, i, lineno, + type, ECPGt_NO_INDICATOR, + sqlda->sqlvar[i].sqldata, NULL, 0, 0, 0, + ECPG_ARRAY_NONE, ECPG_COMPAT_INFORMIX, false); + else + strcpy(sqlda->sqlvar[i].sqldata, PQgetvalue(res, row, i)); + } + } + } + diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/typename.c pgsql.sqlda/src/interfaces/ecpg/ecpglib/typename.c *** pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/typename.c 2009-08-07 13:06:28.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/ecpglib/typename.c 2009-10-05 13:30:08.000000000 +0200 *************** *** 7,12 **** --- 7,13 ---- #include "ecpgtype.h" #include "ecpglib.h" #include "extern.h" + #include "sqltypes.h" #include "sql3types.h" #include "pg_type.h" *************** ecpg_dynamic_type(Oid type) *** 100,102 **** --- 101,190 ---- return -(int) type; } } + + int + ecpg_sqlda_type(int type) + { + switch (type) + { + case SQLCHAR: + case SQLNCHAR: + return ECPGt_char; + case SQLSMINT: + return ECPGt_short; + case SQLINT: + return ECPGt_int; + case SQLFLOAT: + return ECPGt_double; + case SQLSMFLOAT: + return ECPGt_float; + case SQLDECIMAL: + return ECPGt_decimal; + case SQLSERIAL: + return ECPGt_int; + case SQLDATE: + return ECPGt_date; + #if 0 + case SQLMONEY: + return ???; + case SQLNULL: + return ???; + #endif + case SQLDTIME: + return ECPGt_timestamp; + #if 0 + case SQLBYTES: + return ???; + #endif + case SQLTEXT: + return ECPGt_char; + case SQLVCHAR: + case SQLNVCHAR: + return ECPGt_varchar; + case SQLINTERVAL: + return ECPGt_interval; + case SQLINT8: + case SQLSERIAL8: + return ECPGt_long_long; + default: + return (-type); + } + } + + int + ecpg_to_sqlda_type(Oid type) + { + switch (type) + { + case CHAROID: + case BPCHAROID: + return SQLCHAR; + case INT2OID: + return SQLSMINT; + case INT4OID: + return SQLINT; + case FLOAT8OID: + return SQLFLOAT; + case FLOAT4OID: + return SQLSMFLOAT; + case NUMERICOID: + return SQLDECIMAL; + case DATEOID: + return SQLDATE; + case CASHOID: + return SQLMONEY; + case TIMESTAMPOID: + case TIMESTAMPTZOID: + return SQLDTIME; + case TEXTOID: + return SQLTEXT; + case VARCHAROID: + return SQLVCHAR; + case INTERVALOID: + return SQLINTERVAL; + case INT8OID: + return SQLINT8; + default: + return (-type); + } + } diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/include/ecpgtype.h pgsql.sqlda/src/interfaces/ecpg/include/ecpgtype.h *** pgsql.fixparsepl/src/interfaces/ecpg/include/ecpgtype.h 2009-08-07 13:06:28.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/include/ecpgtype.h 2009-10-05 13:30:08.000000000 +0200 *************** enum ECPGttype *** 62,68 **** ECPGt_EOIT, /* End of insert types. */ ECPGt_EORT, /* End of result types. */ ECPGt_NO_INDICATOR, /* no indicator */ ! ECPGt_string /* trimmed (char *) type */ }; /* descriptor items */ --- 62,69 ---- ECPGt_EOIT, /* End of insert types. */ ECPGt_EORT, /* End of result types. */ ECPGt_NO_INDICATOR, /* no indicator */ ! ECPGt_string, /* trimmed (char *) type */ ! ECPGt_sqlda /* C struct descriptor */ }; /* descriptor items */ diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/include/sqlda.h pgsql.sqlda/src/interfaces/ecpg/include/sqlda.h *** pgsql.fixparsepl/src/interfaces/ecpg/include/sqlda.h 2009-06-13 18:25:05.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/include/sqlda.h 2009-10-05 13:30:08.000000000 +0200 *************** *** 1,3 **** --- 1,74 ---- /* * $PostgreSQL: pgsql/src/interfaces/ecpg/include/sqlda.h,v 1.4 2009/06/11 14:49:13 momjian Exp $ */ + + #ifndef POSTGRES_SQLDA_H + #define POSTGRES_SQLDA_H + + /* Define Informix "standard" types */ + #ifndef C_H + typedef int int4; + typedef short int2; + #endif + typedef char int1; + + typedef int mint; + typedef long mlong; + + typedef short MSHORT; + typedef char MCHAR; + + typedef unsigned int uint4; + typedef unsigned short uint2; + typedef unsigned char uint1; + + typedef unsigned int muint; + typedef unsigned long mulong; + + typedef unsigned short MUSHORT; + typedef unsigned char MUCHAR; + + #define MI_INT_SIZE (sizeof(int) * 8) + #define MI_LONG_SIZE (sizeof(long) * 8) + #define MI_PTR_SIZE (sizeof(char *) * 8) + + typedef struct sqlvar_struct + { + int2 sqltype; /* variable type */ + int4 sqllen; /* length in bytes */ + char *sqldata; /* pointer to data */ + int2 *sqlind; /* pointer to indicator */ + char *sqlname; /* variable name */ + char *sqlformat; /* reserved for future use */ + int2 sqlitype; /* ind variable type */ + int2 sqlilen; /* ind length in bytes */ + char *sqlidata; /* ind data pointer */ + int4 sqlxid; /* extended id type */ + char *sqltypename; /* extended type name */ + int2 sqltypelen; /* length of extended type name */ + int2 sqlownerlen; /* length of owner name */ + int2 sqlsourcetype; /* source type for distinct of built-ins */ + char *sqlownername; /* owner name */ + int4 sqlsourceid; /* extended id of source type */ + + /* + * sqlilongdata is new. It supports data that exceeds the 32k + * limit. sqlilen and sqlidata are for backward compatibility + * and they have maximum value of <32K. + */ + char *sqlilongdata; /* for data field beyond 32K */ + int4 sqlflags; /* for internal use only */ + void *sqlreserved; /* reserved for future use */ + } pg_sqlvar_t; + + typedef struct sqlda + { + int2 sqld; + pg_sqlvar_t *sqlvar; + char desc_name[19]; /* descriptor name */ + int2 desc_occ; /* size of sqlda structure */ + struct sqlda *desc_next; /* pointer to next sqlda struct */ + void *reserved; /* reserved for future use */ + } pg_sqlda_t; + + #endif /* POSTGRES_SQLDA_H */ diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/include/sqltypes.h pgsql.sqlda/src/interfaces/ecpg/include/sqltypes.h *** pgsql.fixparsepl/src/interfaces/ecpg/include/sqltypes.h 2009-06-13 18:25:05.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/include/sqltypes.h 2009-10-05 13:30:08.000000000 +0200 *************** *** 30,33 **** --- 30,55 ---- #define CLVCHARPTRTYPE 124 #define CTYPEMAX 25 + /* + * Values used in sqlda->sqlvar[i]->sqltype + */ + #define SQLCHAR 0 + #define SQLSMINT 1 + #define SQLINT 2 + #define SQLFLOAT 3 + #define SQLSMFLOAT 4 + #define SQLDECIMAL 5 + #define SQLSERIAL 6 + #define SQLDATE 7 + #define SQLMONEY 8 + #define SQLDTIME 10 + #define SQLBYTES 11 + #define SQLTEXT 12 + #define SQLVCHAR 13 + #define SQLINTERVAL 14 + #define SQLNCHAR 15 + #define SQLNVCHAR 16 + #define SQLINT8 17 + #define SQLSERIAL8 18 + #endif /* ndef ECPG_SQLTYPES_H */ diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/preproc/descriptor.c pgsql.sqlda/src/interfaces/ecpg/preproc/descriptor.c *** pgsql.fixparsepl/src/interfaces/ecpg/preproc/descriptor.c 2009-01-30 17:28:46.000000000 +0100 --- pgsql.sqlda/src/interfaces/ecpg/preproc/descriptor.c 2009-10-05 13:30:08.000000000 +0200 *************** descriptor_variable(const char *name, in *** 326,328 **** --- 326,347 ---- strlcpy(descriptor_names[input], name, sizeof(descriptor_names[input])); return (struct variable *) & varspace[input]; } + + struct variable * + sqlda_variable(const char *name) + { + struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable)); + + p->name = mm_strdup(name); + p->type = (struct ECPGtype *) mm_alloc(sizeof(struct ECPGtype)); + p->type->type = ECPGt_sqlda; + p->type->size = NULL; + p->type->struct_sizeof = NULL; + p->type->u.element = NULL; + p->type->lineno = 0; + p->brace_level = 0; + p->next = NULL; + + return p; + } + diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/preproc/ecpg.addons pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.addons *** pgsql.fixparsepl/src/interfaces/ecpg/preproc/ecpg.addons 2009-10-03 01:54:43.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.addons 2009-10-05 13:33:06.000000000 +0200 *************** ECPG: VariableShowStmtSHOWALL block *** 402,430 **** $$ = EMPTY; } ECPG: FetchStmtMOVEfetch_args rule ! | FETCH fetch_args ecpg_into { $$ = cat2_str(make_str("fetch"), $2); } ! | FETCH FORWARD cursor_name opt_ecpg_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat_str(2, make_str("fetch forward"), cursor_marker); } ! | FETCH FORWARD from_in cursor_name opt_ecpg_into { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); $$ = cat_str(2, make_str("fetch forward from"), cursor_marker); } ! | FETCH BACKWARD cursor_name opt_ecpg_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat_str(2, make_str("fetch backward"), cursor_marker); } ! | FETCH BACKWARD from_in cursor_name opt_ecpg_into { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); --- 402,430 ---- $$ = EMPTY; } ECPG: FetchStmtMOVEfetch_args rule ! | FETCH fetch_args ecpg_fetch_into { $$ = cat2_str(make_str("fetch"), $2); } ! | FETCH FORWARD cursor_name opt_ecpg_fetch_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat_str(2, make_str("fetch forward"), cursor_marker); } ! | FETCH FORWARD from_in cursor_name opt_ecpg_fetch_into { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); $$ = cat_str(2, make_str("fetch forward from"), cursor_marker); } ! | FETCH BACKWARD cursor_name opt_ecpg_fetch_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat_str(2, make_str("fetch backward"), cursor_marker); } ! | FETCH BACKWARD from_in cursor_name opt_ecpg_fetch_into { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/preproc/ecpg.trailer pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.trailer *** pgsql.fixparsepl/src/interfaces/ecpg/preproc/ecpg.trailer 2009-10-03 02:05:58.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.trailer 2009-10-05 13:40:15.000000000 +0200 *************** ecpg_using: USING using_list { $$ = EMP *** 1017,1035 **** using_descriptor: USING opt_sql SQL_DESCRIPTOR quoted_ident_stringvar { ! add_variable_to_head(&argsinsert, descriptor_variable($4,0), &no_indicator); $$ = EMPTY; } ; into_descriptor: INTO opt_sql SQL_DESCRIPTOR quoted_ident_stringvar { ! add_variable_to_head(&argsresult, descriptor_variable($4,1), &no_indicator); $$ = EMPTY; } ; ! opt_sql: /*EMPTY*/ | SQL_SQL; using_list: UsingValue | UsingValue ',' using_list; --- 1017,1065 ---- using_descriptor: USING opt_sql SQL_DESCRIPTOR quoted_ident_stringvar { ! if (strlen($2) || !(INFORMIX_MODE)) ! add_variable_to_head(&argsinsert, descriptor_variable($4,0), &no_indicator); ! else ! { ! if ($4[0] == '\"') ! { ! char *pos; ! ! $4[0] = ' '; ! for (pos = $4; *pos; pos++) ! if (*pos == '\"') ! *pos = ' '; ! } ! add_variable_to_head(&argsinsert, sqlda_variable($4), &no_indicator); ! } $$ = EMPTY; } ; into_descriptor: INTO opt_sql SQL_DESCRIPTOR quoted_ident_stringvar { ! if (strlen($2) || !(INFORMIX_MODE)) ! add_variable_to_head(&argsresult, descriptor_variable($4,1), &no_indicator); ! else ! { ! if ($4[0] == '\"') ! { ! char *pos; ! ! $4[0] = ' '; ! for (pos = $4; *pos; pos++) ! if (*pos == '\"') ! *pos = ' '; ! } ! add_variable_to_head(&argsresult, sqlda_variable($4), &no_indicator); ! } $$ = EMPTY; } ; ! opt_sql: /*EMPTY*/ { $$ = EMPTY; } ! | SQL_SQL { $$ = make_str("sql"); } ! ; using_list: UsingValue | UsingValue ',' using_list; *************** ecpg_into: INTO into_list { $$ = EMPTY; *** 2052,2058 **** | into_descriptor { $$ = $1; } ; ! opt_ecpg_into: /* EMPTY */ { $$ = EMPTY; } | ecpg_into { $$ = $1; } ; --- 2082,2103 ---- | into_descriptor { $$ = $1; } ; ! ecpg_fetch_into: ecpg_into { $$ = $1; } ! | using_descriptor ! { ! struct variable *var; ! ! if (!INFORMIX_MODE) ! mmerror(PARSE_ERROR, ET_ERROR, "Not in Informix compatibility mode"); ! ! var = argsinsert->variable; ! remove_variable_from_list(&argsinsert, var); ! add_variable_to_head(&argsresult, var, &no_indicator); ! $$ = $1; ! } ! ; ! ! opt_ecpg_fetch_into: /* EMPTY */ { $$ = EMPTY; } | ecpg_into { $$ = $1; } ; diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/preproc/ecpg.type pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.type *** pgsql.fixparsepl/src/interfaces/ecpg/preproc/ecpg.type 2009-10-03 02:03:31.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.type 2009-10-05 13:30:08.000000000 +0200 *************** *** 62,67 **** --- 62,68 ---- %type <str> ecpg_ident %type <str> ecpg_interval %type <str> ecpg_into + %type <str> ecpg_fetch_into %type <str> ecpg_param %type <str> ecpg_sconst %type <str> ecpg_using *************** *** 77,83 **** %type <str> opt_bit_field %type <str> opt_connection_name %type <str> opt_database_name ! %type <str> opt_ecpg_into %type <str> opt_ecpg_using %type <str> opt_initializer %type <str> opt_options --- 78,84 ---- %type <str> opt_bit_field %type <str> opt_connection_name %type <str> opt_database_name ! %type <str> opt_ecpg_fetch_into %type <str> opt_ecpg_using %type <str> opt_initializer %type <str> opt_options *************** *** 87,92 **** --- 88,94 ---- %type <str> opt_reference %type <str> opt_scale %type <str> opt_server + %type <str> opt_sql %type <str> opt_user %type <str> opt_opt_value %type <str> ora_user diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/preproc/extern.h pgsql.sqlda/src/interfaces/ecpg/preproc/extern.h *** pgsql.fixparsepl/src/interfaces/ecpg/preproc/extern.h 2009-10-03 01:07:54.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/preproc/extern.h 2009-10-05 13:30:08.000000000 +0200 *************** extern void add_descriptor(char *, char *** 88,93 **** --- 88,94 ---- extern void drop_descriptor(char *, char *); extern struct descriptor *lookup_descriptor(char *, char *); extern struct variable *descriptor_variable(const char *name, int input); + extern struct variable *sqlda_variable(const char *name); extern void add_variable_to_head(struct arguments **, struct variable *, struct variable *); extern void add_variable_to_tail(struct arguments **, struct variable *, struct variable *); extern void remove_variable_from_list(struct arguments ** list, struct variable * var); diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/preproc/type.c pgsql.sqlda/src/interfaces/ecpg/preproc/type.c *** pgsql.fixparsepl/src/interfaces/ecpg/preproc/type.c 2009-09-03 12:25:47.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/preproc/type.c 2009-10-05 13:30:08.000000000 +0200 *************** get_type(enum ECPGttype type) *** 194,199 **** --- 194,202 ---- case ECPGt_descriptor: return ("ECPGt_descriptor"); break; + case ECPGt_sqlda: + return ("ECPGt_sqlda"); + break; case ECPGt_date: return ("ECPGt_date"); break; *************** ECPGdump_a_simple(FILE *o, const char *n *** 328,333 **** --- 331,338 ---- else if (type == ECPGt_descriptor) /* remember that name here already contains quotes (if needed) */ fprintf(o, "\n\tECPGt_descriptor, %s, 0L, 0L, 0L, ", name); + else if (type == ECPGt_sqlda) + fprintf(o, "\n\tECPGt_sqlda, &%s, 0L, 0L, 0L, ", name); else { char *variable = (char *) mm_alloc(strlen(name) + ((prefix == NULL) ? 0 : strlen(prefix)) + 4); diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/compat_informix/Makefile pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/Makefile *** pgsql.fixparsepl/src/interfaces/ecpg/test/compat_informix/Makefile 2009-10-03 02:11:20.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/Makefile 2009-10-05 13:30:08.000000000 +0200 *************** TESTS = test_informix test_informix.c \ *** 17,22 **** --- 17,23 ---- rfmtdate rfmtdate.c \ rfmtlong rfmtlong.c \ rnull rnull.c \ + sqlda sqlda.c \ charfuncs charfuncs.c all: $(TESTS) *************** test_informix2.c: test_informix2.pgc ../ *** 30,35 **** --- 31,39 ---- cursor.c: cursor.pgc ../regression.h $(ECPG) -o $@ -I$(srcdir) $< + sqlda.c: sqlda.pgc ../regression.h + $(ECPG) -o $@ -I$(srcdir) $< + dec_test.c: dec_test.pgc ../regression.h $(ECPG) -o $@ -I$(srcdir) $< diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/compat_informix/sqlda.pgc pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/sqlda.pgc *** pgsql.fixparsepl/src/interfaces/ecpg/test/compat_informix/sqlda.pgc 1970-01-01 01:00:00.000000000 +0100 --- pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/sqlda.pgc 2009-10-05 13:30:08.000000000 +0200 *************** *** 0 **** --- 1,252 ---- + #include <stdlib.h> + #include <string.h> + #include <inttypes.h> + + exec sql include ../regression; + + exec sql include sqlda.h; + exec sql include sqltypes.h; + + exec sql whenever sqlerror stop; + + /* These shouldn't be under DECLARE SECTION */ + pg_sqlda_t *inp_sqlda, *outp_sqlda; + + static void + dump_sqlda(pg_sqlda_t *sqlda) + { + int i; + + for (i = 0; i < sqlda->sqld; i++) + { + if (outp_sqlda->sqlvar[i].sqlind && *(outp_sqlda->sqlvar[i].sqlind) == -1) + printf("name sqlda descriptor: '%s' value NULL'\n", outp_sqlda->sqlvar[i].sqlname); + else + switch (sqlda->sqlvar[i].sqltype) + { + case SQLCHAR: + case SQLVCHAR: + case SQLTEXT: + printf("name sqlda descriptor: '%s' value '%s'\n", sqlda->sqlvar[i].sqlname, sqlda->sqlvar[i].sqldata); + break; + case SQLSERIAL: + case SQLINT: + printf("name sqlda descriptor: '%s' value %d\n", sqlda->sqlvar[i].sqlname, *(int *)sqlda->sqlvar[i].sqldata); + break; + case SQLSERIAL8: + case SQLINT8: + printf("name sqlda descriptor: '%s' value %" PRId64 "\n", sqlda->sqlvar[i].sqlname, *(int64_t *)sqlda->sqlvar[i].sqldata); + break; + case SQLFLOAT: + printf("name sqlda descriptor: '%s' value %lf\n", sqlda->sqlvar[i].sqlname, *(double *)sqlda->sqlvar[i].sqldata); + break; + case SQLDECIMAL: + { + char val[64]; + dectoasc((dec_t *)sqlda->sqlvar[i].sqldata, val, 64, -1); + printf("name sqlda descriptor: '%s' value DECIMAL '%s'\n", sqlda->sqlvar[i].sqlname, val); + break; + } + } + } + } + + int + main (void) + { + exec sql begin declare section; + char *stmt1 = "SELECT * FROM t1"; + char *stmt2 = "SELECT * FROM t1 WHERE id = ?"; + int rec; + int id; + exec sql end declare section; + + char msg[128]; + + ECPGdebug(1, stderr); + + strcpy(msg, "connect"); + exec sql connect to REGRESSDB1 as regress1; + + strcpy(msg, "set"); + exec sql set datestyle to iso; + + strcpy(msg, "create"); + exec sql create table t1( + id integer, + t text, + d1 numeric, + d2 float8, + c char(10)); + + strcpy(msg, "insert"); + exec sql insert into t1 values + (1, 'a', 1.0, 1, 'a'), + (2, null, null, null, null), + (3, '"c"', -3, 'nan'::float8, 'c'), + (4, 'd', 4.0, 4, 'd'); + + strcpy(msg, "commit"); + exec sql commit; + + /* SQLDA test for getting all records from a table */ + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + exec sql prepare st_id1 from :stmt1; + + strcpy(msg, "declare"); + exec sql declare mycur1 cursor for st_id1; + + strcpy(msg, "open"); + exec sql open mycur1; + + exec sql whenever not found do break; + + rec = 0; + while (1) + { + strcpy(msg, "fetch"); + exec sql fetch 1 from mycur1 into descriptor outp_sqlda; + + printf("FETCH RECORD %d\n", ++rec); + dump_sqlda(outp_sqlda); + } + + exec sql whenever not found continue; + + strcpy(msg, "close"); + exec sql close mycur1; + + strcpy(msg, "deallocate"); + exec sql deallocate prepare st_id1; + + free(outp_sqlda); + + /* SQLDA test for getting all records from a table + using the Informix-specific FETCH ... USING DESCRIPTOR + */ + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + exec sql prepare st_id2 from :stmt1; + + strcpy(msg, "declare"); + exec sql declare mycur2 cursor for st_id2; + + strcpy(msg, "open"); + exec sql open mycur2; + + exec sql whenever not found do break; + + rec = 0; + while (1) + { + strcpy(msg, "fetch"); + exec sql fetch from mycur2 using descriptor outp_sqlda; + + printf("FETCH RECORD %d\n", ++rec); + dump_sqlda(outp_sqlda); + } + + exec sql whenever not found continue; + + strcpy(msg, "close"); + exec sql close mycur2; + + strcpy(msg, "deallocate"); + exec sql deallocate prepare st_id2; + + free(outp_sqlda); + + /* SQLDA test for getting one record using an input descriptor */ + + /* Input sqlda has to be built manually */ + inp_sqlda = (pg_sqlda_t *)malloc(sizeof(pg_sqlda_t)); + memset(inp_sqlda, 0, sizeof(pg_sqlda_t)); + inp_sqlda->sqld = 1; + inp_sqlda->sqlvar = malloc(sizeof(pg_sqlvar_t)); + memset(inp_sqlda->sqlvar, 0, sizeof(pg_sqlvar_t)); + + inp_sqlda->sqlvar[0].sqltype = SQLINT; + inp_sqlda->sqlvar[0].sqldata = (char *)&id; + + printf("EXECUTE RECORD 4\n"); + + id = 4; + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + exec sql prepare st_id3 FROM :stmt2; + + strcpy(msg, "execute"); + exec sql execute st_id3 using descriptor inp_sqlda into descriptor outp_sqlda; + + dump_sqlda(outp_sqlda); + + strcpy(msg, "deallocate"); + exec sql deallocate prepare st_id3; + + free(inp_sqlda->sqlvar); + free(inp_sqlda); + free(outp_sqlda); + + /* SQLDA test for getting one record using an input descriptor + * on a named connection + */ + + exec sql connect to REGRESSDB1 as con2; + + /* Input sqlda has to be built manually */ + inp_sqlda = (pg_sqlda_t *)malloc(sizeof(pg_sqlda_t)); + memset(inp_sqlda, 0, sizeof(pg_sqlda_t)); + inp_sqlda->sqld = 1; + inp_sqlda->sqlvar = malloc(sizeof(pg_sqlvar_t)); + memset(inp_sqlda->sqlvar, 0, sizeof(pg_sqlvar_t)); + + inp_sqlda->sqlvar[0].sqltype = SQLINT; + inp_sqlda->sqlvar[0].sqldata = (char *)&id; + + printf("EXECUTE RECORD 4\n"); + + id = 4; + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + exec sql at con2 prepare st_id4 FROM :stmt2; + + strcpy(msg, "execute"); + exec sql at con2 execute st_id4 using descriptor inp_sqlda into descriptor outp_sqlda; + + dump_sqlda(outp_sqlda); + + strcpy(msg, "commit"); + exec sql at con2 commit; + + strcpy(msg, "deallocate"); + exec sql deallocate prepare st_id4; + + free(inp_sqlda->sqlvar); + free(inp_sqlda); + free(outp_sqlda); + + strcpy(msg, "disconnect"); + exec sql disconnect con2; + + /* End test */ + + strcpy(msg, "drop"); + exec sql drop table t1; + + strcpy(msg, "commit"); + exec sql commit; + + strcpy(msg, "disconnect"); + exec sql disconnect; + + return (0); + } diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/ecpg_schedule pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule *** pgsql.fixparsepl/src/interfaces/ecpg/test/ecpg_schedule 2009-10-03 02:11:20.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule 2009-10-05 13:30:08.000000000 +0200 *************** test: compat_informix/rfmtdate *** 4,9 **** --- 4,10 ---- test: compat_informix/rfmtlong test: compat_informix/rnull test: compat_informix/cursor + test: compat_informix/sqlda test: compat_informix/test_informix test: compat_informix/test_informix2 test: connect/test2 diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/ecpg_schedule_tcp pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule_tcp *** pgsql.fixparsepl/src/interfaces/ecpg/test/ecpg_schedule_tcp 2009-10-03 02:11:20.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule_tcp 2009-10-05 13:30:08.000000000 +0200 *************** test: compat_informix/rfmtdate *** 4,9 **** --- 4,10 ---- test: compat_informix/rfmtlong test: compat_informix/rnull test: compat_informix/cursor + test: compat_informix/sqlda test: compat_informix/test_informix test: compat_informix/test_informix2 test: connect/test2 diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c *** pgsql.fixparsepl/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c 1970-01-01 01:00:00.000000000 +0100 --- pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c 2009-10-05 13:30:08.000000000 +0200 *************** *** 0 **** --- 1,585 ---- + /* Processed by ecpg (regression mode) */ + /* These include files are added by the preprocessor */ + #include <ecpglib.h> + #include <ecpgerrno.h> + #include <sqlca.h> + /* Needed for informix compatibility */ + #include <ecpg_informix.h> + /* End of automatic include section */ + #define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y)) + + #line 1 "sqlda.pgc" + #include <stdlib.h> + #include <string.h> + #include <inttypes.h> + + + #line 1 "regression.h" + + + + + + + #line 5 "sqlda.pgc" + + + + #line 1 "sqlda.h" + /* + * $PostgreSQL: pgsql/src/interfaces/ecpg/include/sqlda.h,v 1.4 2009/06/11 14:49:13 momjian Exp $ + */ + + #ifndef POSTGRES_SQLDA_H + #define POSTGRES_SQLDA_H + + /* Define Informix "standard" types */ + #ifndef C_H + typedef int int4; + typedef short int2; + #endif + typedef char int1; + + typedef int mint; + typedef long mlong; + + typedef short MSHORT; + typedef char MCHAR; + + typedef unsigned int uint4; + typedef unsigned short uint2; + typedef unsigned char uint1; + + typedef unsigned int muint; + typedef unsigned long mulong; + + typedef unsigned short MUSHORT; + typedef unsigned char MUCHAR; + + #define MI_INT_SIZE (sizeof(int) * 8) + #define MI_LONG_SIZE (sizeof(long) * 8) + #define MI_PTR_SIZE (sizeof(char *) * 8) + + typedef struct sqlvar_struct + { + int2 sqltype; /* variable type */ + int4 sqllen; /* length in bytes */ + char *sqldata; /* pointer to data */ + int2 *sqlind; /* pointer to indicator */ + char *sqlname; /* variable name */ + char *sqlformat; /* reserved for future use */ + int2 sqlitype; /* ind variable type */ + int2 sqlilen; /* ind length in bytes */ + char *sqlidata; /* ind data pointer */ + int4 sqlxid; /* extended id type */ + char *sqltypename; /* extended type name */ + int2 sqltypelen; /* length of extended type name */ + int2 sqlownerlen; /* length of owner name */ + int2 sqlsourcetype; /* source type for distinct of built-ins */ + char *sqlownername; /* owner name */ + int4 sqlsourceid; /* extended id of source type */ + + /* + * sqlilongdata is new. It supports data that exceeds the 32k + * limit. sqlilen and sqlidata are for backward compatibility + * and they have maximum value of <32K. + */ + char *sqlilongdata; /* for data field beyond 32K */ + int4 sqlflags; /* for internal use only */ + void *sqlreserved; /* reserved for future use */ + } pg_sqlvar_t; + + typedef struct sqlda + { + int2 sqld; + pg_sqlvar_t *sqlvar; + char desc_name[19]; /* descriptor name */ + int2 desc_occ; /* size of sqlda structure */ + struct sqlda *desc_next; /* pointer to next sqlda struct */ + void *reserved; /* reserved for future use */ + } pg_sqlda_t; + + #endif /* POSTGRES_SQLDA_H */ + + #line 7 "sqlda.pgc" + + + #line 1 "sqltypes.h" + /* + * $PostgreSQL: pgsql/src/interfaces/ecpg/include/sqltypes.h,v 1.9 2009/06/11 14:49:13 momjian Exp $ + */ + #ifndef ECPG_SQLTYPES_H + #define ECPG_SQLTYPES_H + + #define CCHARTYPE ECPGt_char + #define CSHORTTYPE ECPGt_short + #define CINTTYPE ECPGt_int + #define CLONGTYPE ECPGt_long + #define CFLOATTYPE ECPGt_float + #define CDOUBLETYPE ECPGt_double + #define CDECIMALTYPE ECPGt_decimal + #define CFIXCHARTYPE 108 + #define CSTRINGTYPE ECPGt_char + #define CDATETYPE ECPGt_date + #define CMONEYTYPE 111 + #define CDTIMETYPE ECPGt_timestamp + #define CLOCATORTYPE 113 + #define CVCHARTYPE ECPGt_varchar + #define CINVTYPE 115 + #define CFILETYPE 116 + #define CINT8TYPE ECPGt_long_long + #define CCOLLTYPE 118 + #define CLVCHARTYPE 119 + #define CFIXBINTYPE 120 + #define CVARBINTYPE 121 + #define CBOOLTYPE ECPGt_bool + #define CROWTYPE 123 + #define CLVCHARPTRTYPE 124 + #define CTYPEMAX 25 + + /* + * Values used in sqlda->sqlvar[i]->sqltype + */ + #define SQLCHAR 0 + #define SQLSMINT 1 + #define SQLINT 2 + #define SQLFLOAT 3 + #define SQLSMFLOAT 4 + #define SQLDECIMAL 5 + #define SQLSERIAL 6 + #define SQLDATE 7 + #define SQLMONEY 8 + #define SQLDTIME 10 + #define SQLBYTES 11 + #define SQLTEXT 12 + #define SQLVCHAR 13 + #define SQLINTERVAL 14 + #define SQLNCHAR 15 + #define SQLNVCHAR 16 + #define SQLINT8 17 + #define SQLSERIAL8 18 + + #endif /* ndef ECPG_SQLTYPES_H */ + + #line 8 "sqlda.pgc" + + + /* exec sql whenever sqlerror stop ; */ + #line 10 "sqlda.pgc" + + + /* These shouldn't be under DECLARE SECTION */ + pg_sqlda_t *inp_sqlda, *outp_sqlda; + + static void + dump_sqlda(pg_sqlda_t *sqlda) + { + int i; + + for (i = 0; i < sqlda->sqld; i++) + { + if (outp_sqlda->sqlvar[i].sqlind && *(outp_sqlda->sqlvar[i].sqlind) == -1) + printf("name sqlda descriptor: '%s' value NULL'\n", outp_sqlda->sqlvar[i].sqlname); + else + switch (sqlda->sqlvar[i].sqltype) + { + case SQLCHAR: + case SQLVCHAR: + case SQLTEXT: + printf("name sqlda descriptor: '%s' value '%s'\n", sqlda->sqlvar[i].sqlname, sqlda->sqlvar[i].sqldata); + break; + case SQLSERIAL: + case SQLINT: + printf("name sqlda descriptor: '%s' value %d\n", sqlda->sqlvar[i].sqlname, *(int *)sqlda->sqlvar[i].sqldata); + break; + case SQLSERIAL8: + case SQLINT8: + printf("name sqlda descriptor: '%s' value %" PRId64 "\n", sqlda->sqlvar[i].sqlname, *(int64_t *)sqlda->sqlvar[i].sqldata); + break; + case SQLFLOAT: + printf("name sqlda descriptor: '%s' value %lf\n", sqlda->sqlvar[i].sqlname, *(double *)sqlda->sqlvar[i].sqldata); + break; + case SQLDECIMAL: + { + char val[64]; + dectoasc((decimal *)sqlda->sqlvar[i].sqldata, val, 64, -1); + printf("name sqlda descriptor: '%s' value DECIMAL '%s'\n", sqlda->sqlvar[i].sqlname, val); + break; + } + } + } + } + + int + main (void) + { + /* exec sql begin declare section */ + + + + + + #line 58 "sqlda.pgc" + char * stmt1 = "SELECT * FROM t1" ; + + #line 59 "sqlda.pgc" + char * stmt2 = "SELECT * FROM t1 WHERE id = ?" ; + + #line 60 "sqlda.pgc" + int rec ; + + #line 61 "sqlda.pgc" + int id ; + /* exec sql end declare section */ + #line 62 "sqlda.pgc" + + + char msg[128]; + + ECPGdebug(1, stderr); + + strcpy(msg, "connect"); + { ECPGconnect(__LINE__, 1, "regress1" , NULL, NULL , "regress1", 0); + #line 69 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 69 "sqlda.pgc" + + + strcpy(msg, "set"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "set datestyle to iso", ECPGt_EOIT, ECPGt_EORT); + #line 72 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 72 "sqlda.pgc" + + + strcpy(msg, "create"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "create table t1 ( id integer , t text , d1 numeric , d2 float8 ,c char ( 10 ) )", ECPGt_EOIT, ECPGt_EORT); + #line 80 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 80 "sqlda.pgc" + + + strcpy(msg, "insert"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "insert into t1 values ( 1 , 'a' , 1.0 , 1 , 'a' ) , ( 2 , null ,null , null , null ) , ( 3 , '\"c\"' , - 3 , 'nan' :: float8 , 'c' ) , ( 4 , 'd' , 4.0 , 4 , 'd' )", ECPGt_EOIT, ECPGt_EORT); + #line 87 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 87 "sqlda.pgc" + + + strcpy(msg, "commit"); + { ECPGtrans(__LINE__, NULL, "commit"); + #line 90 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 90 "sqlda.pgc" + + + /* SQLDA test for getting all records from a table */ + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + { ECPGprepare(__LINE__, NULL, 0, "st_id1", stmt1); + #line 97 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 97 "sqlda.pgc" + + + strcpy(msg, "declare"); + ECPG_informix_reset_sqlca(); /* declare mycur1 cursor for $1 */ + #line 100 "sqlda.pgc" + + + strcpy(msg, "open"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "declare mycur1 cursor for $1", + ECPGt_char_variable,(ECPGprepared_statement(NULL, "st_id1", __LINE__)),(long)1,(long)1,(1)*sizeof(char), + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT); + #line 103 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 103 "sqlda.pgc" + + + /* exec sql whenever not found break ; */ + #line 105 "sqlda.pgc" + + + rec = 0; + while (1) + { + strcpy(msg, "fetch"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch 1 from mycur1", ECPGt_EOIT, + ECPGt_sqlda, & outp_sqlda , 0L, 0L, 0L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT); + #line 111 "sqlda.pgc" + + if (sqlca.sqlcode == ECPG_NOT_FOUND) break; + #line 111 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 111 "sqlda.pgc" + + + printf("FETCH RECORD %d\n", ++rec); + dump_sqlda(outp_sqlda); + } + + /* exec sql whenever not found continue ; */ + #line 117 "sqlda.pgc" + + + strcpy(msg, "close"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "close mycur1", ECPGt_EOIT, ECPGt_EORT); + #line 120 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 120 "sqlda.pgc" + + + strcpy(msg, "deallocate"); + { ECPGdeallocate(__LINE__, 1, NULL, "st_id1"); + #line 123 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 123 "sqlda.pgc" + + + free(outp_sqlda); + + /* SQLDA test for getting all records from a table + using the Informix-specific FETCH ... USING DESCRIPTOR + */ + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + { ECPGprepare(__LINE__, NULL, 0, "st_id2", stmt1); + #line 134 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 134 "sqlda.pgc" + + + strcpy(msg, "declare"); + ECPG_informix_reset_sqlca(); /* declare mycur2 cursor for $1 */ + #line 137 "sqlda.pgc" + + + strcpy(msg, "open"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "declare mycur2 cursor for $1", + ECPGt_char_variable,(ECPGprepared_statement(NULL, "st_id2", __LINE__)),(long)1,(long)1,(1)*sizeof(char), + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT); + #line 140 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 140 "sqlda.pgc" + + + /* exec sql whenever not found break ; */ + #line 142 "sqlda.pgc" + + + rec = 0; + while (1) + { + strcpy(msg, "fetch"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch from mycur2", ECPGt_EOIT, + ECPGt_sqlda, & outp_sqlda , 0L, 0L, 0L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT); + #line 148 "sqlda.pgc" + + if (sqlca.sqlcode == ECPG_NOT_FOUND) break; + #line 148 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 148 "sqlda.pgc" + + + printf("FETCH RECORD %d\n", ++rec); + dump_sqlda(outp_sqlda); + } + + /* exec sql whenever not found continue ; */ + #line 154 "sqlda.pgc" + + + strcpy(msg, "close"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "close mycur2", ECPGt_EOIT, ECPGt_EORT); + #line 157 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 157 "sqlda.pgc" + + + strcpy(msg, "deallocate"); + { ECPGdeallocate(__LINE__, 1, NULL, "st_id2"); + #line 160 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 160 "sqlda.pgc" + + + free(outp_sqlda); + + /* SQLDA test for getting one record using an input descriptor */ + + /* Input sqlda has to be built manually */ + inp_sqlda = (pg_sqlda_t *)malloc(sizeof(pg_sqlda_t)); + memset(inp_sqlda, 0, sizeof(pg_sqlda_t)); + inp_sqlda->sqld = 1; + inp_sqlda->sqlvar = malloc(sizeof(pg_sqlvar_t)); + memset(inp_sqlda->sqlvar, 0, sizeof(pg_sqlvar_t)); + + inp_sqlda->sqlvar[0].sqltype = SQLINT; + inp_sqlda->sqlvar[0].sqldata = (char *)&id; + + printf("EXECUTE RECORD 4\n"); + + id = 4; + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + { ECPGprepare(__LINE__, NULL, 0, "st_id3", stmt2); + #line 183 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 183 "sqlda.pgc" + + + strcpy(msg, "execute"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, 1, "st_id3", + ECPGt_sqlda, & inp_sqlda , 0L, 0L, 0L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, + ECPGt_sqlda, & outp_sqlda , 0L, 0L, 0L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT); + #line 186 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 186 "sqlda.pgc" + + + dump_sqlda(outp_sqlda); + + strcpy(msg, "deallocate"); + { ECPGdeallocate(__LINE__, 1, NULL, "st_id3"); + #line 191 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 191 "sqlda.pgc" + + + free(inp_sqlda->sqlvar); + free(inp_sqlda); + free(outp_sqlda); + + /* SQLDA test for getting one record using an input descriptor + * on a named connection + */ + + { ECPGconnect(__LINE__, 1, "regress1" , NULL, NULL , "con2", 0); + #line 201 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 201 "sqlda.pgc" + + + /* Input sqlda has to be built manually */ + inp_sqlda = (pg_sqlda_t *)malloc(sizeof(pg_sqlda_t)); + memset(inp_sqlda, 0, sizeof(pg_sqlda_t)); + inp_sqlda->sqld = 1; + inp_sqlda->sqlvar = malloc(sizeof(pg_sqlvar_t)); + memset(inp_sqlda->sqlvar, 0, sizeof(pg_sqlvar_t)); + + inp_sqlda->sqlvar[0].sqltype = SQLINT; + inp_sqlda->sqlvar[0].sqldata = (char *)&id; + + printf("EXECUTE RECORD 4\n"); + + id = 4; + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + { ECPGprepare(__LINE__, "con2", 0, "st_id4", stmt2); + #line 220 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 220 "sqlda.pgc" + + + strcpy(msg, "execute"); + { ECPGdo(__LINE__, 1, 1, "con2", 0, 1, "st_id4", + ECPGt_sqlda, & inp_sqlda , 0L, 0L, 0L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, + ECPGt_sqlda, & outp_sqlda , 0L, 0L, 0L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT); + #line 223 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 223 "sqlda.pgc" + + + dump_sqlda(outp_sqlda); + + strcpy(msg, "commit"); + { ECPGtrans(__LINE__, "con2", "commit"); + #line 228 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 228 "sqlda.pgc" + + + strcpy(msg, "deallocate"); + { ECPGdeallocate(__LINE__, 1, NULL, "st_id4"); + #line 231 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 231 "sqlda.pgc" + + + free(inp_sqlda->sqlvar); + free(inp_sqlda); + free(outp_sqlda); + + strcpy(msg, "disconnect"); + { ECPGdisconnect(__LINE__, "con2"); + #line 238 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 238 "sqlda.pgc" + + + /* End test */ + + strcpy(msg, "drop"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "drop table t1", ECPGt_EOIT, ECPGt_EORT); + #line 243 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 243 "sqlda.pgc" + + + strcpy(msg, "commit"); + { ECPGtrans(__LINE__, NULL, "commit"); + #line 246 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 246 "sqlda.pgc" + + + strcpy(msg, "disconnect"); + { ECPGdisconnect(__LINE__, "CURRENT"); + #line 249 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 249 "sqlda.pgc" + + + return (0); + } diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr *** pgsql.fixparsepl/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr 1970-01-01 01:00:00.000000000 +0100 --- pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr 2009-10-05 13:30:08.000000000 +0200 *************** *** 0 **** --- 1,252 ---- + [NO_PID]: ECPGdebug: set to 1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGconnect: opening database regress1 on <DEFAULT> port <DEFAULT> + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 72: query: set datestyle to iso; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 72: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 72: OK: SET + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 75: query: create table t1 ( id integer , t text , d1 numeric , d2 float8 , c char ( 10) ); with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 75: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 75: OK: CREATE TABLE + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 83: query: insert into t1 values ( 1 , 'a' , 1.0 , 1 , 'a' ) , ( 2 , null , null , null, null ) , ( 3 , '"c"' , - 3 , 'nan' :: float8 , 'c' ) , ( 4 , 'd' , 4.0 , 4 , 'd' ); with 0 parameter(s) on connectionregress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 83: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 83: OK: INSERT 0 4 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGtrans on line 90: action "commit"; connection "regress1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGprepare on line 97: name st_id1; query: "SELECT * FROM t1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 103: query: declare mycur1 cursor for SELECT * FROM t1; with 0 parameter(s) on connectionregress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 103: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 103: OK: DECLARE CURSOR + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 1 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 1.0 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 1 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 2 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 3 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: -3 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: NaN offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 4.0 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: correctly got 0 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: raising sqlcode 100 on line 111: no data found on line 111 + [NO_PID]: sqlca: code: 100, state: 02000 + [NO_PID]: ecpg_execute on line 120: query: close mycur1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 120: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 120: OK: CLOSE CURSOR + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGdeallocate on line 123: name st_id1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGprepare on line 134: name st_id2; query: "SELECT * FROM t1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 140: query: declare mycur2 cursor for SELECT * FROM t1; with 0 parameter(s) on connectionregress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 140: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 140: OK: DECLARE CURSOR + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 1 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 1.0 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 1 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 2 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 3 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: -3 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: NaN offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 4.0 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: correctly got 0 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: raising sqlcode 100 on line 148: no data found on line 148 + [NO_PID]: sqlca: code: 100, state: 02000 + [NO_PID]: ecpg_execute on line 157: query: close mycur2; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 157: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 157: OK: CLOSE CURSOR + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGdeallocate on line 160: name st_id2 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGprepare on line 183: name st_id3; query: "SELECT * FROM t1 WHERE id = $1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 186: query: SELECT * FROM t1 WHERE id = $1; with 1 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 186: using PQexecPrepared for "SELECT * FROM t1 WHERE id = $1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: free_params on line 186: parameter 1 = 4 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 186: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 186: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 186: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 186: RESULT: 4.0 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 186: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 186: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGdeallocate on line 191: name st_id3 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGconnect: opening database regress1 on <DEFAULT> port <DEFAULT> + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGprepare on line 220: name st_id4; query: "SELECT * FROM t1 WHERE id = $1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 223: query: SELECT * FROM t1 WHERE id = $1; with 1 parameter(s) on connection con2 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 223: using PQexecPrepared for "SELECT * FROM t1 WHERE id = $1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: free_params on line 223: parameter 1 = 4 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 223: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 223: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 223: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 223: RESULT: 4.0 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 223: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 223: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGtrans on line 228: action "commit"; connection "con2" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGdeallocate on line 231: name st_id4 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_finish: connection con2 closed + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 243: query: drop table t1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 243: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 243: OK: DROP TABLE + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGtrans on line 246: action "commit"; connection "regress1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_finish: connection regress1 closed + [NO_PID]: sqlca: code: 0, state: 00000 diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout *** pgsql.fixparsepl/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout 1970-01-01 01:00:00.000000000 +0100 --- pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout 2009-10-05 13:30:08.000000000 +0200 *************** *** 0 **** --- 1,60 ---- + FETCH RECORD 1 + name sqlda descriptor: 'id' value 1 + name sqlda descriptor: 't' value 'a' + name sqlda descriptor: 'd1' value DECIMAL '1.0' + name sqlda descriptor: 'd2' value 1.000000 + name sqlda descriptor: 'c' value 'a ' + FETCH RECORD 2 + name sqlda descriptor: 'id' value 2 + name sqlda descriptor: 't' value NULL' + name sqlda descriptor: 'd1' value NULL' + name sqlda descriptor: 'd2' value NULL' + name sqlda descriptor: 'c' value NULL' + FETCH RECORD 3 + name sqlda descriptor: 'id' value 3 + name sqlda descriptor: 't' value '"c"' + name sqlda descriptor: 'd1' value DECIMAL '-3' + name sqlda descriptor: 'd2' value nan + name sqlda descriptor: 'c' value 'c ' + FETCH RECORD 4 + name sqlda descriptor: 'id' value 4 + name sqlda descriptor: 't' value 'd' + name sqlda descriptor: 'd1' value DECIMAL '4.0' + name sqlda descriptor: 'd2' value 4.000000 + name sqlda descriptor: 'c' value 'd ' + FETCH RECORD 1 + name sqlda descriptor: 'id' value 1 + name sqlda descriptor: 't' value 'a' + name sqlda descriptor: 'd1' value DECIMAL '1.0' + name sqlda descriptor: 'd2' value 1.000000 + name sqlda descriptor: 'c' value 'a ' + FETCH RECORD 2 + name sqlda descriptor: 'id' value 2 + name sqlda descriptor: 't' value NULL' + name sqlda descriptor: 'd1' value NULL' + name sqlda descriptor: 'd2' value NULL' + name sqlda descriptor: 'c' value NULL' + FETCH RECORD 3 + name sqlda descriptor: 'id' value 3 + name sqlda descriptor: 't' value '"c"' + name sqlda descriptor: 'd1' value DECIMAL '-3' + name sqlda descriptor: 'd2' value nan + name sqlda descriptor: 'c' value 'c ' + FETCH RECORD 4 + name sqlda descriptor: 'id' value 4 + name sqlda descriptor: 't' value 'd' + name sqlda descriptor: 'd1' value DECIMAL '4.0' + name sqlda descriptor: 'd2' value 4.000000 + name sqlda descriptor: 'c' value 'd ' + EXECUTE RECORD 4 + name sqlda descriptor: 'id' value 4 + name sqlda descriptor: 't' value 'd' + name sqlda descriptor: 'd1' value DECIMAL '4.0' + name sqlda descriptor: 'd2' value 4.000000 + name sqlda descriptor: 'c' value 'd ' + EXECUTE RECORD 4 + name sqlda descriptor: 'id' value 4 + name sqlda descriptor: 't' value 'd' + name sqlda descriptor: 'd1' value DECIMAL '4.0' + name sqlda descriptor: 'd2' value 4.000000 + name sqlda descriptor: 'c' value 'd '
On Mon, Oct 05, 2009 at 02:23:57PM +0200, Boszormenyi Zoltan wrote: > Noah Misch ?rta: > I will post a new patch for SQLDA and for all others that need > updating. Thanks; that one does apply cleanly. > > The main test suite acquired no regressions, but I get failures in two tests of > > the ecpg test suite (make -C src/interfaces/ecpg/test check). > No, this is not a real error. I have run into this as well, > which is quickly solved if you execute "make install" > before running "make check" under the ecpg directory. > I guess you already have an installed PG tree at the same > prefix as where you have pointed the new one with the > SQLDA patch applied. Another solution may be to use > a different prefix for the SQLDA source tree. This was exactly the problem; with an unoccupied prefix, all the tests do pass. > > As a side note, with patch 1* but not patch 2, test_informix entered an infinite > > loop with this error: > > ERROR: syntax error at or near "c" at character 15 > > STATEMENT: fetch forward c > Do you mean that you applied all the split-up patches posted > for the dynamic cursorname extension? I didn't get this error. > What did you do exactly? Having started over from a clean base tree, I can no longer reproduce this. Another operator error, no doubt. All tests now pass here with 1a-1h of "Dynamic cursor support for ECPG" alone, with "SQLDA support for ECPG" also applied, and with "DESCRIBE [OUTPUT] support for ECPG" additionally. I will report on the sqlda patch in more detail on 2009-10-10. The one concern that's clear now is a lack of documentation update. Thank you, nm
Noah Misch írta: > I will report on the sqlda patch in more detail on > 2009-10-10. I am attaching a new one, please review this. Changes: - set sqllen, sqlind, sqlilen and sqlitype per-field properties - SQLINT8 and SQLSERIAL8 are ECPGt_long on 64-bit, not ECPGt_long_long > The one concern that's clear now is a lack of documentation update. > That will come in a separate patch. Thanks, Zoltán Böszörményi -- Bible has answers for everything. Proof: "But let your communication be, Yea, yea; Nay, nay: for whatsoever is more than these cometh of evil." (Matthew 5:37) - basics of digital technology. "May your kingdom come" - superficial description of plate tectonics ---------------------------------- Zoltán Böszörményi Cybertec Schönig & Schönig GmbH http://www.postgresql.at/ diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/execute.c pgsql.sqlda/src/interfaces/ecpg/ecpglib/execute.c *** pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/execute.c 2009-09-03 14:37:34.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/ecpglib/execute.c 2009-10-05 15:18:01.000000000 +0200 *************** *** 25,30 **** --- 25,31 ---- #include "ecpgerrno.h" #include "extern.h" #include "sqlca.h" + #include "sqlda.h" #include "sql3types.h" #include "pgtypes_numeric.h" #include "pgtypes_date.h" *************** ecpg_store_input(const int lineno, const *** 1033,1038 **** --- 1034,1040 ---- break; case ECPGt_descriptor: + case ECPGt_sqlda: break; default: *************** ecpg_execute(struct statement * stmt) *** 1172,1177 **** --- 1174,1235 ---- if (desc->count == desc_counter) desc_counter = 0; } + else if (var->type == ECPGt_sqlda) + { + pg_sqlda_t **_sqlda = (pg_sqlda_t **)var->pointer; + pg_sqlda_t *sqlda = *_sqlda; + struct variable desc_inlist; + int i; + + if (sqlda == NULL) + return false; + + desc_counter++; + for (i = 0; i < sqlda->sqld; i++) + { + if (i + 1 == desc_counter) + { + desc_inlist.type = ecpg_sqlda_type(sqlda->sqlvar[i].sqltype); + desc_inlist.value = sqlda->sqlvar[i].sqldata; + desc_inlist.pointer = &(sqlda->sqlvar[i].sqldata); + switch (desc_inlist.type) + { + case ECPGt_char: + case ECPGt_varchar: + desc_inlist.varcharsize = strlen(sqlda->sqlvar[i].sqldata); + break; + default: + desc_inlist.varcharsize = 0; + break; + } + desc_inlist.arrsize = 1; + desc_inlist.offset = 0; + if (sqlda->sqlvar[i].sqlind) + { + desc_inlist.ind_type = ECPGt_short; + /* ECPG expects indicator value < 0 */ + if (*(sqlda->sqlvar[i].sqlind)) + *(sqlda->sqlvar[i].sqlind) = -1; + desc_inlist.ind_value = sqlda->sqlvar[i].sqlind; + desc_inlist.ind_pointer = &(sqlda->sqlvar[i].sqlind); + desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = 1; + desc_inlist.ind_offset = 0; + } + else + { + desc_inlist.ind_type = ECPGt_NO_INDICATOR; + desc_inlist.ind_value = desc_inlist.ind_pointer = NULL; + desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = desc_inlist.ind_offset = 0; + } + if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, &desc_inlist, &tobeinserted, false)) + return false; + + break; + } + } + if (sqlda->sqld == desc_counter) + desc_counter = 0; + } else { if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, var, &tobeinserted, false)) *************** ecpg_execute(struct statement * stmt) *** 1353,1358 **** --- 1411,1452 ---- } var = var->next; } + else if (var != NULL && var->type == ECPGt_sqlda) + { + pg_sqlda_t **_sqlda = (pg_sqlda_t **)var->pointer; + pg_sqlda_t *sqlda = *_sqlda; + pg_sqlda_t *sqlda_new; + + /* Build a new sqlda structure. Note that only fetching 1 record is supported */ + sqlda_new = ecpg_build_sqlda_for_PGresult(stmt->lineno, results, 0); + + if (!sqlda_new) + { + ecpg_log("ecpg_execute on line %d: out of memory allocating a new sqlda\n", stmt->lineno); + status = false; + } + else + { + ecpg_log("ecpg_execute on line %d: new sqlda was built\n", stmt->lineno); + + /* If we are passed in a previously existing sqlda then free it. */ + if (sqlda) + { + if (sqlda->sqlvar != (pg_sqlvar_t *)(sqlda + 1)) + free(sqlda->sqlvar); + free(sqlda); + sqlda = NULL; + } + + *_sqlda = sqlda_new; + + ecpg_set_sqlda_from_PGresult(stmt->lineno, _sqlda, results, 0); + ecpg_log("ecpg_execute on line %d: putting result (1 tuple %d fields) into sqlda descriptor\n", + stmt->lineno, PQnfields(results)); + } + + var = var->next; + } else for (act_field = 0; act_field < nfields && status; act_field++) { diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/extern.h pgsql.sqlda/src/interfaces/ecpg/ecpglib/extern.h *** pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/extern.h 2009-05-25 12:08:48.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/ecpglib/extern.h 2009-10-05 15:18:01.000000000 +0200 *************** *** 6,11 **** --- 6,12 ---- #include "postgres_fe.h" #include "libpq-fe.h" #include "sqlca.h" + #include "sqlda.h" #include "ecpg_config.h" #ifndef CHAR_BIT #include <limits.h> *************** bool ecpg_init(const struct connection *** 129,134 **** --- 130,137 ---- char *ecpg_strdup(const char *, int); const char *ecpg_type_name(enum ECPGttype); int ecpg_dynamic_type(Oid); + int ecpg_sqlda_type(int); + int ecpg_to_sqlda_type(Oid); void ecpg_free_auto_mem(void); void ecpg_clear_auto_mem(void); *************** void ecpg_log(const char *format,...); *** 149,154 **** --- 152,160 ---- bool ecpg_auto_prepare(int, const char *, const int, char **, const char *); void ecpg_init_sqlca(struct sqlca_t * sqlca); + pg_sqlda_t *ecpg_build_sqlda_for_PGresult(int, PGresult *, int); + void ecpg_set_sqlda_from_PGresult(int, pg_sqlda_t **, const PGresult *, int); + /* SQLSTATE values generated or processed by ecpglib (intentionally * not exported -- users should refer to the codes directly) */ diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/Makefile pgsql.sqlda/src/interfaces/ecpg/ecpglib/Makefile *** pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/Makefile 2009-07-13 11:16:41.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/ecpglib/Makefile 2009-10-05 15:18:01.000000000 +0200 *************** override CFLAGS += $(PTHREAD_CFLAGS) *** 24,30 **** # Need to recompile any libpgport object files LIBS := $(filter-out -lpgport, $(LIBS)) ! OBJS= execute.o typename.o descriptor.o data.o error.o prepare.o memory.o \ connect.o misc.o path.o pgstrcasecmp.o \ $(filter snprintf.o strlcpy.o, $(LIBOBJS)) --- 24,30 ---- # Need to recompile any libpgport object files LIBS := $(filter-out -lpgport, $(LIBS)) ! OBJS= execute.o typename.o descriptor.o sqlda.o data.o error.o prepare.o memory.o \ connect.o misc.o path.o pgstrcasecmp.o \ $(filter snprintf.o strlcpy.o, $(LIBOBJS)) diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/sqlda.c pgsql.sqlda/src/interfaces/ecpg/ecpglib/sqlda.c *** pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/sqlda.c 1970-01-01 01:00:00.000000000 +0100 --- pgsql.sqlda/src/interfaces/ecpg/ecpglib/sqlda.c 2009-10-07 14:06:07.000000000 +0200 *************** *** 0 **** --- 1,289 ---- + /* + * Crude SQLDA support routines + * Only supports fetching 1 record at a time + * + * The allocated memory area pointed by an sqlda pointer + * contains both the metadata and the data, so freeing up + * is a simple free(sqlda) as expected by the ESQL/C examples. + */ + + #define POSTGRES_ECPG_INTERNAL + #include "postgres_fe.h" + #include "pg_type.h" + + #include <inttypes.h> + #include <dlfcn.h> + + #include "ecpg-pthread-win32.h" + #include "decimal.h" + #include "ecpgtype.h" + #include "ecpglib.h" + #include "ecpgerrno.h" + #include "extern.h" + #include "sqlca.h" + #include "sqlda.h" + #include "sqltypes.h" + + /* + * Compute the next variable's offset with + * the current variable's size and alignment. + */ + static long + ecpg_sqlda_size_round_align(long offset, int alignment, int size) + { + if (offset % alignment) + offset += alignment - (offset % alignment); + offset += size; + return offset; + } + + /* + * Compute the current variable's offset with alignment. + */ + static long + ecpg_sqlda_size_align(long offset, int alignment) + { + if (offset % alignment) + offset += alignment - (offset % alignment); + return offset; + } + + static long + ecpg_sqlda_empty_size(const PGresult *res) + { + long size; + int i; + int sqld = PQnfields(res); + + /* Initial size to store main structure and field structures */ + size = sizeof(pg_sqlda_t) + sqld * sizeof(pg_sqlvar_t); + + /* Add space for field names */ + for (i = 0; i < sqld; i++) + size += strlen(PQfname(res, i)) + 1; + + /* Add padding to the first field value */ + size = ecpg_sqlda_size_align(size, sizeof(int)); + + return size; + } + + static long + ecpg_sqlda_total_size(const PGresult *res, int row) + { + int i; + int sqld = PQnfields(res); + long size; + + size = ecpg_sqlda_empty_size(res); + + if (row < 0) + return size; + + /* Add space for the field values */ + for (i = 0; i < sqld; i++) + { + switch (ecpg_to_sqlda_type(PQftype(res, i))) + { + case SQLSMINT: + size = ecpg_sqlda_size_round_align(size, sizeof(short), sizeof(short)); + break; + case SQLINT: + case SQLSERIAL: + size = ecpg_sqlda_size_round_align(size, sizeof(int), sizeof(int)); + break; + case SQLFLOAT: + size = ecpg_sqlda_size_round_align(size, sizeof(double), sizeof(double)); + break; + case SQLSMFLOAT: + size = ecpg_sqlda_size_round_align(size, sizeof(float), sizeof(float)); + break; + case SQLDECIMAL: + size = ecpg_sqlda_size_round_align(size, sizeof(int), sizeof(decimal)); + break; + case SQLINT8: + case SQLSERIAL8: + size = ecpg_sqlda_size_round_align(size, sizeof(int64_t), sizeof(int64_t)); + break; + + /* + * These types will be passed as character strings + * copied as is from the PGresult until we know + * what to do with them. + */ + case SQLCHAR: + case SQLTEXT: + case SQLVCHAR: + case SQLNCHAR: + case SQLNVCHAR: + case SQLMONEY: + case SQLDATE: + case SQLDTIME: + case SQLINTERVAL: + default: + size += strlen(PQgetvalue(res, row, i)) + 1; + break; + } + } + return size; + } + + /* + * Build pg_sqlda_t (metadata only) from PGresult + * leaving enough space for the field values in + * the given row number + */ + pg_sqlda_t * + ecpg_build_sqlda_for_PGresult(int line, PGresult *res, int row) + { + pg_sqlda_t *sqlda; + pg_sqlvar_t*sqlvar; + char *fname; + long size; + int sqld; + int i; + + size = ecpg_sqlda_total_size(res, row); + sqlda = (pg_sqlda_t *)ecpg_alloc(size, line); + if (!sqlda) + return NULL; + + memset(sqlda, 0, size); + sqlvar = (pg_sqlvar_t *)(sqlda + 1); + sqld = PQnfields(res); + fname = (char *)(sqlvar + sqld); + + sqlda->sqld = sqld; + sqlda->desc_occ = size; /* cheat here, keep the full allocated size */ + sqlda->sqlvar = sqlvar; + + for (i = 0; i < sqlda->sqld; i++) + { + sqlda->sqlvar[i].sqltype = ecpg_to_sqlda_type(PQftype(res, i)); + strcpy(fname, PQfname(res, i)); + sqlda->sqlvar[i].sqlname = fname; + fname += strlen(sqlda->sqlvar[i].sqlname) + 1; + sqlda->sqlvar[i].sqlformat = (char *)(long)PQfformat(res, i); + sqlda->sqlvar[i].sqlxid = PQftype(res, i); + sqlda->sqlvar[i].sqltypelen = PQfsize(res, i); + } + + return sqlda; + } + + /* + * Sets values from PGresult. + */ + void + ecpg_set_sqlda_from_PGresult(int lineno, pg_sqlda_t **_sqlda, const PGresult *res, int row) + { + pg_sqlda_t *sqlda = (*_sqlda); + int i; + long size; + static int2 value_is_null = -1; + static int2 value_is_not_null = 0; + + /* Offset for the first field value */ + size = ecpg_sqlda_empty_size(res); + + /* + * Set sqlvar[i]->sqldata pointers and convert values to correct format + */ + for (i = 0; i < sqlda->sqld; i++) + { + int type = -1, isnull; + int use_getdata = true; + int datalen; + + switch (sqlda->sqlvar[i].sqltype) + { + case SQLSMINT: + size = ecpg_sqlda_size_align(size, sizeof(short)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + sqlda->sqlvar[i].sqllen = sizeof(short); + size += sizeof(short); + type = ECPGt_short; + break; + case SQLINT: + case SQLSERIAL: + size = ecpg_sqlda_size_align(size, sizeof(int)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + sqlda->sqlvar[i].sqllen = sizeof(int); + size += sizeof(int); + type = ECPGt_int; + break; + case SQLFLOAT: + size = ecpg_sqlda_size_align(size, sizeof(double)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + sqlda->sqlvar[i].sqllen = sizeof(double); + size += sizeof(double); + type = ECPGt_double; + break; + case SQLSMFLOAT: + size = ecpg_sqlda_size_align(size, sizeof(float)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + sqlda->sqlvar[i].sqllen = sizeof(float); + size += sizeof(float); + type = ECPGt_float; + break; + case SQLDECIMAL: + { + size = ecpg_sqlda_size_align(size, sizeof(int)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + sqlda->sqlvar[i].sqllen = sizeof(decimal); + size += sizeof(decimal); + type = ECPGt_decimal; + break; + } + case SQLINT8: + case SQLSERIAL8: + size = ecpg_sqlda_size_align(size, sizeof(int64_t)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + sqlda->sqlvar[i].sqllen = sizeof(int64_t); + size += sizeof(int64_t); + type = ECPGt_long_long; + break; + + /* + * These types will be passed as character strings until + * it's known what to do with them. We use sqlvar->sqldata + * in all cases regardless of length, don't care about + * sqlvar->sqlilongdata. + */ + case SQLCHAR: + case SQLTEXT: + case SQLVCHAR: + case SQLNCHAR: + case SQLNVCHAR: + case SQLMONEY: + case SQLDATE: + case SQLDTIME: + case SQLINTERVAL: + default: + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + datalen = strlen(PQgetvalue(res, row, i)) + 1; + sqlda->sqlvar[i].sqllen = datalen; + size += datalen; + if (datalen > 32768) + sqlda->sqlvar[i].sqlilongdata = sqlda->sqlvar[i].sqldata; + use_getdata = false; + break; + } + + isnull = PQgetisnull(res, 0, i); + sqlda->sqlvar[i].sqlind = isnull ? &value_is_null : &value_is_not_null; + sqlda->sqlvar[i].sqlitype = SQLSMINT; + sqlda->sqlvar[i].sqlilen = sizeof(short); + if (!isnull) + { + if (use_getdata) + ecpg_get_data(res, row, i, lineno, + type, ECPGt_NO_INDICATOR, + sqlda->sqlvar[i].sqldata, NULL, 0, 0, 0, + ECPG_ARRAY_NONE, ECPG_COMPAT_INFORMIX, false); + else + strcpy(sqlda->sqlvar[i].sqldata, PQgetvalue(res, row, i)); + } + } + } + diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/typename.c pgsql.sqlda/src/interfaces/ecpg/ecpglib/typename.c *** pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/typename.c 2009-08-07 13:06:28.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/ecpglib/typename.c 2009-10-08 12:14:07.000000000 +0200 *************** *** 7,12 **** --- 7,13 ---- #include "ecpgtype.h" #include "ecpglib.h" #include "extern.h" + #include "sqltypes.h" #include "sql3types.h" #include "pg_type.h" *************** ecpg_dynamic_type(Oid type) *** 100,102 **** --- 101,194 ---- return -(int) type; } } + + int + ecpg_sqlda_type(int type) + { + switch (type) + { + case SQLCHAR: + case SQLNCHAR: + return ECPGt_char; + case SQLSMINT: + return ECPGt_short; + case SQLINT: + return ECPGt_int; + case SQLFLOAT: + return ECPGt_double; + case SQLSMFLOAT: + return ECPGt_float; + case SQLDECIMAL: + return ECPGt_decimal; + case SQLSERIAL: + return ECPGt_int; + case SQLDATE: + return ECPGt_date; + #if 0 + case SQLMONEY: + return ???; + case SQLNULL: + return ???; + #endif + case SQLDTIME: + return ECPGt_timestamp; + #if 0 + case SQLBYTES: + return ???; + #endif + case SQLTEXT: + return ECPGt_char; + case SQLVCHAR: + case SQLNVCHAR: + return ECPGt_varchar; + case SQLINTERVAL: + return ECPGt_interval; + case SQLINT8: + case SQLSERIAL8: + #ifdef HAVE_LONG_LONG_INT_64 + return ECPGt_long_long; + #else + return ECPGt_long; + #endif + default: + return (-type); + } + } + + int + ecpg_to_sqlda_type(Oid type) + { + switch (type) + { + case CHAROID: + case BPCHAROID: + return SQLCHAR; + case INT2OID: + return SQLSMINT; + case INT4OID: + return SQLINT; + case FLOAT8OID: + return SQLFLOAT; + case FLOAT4OID: + return SQLSMFLOAT; + case NUMERICOID: + return SQLDECIMAL; + case DATEOID: + return SQLDATE; + case CASHOID: + return SQLMONEY; + case TIMESTAMPOID: + case TIMESTAMPTZOID: + return SQLDTIME; + case TEXTOID: + return SQLTEXT; + case VARCHAROID: + return SQLVCHAR; + case INTERVALOID: + return SQLINTERVAL; + case INT8OID: + return SQLINT8; + default: + return (-type); + } + } diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/include/ecpgtype.h pgsql.sqlda/src/interfaces/ecpg/include/ecpgtype.h *** pgsql.fixparsepl/src/interfaces/ecpg/include/ecpgtype.h 2009-08-07 13:06:28.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/include/ecpgtype.h 2009-10-05 15:18:01.000000000 +0200 *************** enum ECPGttype *** 62,68 **** ECPGt_EOIT, /* End of insert types. */ ECPGt_EORT, /* End of result types. */ ECPGt_NO_INDICATOR, /* no indicator */ ! ECPGt_string /* trimmed (char *) type */ }; /* descriptor items */ --- 62,69 ---- ECPGt_EOIT, /* End of insert types. */ ECPGt_EORT, /* End of result types. */ ECPGt_NO_INDICATOR, /* no indicator */ ! ECPGt_string, /* trimmed (char *) type */ ! ECPGt_sqlda /* C struct descriptor */ }; /* descriptor items */ diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/include/sqlda.h pgsql.sqlda/src/interfaces/ecpg/include/sqlda.h *** pgsql.fixparsepl/src/interfaces/ecpg/include/sqlda.h 2009-06-13 18:25:05.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/include/sqlda.h 2009-10-05 15:18:01.000000000 +0200 *************** *** 1,3 **** --- 1,74 ---- /* * $PostgreSQL: pgsql/src/interfaces/ecpg/include/sqlda.h,v 1.4 2009/06/11 14:49:13 momjian Exp $ */ + + #ifndef POSTGRES_SQLDA_H + #define POSTGRES_SQLDA_H + + /* Define Informix "standard" types */ + #ifndef C_H + typedef int int4; + typedef short int2; + #endif + typedef char int1; + + typedef int mint; + typedef long mlong; + + typedef short MSHORT; + typedef char MCHAR; + + typedef unsigned int uint4; + typedef unsigned short uint2; + typedef unsigned char uint1; + + typedef unsigned int muint; + typedef unsigned long mulong; + + typedef unsigned short MUSHORT; + typedef unsigned char MUCHAR; + + #define MI_INT_SIZE (sizeof(int) * 8) + #define MI_LONG_SIZE (sizeof(long) * 8) + #define MI_PTR_SIZE (sizeof(char *) * 8) + + typedef struct sqlvar_struct + { + int2 sqltype; /* variable type */ + int4 sqllen; /* length in bytes */ + char *sqldata; /* pointer to data */ + int2 *sqlind; /* pointer to indicator */ + char *sqlname; /* variable name */ + char *sqlformat; /* reserved for future use */ + int2 sqlitype; /* ind variable type */ + int2 sqlilen; /* ind length in bytes */ + char *sqlidata; /* ind data pointer */ + int4 sqlxid; /* extended id type */ + char *sqltypename; /* extended type name */ + int2 sqltypelen; /* length of extended type name */ + int2 sqlownerlen; /* length of owner name */ + int2 sqlsourcetype; /* source type for distinct of built-ins */ + char *sqlownername; /* owner name */ + int4 sqlsourceid; /* extended id of source type */ + + /* + * sqlilongdata is new. It supports data that exceeds the 32k + * limit. sqlilen and sqlidata are for backward compatibility + * and they have maximum value of <32K. + */ + char *sqlilongdata; /* for data field beyond 32K */ + int4 sqlflags; /* for internal use only */ + void *sqlreserved; /* reserved for future use */ + } pg_sqlvar_t; + + typedef struct sqlda + { + int2 sqld; + pg_sqlvar_t *sqlvar; + char desc_name[19]; /* descriptor name */ + int2 desc_occ; /* size of sqlda structure */ + struct sqlda *desc_next; /* pointer to next sqlda struct */ + void *reserved; /* reserved for future use */ + } pg_sqlda_t; + + #endif /* POSTGRES_SQLDA_H */ diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/include/sqltypes.h pgsql.sqlda/src/interfaces/ecpg/include/sqltypes.h *** pgsql.fixparsepl/src/interfaces/ecpg/include/sqltypes.h 2009-06-13 18:25:05.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/include/sqltypes.h 2009-10-05 15:18:01.000000000 +0200 *************** *** 30,33 **** --- 30,55 ---- #define CLVCHARPTRTYPE 124 #define CTYPEMAX 25 + /* + * Values used in sqlda->sqlvar[i]->sqltype + */ + #define SQLCHAR 0 + #define SQLSMINT 1 + #define SQLINT 2 + #define SQLFLOAT 3 + #define SQLSMFLOAT 4 + #define SQLDECIMAL 5 + #define SQLSERIAL 6 + #define SQLDATE 7 + #define SQLMONEY 8 + #define SQLDTIME 10 + #define SQLBYTES 11 + #define SQLTEXT 12 + #define SQLVCHAR 13 + #define SQLINTERVAL 14 + #define SQLNCHAR 15 + #define SQLNVCHAR 16 + #define SQLINT8 17 + #define SQLSERIAL8 18 + #endif /* ndef ECPG_SQLTYPES_H */ diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/preproc/descriptor.c pgsql.sqlda/src/interfaces/ecpg/preproc/descriptor.c *** pgsql.fixparsepl/src/interfaces/ecpg/preproc/descriptor.c 2009-01-30 17:28:46.000000000 +0100 --- pgsql.sqlda/src/interfaces/ecpg/preproc/descriptor.c 2009-10-05 15:18:01.000000000 +0200 *************** descriptor_variable(const char *name, in *** 326,328 **** --- 326,347 ---- strlcpy(descriptor_names[input], name, sizeof(descriptor_names[input])); return (struct variable *) & varspace[input]; } + + struct variable * + sqlda_variable(const char *name) + { + struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable)); + + p->name = mm_strdup(name); + p->type = (struct ECPGtype *) mm_alloc(sizeof(struct ECPGtype)); + p->type->type = ECPGt_sqlda; + p->type->size = NULL; + p->type->struct_sizeof = NULL; + p->type->u.element = NULL; + p->type->lineno = 0; + p->brace_level = 0; + p->next = NULL; + + return p; + } + diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/preproc/ecpg.addons pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.addons *** pgsql.fixparsepl/src/interfaces/ecpg/preproc/ecpg.addons 2009-10-03 01:54:43.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.addons 2009-10-05 15:18:01.000000000 +0200 *************** ECPG: VariableShowStmtSHOWALL block *** 402,430 **** $$ = EMPTY; } ECPG: FetchStmtMOVEfetch_args rule ! | FETCH fetch_args ecpg_into { $$ = cat2_str(make_str("fetch"), $2); } ! | FETCH FORWARD cursor_name opt_ecpg_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat_str(2, make_str("fetch forward"), cursor_marker); } ! | FETCH FORWARD from_in cursor_name opt_ecpg_into { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); $$ = cat_str(2, make_str("fetch forward from"), cursor_marker); } ! | FETCH BACKWARD cursor_name opt_ecpg_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat_str(2, make_str("fetch backward"), cursor_marker); } ! | FETCH BACKWARD from_in cursor_name opt_ecpg_into { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); --- 402,430 ---- $$ = EMPTY; } ECPG: FetchStmtMOVEfetch_args rule ! | FETCH fetch_args ecpg_fetch_into { $$ = cat2_str(make_str("fetch"), $2); } ! | FETCH FORWARD cursor_name opt_ecpg_fetch_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat_str(2, make_str("fetch forward"), cursor_marker); } ! | FETCH FORWARD from_in cursor_name opt_ecpg_fetch_into { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); $$ = cat_str(2, make_str("fetch forward from"), cursor_marker); } ! | FETCH BACKWARD cursor_name opt_ecpg_fetch_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat_str(2, make_str("fetch backward"), cursor_marker); } ! | FETCH BACKWARD from_in cursor_name opt_ecpg_fetch_into { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/preproc/ecpg.trailer pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.trailer *** pgsql.fixparsepl/src/interfaces/ecpg/preproc/ecpg.trailer 2009-10-03 02:05:58.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.trailer 2009-10-05 15:18:01.000000000 +0200 *************** ecpg_using: USING using_list { $$ = EMP *** 1017,1035 **** using_descriptor: USING opt_sql SQL_DESCRIPTOR quoted_ident_stringvar { ! add_variable_to_head(&argsinsert, descriptor_variable($4,0), &no_indicator); $$ = EMPTY; } ; into_descriptor: INTO opt_sql SQL_DESCRIPTOR quoted_ident_stringvar { ! add_variable_to_head(&argsresult, descriptor_variable($4,1), &no_indicator); $$ = EMPTY; } ; ! opt_sql: /*EMPTY*/ | SQL_SQL; using_list: UsingValue | UsingValue ',' using_list; --- 1017,1065 ---- using_descriptor: USING opt_sql SQL_DESCRIPTOR quoted_ident_stringvar { ! if (strlen($2) || !(INFORMIX_MODE)) ! add_variable_to_head(&argsinsert, descriptor_variable($4,0), &no_indicator); ! else ! { ! if ($4[0] == '\"') ! { ! char *pos; ! ! $4[0] = ' '; ! for (pos = $4; *pos; pos++) ! if (*pos == '\"') ! *pos = ' '; ! } ! add_variable_to_head(&argsinsert, sqlda_variable($4), &no_indicator); ! } $$ = EMPTY; } ; into_descriptor: INTO opt_sql SQL_DESCRIPTOR quoted_ident_stringvar { ! if (strlen($2) || !(INFORMIX_MODE)) ! add_variable_to_head(&argsresult, descriptor_variable($4,1), &no_indicator); ! else ! { ! if ($4[0] == '\"') ! { ! char *pos; ! ! $4[0] = ' '; ! for (pos = $4; *pos; pos++) ! if (*pos == '\"') ! *pos = ' '; ! } ! add_variable_to_head(&argsresult, sqlda_variable($4), &no_indicator); ! } $$ = EMPTY; } ; ! opt_sql: /*EMPTY*/ { $$ = EMPTY; } ! | SQL_SQL { $$ = make_str("sql"); } ! ; using_list: UsingValue | UsingValue ',' using_list; *************** ecpg_into: INTO into_list { $$ = EMPTY; *** 2052,2058 **** | into_descriptor { $$ = $1; } ; ! opt_ecpg_into: /* EMPTY */ { $$ = EMPTY; } | ecpg_into { $$ = $1; } ; --- 2082,2103 ---- | into_descriptor { $$ = $1; } ; ! ecpg_fetch_into: ecpg_into { $$ = $1; } ! | using_descriptor ! { ! struct variable *var; ! ! if (!INFORMIX_MODE) ! mmerror(PARSE_ERROR, ET_ERROR, "Not in Informix compatibility mode"); ! ! var = argsinsert->variable; ! remove_variable_from_list(&argsinsert, var); ! add_variable_to_head(&argsresult, var, &no_indicator); ! $$ = $1; ! } ! ; ! ! opt_ecpg_fetch_into: /* EMPTY */ { $$ = EMPTY; } | ecpg_into { $$ = $1; } ; diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/preproc/ecpg.type pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.type *** pgsql.fixparsepl/src/interfaces/ecpg/preproc/ecpg.type 2009-10-03 02:03:31.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.type 2009-10-05 15:18:01.000000000 +0200 *************** *** 62,67 **** --- 62,68 ---- %type <str> ecpg_ident %type <str> ecpg_interval %type <str> ecpg_into + %type <str> ecpg_fetch_into %type <str> ecpg_param %type <str> ecpg_sconst %type <str> ecpg_using *************** *** 77,83 **** %type <str> opt_bit_field %type <str> opt_connection_name %type <str> opt_database_name ! %type <str> opt_ecpg_into %type <str> opt_ecpg_using %type <str> opt_initializer %type <str> opt_options --- 78,84 ---- %type <str> opt_bit_field %type <str> opt_connection_name %type <str> opt_database_name ! %type <str> opt_ecpg_fetch_into %type <str> opt_ecpg_using %type <str> opt_initializer %type <str> opt_options *************** *** 87,92 **** --- 88,94 ---- %type <str> opt_reference %type <str> opt_scale %type <str> opt_server + %type <str> opt_sql %type <str> opt_user %type <str> opt_opt_value %type <str> ora_user diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/preproc/extern.h pgsql.sqlda/src/interfaces/ecpg/preproc/extern.h *** pgsql.fixparsepl/src/interfaces/ecpg/preproc/extern.h 2009-10-03 01:07:54.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/preproc/extern.h 2009-10-05 15:18:01.000000000 +0200 *************** extern void add_descriptor(char *, char *** 88,93 **** --- 88,94 ---- extern void drop_descriptor(char *, char *); extern struct descriptor *lookup_descriptor(char *, char *); extern struct variable *descriptor_variable(const char *name, int input); + extern struct variable *sqlda_variable(const char *name); extern void add_variable_to_head(struct arguments **, struct variable *, struct variable *); extern void add_variable_to_tail(struct arguments **, struct variable *, struct variable *); extern void remove_variable_from_list(struct arguments ** list, struct variable * var); diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/preproc/type.c pgsql.sqlda/src/interfaces/ecpg/preproc/type.c *** pgsql.fixparsepl/src/interfaces/ecpg/preproc/type.c 2009-09-03 12:25:47.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/preproc/type.c 2009-10-05 15:18:01.000000000 +0200 *************** get_type(enum ECPGttype type) *** 194,199 **** --- 194,202 ---- case ECPGt_descriptor: return ("ECPGt_descriptor"); break; + case ECPGt_sqlda: + return ("ECPGt_sqlda"); + break; case ECPGt_date: return ("ECPGt_date"); break; *************** ECPGdump_a_simple(FILE *o, const char *n *** 328,333 **** --- 331,338 ---- else if (type == ECPGt_descriptor) /* remember that name here already contains quotes (if needed) */ fprintf(o, "\n\tECPGt_descriptor, %s, 0L, 0L, 0L, ", name); + else if (type == ECPGt_sqlda) + fprintf(o, "\n\tECPGt_sqlda, &%s, 0L, 0L, 0L, ", name); else { char *variable = (char *) mm_alloc(strlen(name) + ((prefix == NULL) ? 0 : strlen(prefix)) + 4); diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/compat_informix/Makefile pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/Makefile *** pgsql.fixparsepl/src/interfaces/ecpg/test/compat_informix/Makefile 2009-10-03 02:11:20.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/Makefile 2009-10-05 15:18:01.000000000 +0200 *************** TESTS = test_informix test_informix.c \ *** 17,22 **** --- 17,23 ---- rfmtdate rfmtdate.c \ rfmtlong rfmtlong.c \ rnull rnull.c \ + sqlda sqlda.c \ charfuncs charfuncs.c all: $(TESTS) *************** test_informix2.c: test_informix2.pgc ../ *** 30,35 **** --- 31,39 ---- cursor.c: cursor.pgc ../regression.h $(ECPG) -o $@ -I$(srcdir) $< + sqlda.c: sqlda.pgc ../regression.h + $(ECPG) -o $@ -I$(srcdir) $< + dec_test.c: dec_test.pgc ../regression.h $(ECPG) -o $@ -I$(srcdir) $< diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/compat_informix/sqlda.pgc pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/sqlda.pgc *** pgsql.fixparsepl/src/interfaces/ecpg/test/compat_informix/sqlda.pgc 1970-01-01 01:00:00.000000000 +0100 --- pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/sqlda.pgc 2009-10-05 15:18:01.000000000 +0200 *************** *** 0 **** --- 1,252 ---- + #include <stdlib.h> + #include <string.h> + #include <inttypes.h> + + exec sql include ../regression; + + exec sql include sqlda.h; + exec sql include sqltypes.h; + + exec sql whenever sqlerror stop; + + /* These shouldn't be under DECLARE SECTION */ + pg_sqlda_t *inp_sqlda, *outp_sqlda; + + static void + dump_sqlda(pg_sqlda_t *sqlda) + { + int i; + + for (i = 0; i < sqlda->sqld; i++) + { + if (outp_sqlda->sqlvar[i].sqlind && *(outp_sqlda->sqlvar[i].sqlind) == -1) + printf("name sqlda descriptor: '%s' value NULL'\n", outp_sqlda->sqlvar[i].sqlname); + else + switch (sqlda->sqlvar[i].sqltype) + { + case SQLCHAR: + case SQLVCHAR: + case SQLTEXT: + printf("name sqlda descriptor: '%s' value '%s'\n", sqlda->sqlvar[i].sqlname, sqlda->sqlvar[i].sqldata); + break; + case SQLSERIAL: + case SQLINT: + printf("name sqlda descriptor: '%s' value %d\n", sqlda->sqlvar[i].sqlname, *(int *)sqlda->sqlvar[i].sqldata); + break; + case SQLSERIAL8: + case SQLINT8: + printf("name sqlda descriptor: '%s' value %" PRId64 "\n", sqlda->sqlvar[i].sqlname, *(int64_t *)sqlda->sqlvar[i].sqldata); + break; + case SQLFLOAT: + printf("name sqlda descriptor: '%s' value %lf\n", sqlda->sqlvar[i].sqlname, *(double *)sqlda->sqlvar[i].sqldata); + break; + case SQLDECIMAL: + { + char val[64]; + dectoasc((dec_t *)sqlda->sqlvar[i].sqldata, val, 64, -1); + printf("name sqlda descriptor: '%s' value DECIMAL '%s'\n", sqlda->sqlvar[i].sqlname, val); + break; + } + } + } + } + + int + main (void) + { + exec sql begin declare section; + char *stmt1 = "SELECT * FROM t1"; + char *stmt2 = "SELECT * FROM t1 WHERE id = ?"; + int rec; + int id; + exec sql end declare section; + + char msg[128]; + + ECPGdebug(1, stderr); + + strcpy(msg, "connect"); + exec sql connect to REGRESSDB1 as regress1; + + strcpy(msg, "set"); + exec sql set datestyle to iso; + + strcpy(msg, "create"); + exec sql create table t1( + id integer, + t text, + d1 numeric, + d2 float8, + c char(10)); + + strcpy(msg, "insert"); + exec sql insert into t1 values + (1, 'a', 1.0, 1, 'a'), + (2, null, null, null, null), + (3, '"c"', -3, 'nan'::float8, 'c'), + (4, 'd', 4.0, 4, 'd'); + + strcpy(msg, "commit"); + exec sql commit; + + /* SQLDA test for getting all records from a table */ + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + exec sql prepare st_id1 from :stmt1; + + strcpy(msg, "declare"); + exec sql declare mycur1 cursor for st_id1; + + strcpy(msg, "open"); + exec sql open mycur1; + + exec sql whenever not found do break; + + rec = 0; + while (1) + { + strcpy(msg, "fetch"); + exec sql fetch 1 from mycur1 into descriptor outp_sqlda; + + printf("FETCH RECORD %d\n", ++rec); + dump_sqlda(outp_sqlda); + } + + exec sql whenever not found continue; + + strcpy(msg, "close"); + exec sql close mycur1; + + strcpy(msg, "deallocate"); + exec sql deallocate prepare st_id1; + + free(outp_sqlda); + + /* SQLDA test for getting all records from a table + using the Informix-specific FETCH ... USING DESCRIPTOR + */ + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + exec sql prepare st_id2 from :stmt1; + + strcpy(msg, "declare"); + exec sql declare mycur2 cursor for st_id2; + + strcpy(msg, "open"); + exec sql open mycur2; + + exec sql whenever not found do break; + + rec = 0; + while (1) + { + strcpy(msg, "fetch"); + exec sql fetch from mycur2 using descriptor outp_sqlda; + + printf("FETCH RECORD %d\n", ++rec); + dump_sqlda(outp_sqlda); + } + + exec sql whenever not found continue; + + strcpy(msg, "close"); + exec sql close mycur2; + + strcpy(msg, "deallocate"); + exec sql deallocate prepare st_id2; + + free(outp_sqlda); + + /* SQLDA test for getting one record using an input descriptor */ + + /* Input sqlda has to be built manually */ + inp_sqlda = (pg_sqlda_t *)malloc(sizeof(pg_sqlda_t)); + memset(inp_sqlda, 0, sizeof(pg_sqlda_t)); + inp_sqlda->sqld = 1; + inp_sqlda->sqlvar = malloc(sizeof(pg_sqlvar_t)); + memset(inp_sqlda->sqlvar, 0, sizeof(pg_sqlvar_t)); + + inp_sqlda->sqlvar[0].sqltype = SQLINT; + inp_sqlda->sqlvar[0].sqldata = (char *)&id; + + printf("EXECUTE RECORD 4\n"); + + id = 4; + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + exec sql prepare st_id3 FROM :stmt2; + + strcpy(msg, "execute"); + exec sql execute st_id3 using descriptor inp_sqlda into descriptor outp_sqlda; + + dump_sqlda(outp_sqlda); + + strcpy(msg, "deallocate"); + exec sql deallocate prepare st_id3; + + free(inp_sqlda->sqlvar); + free(inp_sqlda); + free(outp_sqlda); + + /* SQLDA test for getting one record using an input descriptor + * on a named connection + */ + + exec sql connect to REGRESSDB1 as con2; + + /* Input sqlda has to be built manually */ + inp_sqlda = (pg_sqlda_t *)malloc(sizeof(pg_sqlda_t)); + memset(inp_sqlda, 0, sizeof(pg_sqlda_t)); + inp_sqlda->sqld = 1; + inp_sqlda->sqlvar = malloc(sizeof(pg_sqlvar_t)); + memset(inp_sqlda->sqlvar, 0, sizeof(pg_sqlvar_t)); + + inp_sqlda->sqlvar[0].sqltype = SQLINT; + inp_sqlda->sqlvar[0].sqldata = (char *)&id; + + printf("EXECUTE RECORD 4\n"); + + id = 4; + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + exec sql at con2 prepare st_id4 FROM :stmt2; + + strcpy(msg, "execute"); + exec sql at con2 execute st_id4 using descriptor inp_sqlda into descriptor outp_sqlda; + + dump_sqlda(outp_sqlda); + + strcpy(msg, "commit"); + exec sql at con2 commit; + + strcpy(msg, "deallocate"); + exec sql deallocate prepare st_id4; + + free(inp_sqlda->sqlvar); + free(inp_sqlda); + free(outp_sqlda); + + strcpy(msg, "disconnect"); + exec sql disconnect con2; + + /* End test */ + + strcpy(msg, "drop"); + exec sql drop table t1; + + strcpy(msg, "commit"); + exec sql commit; + + strcpy(msg, "disconnect"); + exec sql disconnect; + + return (0); + } diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/ecpg_schedule pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule *** pgsql.fixparsepl/src/interfaces/ecpg/test/ecpg_schedule 2009-10-03 02:11:20.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule 2009-10-05 15:18:01.000000000 +0200 *************** test: compat_informix/rfmtdate *** 4,9 **** --- 4,10 ---- test: compat_informix/rfmtlong test: compat_informix/rnull test: compat_informix/cursor + test: compat_informix/sqlda test: compat_informix/test_informix test: compat_informix/test_informix2 test: connect/test2 diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/ecpg_schedule_tcp pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule_tcp *** pgsql.fixparsepl/src/interfaces/ecpg/test/ecpg_schedule_tcp 2009-10-03 02:11:20.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule_tcp 2009-10-05 15:18:01.000000000 +0200 *************** test: compat_informix/rfmtdate *** 4,9 **** --- 4,10 ---- test: compat_informix/rfmtlong test: compat_informix/rnull test: compat_informix/cursor + test: compat_informix/sqlda test: compat_informix/test_informix test: compat_informix/test_informix2 test: connect/test2 diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c *** pgsql.fixparsepl/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c 1970-01-01 01:00:00.000000000 +0100 --- pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c 2009-10-05 15:18:01.000000000 +0200 *************** *** 0 **** --- 1,585 ---- + /* Processed by ecpg (regression mode) */ + /* These include files are added by the preprocessor */ + #include <ecpglib.h> + #include <ecpgerrno.h> + #include <sqlca.h> + /* Needed for informix compatibility */ + #include <ecpg_informix.h> + /* End of automatic include section */ + #define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y)) + + #line 1 "sqlda.pgc" + #include <stdlib.h> + #include <string.h> + #include <inttypes.h> + + + #line 1 "regression.h" + + + + + + + #line 5 "sqlda.pgc" + + + + #line 1 "sqlda.h" + /* + * $PostgreSQL: pgsql/src/interfaces/ecpg/include/sqlda.h,v 1.4 2009/06/11 14:49:13 momjian Exp $ + */ + + #ifndef POSTGRES_SQLDA_H + #define POSTGRES_SQLDA_H + + /* Define Informix "standard" types */ + #ifndef C_H + typedef int int4; + typedef short int2; + #endif + typedef char int1; + + typedef int mint; + typedef long mlong; + + typedef short MSHORT; + typedef char MCHAR; + + typedef unsigned int uint4; + typedef unsigned short uint2; + typedef unsigned char uint1; + + typedef unsigned int muint; + typedef unsigned long mulong; + + typedef unsigned short MUSHORT; + typedef unsigned char MUCHAR; + + #define MI_INT_SIZE (sizeof(int) * 8) + #define MI_LONG_SIZE (sizeof(long) * 8) + #define MI_PTR_SIZE (sizeof(char *) * 8) + + typedef struct sqlvar_struct + { + int2 sqltype; /* variable type */ + int4 sqllen; /* length in bytes */ + char *sqldata; /* pointer to data */ + int2 *sqlind; /* pointer to indicator */ + char *sqlname; /* variable name */ + char *sqlformat; /* reserved for future use */ + int2 sqlitype; /* ind variable type */ + int2 sqlilen; /* ind length in bytes */ + char *sqlidata; /* ind data pointer */ + int4 sqlxid; /* extended id type */ + char *sqltypename; /* extended type name */ + int2 sqltypelen; /* length of extended type name */ + int2 sqlownerlen; /* length of owner name */ + int2 sqlsourcetype; /* source type for distinct of built-ins */ + char *sqlownername; /* owner name */ + int4 sqlsourceid; /* extended id of source type */ + + /* + * sqlilongdata is new. It supports data that exceeds the 32k + * limit. sqlilen and sqlidata are for backward compatibility + * and they have maximum value of <32K. + */ + char *sqlilongdata; /* for data field beyond 32K */ + int4 sqlflags; /* for internal use only */ + void *sqlreserved; /* reserved for future use */ + } pg_sqlvar_t; + + typedef struct sqlda + { + int2 sqld; + pg_sqlvar_t *sqlvar; + char desc_name[19]; /* descriptor name */ + int2 desc_occ; /* size of sqlda structure */ + struct sqlda *desc_next; /* pointer to next sqlda struct */ + void *reserved; /* reserved for future use */ + } pg_sqlda_t; + + #endif /* POSTGRES_SQLDA_H */ + + #line 7 "sqlda.pgc" + + + #line 1 "sqltypes.h" + /* + * $PostgreSQL: pgsql/src/interfaces/ecpg/include/sqltypes.h,v 1.9 2009/06/11 14:49:13 momjian Exp $ + */ + #ifndef ECPG_SQLTYPES_H + #define ECPG_SQLTYPES_H + + #define CCHARTYPE ECPGt_char + #define CSHORTTYPE ECPGt_short + #define CINTTYPE ECPGt_int + #define CLONGTYPE ECPGt_long + #define CFLOATTYPE ECPGt_float + #define CDOUBLETYPE ECPGt_double + #define CDECIMALTYPE ECPGt_decimal + #define CFIXCHARTYPE 108 + #define CSTRINGTYPE ECPGt_char + #define CDATETYPE ECPGt_date + #define CMONEYTYPE 111 + #define CDTIMETYPE ECPGt_timestamp + #define CLOCATORTYPE 113 + #define CVCHARTYPE ECPGt_varchar + #define CINVTYPE 115 + #define CFILETYPE 116 + #define CINT8TYPE ECPGt_long_long + #define CCOLLTYPE 118 + #define CLVCHARTYPE 119 + #define CFIXBINTYPE 120 + #define CVARBINTYPE 121 + #define CBOOLTYPE ECPGt_bool + #define CROWTYPE 123 + #define CLVCHARPTRTYPE 124 + #define CTYPEMAX 25 + + /* + * Values used in sqlda->sqlvar[i]->sqltype + */ + #define SQLCHAR 0 + #define SQLSMINT 1 + #define SQLINT 2 + #define SQLFLOAT 3 + #define SQLSMFLOAT 4 + #define SQLDECIMAL 5 + #define SQLSERIAL 6 + #define SQLDATE 7 + #define SQLMONEY 8 + #define SQLDTIME 10 + #define SQLBYTES 11 + #define SQLTEXT 12 + #define SQLVCHAR 13 + #define SQLINTERVAL 14 + #define SQLNCHAR 15 + #define SQLNVCHAR 16 + #define SQLINT8 17 + #define SQLSERIAL8 18 + + #endif /* ndef ECPG_SQLTYPES_H */ + + #line 8 "sqlda.pgc" + + + /* exec sql whenever sqlerror stop ; */ + #line 10 "sqlda.pgc" + + + /* These shouldn't be under DECLARE SECTION */ + pg_sqlda_t *inp_sqlda, *outp_sqlda; + + static void + dump_sqlda(pg_sqlda_t *sqlda) + { + int i; + + for (i = 0; i < sqlda->sqld; i++) + { + if (outp_sqlda->sqlvar[i].sqlind && *(outp_sqlda->sqlvar[i].sqlind) == -1) + printf("name sqlda descriptor: '%s' value NULL'\n", outp_sqlda->sqlvar[i].sqlname); + else + switch (sqlda->sqlvar[i].sqltype) + { + case SQLCHAR: + case SQLVCHAR: + case SQLTEXT: + printf("name sqlda descriptor: '%s' value '%s'\n", sqlda->sqlvar[i].sqlname, sqlda->sqlvar[i].sqldata); + break; + case SQLSERIAL: + case SQLINT: + printf("name sqlda descriptor: '%s' value %d\n", sqlda->sqlvar[i].sqlname, *(int *)sqlda->sqlvar[i].sqldata); + break; + case SQLSERIAL8: + case SQLINT8: + printf("name sqlda descriptor: '%s' value %" PRId64 "\n", sqlda->sqlvar[i].sqlname, *(int64_t *)sqlda->sqlvar[i].sqldata); + break; + case SQLFLOAT: + printf("name sqlda descriptor: '%s' value %lf\n", sqlda->sqlvar[i].sqlname, *(double *)sqlda->sqlvar[i].sqldata); + break; + case SQLDECIMAL: + { + char val[64]; + dectoasc((decimal *)sqlda->sqlvar[i].sqldata, val, 64, -1); + printf("name sqlda descriptor: '%s' value DECIMAL '%s'\n", sqlda->sqlvar[i].sqlname, val); + break; + } + } + } + } + + int + main (void) + { + /* exec sql begin declare section */ + + + + + + #line 58 "sqlda.pgc" + char * stmt1 = "SELECT * FROM t1" ; + + #line 59 "sqlda.pgc" + char * stmt2 = "SELECT * FROM t1 WHERE id = ?" ; + + #line 60 "sqlda.pgc" + int rec ; + + #line 61 "sqlda.pgc" + int id ; + /* exec sql end declare section */ + #line 62 "sqlda.pgc" + + + char msg[128]; + + ECPGdebug(1, stderr); + + strcpy(msg, "connect"); + { ECPGconnect(__LINE__, 1, "regress1" , NULL, NULL , "regress1", 0); + #line 69 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 69 "sqlda.pgc" + + + strcpy(msg, "set"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "set datestyle to iso", ECPGt_EOIT, ECPGt_EORT); + #line 72 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 72 "sqlda.pgc" + + + strcpy(msg, "create"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "create table t1 ( id integer , t text , d1 numeric , d2 float8 ,c char ( 10 ) )", ECPGt_EOIT, ECPGt_EORT); + #line 80 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 80 "sqlda.pgc" + + + strcpy(msg, "insert"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "insert into t1 values ( 1 , 'a' , 1.0 , 1 , 'a' ) , ( 2 , null ,null , null , null ) , ( 3 , '\"c\"' , - 3 , 'nan' :: float8 , 'c' ) , ( 4 , 'd' , 4.0 , 4 , 'd' )", ECPGt_EOIT, ECPGt_EORT); + #line 87 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 87 "sqlda.pgc" + + + strcpy(msg, "commit"); + { ECPGtrans(__LINE__, NULL, "commit"); + #line 90 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 90 "sqlda.pgc" + + + /* SQLDA test for getting all records from a table */ + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + { ECPGprepare(__LINE__, NULL, 0, "st_id1", stmt1); + #line 97 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 97 "sqlda.pgc" + + + strcpy(msg, "declare"); + ECPG_informix_reset_sqlca(); /* declare mycur1 cursor for $1 */ + #line 100 "sqlda.pgc" + + + strcpy(msg, "open"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "declare mycur1 cursor for $1", + ECPGt_char_variable,(ECPGprepared_statement(NULL, "st_id1", __LINE__)),(long)1,(long)1,(1)*sizeof(char), + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT); + #line 103 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 103 "sqlda.pgc" + + + /* exec sql whenever not found break ; */ + #line 105 "sqlda.pgc" + + + rec = 0; + while (1) + { + strcpy(msg, "fetch"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch 1 from mycur1", ECPGt_EOIT, + ECPGt_sqlda, & outp_sqlda , 0L, 0L, 0L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT); + #line 111 "sqlda.pgc" + + if (sqlca.sqlcode == ECPG_NOT_FOUND) break; + #line 111 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 111 "sqlda.pgc" + + + printf("FETCH RECORD %d\n", ++rec); + dump_sqlda(outp_sqlda); + } + + /* exec sql whenever not found continue ; */ + #line 117 "sqlda.pgc" + + + strcpy(msg, "close"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "close mycur1", ECPGt_EOIT, ECPGt_EORT); + #line 120 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 120 "sqlda.pgc" + + + strcpy(msg, "deallocate"); + { ECPGdeallocate(__LINE__, 1, NULL, "st_id1"); + #line 123 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 123 "sqlda.pgc" + + + free(outp_sqlda); + + /* SQLDA test for getting all records from a table + using the Informix-specific FETCH ... USING DESCRIPTOR + */ + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + { ECPGprepare(__LINE__, NULL, 0, "st_id2", stmt1); + #line 134 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 134 "sqlda.pgc" + + + strcpy(msg, "declare"); + ECPG_informix_reset_sqlca(); /* declare mycur2 cursor for $1 */ + #line 137 "sqlda.pgc" + + + strcpy(msg, "open"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "declare mycur2 cursor for $1", + ECPGt_char_variable,(ECPGprepared_statement(NULL, "st_id2", __LINE__)),(long)1,(long)1,(1)*sizeof(char), + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT); + #line 140 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 140 "sqlda.pgc" + + + /* exec sql whenever not found break ; */ + #line 142 "sqlda.pgc" + + + rec = 0; + while (1) + { + strcpy(msg, "fetch"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch from mycur2", ECPGt_EOIT, + ECPGt_sqlda, & outp_sqlda , 0L, 0L, 0L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT); + #line 148 "sqlda.pgc" + + if (sqlca.sqlcode == ECPG_NOT_FOUND) break; + #line 148 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 148 "sqlda.pgc" + + + printf("FETCH RECORD %d\n", ++rec); + dump_sqlda(outp_sqlda); + } + + /* exec sql whenever not found continue ; */ + #line 154 "sqlda.pgc" + + + strcpy(msg, "close"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "close mycur2", ECPGt_EOIT, ECPGt_EORT); + #line 157 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 157 "sqlda.pgc" + + + strcpy(msg, "deallocate"); + { ECPGdeallocate(__LINE__, 1, NULL, "st_id2"); + #line 160 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 160 "sqlda.pgc" + + + free(outp_sqlda); + + /* SQLDA test for getting one record using an input descriptor */ + + /* Input sqlda has to be built manually */ + inp_sqlda = (pg_sqlda_t *)malloc(sizeof(pg_sqlda_t)); + memset(inp_sqlda, 0, sizeof(pg_sqlda_t)); + inp_sqlda->sqld = 1; + inp_sqlda->sqlvar = malloc(sizeof(pg_sqlvar_t)); + memset(inp_sqlda->sqlvar, 0, sizeof(pg_sqlvar_t)); + + inp_sqlda->sqlvar[0].sqltype = SQLINT; + inp_sqlda->sqlvar[0].sqldata = (char *)&id; + + printf("EXECUTE RECORD 4\n"); + + id = 4; + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + { ECPGprepare(__LINE__, NULL, 0, "st_id3", stmt2); + #line 183 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 183 "sqlda.pgc" + + + strcpy(msg, "execute"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, 1, "st_id3", + ECPGt_sqlda, & inp_sqlda , 0L, 0L, 0L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, + ECPGt_sqlda, & outp_sqlda , 0L, 0L, 0L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT); + #line 186 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 186 "sqlda.pgc" + + + dump_sqlda(outp_sqlda); + + strcpy(msg, "deallocate"); + { ECPGdeallocate(__LINE__, 1, NULL, "st_id3"); + #line 191 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 191 "sqlda.pgc" + + + free(inp_sqlda->sqlvar); + free(inp_sqlda); + free(outp_sqlda); + + /* SQLDA test for getting one record using an input descriptor + * on a named connection + */ + + { ECPGconnect(__LINE__, 1, "regress1" , NULL, NULL , "con2", 0); + #line 201 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 201 "sqlda.pgc" + + + /* Input sqlda has to be built manually */ + inp_sqlda = (pg_sqlda_t *)malloc(sizeof(pg_sqlda_t)); + memset(inp_sqlda, 0, sizeof(pg_sqlda_t)); + inp_sqlda->sqld = 1; + inp_sqlda->sqlvar = malloc(sizeof(pg_sqlvar_t)); + memset(inp_sqlda->sqlvar, 0, sizeof(pg_sqlvar_t)); + + inp_sqlda->sqlvar[0].sqltype = SQLINT; + inp_sqlda->sqlvar[0].sqldata = (char *)&id; + + printf("EXECUTE RECORD 4\n"); + + id = 4; + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + { ECPGprepare(__LINE__, "con2", 0, "st_id4", stmt2); + #line 220 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 220 "sqlda.pgc" + + + strcpy(msg, "execute"); + { ECPGdo(__LINE__, 1, 1, "con2", 0, 1, "st_id4", + ECPGt_sqlda, & inp_sqlda , 0L, 0L, 0L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, + ECPGt_sqlda, & outp_sqlda , 0L, 0L, 0L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT); + #line 223 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 223 "sqlda.pgc" + + + dump_sqlda(outp_sqlda); + + strcpy(msg, "commit"); + { ECPGtrans(__LINE__, "con2", "commit"); + #line 228 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 228 "sqlda.pgc" + + + strcpy(msg, "deallocate"); + { ECPGdeallocate(__LINE__, 1, NULL, "st_id4"); + #line 231 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 231 "sqlda.pgc" + + + free(inp_sqlda->sqlvar); + free(inp_sqlda); + free(outp_sqlda); + + strcpy(msg, "disconnect"); + { ECPGdisconnect(__LINE__, "con2"); + #line 238 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 238 "sqlda.pgc" + + + /* End test */ + + strcpy(msg, "drop"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "drop table t1", ECPGt_EOIT, ECPGt_EORT); + #line 243 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 243 "sqlda.pgc" + + + strcpy(msg, "commit"); + { ECPGtrans(__LINE__, NULL, "commit"); + #line 246 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 246 "sqlda.pgc" + + + strcpy(msg, "disconnect"); + { ECPGdisconnect(__LINE__, "CURRENT"); + #line 249 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 249 "sqlda.pgc" + + + return (0); + } diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr *** pgsql.fixparsepl/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr 1970-01-01 01:00:00.000000000 +0100 --- pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr 2009-10-05 15:18:01.000000000 +0200 *************** *** 0 **** --- 1,252 ---- + [NO_PID]: ECPGdebug: set to 1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGconnect: opening database regress1 on <DEFAULT> port <DEFAULT> + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 72: query: set datestyle to iso; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 72: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 72: OK: SET + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 75: query: create table t1 ( id integer , t text , d1 numeric , d2 float8 , c char ( 10) ); with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 75: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 75: OK: CREATE TABLE + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 83: query: insert into t1 values ( 1 , 'a' , 1.0 , 1 , 'a' ) , ( 2 , null , null , null, null ) , ( 3 , '"c"' , - 3 , 'nan' :: float8 , 'c' ) , ( 4 , 'd' , 4.0 , 4 , 'd' ); with 0 parameter(s) on connectionregress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 83: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 83: OK: INSERT 0 4 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGtrans on line 90: action "commit"; connection "regress1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGprepare on line 97: name st_id1; query: "SELECT * FROM t1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 103: query: declare mycur1 cursor for SELECT * FROM t1; with 0 parameter(s) on connectionregress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 103: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 103: OK: DECLARE CURSOR + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 1 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 1.0 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 1 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 2 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 3 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: -3 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: NaN offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 4.0 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: correctly got 0 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: raising sqlcode 100 on line 111: no data found on line 111 + [NO_PID]: sqlca: code: 100, state: 02000 + [NO_PID]: ecpg_execute on line 120: query: close mycur1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 120: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 120: OK: CLOSE CURSOR + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGdeallocate on line 123: name st_id1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGprepare on line 134: name st_id2; query: "SELECT * FROM t1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 140: query: declare mycur2 cursor for SELECT * FROM t1; with 0 parameter(s) on connectionregress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 140: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 140: OK: DECLARE CURSOR + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 1 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 1.0 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 1 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 2 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 3 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: -3 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: NaN offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 4.0 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: correctly got 0 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: raising sqlcode 100 on line 148: no data found on line 148 + [NO_PID]: sqlca: code: 100, state: 02000 + [NO_PID]: ecpg_execute on line 157: query: close mycur2; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 157: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 157: OK: CLOSE CURSOR + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGdeallocate on line 160: name st_id2 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGprepare on line 183: name st_id3; query: "SELECT * FROM t1 WHERE id = $1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 186: query: SELECT * FROM t1 WHERE id = $1; with 1 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 186: using PQexecPrepared for "SELECT * FROM t1 WHERE id = $1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: free_params on line 186: parameter 1 = 4 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 186: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 186: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 186: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 186: RESULT: 4.0 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 186: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 186: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGdeallocate on line 191: name st_id3 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGconnect: opening database regress1 on <DEFAULT> port <DEFAULT> + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGprepare on line 220: name st_id4; query: "SELECT * FROM t1 WHERE id = $1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 223: query: SELECT * FROM t1 WHERE id = $1; with 1 parameter(s) on connection con2 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 223: using PQexecPrepared for "SELECT * FROM t1 WHERE id = $1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: free_params on line 223: parameter 1 = 4 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 223: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 223: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 223: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 223: RESULT: 4.0 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 223: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 223: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGtrans on line 228: action "commit"; connection "con2" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGdeallocate on line 231: name st_id4 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_finish: connection con2 closed + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 243: query: drop table t1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 243: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 243: OK: DROP TABLE + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGtrans on line 246: action "commit"; connection "regress1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_finish: connection regress1 closed + [NO_PID]: sqlca: code: 0, state: 00000 diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout *** pgsql.fixparsepl/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout 1970-01-01 01:00:00.000000000 +0100 --- pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout 2009-10-05 15:18:01.000000000 +0200 *************** *** 0 **** --- 1,60 ---- + FETCH RECORD 1 + name sqlda descriptor: 'id' value 1 + name sqlda descriptor: 't' value 'a' + name sqlda descriptor: 'd1' value DECIMAL '1.0' + name sqlda descriptor: 'd2' value 1.000000 + name sqlda descriptor: 'c' value 'a ' + FETCH RECORD 2 + name sqlda descriptor: 'id' value 2 + name sqlda descriptor: 't' value NULL' + name sqlda descriptor: 'd1' value NULL' + name sqlda descriptor: 'd2' value NULL' + name sqlda descriptor: 'c' value NULL' + FETCH RECORD 3 + name sqlda descriptor: 'id' value 3 + name sqlda descriptor: 't' value '"c"' + name sqlda descriptor: 'd1' value DECIMAL '-3' + name sqlda descriptor: 'd2' value nan + name sqlda descriptor: 'c' value 'c ' + FETCH RECORD 4 + name sqlda descriptor: 'id' value 4 + name sqlda descriptor: 't' value 'd' + name sqlda descriptor: 'd1' value DECIMAL '4.0' + name sqlda descriptor: 'd2' value 4.000000 + name sqlda descriptor: 'c' value 'd ' + FETCH RECORD 1 + name sqlda descriptor: 'id' value 1 + name sqlda descriptor: 't' value 'a' + name sqlda descriptor: 'd1' value DECIMAL '1.0' + name sqlda descriptor: 'd2' value 1.000000 + name sqlda descriptor: 'c' value 'a ' + FETCH RECORD 2 + name sqlda descriptor: 'id' value 2 + name sqlda descriptor: 't' value NULL' + name sqlda descriptor: 'd1' value NULL' + name sqlda descriptor: 'd2' value NULL' + name sqlda descriptor: 'c' value NULL' + FETCH RECORD 3 + name sqlda descriptor: 'id' value 3 + name sqlda descriptor: 't' value '"c"' + name sqlda descriptor: 'd1' value DECIMAL '-3' + name sqlda descriptor: 'd2' value nan + name sqlda descriptor: 'c' value 'c ' + FETCH RECORD 4 + name sqlda descriptor: 'id' value 4 + name sqlda descriptor: 't' value 'd' + name sqlda descriptor: 'd1' value DECIMAL '4.0' + name sqlda descriptor: 'd2' value 4.000000 + name sqlda descriptor: 'c' value 'd ' + EXECUTE RECORD 4 + name sqlda descriptor: 'id' value 4 + name sqlda descriptor: 't' value 'd' + name sqlda descriptor: 'd1' value DECIMAL '4.0' + name sqlda descriptor: 'd2' value 4.000000 + name sqlda descriptor: 'c' value 'd ' + EXECUTE RECORD 4 + name sqlda descriptor: 'id' value 4 + name sqlda descriptor: 't' value 'd' + name sqlda descriptor: 'd1' value DECIMAL '4.0' + name sqlda descriptor: 'd2' value 4.000000 + name sqlda descriptor: 'c' value 'd '
On Thu, Oct 8, 2009 at 6:22 AM, Boszormenyi Zoltan <zb@cybertec.at> wrote: > Noah Misch írta: >> I will report on the sqlda patch in more detail on >> 2009-10-10. > > I am attaching a new one, please review this. Changes: > - set sqllen, sqlind, sqlilen and sqlitype per-field properties > - SQLINT8 and SQLSERIAL8 are ECPGt_long on 64-bit, not ECPGt_long_long > >> The one concern that's clear now is a lack of documentation update. >> > > That will come in a separate patch. What's the point of that? It can't be applied without documentation, and it just makes life more complicated to have two separate patch files floating around. ...Robert
Robert Haas írta: > On Thu, Oct 8, 2009 at 6:22 AM, Boszormenyi Zoltan <zb@cybertec.at> wrote: > >> Noah Misch írta: >> >>> I will report on the sqlda patch in more detail on >>> 2009-10-10. >>> >> I am attaching a new one, please review this. Changes: >> - set sqllen, sqlind, sqlilen and sqlitype per-field properties >> - SQLINT8 and SQLSERIAL8 are ECPGt_long on 64-bit, not ECPGt_long_long >> >> >>> The one concern that's clear now is a lack of documentation update. >>> >>> >> That will come in a separate patch. >> > > What's the point of that? It can't be applied without documentation, > and it just makes life more complicated to have two separate patch > files floating around. > > ...Robert > It's easier to write the documentation for all changes at once. I would have the same situation that happened with the code, the patches with the documentation added would strictly depend on each other again. Also, Michael Meskes applied the "string" pseudo-type patch without the documentation, despite the patch had it, maybe at an improper place. With a tongue-in-cheek "no comment" ;-) I point to this paragraph in the ECPG part of the documentation: "This documentation is quite incomplete. But since this interface is standardized, additional information can be found in many resources about SQL." The doc patch is attached. Details: - documented "string" pseudo-type - documented two more statements under section "Additional embedded SQL statements" which is now called "Additional/missing embedded SQL statements" This is about the current state of ECPG, no code changed. - document that INTO and USING are interchangeable if the target is a Descriptor Areas - document that the SQL keyword is not optional for DAs - document SQLDA - document DESCRIBE in section "Using SQL Descriptor Areas" Best regards, Zoltán Böszörményi -- Bible has answers for everything. Proof: "But let your communication be, Yea, yea; Nay, nay: for whatsoever is more than these cometh of evil." (Matthew 5:37) - basics of digital technology. "May your kingdom come" - superficial description of plate tectonics ---------------------------------- Zoltán Böszörményi Cybertec Schönig & Schönig GmbH http://www.postgresql.at/ *** pgsql.doc/doc/src/sgml/ecpg.sgml.old 2009-10-07 12:05:28.000000000 +0200 --- pgsql.doc/doc/src/sgml/ecpg.sgml 2009-10-08 12:55:15.785009096 +0200 *************** *** 2420,2428 **** </para> <sect2> ! <title>Additional embedded SQL statements</title> <para> <variablelist> <varlistentry> <term><literal>CLOSE DATABASE</></term> <listitem> --- 2420,2445 ---- </para> <sect2> ! <title>Additional types</title> ! <para> ! The Informix-special "string" pseudo-type for storing right-trimmed character string data is now ! supported in Informix-mode without using <literal>typedef</literal>. In fact, in Informix-mode, ! ECPG refuses to process source files that contain <literal>typedef sometype string;</literal> ! <programlisting> ! EXEC SQL BEGIN DECLARE SECTION; ! string userid; /* this variable will contain trimmed data */ ! EXEC SQL END DECLARE SECTION; ! ! EXEC SQL FETCH MYCUR INTO :userid; ! </programlisting> ! </para> ! </sect2> ! ! <sect2> ! <title>Additional/missing embedded SQL statements</title> <para> <variablelist> + <varlistentry> <term><literal>CLOSE DATABASE</></term> <listitem> *************** *** 2436,2446 **** --- 2453,2755 ---- </para> </listitem> </varlistentry> + + <varlistentry> + <term><literal>FREE cursor_name</></term> + <listitem> + <para> + Due to the differences how ECPG works (i.e. which steps are purely grammar transformations + and which steps rely on the underlying runtime library compared to Informix's ESQL/C) + there is no <literal>FREE cursor_name</> statement in ECPG. This is because in ECPG, + <literal>DECLARE CURSOR</literal> previously didn't translate to a function call into + the runtime library at all. Now it does, just to simply reset SQLCA to follow Informix + behaviour. But it's still true that there's no runtime bookkeeping of SQL cursors in + the ECPG runtime library, only in the PostgreSQL server. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>FREE statement_name</></term> + <listitem> + <para> + <literal>FREE statement_name</> is a synonym for <literal>DEALLOCATE PREPARE statement_name</>. + </para> + </listitem> + </varlistentry> + + </variablelist> + </para> + </sect2> + + <sect2> + <title>Additional syntax forms</title> + <para> + <variablelist> + + <varlistentry> + <term>Interchangeable <literal>USING</> and <literal>INTO</></term> + <listitem> + <para> + In <literal>DECRIBE</> and <literal>FETCH</> statements, the <literal>USING</> + and <literal>INTO</> keywords are interchangeable if the target is a Descriptor Area. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Non-optional <literal>SQL</> keyword for Descriptor Areas</term> + <listitem> + <para> + In <literal>DECRIBE</> and <literal>FETCH</> statements using Descriptor Areas, + the <literal>SQL</> keyword is not optional. <literal>DESCRIPTOR</> means an + SQLDA Descriptor Area, <literal>SQL DESCRIPTOR</> means a named SQL Descriptor Area. + </para> + </listitem> + </varlistentry> + </variablelist> </para> </sect2> <sect2> + <title>Additional SQL descriptor type: SQLDA C-structure</title> + <para> + Besides the named SQL descriptors, ECPG now supports Informix-special SQLDA descriptors + for accessing fields properties and data from low-level C code. Global properties are: + + <variablelist> + + <varlistentry> + <term><literal>sqld</></term> + <listitem> + <para> + The number of fields in the <literal>SQLDA</> descriptor. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>sqlvar</></term> + <listitem> + <para> + Pointer to the per-field properties. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>desc_name</></term> + <listitem> + <para> + Unused, filled with zerobytes. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>desc_occ</></term> + <listitem> + <para> + Size of the allocated structure. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>desc_next</></term> + <listitem> + <para> + Pointer to the structure, unused, contains NULL. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>reserved</></term> + <listitem> + <para> + Unused pointer, contains NULL. Kept for Informix-compatibility. + </para> + </listitem> + </varlistentry> + + </variablelist> + + The per-field properties are below, they are stored in the <literal>sqlvar</literal> array: + + <variablelist> + + <varlistentry> + <term><literal>sqltype</></term> + <listitem> + <para> + Type of the field. Constants are in <literal>sqltypes.h</literal> + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>sqllen</></term> + <listitem> + <para> + Length of the field data. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>sqldata</></term> + <listitem> + <para> + Pointer to the field data. The pointer is of <literal>char *</literal> type, + the data pointed by it is in a binary format. Example: + <programlisting> + int intval; + + switch (sqldata->sqlvar[i].sqltype) + { + case SQLINTEGER: + intval = *(int *)sqldata->sqlvar[i].sqldata; + break; + ... + } + </programlisting> + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>sqlind</></term> + <listitem> + <para> + Pointer to the NULL indicator. If returned by DESCRIBE or FETCH then it's always a valid pointer. + If used as input for <literal>EXECUTE ... USING sqlda;</literal> then NULL-pointer value means + that the value for this field is non-NULL. Otherwise a valid pointer and <literal>sqlitype</literal> + has to be properly set. Example: + <programlisting> + if (*(int2 *)sqldata->sqlvar[i].sqlind != 0) + printf("value is NULL\n"); + </programlisting> + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>sqlname</></term> + <listitem> + <para> + Name of the field. 0-terminated string. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>sqlformat</></term> + <listitem> + <para> + Reserved in Informix, value of PQfformat() for the field. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>sqlitype</></term> + <listitem> + <para> + Type of the NULL indicator data. It's always SQLSMINT when returning data from the server. + When the <literal>SQLDA</literal> is used for a parametrized query, the data is treated + according to the set type. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>sqlilen</></term> + <listitem> + <para> + Length of the NULL indicator data. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>sqlxid</></term> + <listitem> + <para> + Extended type of the field, result of PQftype(). + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>sqltypename</></term> + <term><literal>sqltypelen</></term> + <term><literal>sqlownerlen</></term> + <term><literal>sqlsourcetype</></term> + <term><literal>sqlownername</></term> + <term><literal>sqlsourceid</></term> + <term><literal>sqlflags</></term> + <term><literal>sqlreserved</></term> + <listitem> + <para> + Unused. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>sqlilongdata</></term> + <listitem> + <para> + It equals to <literal>sqldata</literal> if <literal>sqllen</literal> is larger than 32KB. + </para> + </listitem> + </varlistentry> + + </variablelist> + + Example: + <programlisting> + EXEC SQL INCLUDE sqlda.h; + + pg_sqlda_t *sqlda; /* This doesn't need to be under embedded DECLARE SECTION */ + + EXEC SQL BEGIN DECLARE SECTION; + char *prep_stmt = "select * from table1"; + int i; + EXEC SQL END DECLARE SECTION; + + ... + + EXEC SQL PREPARE mystmt FROM :prep_stmt; + + EXEC SQL DESCRIBE mystmt INTO sqlda; + + printf("# of fields: %d\n", sqlda->sqld); + for (i = 0; i < sqlda->sqld; i++) + printf("field %d: \"%s\"\n", sqlda->sqlvar[i]->sqlname); + + EXEC SQL DECLARE mycursor CURSOR FOR mystmt; + EXEC SQL OPEN mycursor; + EXEC SQL WHENEVER NOT FOUND GOTO out; + + while (1) + { + EXEC SQL FETCH mycursor USING sqlda; + } + + EXEC SQL CLOSE mycursor; + + free(sqlda); /* The main structure is all to be free(), + * sqlda and sqlda->sqlvar is in one allocated area */ + </programlisting> + For more information, see the <literal>sqlda.h</> header and the + <literal>src/interfaces/ecpg/test/compat_informix/sqlda.pgc</literal> regression test. + </para> + </sect2> + + <sect2> <title>Additional functions</title> <para> <variablelist> *************** *** 3696,3705 **** <para> To use a descriptor area, specify it as the storage target in an ! <literal>INTO</literal> clause, instead of listing host variables: <programlisting> EXEC SQL FETCH NEXT FROM mycursor INTO DESCRIPTOR mydesc; </programlisting> </para> <para> --- 4005,4028 ---- <para> To use a descriptor area, specify it as the storage target in an ! <literal>INTO</literal> clause in a <literal>DESCRIBE [OUTPUT]</literal> statement: ! <programlisting> ! EXEC SQL BEGIN DECLARE SECTION; ! char *stmt = "SELECT * FROM table1"; ! EXEC SQL END DECLARE SECTION; ! ! EXEC SQL PREPARE stmt1 FROM :stmt; ! EXEC SQL DESCRIBE stmt1 INTO DESCRIPTOR mydesc; ! EXEC SQL DESCRIBE stmt1 INTO SQL DESCRIPTOR mydesc; /* the SQL keyword is optional */ ! </programlisting> ! or a <literal>FETCH</literal> statement, instead of listing host variables: <programlisting> EXEC SQL FETCH NEXT FROM mycursor INTO DESCRIPTOR mydesc; + EXEC SQL FETCH NEXT FROM mycursor INTO SQL DESCRIPTOR mydesc /* the SQL keyword is optional */; </programlisting> + The difference between <literal>DESCRIBE</literal> and <literal>FETCH</literal> + statements above is that <literal>DESCRIBE</literal> on an empty resultset + gives the field metadata, e.g. its name, while <literal>FETCH</literal> doesn't. </para> <para>
Boszormenyi Zoltan írta: > Noah Misch írta: > >> I will report on the sqlda patch in more detail on >> 2009-10-10. >> > > I am attaching a new one, please review this. Changes: > - set sqllen, sqlind, sqlilen and sqlitype per-field properties > - SQLINT8 and SQLSERIAL8 are ECPGt_long on 64-bit, not ECPGt_long_long > New one attached, the second one is now really fixed, sorry for the previous one. -- Bible has answers for everything. Proof: "But let your communication be, Yea, yea; Nay, nay: for whatsoever is more than these cometh of evil." (Matthew 5:37) - basics of digital technology. "May your kingdom come" - superficial description of plate tectonics ---------------------------------- Zoltán Böszörményi Cybertec Schönig & Schönig GmbH http://www.postgresql.at/ diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/execute.c pgsql.sqlda/src/interfaces/ecpg/ecpglib/execute.c *** pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/execute.c 2009-09-03 14:37:34.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/ecpglib/execute.c 2009-10-05 15:18:01.000000000 +0200 *************** *** 25,30 **** --- 25,31 ---- #include "ecpgerrno.h" #include "extern.h" #include "sqlca.h" + #include "sqlda.h" #include "sql3types.h" #include "pgtypes_numeric.h" #include "pgtypes_date.h" *************** ecpg_store_input(const int lineno, const *** 1033,1038 **** --- 1034,1040 ---- break; case ECPGt_descriptor: + case ECPGt_sqlda: break; default: *************** ecpg_execute(struct statement * stmt) *** 1172,1177 **** --- 1174,1235 ---- if (desc->count == desc_counter) desc_counter = 0; } + else if (var->type == ECPGt_sqlda) + { + pg_sqlda_t **_sqlda = (pg_sqlda_t **)var->pointer; + pg_sqlda_t *sqlda = *_sqlda; + struct variable desc_inlist; + int i; + + if (sqlda == NULL) + return false; + + desc_counter++; + for (i = 0; i < sqlda->sqld; i++) + { + if (i + 1 == desc_counter) + { + desc_inlist.type = ecpg_sqlda_type(sqlda->sqlvar[i].sqltype); + desc_inlist.value = sqlda->sqlvar[i].sqldata; + desc_inlist.pointer = &(sqlda->sqlvar[i].sqldata); + switch (desc_inlist.type) + { + case ECPGt_char: + case ECPGt_varchar: + desc_inlist.varcharsize = strlen(sqlda->sqlvar[i].sqldata); + break; + default: + desc_inlist.varcharsize = 0; + break; + } + desc_inlist.arrsize = 1; + desc_inlist.offset = 0; + if (sqlda->sqlvar[i].sqlind) + { + desc_inlist.ind_type = ECPGt_short; + /* ECPG expects indicator value < 0 */ + if (*(sqlda->sqlvar[i].sqlind)) + *(sqlda->sqlvar[i].sqlind) = -1; + desc_inlist.ind_value = sqlda->sqlvar[i].sqlind; + desc_inlist.ind_pointer = &(sqlda->sqlvar[i].sqlind); + desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = 1; + desc_inlist.ind_offset = 0; + } + else + { + desc_inlist.ind_type = ECPGt_NO_INDICATOR; + desc_inlist.ind_value = desc_inlist.ind_pointer = NULL; + desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = desc_inlist.ind_offset = 0; + } + if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, &desc_inlist, &tobeinserted, false)) + return false; + + break; + } + } + if (sqlda->sqld == desc_counter) + desc_counter = 0; + } else { if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, var, &tobeinserted, false)) *************** ecpg_execute(struct statement * stmt) *** 1353,1358 **** --- 1411,1452 ---- } var = var->next; } + else if (var != NULL && var->type == ECPGt_sqlda) + { + pg_sqlda_t **_sqlda = (pg_sqlda_t **)var->pointer; + pg_sqlda_t *sqlda = *_sqlda; + pg_sqlda_t *sqlda_new; + + /* Build a new sqlda structure. Note that only fetching 1 record is supported */ + sqlda_new = ecpg_build_sqlda_for_PGresult(stmt->lineno, results, 0); + + if (!sqlda_new) + { + ecpg_log("ecpg_execute on line %d: out of memory allocating a new sqlda\n", stmt->lineno); + status = false; + } + else + { + ecpg_log("ecpg_execute on line %d: new sqlda was built\n", stmt->lineno); + + /* If we are passed in a previously existing sqlda then free it. */ + if (sqlda) + { + if (sqlda->sqlvar != (pg_sqlvar_t *)(sqlda + 1)) + free(sqlda->sqlvar); + free(sqlda); + sqlda = NULL; + } + + *_sqlda = sqlda_new; + + ecpg_set_sqlda_from_PGresult(stmt->lineno, _sqlda, results, 0); + ecpg_log("ecpg_execute on line %d: putting result (1 tuple %d fields) into sqlda descriptor\n", + stmt->lineno, PQnfields(results)); + } + + var = var->next; + } else for (act_field = 0; act_field < nfields && status; act_field++) { diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/extern.h pgsql.sqlda/src/interfaces/ecpg/ecpglib/extern.h *** pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/extern.h 2009-05-25 12:08:48.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/ecpglib/extern.h 2009-10-05 15:18:01.000000000 +0200 *************** *** 6,11 **** --- 6,12 ---- #include "postgres_fe.h" #include "libpq-fe.h" #include "sqlca.h" + #include "sqlda.h" #include "ecpg_config.h" #ifndef CHAR_BIT #include <limits.h> *************** bool ecpg_init(const struct connection *** 129,134 **** --- 130,137 ---- char *ecpg_strdup(const char *, int); const char *ecpg_type_name(enum ECPGttype); int ecpg_dynamic_type(Oid); + int ecpg_sqlda_type(int); + int ecpg_to_sqlda_type(Oid); void ecpg_free_auto_mem(void); void ecpg_clear_auto_mem(void); *************** void ecpg_log(const char *format,...); *** 149,154 **** --- 152,160 ---- bool ecpg_auto_prepare(int, const char *, const int, char **, const char *); void ecpg_init_sqlca(struct sqlca_t * sqlca); + pg_sqlda_t *ecpg_build_sqlda_for_PGresult(int, PGresult *, int); + void ecpg_set_sqlda_from_PGresult(int, pg_sqlda_t **, const PGresult *, int); + /* SQLSTATE values generated or processed by ecpglib (intentionally * not exported -- users should refer to the codes directly) */ diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/Makefile pgsql.sqlda/src/interfaces/ecpg/ecpglib/Makefile *** pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/Makefile 2009-07-13 11:16:41.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/ecpglib/Makefile 2009-10-05 15:18:01.000000000 +0200 *************** override CFLAGS += $(PTHREAD_CFLAGS) *** 24,30 **** # Need to recompile any libpgport object files LIBS := $(filter-out -lpgport, $(LIBS)) ! OBJS= execute.o typename.o descriptor.o data.o error.o prepare.o memory.o \ connect.o misc.o path.o pgstrcasecmp.o \ $(filter snprintf.o strlcpy.o, $(LIBOBJS)) --- 24,30 ---- # Need to recompile any libpgport object files LIBS := $(filter-out -lpgport, $(LIBS)) ! OBJS= execute.o typename.o descriptor.o sqlda.o data.o error.o prepare.o memory.o \ connect.o misc.o path.o pgstrcasecmp.o \ $(filter snprintf.o strlcpy.o, $(LIBOBJS)) diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/sqlda.c pgsql.sqlda/src/interfaces/ecpg/ecpglib/sqlda.c *** pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/sqlda.c 1970-01-01 01:00:00.000000000 +0100 --- pgsql.sqlda/src/interfaces/ecpg/ecpglib/sqlda.c 2009-10-08 13:32:44.000000000 +0200 *************** *** 0 **** --- 1,293 ---- + /* + * Crude SQLDA support routines + * Only supports fetching 1 record at a time + * + * The allocated memory area pointed by an sqlda pointer + * contains both the metadata and the data, so freeing up + * is a simple free(sqlda) as expected by the ESQL/C examples. + */ + + #define POSTGRES_ECPG_INTERNAL + #include "postgres_fe.h" + #include "pg_type.h" + + #include <inttypes.h> + #include <dlfcn.h> + + #include "ecpg-pthread-win32.h" + #include "decimal.h" + #include "ecpgtype.h" + #include "ecpglib.h" + #include "ecpgerrno.h" + #include "extern.h" + #include "sqlca.h" + #include "sqlda.h" + #include "sqltypes.h" + + /* + * Compute the next variable's offset with + * the current variable's size and alignment. + */ + static long + ecpg_sqlda_size_round_align(long offset, int alignment, int size) + { + if (offset % alignment) + offset += alignment - (offset % alignment); + offset += size; + return offset; + } + + /* + * Compute the current variable's offset with alignment. + */ + static long + ecpg_sqlda_size_align(long offset, int alignment) + { + if (offset % alignment) + offset += alignment - (offset % alignment); + return offset; + } + + static long + ecpg_sqlda_empty_size(const PGresult *res) + { + long size; + int i; + int sqld = PQnfields(res); + + /* Initial size to store main structure and field structures */ + size = sizeof(pg_sqlda_t) + sqld * sizeof(pg_sqlvar_t); + + /* Add space for field names */ + for (i = 0; i < sqld; i++) + size += strlen(PQfname(res, i)) + 1; + + /* Add padding to the first field value */ + size = ecpg_sqlda_size_align(size, sizeof(int)); + + return size; + } + + static long + ecpg_sqlda_total_size(const PGresult *res, int row) + { + int i; + int sqld = PQnfields(res); + long size; + + size = ecpg_sqlda_empty_size(res); + + if (row < 0) + return size; + + /* Add space for the field values */ + for (i = 0; i < sqld; i++) + { + switch (ecpg_to_sqlda_type(PQftype(res, i))) + { + case SQLSMINT: + size = ecpg_sqlda_size_round_align(size, sizeof(short), sizeof(short)); + break; + case SQLINT: + case SQLSERIAL: + size = ecpg_sqlda_size_round_align(size, sizeof(int), sizeof(int)); + break; + case SQLFLOAT: + size = ecpg_sqlda_size_round_align(size, sizeof(double), sizeof(double)); + break; + case SQLSMFLOAT: + size = ecpg_sqlda_size_round_align(size, sizeof(float), sizeof(float)); + break; + case SQLDECIMAL: + size = ecpg_sqlda_size_round_align(size, sizeof(int), sizeof(decimal)); + break; + case SQLINT8: + case SQLSERIAL8: + size = ecpg_sqlda_size_round_align(size, sizeof(int64_t), sizeof(int64_t)); + break; + + /* + * These types will be passed as character strings + * copied as is from the PGresult until we know + * what to do with them. + */ + case SQLCHAR: + case SQLTEXT: + case SQLVCHAR: + case SQLNCHAR: + case SQLNVCHAR: + case SQLMONEY: + case SQLDATE: + case SQLDTIME: + case SQLINTERVAL: + default: + size += strlen(PQgetvalue(res, row, i)) + 1; + break; + } + } + return size; + } + + /* + * Build pg_sqlda_t (metadata only) from PGresult + * leaving enough space for the field values in + * the given row number + */ + pg_sqlda_t * + ecpg_build_sqlda_for_PGresult(int line, PGresult *res, int row) + { + pg_sqlda_t *sqlda; + pg_sqlvar_t*sqlvar; + char *fname; + long size; + int sqld; + int i; + + size = ecpg_sqlda_total_size(res, row); + sqlda = (pg_sqlda_t *)ecpg_alloc(size, line); + if (!sqlda) + return NULL; + + memset(sqlda, 0, size); + sqlvar = (pg_sqlvar_t *)(sqlda + 1); + sqld = PQnfields(res); + fname = (char *)(sqlvar + sqld); + + sqlda->sqld = sqld; + sqlda->desc_occ = size; /* cheat here, keep the full allocated size */ + sqlda->sqlvar = sqlvar; + + for (i = 0; i < sqlda->sqld; i++) + { + sqlda->sqlvar[i].sqltype = ecpg_to_sqlda_type(PQftype(res, i)); + strcpy(fname, PQfname(res, i)); + sqlda->sqlvar[i].sqlname = fname; + fname += strlen(sqlda->sqlvar[i].sqlname) + 1; + sqlda->sqlvar[i].sqlformat = (char *)(long)PQfformat(res, i); + sqlda->sqlvar[i].sqlxid = PQftype(res, i); + sqlda->sqlvar[i].sqltypelen = PQfsize(res, i); + } + + return sqlda; + } + + /* + * Sets values from PGresult. + */ + void + ecpg_set_sqlda_from_PGresult(int lineno, pg_sqlda_t **_sqlda, const PGresult *res, int row) + { + pg_sqlda_t *sqlda = (*_sqlda); + int i; + long size; + static int2 value_is_null = -1; + static int2 value_is_not_null = 0; + + /* Offset for the first field value */ + size = ecpg_sqlda_empty_size(res); + + /* + * Set sqlvar[i]->sqldata pointers and convert values to correct format + */ + for (i = 0; i < sqlda->sqld; i++) + { + int type = -1, isnull; + int use_getdata = true; + int datalen; + + switch (sqlda->sqlvar[i].sqltype) + { + case SQLSMINT: + size = ecpg_sqlda_size_align(size, sizeof(short)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + sqlda->sqlvar[i].sqllen = sizeof(short); + size += sizeof(short); + type = ECPGt_short; + break; + case SQLINT: + case SQLSERIAL: + size = ecpg_sqlda_size_align(size, sizeof(int)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + sqlda->sqlvar[i].sqllen = sizeof(int); + size += sizeof(int); + type = ECPGt_int; + break; + case SQLFLOAT: + size = ecpg_sqlda_size_align(size, sizeof(double)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + sqlda->sqlvar[i].sqllen = sizeof(double); + size += sizeof(double); + type = ECPGt_double; + break; + case SQLSMFLOAT: + size = ecpg_sqlda_size_align(size, sizeof(float)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + sqlda->sqlvar[i].sqllen = sizeof(float); + size += sizeof(float); + type = ECPGt_float; + break; + case SQLDECIMAL: + { + size = ecpg_sqlda_size_align(size, sizeof(int)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + sqlda->sqlvar[i].sqllen = sizeof(decimal); + size += sizeof(decimal); + type = ECPGt_decimal; + break; + } + case SQLINT8: + case SQLSERIAL8: + size = ecpg_sqlda_size_align(size, sizeof(int64_t)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + sqlda->sqlvar[i].sqllen = sizeof(int64_t); + size += sizeof(int64_t); + #ifdef HAVE_LONG_LONG_INT_64 + type = ECPGt_long_long; + #else + type = ECPGt_long; + #endif + break; + + /* + * These types will be passed as character strings until + * it's known what to do with them. We use sqlvar->sqldata + * in all cases regardless of length, don't care about + * sqlvar->sqlilongdata. + */ + case SQLCHAR: + case SQLTEXT: + case SQLVCHAR: + case SQLNCHAR: + case SQLNVCHAR: + case SQLMONEY: + case SQLDATE: + case SQLDTIME: + case SQLINTERVAL: + default: + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + datalen = strlen(PQgetvalue(res, row, i)) + 1; + sqlda->sqlvar[i].sqllen = datalen; + size += datalen; + if (datalen > 32768) + sqlda->sqlvar[i].sqlilongdata = sqlda->sqlvar[i].sqldata; + use_getdata = false; + break; + } + + isnull = PQgetisnull(res, 0, i); + sqlda->sqlvar[i].sqlind = isnull ? &value_is_null : &value_is_not_null; + sqlda->sqlvar[i].sqlitype = SQLSMINT; + sqlda->sqlvar[i].sqlilen = sizeof(short); + if (!isnull) + { + if (use_getdata) + ecpg_get_data(res, row, i, lineno, + type, ECPGt_NO_INDICATOR, + sqlda->sqlvar[i].sqldata, NULL, 0, 0, 0, + ECPG_ARRAY_NONE, ECPG_COMPAT_INFORMIX, false); + else + strcpy(sqlda->sqlvar[i].sqldata, PQgetvalue(res, row, i)); + } + } + } + diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/typename.c pgsql.sqlda/src/interfaces/ecpg/ecpglib/typename.c *** pgsql.fixparsepl/src/interfaces/ecpg/ecpglib/typename.c 2009-08-07 13:06:28.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/ecpglib/typename.c 2009-10-08 12:14:07.000000000 +0200 *************** *** 7,12 **** --- 7,13 ---- #include "ecpgtype.h" #include "ecpglib.h" #include "extern.h" + #include "sqltypes.h" #include "sql3types.h" #include "pg_type.h" *************** ecpg_dynamic_type(Oid type) *** 100,102 **** --- 101,194 ---- return -(int) type; } } + + int + ecpg_sqlda_type(int type) + { + switch (type) + { + case SQLCHAR: + case SQLNCHAR: + return ECPGt_char; + case SQLSMINT: + return ECPGt_short; + case SQLINT: + return ECPGt_int; + case SQLFLOAT: + return ECPGt_double; + case SQLSMFLOAT: + return ECPGt_float; + case SQLDECIMAL: + return ECPGt_decimal; + case SQLSERIAL: + return ECPGt_int; + case SQLDATE: + return ECPGt_date; + #if 0 + case SQLMONEY: + return ???; + case SQLNULL: + return ???; + #endif + case SQLDTIME: + return ECPGt_timestamp; + #if 0 + case SQLBYTES: + return ???; + #endif + case SQLTEXT: + return ECPGt_char; + case SQLVCHAR: + case SQLNVCHAR: + return ECPGt_varchar; + case SQLINTERVAL: + return ECPGt_interval; + case SQLINT8: + case SQLSERIAL8: + #ifdef HAVE_LONG_LONG_INT_64 + return ECPGt_long_long; + #else + return ECPGt_long; + #endif + default: + return (-type); + } + } + + int + ecpg_to_sqlda_type(Oid type) + { + switch (type) + { + case CHAROID: + case BPCHAROID: + return SQLCHAR; + case INT2OID: + return SQLSMINT; + case INT4OID: + return SQLINT; + case FLOAT8OID: + return SQLFLOAT; + case FLOAT4OID: + return SQLSMFLOAT; + case NUMERICOID: + return SQLDECIMAL; + case DATEOID: + return SQLDATE; + case CASHOID: + return SQLMONEY; + case TIMESTAMPOID: + case TIMESTAMPTZOID: + return SQLDTIME; + case TEXTOID: + return SQLTEXT; + case VARCHAROID: + return SQLVCHAR; + case INTERVALOID: + return SQLINTERVAL; + case INT8OID: + return SQLINT8; + default: + return (-type); + } + } diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/include/ecpgtype.h pgsql.sqlda/src/interfaces/ecpg/include/ecpgtype.h *** pgsql.fixparsepl/src/interfaces/ecpg/include/ecpgtype.h 2009-08-07 13:06:28.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/include/ecpgtype.h 2009-10-05 15:18:01.000000000 +0200 *************** enum ECPGttype *** 62,68 **** ECPGt_EOIT, /* End of insert types. */ ECPGt_EORT, /* End of result types. */ ECPGt_NO_INDICATOR, /* no indicator */ ! ECPGt_string /* trimmed (char *) type */ }; /* descriptor items */ --- 62,69 ---- ECPGt_EOIT, /* End of insert types. */ ECPGt_EORT, /* End of result types. */ ECPGt_NO_INDICATOR, /* no indicator */ ! ECPGt_string, /* trimmed (char *) type */ ! ECPGt_sqlda /* C struct descriptor */ }; /* descriptor items */ diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/include/sqlda.h pgsql.sqlda/src/interfaces/ecpg/include/sqlda.h *** pgsql.fixparsepl/src/interfaces/ecpg/include/sqlda.h 2009-06-13 18:25:05.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/include/sqlda.h 2009-10-05 15:18:01.000000000 +0200 *************** *** 1,3 **** --- 1,74 ---- /* * $PostgreSQL: pgsql/src/interfaces/ecpg/include/sqlda.h,v 1.4 2009/06/11 14:49:13 momjian Exp $ */ + + #ifndef POSTGRES_SQLDA_H + #define POSTGRES_SQLDA_H + + /* Define Informix "standard" types */ + #ifndef C_H + typedef int int4; + typedef short int2; + #endif + typedef char int1; + + typedef int mint; + typedef long mlong; + + typedef short MSHORT; + typedef char MCHAR; + + typedef unsigned int uint4; + typedef unsigned short uint2; + typedef unsigned char uint1; + + typedef unsigned int muint; + typedef unsigned long mulong; + + typedef unsigned short MUSHORT; + typedef unsigned char MUCHAR; + + #define MI_INT_SIZE (sizeof(int) * 8) + #define MI_LONG_SIZE (sizeof(long) * 8) + #define MI_PTR_SIZE (sizeof(char *) * 8) + + typedef struct sqlvar_struct + { + int2 sqltype; /* variable type */ + int4 sqllen; /* length in bytes */ + char *sqldata; /* pointer to data */ + int2 *sqlind; /* pointer to indicator */ + char *sqlname; /* variable name */ + char *sqlformat; /* reserved for future use */ + int2 sqlitype; /* ind variable type */ + int2 sqlilen; /* ind length in bytes */ + char *sqlidata; /* ind data pointer */ + int4 sqlxid; /* extended id type */ + char *sqltypename; /* extended type name */ + int2 sqltypelen; /* length of extended type name */ + int2 sqlownerlen; /* length of owner name */ + int2 sqlsourcetype; /* source type for distinct of built-ins */ + char *sqlownername; /* owner name */ + int4 sqlsourceid; /* extended id of source type */ + + /* + * sqlilongdata is new. It supports data that exceeds the 32k + * limit. sqlilen and sqlidata are for backward compatibility + * and they have maximum value of <32K. + */ + char *sqlilongdata; /* for data field beyond 32K */ + int4 sqlflags; /* for internal use only */ + void *sqlreserved; /* reserved for future use */ + } pg_sqlvar_t; + + typedef struct sqlda + { + int2 sqld; + pg_sqlvar_t *sqlvar; + char desc_name[19]; /* descriptor name */ + int2 desc_occ; /* size of sqlda structure */ + struct sqlda *desc_next; /* pointer to next sqlda struct */ + void *reserved; /* reserved for future use */ + } pg_sqlda_t; + + #endif /* POSTGRES_SQLDA_H */ diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/include/sqltypes.h pgsql.sqlda/src/interfaces/ecpg/include/sqltypes.h *** pgsql.fixparsepl/src/interfaces/ecpg/include/sqltypes.h 2009-06-13 18:25:05.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/include/sqltypes.h 2009-10-05 15:18:01.000000000 +0200 *************** *** 30,33 **** --- 30,55 ---- #define CLVCHARPTRTYPE 124 #define CTYPEMAX 25 + /* + * Values used in sqlda->sqlvar[i]->sqltype + */ + #define SQLCHAR 0 + #define SQLSMINT 1 + #define SQLINT 2 + #define SQLFLOAT 3 + #define SQLSMFLOAT 4 + #define SQLDECIMAL 5 + #define SQLSERIAL 6 + #define SQLDATE 7 + #define SQLMONEY 8 + #define SQLDTIME 10 + #define SQLBYTES 11 + #define SQLTEXT 12 + #define SQLVCHAR 13 + #define SQLINTERVAL 14 + #define SQLNCHAR 15 + #define SQLNVCHAR 16 + #define SQLINT8 17 + #define SQLSERIAL8 18 + #endif /* ndef ECPG_SQLTYPES_H */ diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/preproc/descriptor.c pgsql.sqlda/src/interfaces/ecpg/preproc/descriptor.c *** pgsql.fixparsepl/src/interfaces/ecpg/preproc/descriptor.c 2009-01-30 17:28:46.000000000 +0100 --- pgsql.sqlda/src/interfaces/ecpg/preproc/descriptor.c 2009-10-05 15:18:01.000000000 +0200 *************** descriptor_variable(const char *name, in *** 326,328 **** --- 326,347 ---- strlcpy(descriptor_names[input], name, sizeof(descriptor_names[input])); return (struct variable *) & varspace[input]; } + + struct variable * + sqlda_variable(const char *name) + { + struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable)); + + p->name = mm_strdup(name); + p->type = (struct ECPGtype *) mm_alloc(sizeof(struct ECPGtype)); + p->type->type = ECPGt_sqlda; + p->type->size = NULL; + p->type->struct_sizeof = NULL; + p->type->u.element = NULL; + p->type->lineno = 0; + p->brace_level = 0; + p->next = NULL; + + return p; + } + diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/preproc/ecpg.addons pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.addons *** pgsql.fixparsepl/src/interfaces/ecpg/preproc/ecpg.addons 2009-10-03 01:54:43.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.addons 2009-10-05 15:18:01.000000000 +0200 *************** ECPG: VariableShowStmtSHOWALL block *** 402,430 **** $$ = EMPTY; } ECPG: FetchStmtMOVEfetch_args rule ! | FETCH fetch_args ecpg_into { $$ = cat2_str(make_str("fetch"), $2); } ! | FETCH FORWARD cursor_name opt_ecpg_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat_str(2, make_str("fetch forward"), cursor_marker); } ! | FETCH FORWARD from_in cursor_name opt_ecpg_into { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); $$ = cat_str(2, make_str("fetch forward from"), cursor_marker); } ! | FETCH BACKWARD cursor_name opt_ecpg_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat_str(2, make_str("fetch backward"), cursor_marker); } ! | FETCH BACKWARD from_in cursor_name opt_ecpg_into { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); --- 402,430 ---- $$ = EMPTY; } ECPG: FetchStmtMOVEfetch_args rule ! | FETCH fetch_args ecpg_fetch_into { $$ = cat2_str(make_str("fetch"), $2); } ! | FETCH FORWARD cursor_name opt_ecpg_fetch_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat_str(2, make_str("fetch forward"), cursor_marker); } ! | FETCH FORWARD from_in cursor_name opt_ecpg_fetch_into { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); $$ = cat_str(2, make_str("fetch forward from"), cursor_marker); } ! | FETCH BACKWARD cursor_name opt_ecpg_fetch_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat_str(2, make_str("fetch backward"), cursor_marker); } ! | FETCH BACKWARD from_in cursor_name opt_ecpg_fetch_into { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/preproc/ecpg.trailer pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.trailer *** pgsql.fixparsepl/src/interfaces/ecpg/preproc/ecpg.trailer 2009-10-03 02:05:58.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.trailer 2009-10-05 15:18:01.000000000 +0200 *************** ecpg_using: USING using_list { $$ = EMP *** 1017,1035 **** using_descriptor: USING opt_sql SQL_DESCRIPTOR quoted_ident_stringvar { ! add_variable_to_head(&argsinsert, descriptor_variable($4,0), &no_indicator); $$ = EMPTY; } ; into_descriptor: INTO opt_sql SQL_DESCRIPTOR quoted_ident_stringvar { ! add_variable_to_head(&argsresult, descriptor_variable($4,1), &no_indicator); $$ = EMPTY; } ; ! opt_sql: /*EMPTY*/ | SQL_SQL; using_list: UsingValue | UsingValue ',' using_list; --- 1017,1065 ---- using_descriptor: USING opt_sql SQL_DESCRIPTOR quoted_ident_stringvar { ! if (strlen($2) || !(INFORMIX_MODE)) ! add_variable_to_head(&argsinsert, descriptor_variable($4,0), &no_indicator); ! else ! { ! if ($4[0] == '\"') ! { ! char *pos; ! ! $4[0] = ' '; ! for (pos = $4; *pos; pos++) ! if (*pos == '\"') ! *pos = ' '; ! } ! add_variable_to_head(&argsinsert, sqlda_variable($4), &no_indicator); ! } $$ = EMPTY; } ; into_descriptor: INTO opt_sql SQL_DESCRIPTOR quoted_ident_stringvar { ! if (strlen($2) || !(INFORMIX_MODE)) ! add_variable_to_head(&argsresult, descriptor_variable($4,1), &no_indicator); ! else ! { ! if ($4[0] == '\"') ! { ! char *pos; ! ! $4[0] = ' '; ! for (pos = $4; *pos; pos++) ! if (*pos == '\"') ! *pos = ' '; ! } ! add_variable_to_head(&argsresult, sqlda_variable($4), &no_indicator); ! } $$ = EMPTY; } ; ! opt_sql: /*EMPTY*/ { $$ = EMPTY; } ! | SQL_SQL { $$ = make_str("sql"); } ! ; using_list: UsingValue | UsingValue ',' using_list; *************** ecpg_into: INTO into_list { $$ = EMPTY; *** 2052,2058 **** | into_descriptor { $$ = $1; } ; ! opt_ecpg_into: /* EMPTY */ { $$ = EMPTY; } | ecpg_into { $$ = $1; } ; --- 2082,2103 ---- | into_descriptor { $$ = $1; } ; ! ecpg_fetch_into: ecpg_into { $$ = $1; } ! | using_descriptor ! { ! struct variable *var; ! ! if (!INFORMIX_MODE) ! mmerror(PARSE_ERROR, ET_ERROR, "Not in Informix compatibility mode"); ! ! var = argsinsert->variable; ! remove_variable_from_list(&argsinsert, var); ! add_variable_to_head(&argsresult, var, &no_indicator); ! $$ = $1; ! } ! ; ! ! opt_ecpg_fetch_into: /* EMPTY */ { $$ = EMPTY; } | ecpg_into { $$ = $1; } ; diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/preproc/ecpg.type pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.type *** pgsql.fixparsepl/src/interfaces/ecpg/preproc/ecpg.type 2009-10-03 02:03:31.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.type 2009-10-05 15:18:01.000000000 +0200 *************** *** 62,67 **** --- 62,68 ---- %type <str> ecpg_ident %type <str> ecpg_interval %type <str> ecpg_into + %type <str> ecpg_fetch_into %type <str> ecpg_param %type <str> ecpg_sconst %type <str> ecpg_using *************** *** 77,83 **** %type <str> opt_bit_field %type <str> opt_connection_name %type <str> opt_database_name ! %type <str> opt_ecpg_into %type <str> opt_ecpg_using %type <str> opt_initializer %type <str> opt_options --- 78,84 ---- %type <str> opt_bit_field %type <str> opt_connection_name %type <str> opt_database_name ! %type <str> opt_ecpg_fetch_into %type <str> opt_ecpg_using %type <str> opt_initializer %type <str> opt_options *************** *** 87,92 **** --- 88,94 ---- %type <str> opt_reference %type <str> opt_scale %type <str> opt_server + %type <str> opt_sql %type <str> opt_user %type <str> opt_opt_value %type <str> ora_user diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/preproc/extern.h pgsql.sqlda/src/interfaces/ecpg/preproc/extern.h *** pgsql.fixparsepl/src/interfaces/ecpg/preproc/extern.h 2009-10-03 01:07:54.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/preproc/extern.h 2009-10-05 15:18:01.000000000 +0200 *************** extern void add_descriptor(char *, char *** 88,93 **** --- 88,94 ---- extern void drop_descriptor(char *, char *); extern struct descriptor *lookup_descriptor(char *, char *); extern struct variable *descriptor_variable(const char *name, int input); + extern struct variable *sqlda_variable(const char *name); extern void add_variable_to_head(struct arguments **, struct variable *, struct variable *); extern void add_variable_to_tail(struct arguments **, struct variable *, struct variable *); extern void remove_variable_from_list(struct arguments ** list, struct variable * var); diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/preproc/type.c pgsql.sqlda/src/interfaces/ecpg/preproc/type.c *** pgsql.fixparsepl/src/interfaces/ecpg/preproc/type.c 2009-09-03 12:25:47.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/preproc/type.c 2009-10-05 15:18:01.000000000 +0200 *************** get_type(enum ECPGttype type) *** 194,199 **** --- 194,202 ---- case ECPGt_descriptor: return ("ECPGt_descriptor"); break; + case ECPGt_sqlda: + return ("ECPGt_sqlda"); + break; case ECPGt_date: return ("ECPGt_date"); break; *************** ECPGdump_a_simple(FILE *o, const char *n *** 328,333 **** --- 331,338 ---- else if (type == ECPGt_descriptor) /* remember that name here already contains quotes (if needed) */ fprintf(o, "\n\tECPGt_descriptor, %s, 0L, 0L, 0L, ", name); + else if (type == ECPGt_sqlda) + fprintf(o, "\n\tECPGt_sqlda, &%s, 0L, 0L, 0L, ", name); else { char *variable = (char *) mm_alloc(strlen(name) + ((prefix == NULL) ? 0 : strlen(prefix)) + 4); diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/compat_informix/Makefile pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/Makefile *** pgsql.fixparsepl/src/interfaces/ecpg/test/compat_informix/Makefile 2009-10-03 02:11:20.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/Makefile 2009-10-05 15:18:01.000000000 +0200 *************** TESTS = test_informix test_informix.c \ *** 17,22 **** --- 17,23 ---- rfmtdate rfmtdate.c \ rfmtlong rfmtlong.c \ rnull rnull.c \ + sqlda sqlda.c \ charfuncs charfuncs.c all: $(TESTS) *************** test_informix2.c: test_informix2.pgc ../ *** 30,35 **** --- 31,39 ---- cursor.c: cursor.pgc ../regression.h $(ECPG) -o $@ -I$(srcdir) $< + sqlda.c: sqlda.pgc ../regression.h + $(ECPG) -o $@ -I$(srcdir) $< + dec_test.c: dec_test.pgc ../regression.h $(ECPG) -o $@ -I$(srcdir) $< diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/compat_informix/sqlda.pgc pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/sqlda.pgc *** pgsql.fixparsepl/src/interfaces/ecpg/test/compat_informix/sqlda.pgc 1970-01-01 01:00:00.000000000 +0100 --- pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/sqlda.pgc 2009-10-05 15:18:01.000000000 +0200 *************** *** 0 **** --- 1,252 ---- + #include <stdlib.h> + #include <string.h> + #include <inttypes.h> + + exec sql include ../regression; + + exec sql include sqlda.h; + exec sql include sqltypes.h; + + exec sql whenever sqlerror stop; + + /* These shouldn't be under DECLARE SECTION */ + pg_sqlda_t *inp_sqlda, *outp_sqlda; + + static void + dump_sqlda(pg_sqlda_t *sqlda) + { + int i; + + for (i = 0; i < sqlda->sqld; i++) + { + if (outp_sqlda->sqlvar[i].sqlind && *(outp_sqlda->sqlvar[i].sqlind) == -1) + printf("name sqlda descriptor: '%s' value NULL'\n", outp_sqlda->sqlvar[i].sqlname); + else + switch (sqlda->sqlvar[i].sqltype) + { + case SQLCHAR: + case SQLVCHAR: + case SQLTEXT: + printf("name sqlda descriptor: '%s' value '%s'\n", sqlda->sqlvar[i].sqlname, sqlda->sqlvar[i].sqldata); + break; + case SQLSERIAL: + case SQLINT: + printf("name sqlda descriptor: '%s' value %d\n", sqlda->sqlvar[i].sqlname, *(int *)sqlda->sqlvar[i].sqldata); + break; + case SQLSERIAL8: + case SQLINT8: + printf("name sqlda descriptor: '%s' value %" PRId64 "\n", sqlda->sqlvar[i].sqlname, *(int64_t *)sqlda->sqlvar[i].sqldata); + break; + case SQLFLOAT: + printf("name sqlda descriptor: '%s' value %lf\n", sqlda->sqlvar[i].sqlname, *(double *)sqlda->sqlvar[i].sqldata); + break; + case SQLDECIMAL: + { + char val[64]; + dectoasc((dec_t *)sqlda->sqlvar[i].sqldata, val, 64, -1); + printf("name sqlda descriptor: '%s' value DECIMAL '%s'\n", sqlda->sqlvar[i].sqlname, val); + break; + } + } + } + } + + int + main (void) + { + exec sql begin declare section; + char *stmt1 = "SELECT * FROM t1"; + char *stmt2 = "SELECT * FROM t1 WHERE id = ?"; + int rec; + int id; + exec sql end declare section; + + char msg[128]; + + ECPGdebug(1, stderr); + + strcpy(msg, "connect"); + exec sql connect to REGRESSDB1 as regress1; + + strcpy(msg, "set"); + exec sql set datestyle to iso; + + strcpy(msg, "create"); + exec sql create table t1( + id integer, + t text, + d1 numeric, + d2 float8, + c char(10)); + + strcpy(msg, "insert"); + exec sql insert into t1 values + (1, 'a', 1.0, 1, 'a'), + (2, null, null, null, null), + (3, '"c"', -3, 'nan'::float8, 'c'), + (4, 'd', 4.0, 4, 'd'); + + strcpy(msg, "commit"); + exec sql commit; + + /* SQLDA test for getting all records from a table */ + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + exec sql prepare st_id1 from :stmt1; + + strcpy(msg, "declare"); + exec sql declare mycur1 cursor for st_id1; + + strcpy(msg, "open"); + exec sql open mycur1; + + exec sql whenever not found do break; + + rec = 0; + while (1) + { + strcpy(msg, "fetch"); + exec sql fetch 1 from mycur1 into descriptor outp_sqlda; + + printf("FETCH RECORD %d\n", ++rec); + dump_sqlda(outp_sqlda); + } + + exec sql whenever not found continue; + + strcpy(msg, "close"); + exec sql close mycur1; + + strcpy(msg, "deallocate"); + exec sql deallocate prepare st_id1; + + free(outp_sqlda); + + /* SQLDA test for getting all records from a table + using the Informix-specific FETCH ... USING DESCRIPTOR + */ + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + exec sql prepare st_id2 from :stmt1; + + strcpy(msg, "declare"); + exec sql declare mycur2 cursor for st_id2; + + strcpy(msg, "open"); + exec sql open mycur2; + + exec sql whenever not found do break; + + rec = 0; + while (1) + { + strcpy(msg, "fetch"); + exec sql fetch from mycur2 using descriptor outp_sqlda; + + printf("FETCH RECORD %d\n", ++rec); + dump_sqlda(outp_sqlda); + } + + exec sql whenever not found continue; + + strcpy(msg, "close"); + exec sql close mycur2; + + strcpy(msg, "deallocate"); + exec sql deallocate prepare st_id2; + + free(outp_sqlda); + + /* SQLDA test for getting one record using an input descriptor */ + + /* Input sqlda has to be built manually */ + inp_sqlda = (pg_sqlda_t *)malloc(sizeof(pg_sqlda_t)); + memset(inp_sqlda, 0, sizeof(pg_sqlda_t)); + inp_sqlda->sqld = 1; + inp_sqlda->sqlvar = malloc(sizeof(pg_sqlvar_t)); + memset(inp_sqlda->sqlvar, 0, sizeof(pg_sqlvar_t)); + + inp_sqlda->sqlvar[0].sqltype = SQLINT; + inp_sqlda->sqlvar[0].sqldata = (char *)&id; + + printf("EXECUTE RECORD 4\n"); + + id = 4; + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + exec sql prepare st_id3 FROM :stmt2; + + strcpy(msg, "execute"); + exec sql execute st_id3 using descriptor inp_sqlda into descriptor outp_sqlda; + + dump_sqlda(outp_sqlda); + + strcpy(msg, "deallocate"); + exec sql deallocate prepare st_id3; + + free(inp_sqlda->sqlvar); + free(inp_sqlda); + free(outp_sqlda); + + /* SQLDA test for getting one record using an input descriptor + * on a named connection + */ + + exec sql connect to REGRESSDB1 as con2; + + /* Input sqlda has to be built manually */ + inp_sqlda = (pg_sqlda_t *)malloc(sizeof(pg_sqlda_t)); + memset(inp_sqlda, 0, sizeof(pg_sqlda_t)); + inp_sqlda->sqld = 1; + inp_sqlda->sqlvar = malloc(sizeof(pg_sqlvar_t)); + memset(inp_sqlda->sqlvar, 0, sizeof(pg_sqlvar_t)); + + inp_sqlda->sqlvar[0].sqltype = SQLINT; + inp_sqlda->sqlvar[0].sqldata = (char *)&id; + + printf("EXECUTE RECORD 4\n"); + + id = 4; + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + exec sql at con2 prepare st_id4 FROM :stmt2; + + strcpy(msg, "execute"); + exec sql at con2 execute st_id4 using descriptor inp_sqlda into descriptor outp_sqlda; + + dump_sqlda(outp_sqlda); + + strcpy(msg, "commit"); + exec sql at con2 commit; + + strcpy(msg, "deallocate"); + exec sql deallocate prepare st_id4; + + free(inp_sqlda->sqlvar); + free(inp_sqlda); + free(outp_sqlda); + + strcpy(msg, "disconnect"); + exec sql disconnect con2; + + /* End test */ + + strcpy(msg, "drop"); + exec sql drop table t1; + + strcpy(msg, "commit"); + exec sql commit; + + strcpy(msg, "disconnect"); + exec sql disconnect; + + return (0); + } diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/ecpg_schedule pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule *** pgsql.fixparsepl/src/interfaces/ecpg/test/ecpg_schedule 2009-10-03 02:11:20.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule 2009-10-05 15:18:01.000000000 +0200 *************** test: compat_informix/rfmtdate *** 4,9 **** --- 4,10 ---- test: compat_informix/rfmtlong test: compat_informix/rnull test: compat_informix/cursor + test: compat_informix/sqlda test: compat_informix/test_informix test: compat_informix/test_informix2 test: connect/test2 diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/ecpg_schedule_tcp pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule_tcp *** pgsql.fixparsepl/src/interfaces/ecpg/test/ecpg_schedule_tcp 2009-10-03 02:11:20.000000000 +0200 --- pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule_tcp 2009-10-05 15:18:01.000000000 +0200 *************** test: compat_informix/rfmtdate *** 4,9 **** --- 4,10 ---- test: compat_informix/rfmtlong test: compat_informix/rnull test: compat_informix/cursor + test: compat_informix/sqlda test: compat_informix/test_informix test: compat_informix/test_informix2 test: connect/test2 diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c *** pgsql.fixparsepl/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c 1970-01-01 01:00:00.000000000 +0100 --- pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c 2009-10-05 15:18:01.000000000 +0200 *************** *** 0 **** --- 1,585 ---- + /* Processed by ecpg (regression mode) */ + /* These include files are added by the preprocessor */ + #include <ecpglib.h> + #include <ecpgerrno.h> + #include <sqlca.h> + /* Needed for informix compatibility */ + #include <ecpg_informix.h> + /* End of automatic include section */ + #define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y)) + + #line 1 "sqlda.pgc" + #include <stdlib.h> + #include <string.h> + #include <inttypes.h> + + + #line 1 "regression.h" + + + + + + + #line 5 "sqlda.pgc" + + + + #line 1 "sqlda.h" + /* + * $PostgreSQL: pgsql/src/interfaces/ecpg/include/sqlda.h,v 1.4 2009/06/11 14:49:13 momjian Exp $ + */ + + #ifndef POSTGRES_SQLDA_H + #define POSTGRES_SQLDA_H + + /* Define Informix "standard" types */ + #ifndef C_H + typedef int int4; + typedef short int2; + #endif + typedef char int1; + + typedef int mint; + typedef long mlong; + + typedef short MSHORT; + typedef char MCHAR; + + typedef unsigned int uint4; + typedef unsigned short uint2; + typedef unsigned char uint1; + + typedef unsigned int muint; + typedef unsigned long mulong; + + typedef unsigned short MUSHORT; + typedef unsigned char MUCHAR; + + #define MI_INT_SIZE (sizeof(int) * 8) + #define MI_LONG_SIZE (sizeof(long) * 8) + #define MI_PTR_SIZE (sizeof(char *) * 8) + + typedef struct sqlvar_struct + { + int2 sqltype; /* variable type */ + int4 sqllen; /* length in bytes */ + char *sqldata; /* pointer to data */ + int2 *sqlind; /* pointer to indicator */ + char *sqlname; /* variable name */ + char *sqlformat; /* reserved for future use */ + int2 sqlitype; /* ind variable type */ + int2 sqlilen; /* ind length in bytes */ + char *sqlidata; /* ind data pointer */ + int4 sqlxid; /* extended id type */ + char *sqltypename; /* extended type name */ + int2 sqltypelen; /* length of extended type name */ + int2 sqlownerlen; /* length of owner name */ + int2 sqlsourcetype; /* source type for distinct of built-ins */ + char *sqlownername; /* owner name */ + int4 sqlsourceid; /* extended id of source type */ + + /* + * sqlilongdata is new. It supports data that exceeds the 32k + * limit. sqlilen and sqlidata are for backward compatibility + * and they have maximum value of <32K. + */ + char *sqlilongdata; /* for data field beyond 32K */ + int4 sqlflags; /* for internal use only */ + void *sqlreserved; /* reserved for future use */ + } pg_sqlvar_t; + + typedef struct sqlda + { + int2 sqld; + pg_sqlvar_t *sqlvar; + char desc_name[19]; /* descriptor name */ + int2 desc_occ; /* size of sqlda structure */ + struct sqlda *desc_next; /* pointer to next sqlda struct */ + void *reserved; /* reserved for future use */ + } pg_sqlda_t; + + #endif /* POSTGRES_SQLDA_H */ + + #line 7 "sqlda.pgc" + + + #line 1 "sqltypes.h" + /* + * $PostgreSQL: pgsql/src/interfaces/ecpg/include/sqltypes.h,v 1.9 2009/06/11 14:49:13 momjian Exp $ + */ + #ifndef ECPG_SQLTYPES_H + #define ECPG_SQLTYPES_H + + #define CCHARTYPE ECPGt_char + #define CSHORTTYPE ECPGt_short + #define CINTTYPE ECPGt_int + #define CLONGTYPE ECPGt_long + #define CFLOATTYPE ECPGt_float + #define CDOUBLETYPE ECPGt_double + #define CDECIMALTYPE ECPGt_decimal + #define CFIXCHARTYPE 108 + #define CSTRINGTYPE ECPGt_char + #define CDATETYPE ECPGt_date + #define CMONEYTYPE 111 + #define CDTIMETYPE ECPGt_timestamp + #define CLOCATORTYPE 113 + #define CVCHARTYPE ECPGt_varchar + #define CINVTYPE 115 + #define CFILETYPE 116 + #define CINT8TYPE ECPGt_long_long + #define CCOLLTYPE 118 + #define CLVCHARTYPE 119 + #define CFIXBINTYPE 120 + #define CVARBINTYPE 121 + #define CBOOLTYPE ECPGt_bool + #define CROWTYPE 123 + #define CLVCHARPTRTYPE 124 + #define CTYPEMAX 25 + + /* + * Values used in sqlda->sqlvar[i]->sqltype + */ + #define SQLCHAR 0 + #define SQLSMINT 1 + #define SQLINT 2 + #define SQLFLOAT 3 + #define SQLSMFLOAT 4 + #define SQLDECIMAL 5 + #define SQLSERIAL 6 + #define SQLDATE 7 + #define SQLMONEY 8 + #define SQLDTIME 10 + #define SQLBYTES 11 + #define SQLTEXT 12 + #define SQLVCHAR 13 + #define SQLINTERVAL 14 + #define SQLNCHAR 15 + #define SQLNVCHAR 16 + #define SQLINT8 17 + #define SQLSERIAL8 18 + + #endif /* ndef ECPG_SQLTYPES_H */ + + #line 8 "sqlda.pgc" + + + /* exec sql whenever sqlerror stop ; */ + #line 10 "sqlda.pgc" + + + /* These shouldn't be under DECLARE SECTION */ + pg_sqlda_t *inp_sqlda, *outp_sqlda; + + static void + dump_sqlda(pg_sqlda_t *sqlda) + { + int i; + + for (i = 0; i < sqlda->sqld; i++) + { + if (outp_sqlda->sqlvar[i].sqlind && *(outp_sqlda->sqlvar[i].sqlind) == -1) + printf("name sqlda descriptor: '%s' value NULL'\n", outp_sqlda->sqlvar[i].sqlname); + else + switch (sqlda->sqlvar[i].sqltype) + { + case SQLCHAR: + case SQLVCHAR: + case SQLTEXT: + printf("name sqlda descriptor: '%s' value '%s'\n", sqlda->sqlvar[i].sqlname, sqlda->sqlvar[i].sqldata); + break; + case SQLSERIAL: + case SQLINT: + printf("name sqlda descriptor: '%s' value %d\n", sqlda->sqlvar[i].sqlname, *(int *)sqlda->sqlvar[i].sqldata); + break; + case SQLSERIAL8: + case SQLINT8: + printf("name sqlda descriptor: '%s' value %" PRId64 "\n", sqlda->sqlvar[i].sqlname, *(int64_t *)sqlda->sqlvar[i].sqldata); + break; + case SQLFLOAT: + printf("name sqlda descriptor: '%s' value %lf\n", sqlda->sqlvar[i].sqlname, *(double *)sqlda->sqlvar[i].sqldata); + break; + case SQLDECIMAL: + { + char val[64]; + dectoasc((decimal *)sqlda->sqlvar[i].sqldata, val, 64, -1); + printf("name sqlda descriptor: '%s' value DECIMAL '%s'\n", sqlda->sqlvar[i].sqlname, val); + break; + } + } + } + } + + int + main (void) + { + /* exec sql begin declare section */ + + + + + + #line 58 "sqlda.pgc" + char * stmt1 = "SELECT * FROM t1" ; + + #line 59 "sqlda.pgc" + char * stmt2 = "SELECT * FROM t1 WHERE id = ?" ; + + #line 60 "sqlda.pgc" + int rec ; + + #line 61 "sqlda.pgc" + int id ; + /* exec sql end declare section */ + #line 62 "sqlda.pgc" + + + char msg[128]; + + ECPGdebug(1, stderr); + + strcpy(msg, "connect"); + { ECPGconnect(__LINE__, 1, "regress1" , NULL, NULL , "regress1", 0); + #line 69 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 69 "sqlda.pgc" + + + strcpy(msg, "set"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "set datestyle to iso", ECPGt_EOIT, ECPGt_EORT); + #line 72 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 72 "sqlda.pgc" + + + strcpy(msg, "create"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "create table t1 ( id integer , t text , d1 numeric , d2 float8 ,c char ( 10 ) )", ECPGt_EOIT, ECPGt_EORT); + #line 80 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 80 "sqlda.pgc" + + + strcpy(msg, "insert"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "insert into t1 values ( 1 , 'a' , 1.0 , 1 , 'a' ) , ( 2 , null ,null , null , null ) , ( 3 , '\"c\"' , - 3 , 'nan' :: float8 , 'c' ) , ( 4 , 'd' , 4.0 , 4 , 'd' )", ECPGt_EOIT, ECPGt_EORT); + #line 87 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 87 "sqlda.pgc" + + + strcpy(msg, "commit"); + { ECPGtrans(__LINE__, NULL, "commit"); + #line 90 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 90 "sqlda.pgc" + + + /* SQLDA test for getting all records from a table */ + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + { ECPGprepare(__LINE__, NULL, 0, "st_id1", stmt1); + #line 97 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 97 "sqlda.pgc" + + + strcpy(msg, "declare"); + ECPG_informix_reset_sqlca(); /* declare mycur1 cursor for $1 */ + #line 100 "sqlda.pgc" + + + strcpy(msg, "open"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "declare mycur1 cursor for $1", + ECPGt_char_variable,(ECPGprepared_statement(NULL, "st_id1", __LINE__)),(long)1,(long)1,(1)*sizeof(char), + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT); + #line 103 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 103 "sqlda.pgc" + + + /* exec sql whenever not found break ; */ + #line 105 "sqlda.pgc" + + + rec = 0; + while (1) + { + strcpy(msg, "fetch"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch 1 from mycur1", ECPGt_EOIT, + ECPGt_sqlda, & outp_sqlda , 0L, 0L, 0L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT); + #line 111 "sqlda.pgc" + + if (sqlca.sqlcode == ECPG_NOT_FOUND) break; + #line 111 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 111 "sqlda.pgc" + + + printf("FETCH RECORD %d\n", ++rec); + dump_sqlda(outp_sqlda); + } + + /* exec sql whenever not found continue ; */ + #line 117 "sqlda.pgc" + + + strcpy(msg, "close"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "close mycur1", ECPGt_EOIT, ECPGt_EORT); + #line 120 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 120 "sqlda.pgc" + + + strcpy(msg, "deallocate"); + { ECPGdeallocate(__LINE__, 1, NULL, "st_id1"); + #line 123 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 123 "sqlda.pgc" + + + free(outp_sqlda); + + /* SQLDA test for getting all records from a table + using the Informix-specific FETCH ... USING DESCRIPTOR + */ + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + { ECPGprepare(__LINE__, NULL, 0, "st_id2", stmt1); + #line 134 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 134 "sqlda.pgc" + + + strcpy(msg, "declare"); + ECPG_informix_reset_sqlca(); /* declare mycur2 cursor for $1 */ + #line 137 "sqlda.pgc" + + + strcpy(msg, "open"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "declare mycur2 cursor for $1", + ECPGt_char_variable,(ECPGprepared_statement(NULL, "st_id2", __LINE__)),(long)1,(long)1,(1)*sizeof(char), + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT); + #line 140 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 140 "sqlda.pgc" + + + /* exec sql whenever not found break ; */ + #line 142 "sqlda.pgc" + + + rec = 0; + while (1) + { + strcpy(msg, "fetch"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch from mycur2", ECPGt_EOIT, + ECPGt_sqlda, & outp_sqlda , 0L, 0L, 0L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT); + #line 148 "sqlda.pgc" + + if (sqlca.sqlcode == ECPG_NOT_FOUND) break; + #line 148 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 148 "sqlda.pgc" + + + printf("FETCH RECORD %d\n", ++rec); + dump_sqlda(outp_sqlda); + } + + /* exec sql whenever not found continue ; */ + #line 154 "sqlda.pgc" + + + strcpy(msg, "close"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "close mycur2", ECPGt_EOIT, ECPGt_EORT); + #line 157 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 157 "sqlda.pgc" + + + strcpy(msg, "deallocate"); + { ECPGdeallocate(__LINE__, 1, NULL, "st_id2"); + #line 160 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 160 "sqlda.pgc" + + + free(outp_sqlda); + + /* SQLDA test for getting one record using an input descriptor */ + + /* Input sqlda has to be built manually */ + inp_sqlda = (pg_sqlda_t *)malloc(sizeof(pg_sqlda_t)); + memset(inp_sqlda, 0, sizeof(pg_sqlda_t)); + inp_sqlda->sqld = 1; + inp_sqlda->sqlvar = malloc(sizeof(pg_sqlvar_t)); + memset(inp_sqlda->sqlvar, 0, sizeof(pg_sqlvar_t)); + + inp_sqlda->sqlvar[0].sqltype = SQLINT; + inp_sqlda->sqlvar[0].sqldata = (char *)&id; + + printf("EXECUTE RECORD 4\n"); + + id = 4; + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + { ECPGprepare(__LINE__, NULL, 0, "st_id3", stmt2); + #line 183 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 183 "sqlda.pgc" + + + strcpy(msg, "execute"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, 1, "st_id3", + ECPGt_sqlda, & inp_sqlda , 0L, 0L, 0L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, + ECPGt_sqlda, & outp_sqlda , 0L, 0L, 0L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT); + #line 186 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 186 "sqlda.pgc" + + + dump_sqlda(outp_sqlda); + + strcpy(msg, "deallocate"); + { ECPGdeallocate(__LINE__, 1, NULL, "st_id3"); + #line 191 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 191 "sqlda.pgc" + + + free(inp_sqlda->sqlvar); + free(inp_sqlda); + free(outp_sqlda); + + /* SQLDA test for getting one record using an input descriptor + * on a named connection + */ + + { ECPGconnect(__LINE__, 1, "regress1" , NULL, NULL , "con2", 0); + #line 201 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 201 "sqlda.pgc" + + + /* Input sqlda has to be built manually */ + inp_sqlda = (pg_sqlda_t *)malloc(sizeof(pg_sqlda_t)); + memset(inp_sqlda, 0, sizeof(pg_sqlda_t)); + inp_sqlda->sqld = 1; + inp_sqlda->sqlvar = malloc(sizeof(pg_sqlvar_t)); + memset(inp_sqlda->sqlvar, 0, sizeof(pg_sqlvar_t)); + + inp_sqlda->sqlvar[0].sqltype = SQLINT; + inp_sqlda->sqlvar[0].sqldata = (char *)&id; + + printf("EXECUTE RECORD 4\n"); + + id = 4; + + outp_sqlda = NULL; + + strcpy(msg, "prepare"); + { ECPGprepare(__LINE__, "con2", 0, "st_id4", stmt2); + #line 220 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 220 "sqlda.pgc" + + + strcpy(msg, "execute"); + { ECPGdo(__LINE__, 1, 1, "con2", 0, 1, "st_id4", + ECPGt_sqlda, & inp_sqlda , 0L, 0L, 0L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, + ECPGt_sqlda, & outp_sqlda , 0L, 0L, 0L, + ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT); + #line 223 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 223 "sqlda.pgc" + + + dump_sqlda(outp_sqlda); + + strcpy(msg, "commit"); + { ECPGtrans(__LINE__, "con2", "commit"); + #line 228 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 228 "sqlda.pgc" + + + strcpy(msg, "deallocate"); + { ECPGdeallocate(__LINE__, 1, NULL, "st_id4"); + #line 231 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 231 "sqlda.pgc" + + + free(inp_sqlda->sqlvar); + free(inp_sqlda); + free(outp_sqlda); + + strcpy(msg, "disconnect"); + { ECPGdisconnect(__LINE__, "con2"); + #line 238 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 238 "sqlda.pgc" + + + /* End test */ + + strcpy(msg, "drop"); + { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "drop table t1", ECPGt_EOIT, ECPGt_EORT); + #line 243 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 243 "sqlda.pgc" + + + strcpy(msg, "commit"); + { ECPGtrans(__LINE__, NULL, "commit"); + #line 246 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 246 "sqlda.pgc" + + + strcpy(msg, "disconnect"); + { ECPGdisconnect(__LINE__, "CURRENT"); + #line 249 "sqlda.pgc" + + if (sqlca.sqlcode < 0) exit (1);} + #line 249 "sqlda.pgc" + + + return (0); + } diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr *** pgsql.fixparsepl/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr 1970-01-01 01:00:00.000000000 +0100 --- pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr 2009-10-05 15:18:01.000000000 +0200 *************** *** 0 **** --- 1,252 ---- + [NO_PID]: ECPGdebug: set to 1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGconnect: opening database regress1 on <DEFAULT> port <DEFAULT> + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 72: query: set datestyle to iso; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 72: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 72: OK: SET + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 75: query: create table t1 ( id integer , t text , d1 numeric , d2 float8 , c char ( 10) ); with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 75: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 75: OK: CREATE TABLE + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 83: query: insert into t1 values ( 1 , 'a' , 1.0 , 1 , 'a' ) , ( 2 , null , null , null, null ) , ( 3 , '"c"' , - 3 , 'nan' :: float8 , 'c' ) , ( 4 , 'd' , 4.0 , 4 , 'd' ); with 0 parameter(s) on connectionregress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 83: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 83: OK: INSERT 0 4 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGtrans on line 90: action "commit"; connection "regress1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGprepare on line 97: name st_id1; query: "SELECT * FROM t1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 103: query: declare mycur1 cursor for SELECT * FROM t1; with 0 parameter(s) on connectionregress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 103: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 103: OK: DECLARE CURSOR + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 1 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 1.0 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 1 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 2 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 3 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: -3 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: NaN offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 4.0 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 111: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 111: correctly got 0 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: raising sqlcode 100 on line 111: no data found on line 111 + [NO_PID]: sqlca: code: 100, state: 02000 + [NO_PID]: ecpg_execute on line 120: query: close mycur1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 120: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 120: OK: CLOSE CURSOR + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGdeallocate on line 123: name st_id1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGprepare on line 134: name st_id2; query: "SELECT * FROM t1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 140: query: declare mycur2 cursor for SELECT * FROM t1; with 0 parameter(s) on connectionregress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 140: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 140: OK: DECLARE CURSOR + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 1 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 1.0 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 1 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 2 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 3 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: -3 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: NaN offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 4.0 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 148: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 148: correctly got 0 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: raising sqlcode 100 on line 148: no data found on line 148 + [NO_PID]: sqlca: code: 100, state: 02000 + [NO_PID]: ecpg_execute on line 157: query: close mycur2; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 157: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 157: OK: CLOSE CURSOR + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGdeallocate on line 160: name st_id2 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGprepare on line 183: name st_id3; query: "SELECT * FROM t1 WHERE id = $1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 186: query: SELECT * FROM t1 WHERE id = $1; with 1 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 186: using PQexecPrepared for "SELECT * FROM t1 WHERE id = $1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: free_params on line 186: parameter 1 = 4 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 186: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 186: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 186: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 186: RESULT: 4.0 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 186: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 186: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGdeallocate on line 191: name st_id3 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGconnect: opening database regress1 on <DEFAULT> port <DEFAULT> + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGprepare on line 220: name st_id4; query: "SELECT * FROM t1 WHERE id = $1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 223: query: SELECT * FROM t1 WHERE id = $1; with 1 parameter(s) on connection con2 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 223: using PQexecPrepared for "SELECT * FROM t1 WHERE id = $1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: free_params on line 223: parameter 1 = 4 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 223: correctly got 1 tuples with 5 fields + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 223: new sqlda was built + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 223: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 223: RESULT: 4.0 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_get_data on line 223: RESULT: 4 offset: -1; array: yes + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 223: putting result (1 tuple 5 fields) into sqlda descriptor + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGtrans on line 228: action "commit"; connection "con2" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGdeallocate on line 231: name st_id4 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_finish: connection con2 closed + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 243: query: drop table t1; with 0 parameter(s) on connection regress1 + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 243: using PQexec + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_execute on line 243: OK: DROP TABLE + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ECPGtrans on line 246: action "commit"; connection "regress1" + [NO_PID]: sqlca: code: 0, state: 00000 + [NO_PID]: ecpg_finish: connection regress1 closed + [NO_PID]: sqlca: code: 0, state: 00000 diff -dcrpN pgsql.fixparsepl/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout *** pgsql.fixparsepl/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout 1970-01-01 01:00:00.000000000 +0100 --- pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout 2009-10-05 15:18:01.000000000 +0200 *************** *** 0 **** --- 1,60 ---- + FETCH RECORD 1 + name sqlda descriptor: 'id' value 1 + name sqlda descriptor: 't' value 'a' + name sqlda descriptor: 'd1' value DECIMAL '1.0' + name sqlda descriptor: 'd2' value 1.000000 + name sqlda descriptor: 'c' value 'a ' + FETCH RECORD 2 + name sqlda descriptor: 'id' value 2 + name sqlda descriptor: 't' value NULL' + name sqlda descriptor: 'd1' value NULL' + name sqlda descriptor: 'd2' value NULL' + name sqlda descriptor: 'c' value NULL' + FETCH RECORD 3 + name sqlda descriptor: 'id' value 3 + name sqlda descriptor: 't' value '"c"' + name sqlda descriptor: 'd1' value DECIMAL '-3' + name sqlda descriptor: 'd2' value nan + name sqlda descriptor: 'c' value 'c ' + FETCH RECORD 4 + name sqlda descriptor: 'id' value 4 + name sqlda descriptor: 't' value 'd' + name sqlda descriptor: 'd1' value DECIMAL '4.0' + name sqlda descriptor: 'd2' value 4.000000 + name sqlda descriptor: 'c' value 'd ' + FETCH RECORD 1 + name sqlda descriptor: 'id' value 1 + name sqlda descriptor: 't' value 'a' + name sqlda descriptor: 'd1' value DECIMAL '1.0' + name sqlda descriptor: 'd2' value 1.000000 + name sqlda descriptor: 'c' value 'a ' + FETCH RECORD 2 + name sqlda descriptor: 'id' value 2 + name sqlda descriptor: 't' value NULL' + name sqlda descriptor: 'd1' value NULL' + name sqlda descriptor: 'd2' value NULL' + name sqlda descriptor: 'c' value NULL' + FETCH RECORD 3 + name sqlda descriptor: 'id' value 3 + name sqlda descriptor: 't' value '"c"' + name sqlda descriptor: 'd1' value DECIMAL '-3' + name sqlda descriptor: 'd2' value nan + name sqlda descriptor: 'c' value 'c ' + FETCH RECORD 4 + name sqlda descriptor: 'id' value 4 + name sqlda descriptor: 't' value 'd' + name sqlda descriptor: 'd1' value DECIMAL '4.0' + name sqlda descriptor: 'd2' value 4.000000 + name sqlda descriptor: 'c' value 'd ' + EXECUTE RECORD 4 + name sqlda descriptor: 'id' value 4 + name sqlda descriptor: 't' value 'd' + name sqlda descriptor: 'd1' value DECIMAL '4.0' + name sqlda descriptor: 'd2' value 4.000000 + name sqlda descriptor: 'c' value 'd ' + EXECUTE RECORD 4 + name sqlda descriptor: 'id' value 4 + name sqlda descriptor: 't' value 'd' + name sqlda descriptor: 'd1' value DECIMAL '4.0' + name sqlda descriptor: 'd2' value 4.000000 + name sqlda descriptor: 'c' value 'd '
On Thu, Oct 8, 2009 at 7:15 AM, Boszormenyi Zoltan <zb@cybertec.at> wrote: > It's easier to write the documentation for all changes at once. > I would have the same situation that happened with the code, > the patches with the documentation added would strictly depend > on each other again. Also, Michael Meskes applied the "string" > pseudo-type patch without the documentation, despite the patch > had it, maybe at an improper place. With a tongue-in-cheek > "no comment" ;-) I point to this paragraph in the ECPG part of > the documentation: > > "This documentation is quite incomplete. But since this interface is > standardized, > additional information can be found in many resources about SQL." OK, maybe I was overly optimistic. :-( At least for parts of PostgreSQL other than ECPG, it is our usual practice to require documentation to be submitted with the patch. I have not looked at your patches and am not familiar with ECPG, but I wonder if part of the issue here is that there are too many interrelated changes. Maybe you'd be better off submitting some smaller changes, wait to see how they get committed, and then move on to the next thing. On the other hand, given that Michael seems to have no time to review ECPG patches or provide feedback, and given that none of the other committers seem to want to touch this with a ten-foot-pole, maybe that would make this take forever. ...Robert
Robert Haas <robertmhaas@gmail.com> writes: > I have not looked at your patches and am not familiar with ECPG, but I > wonder if part of the issue here is that there are too many > interrelated changes. Maybe you'd be better off submitting some > smaller changes, wait to see how they get committed, and then move on > to the next thing. On the other hand, given that Michael seems to > have no time to review ECPG patches or provide feedback, and given > that none of the other committers seem to want to touch this with a > ten-foot-pole, maybe that would make this take forever. I presume that at some point Michael will have more free time than he does now; we cannot expect him to do the work exactly in sync with an arbitrarily-scheduled commit fest. Since ECPG stuff isn't really blocking anything else, I have no problem with waiting till he does have time. But in the meantime, I think it's probably true that breaking things down into independently-reviewable patches might be helpful. (On the other hand, there are already four separate patches for ECPG in the queue ... does it really need to be broken down more than that?) regards, tom lane
On Thu, Oct 08, 2009 at 01:15:58PM +0200, Boszormenyi Zoltan wrote: > > What's the point of that? It can't be applied without documentation, > > and it just makes life more complicated to have two separate patch > > files floating around. > It's easier to write the documentation for all changes at once. > I would have the same situation that happened with the code, > the patches with the documentation added would strictly depend > on each other again. Also, Michael Meskes applied the "string" > pseudo-type patch without the documentation, despite the patch > had it, maybe at an improper place. With a tongue-in-cheek I don't get it. Are you blaming me for committing you patch although it had no documentation? Or for not committing the documentation part of it? I definitely did not remove anything on purpose. But if I missed something a short note would have been a better way to tell me. If the first interpretation is right I better not comment. Michael -- Michael Meskes Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org) Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!
Michael Meskes írta: > On Thu, Oct 08, 2009 at 01:15:58PM +0200, Boszormenyi Zoltan wrote: > >>> What's the point of that? It can't be applied without documentation, >>> and it just makes life more complicated to have two separate patch >>> files floating around. >>> >> It's easier to write the documentation for all changes at once. >> I would have the same situation that happened with the code, >> the patches with the documentation added would strictly depend >> on each other again. Also, Michael Meskes applied the "string" >> pseudo-type patch without the documentation, despite the patch >> had it, maybe at an improper place. With a tongue-in-cheek >> > > I don't get it. Are you blaming me for committing you patch although it had no > documentation? No blaming, but sorry, it definitely had, in both these rounds of split-up ECPG patchsets: 2009-05-15: http://archives.postgresql.org/message-id/4A5E0F1D.7030004@cybertec.at 2009-08-03: http://archives.postgresql.org/message-id/4A770C7B.1060404@cybertec.at I assumed you have applied it from the second mail, this was the last version sent for the "string" patch. It is my fault that I haven't put it on the CommitFest page. Indeed, the version on the CF page doesn't have documentation. But the code you committed seems to be the one (or very close, with some editorialization) in the second mail quoted above. > Or for not committing the documentation part of it? I definitely > did not remove anything on purpose. I guessed that it was not on purpose, but I only realized last thursday that the documentation for "string" is missing when I wrote the docs for the other patches. > But if I missed something a short note > would have been a better way to tell me. Yes, of course. Sorry. Best regards, Zoltán Böszörményi -- Bible has answers for everything. Proof: "But let your communication be, Yea, yea; Nay, nay: for whatsoever is more than these cometh of evil." (Matthew 5:37) - basics of digital technology. "May your kingdom come" - superficial description of plate tectonics ---------------------------------- Zoltán Böszörményi Cybertec Schönig & Schönig GmbH http://www.postgresql.at/
On Sat, Oct 10, 2009 at 2:09 PM, Boszormenyi Zoltan <zb@cybertec.at> wrote: > Michael Meskes írta: >> On Thu, Oct 08, 2009 at 01:15:58PM +0200, Boszormenyi Zoltan wrote: >> >>>> What's the point of that? It can't be applied without documentation, >>>> and it just makes life more complicated to have two separate patch >>>> files floating around. >>>> >>> It's easier to write the documentation for all changes at once. >>> I would have the same situation that happened with the code, >>> the patches with the documentation added would strictly depend >>> on each other again. Also, Michael Meskes applied the "string" >>> pseudo-type patch without the documentation, despite the patch >>> had it, maybe at an improper place. With a tongue-in-cheek >>> >> >> I don't get it. Are you blaming me for committing you patch although it had no >> documentation? > > No blaming, but sorry, it definitely had, in both these rounds > of split-up ECPG patchsets: > > 2009-05-15: > http://archives.postgresql.org/message-id/4A5E0F1D.7030004@cybertec.at > 2009-08-03: > http://archives.postgresql.org/message-id/4A770C7B.1060404@cybertec.at > > I assumed you have applied it from the second mail, this was > the last version sent for the "string" patch. It is my fault that > I haven't put it on the CommitFest page. Indeed, the version > on the CF page doesn't have documentation. But the code you > committed seems to be the one (or very close, with some > editorialization) in the second mail quoted above. Since it doesn't seem that any of the patches are going to get committed RSN, I have moved all of the open ECPG patches to the next CommitFest and given them their own section. ...Robert