Re: Split-up ECPG patches - Mailing list pgsql-hackers
From | Boszormenyi Zoltan |
---|---|
Subject | Re: Split-up ECPG patches |
Date | |
Msg-id | 4A770C7B.1060404@cybertec.at Whole thread Raw |
In response to | Split-up ECPG patches (Böszörményi Zoltán <zb@cybertec.at>) |
Responses |
Re: Split-up ECPG patches
Re: Split-up ECPG patches Re: Split-up ECPG patches |
List | pgsql-hackers |
Hi, new versions attached, updated to apply to the current CVS cleanly. Changes: - we fixed the case in the dynamic cursor support when the cursor was declared in a way that the query contained a WHERE clause, using host variables as parameters. (leftover bug from our first, non-public, non-parser-only attempt) - sqlda support: - sqlda.c now indicates license - #defines inside #if 0 ... #endif are now omitted from sqltypes.h (both per comments from Jaime Casanova) - describe support: there's no separate ECPGdescribe2() now (as per comment from Michael Meskes, debatable) - string support: I am doing much less now unconditionally, most of the parser changes (e.g. introducing STRING_P) were unnecessary to make it working. - added to the list my second attempt at fixing struct variable in INTO list in Informix-mode. This fix (or the real one if this is not the right approach) should be backpatched, because the bug is real. Best regards, Zoltán Böszörményi Böszörményi Zoltán írta: > Hi, > > as asked by Michael Meskes, I have split up our ECPG patchset: > 1. dynamic cursorname (DECLARE :cursorname ..., etc) > 2. SQLDA support in Informix compat mode (C structure used for > descriptor and data query) > 3. DESCRIBE OUTPUT support for named and sqlda descriptors > 4. "string" pseudo-type in Informix compat mode > > 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 pgsql85dev.0orig/src/backend/parser/gram.y pgsql85dev.1dyncursor/src/backend/parser/gram.y *** pgsql85dev.0orig/src/backend/parser/gram.y 2009-08-03 10:38:28.000000000 +0200 --- pgsql85dev.1dyncursor/src/backend/parser/gram.y 2009-08-03 15:09:45.000000000 +0200 *************** static TypeName *TableFuncTypeName(List *** 253,259 **** %type <str> relation_name copy_file_name database_name access_method_clause access_method attr_name ! index_name name file_name cluster_index_specification %type <list> func_name handler_name qual_Op qual_all_Op subquery_Op opt_class opt_validator validator_clause --- 253,259 ---- %type <str> relation_name copy_file_name database_name access_method_clause access_method attr_name ! index_name name cursor_name file_name cluster_index_specification %type <list> func_name handler_name qual_Op qual_all_Op subquery_Op opt_class opt_validator validator_clause *************** reloption_elem: *** 1915,1921 **** *****************************************************************************/ ClosePortalStmt: ! CLOSE name { ClosePortalStmt *n = makeNode(ClosePortalStmt); n->portalname = $2; --- 1915,1921 ---- *****************************************************************************/ ClosePortalStmt: ! CLOSE cursor_name { ClosePortalStmt *n = makeNode(ClosePortalStmt); n->portalname = $2; *************** comment_text: *** 4082,4095 **** * *****************************************************************************/ ! FetchStmt: FETCH fetch_direction from_in name { FetchStmt *n = (FetchStmt *) $2; n->portalname = $4; n->ismove = FALSE; $$ = (Node *)n; } ! | FETCH name { FetchStmt *n = makeNode(FetchStmt); n->direction = FETCH_FORWARD; --- 4082,4113 ---- * *****************************************************************************/ ! FetchStmt: FETCH BACKWARD from_in cursor_name ! { ! FetchStmt *n = makeNode(FetchStmt); ! n->portalname = $4; ! n->ismove = FALSE; ! n->direction = FETCH_BACKWARD; ! n->howMany = 1; ! $$ = (Node *)n; ! } ! | FETCH FORWARD from_in cursor_name ! { ! FetchStmt *n = makeNode(FetchStmt); ! n->portalname = $4; ! n->ismove = FALSE; ! n->direction = FETCH_FORWARD; ! n->howMany = 1; ! $$ = (Node *)n; ! } ! | FETCH fetch_direction from_in cursor_name { FetchStmt *n = (FetchStmt *) $2; n->portalname = $4; n->ismove = FALSE; $$ = (Node *)n; } ! | FETCH cursor_name { FetchStmt *n = makeNode(FetchStmt); n->direction = FETCH_FORWARD; *************** FetchStmt: FETCH fetch_direction from_in *** 4098,4111 **** n->ismove = FALSE; $$ = (Node *)n; } ! | MOVE fetch_direction from_in name { FetchStmt *n = (FetchStmt *) $2; n->portalname = $4; n->ismove = TRUE; $$ = (Node *)n; } ! | MOVE name { FetchStmt *n = makeNode(FetchStmt); n->direction = FETCH_FORWARD; --- 4116,4147 ---- n->ismove = FALSE; $$ = (Node *)n; } ! | MOVE BACKWARD from_in cursor_name ! { ! FetchStmt *n = makeNode(FetchStmt); ! n->portalname = $4; ! n->ismove = TRUE; ! n->direction = FETCH_BACKWARD; ! n->howMany = 1; ! $$ = (Node *)n; ! } ! | MOVE FORWARD from_in cursor_name ! { ! FetchStmt *n = makeNode(FetchStmt); ! n->portalname = $4; ! n->ismove = TRUE; ! n->direction = FETCH_FORWARD; ! n->howMany = 1; ! $$ = (Node *)n; ! } ! | MOVE fetch_direction from_in cursor_name { FetchStmt *n = (FetchStmt *) $2; n->portalname = $4; n->ismove = TRUE; $$ = (Node *)n; } ! | MOVE cursor_name { FetchStmt *n = makeNode(FetchStmt); n->direction = FETCH_FORWARD; *************** fetch_direction: *** 4180,4192 **** n->howMany = FETCH_ALL; $$ = (Node *)n; } - | FORWARD - { - FetchStmt *n = makeNode(FetchStmt); - n->direction = FETCH_FORWARD; - n->howMany = 1; - $$ = (Node *)n; - } | FORWARD SignedIconst { FetchStmt *n = makeNode(FetchStmt); --- 4216,4221 ---- *************** fetch_direction: *** 4201,4213 **** n->howMany = FETCH_ALL; $$ = (Node *)n; } - | BACKWARD - { - FetchStmt *n = makeNode(FetchStmt); - n->direction = FETCH_BACKWARD; - n->howMany = 1; - $$ = (Node *)n; - } | BACKWARD SignedIconst { FetchStmt *n = makeNode(FetchStmt); --- 4230,4235 ---- *************** set_target_list: *** 6847,6853 **** * CURSOR STATEMENTS * *****************************************************************************/ ! DeclareCursorStmt: DECLARE name cursor_options CURSOR opt_hold FOR SelectStmt { DeclareCursorStmt *n = makeNode(DeclareCursorStmt); n->portalname = $2; --- 6869,6875 ---- * CURSOR STATEMENTS * *****************************************************************************/ ! DeclareCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR SelectStmt { DeclareCursorStmt *n = makeNode(DeclareCursorStmt); n->portalname = $2; *************** DeclareCursorStmt: DECLARE name cursor_o *** 6858,6863 **** --- 6880,6888 ---- } ; + cursor_name: name { $$ = $1; } + ; + cursor_options: /*EMPTY*/ { $$ = 0; } | cursor_options NO SCROLL { $$ = $1 | CURSOR_OPT_NO_SCROLL; } | cursor_options SCROLL { $$ = $1 | CURSOR_OPT_SCROLL; } diff -dcrpN pgsql85dev.0orig/src/interfaces/ecpg/preproc/ecpg.addons pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/ecpg.addons *** pgsql85dev.0orig/src/interfaces/ecpg/preproc/ecpg.addons 2009-01-30 17:28:46.000000000 +0100 --- pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/ecpg.addons 2009-08-03 15:09:45.000000000 +0200 *************** ECPG: fetch_directionBACKWARDSignedIcons *** 221,226 **** --- 221,235 ---- free($2); $2 = make_str("$0"); } + ECPG: cursor_namename rule + | char_civar + { + char *curname = mm_alloc(strlen($1) + 2); + sprintf(curname, ":%s", $1); + free($1); + $1 = curname; + $$ = $1; + } ECPG: PrepareStmtPREPAREprepared_nameprep_type_clauseASPreparableStmt block { $$.name = $2; *************** ECPG: PrepareStmtPREPAREprepared_namepre *** 235,243 **** } ECPG: ExecuteStmtEXECUTEprepared_nameexecute_param_clauseexecute_rest block { $$ = $2; } ! ECPG: DeclareCursorStmtDECLAREnamecursor_optionsCURSORopt_holdFORSelectStmt block { struct cursor *ptr, *this; for (ptr = cur; ptr != NULL; ptr = ptr->next) { --- 244,253 ---- } ECPG: ExecuteStmtEXECUTEprepared_nameexecute_param_clauseexecute_rest block { $$ = $2; } ! ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectStmt block { struct cursor *ptr, *this; + char *cursor_marker = $2[0] == ':' ? make_str("$0") : mm_strdup($2); for (ptr = cur; ptr != NULL; ptr = ptr->next) { *************** ECPG: DeclareCursorStmtDECLAREnamecursor *** 251,257 **** this->name = $2; this->connection = connection; this->opened = false; ! this->command = cat_str(7, make_str("declare"), mm_strdup($2), $3, make_str("cursor"), $5, make_str("for"), $7); this->argsinsert = argsinsert; this->argsresult = argsresult; argsinsert = argsresult = NULL; --- 261,267 ---- this->name = $2; this->connection = connection; this->opened = false; ! this->command = cat_str(7, make_str("declare"), cursor_marker, $3, make_str("cursor"), $5, make_str("for"), $7); this->argsinsert = argsinsert; this->argsresult = argsresult; argsinsert = argsresult = NULL; *************** ECPG: DeclareCursorStmtDECLAREnamecursor *** 262,267 **** --- 272,282 ---- else $$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/")); } + ECPG: ClosePortalStmtCLOSEcursor_name block + { + char *cursor_marker = $2[0] == ':' ? make_str("$0") : $2; + $$ = cat2_str(make_str("close"), cursor_marker); + } ECPG: opt_hold block { if (compat == ECPG_COMPAT_INFORMIX_SE && autocommit == true) *************** ECPG: VariableShowStmtSHOWALL block *** 326,371 **** mmerror(PARSE_ERROR, ET_ERROR, "SHOW ALL is not implemented"); $$ = EMPTY; } ! ECPG: FetchStmtFETCHfetch_directionfrom_inname block { add_additional_variables($4, false); ! $$ = cat_str(4, make_str("fetch"), $2, $3, $4); } ! ECPG: FetchStmtFETCHname block { add_additional_variables($2, false); ! $$ = cat_str(2, make_str("fetch"), $2); } ! ECPG: FetchStmtMOVEname rule ! | FETCH fetch_direction from_in name ecpg_into { add_additional_variables($4, false); ! $$ = cat_str(4, make_str("fetch"), $2, $3, $4); } ! | FETCH fetch_direction name ecpg_into { add_additional_variables($3, false); ! $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3); } ! | FETCH from_in name ecpg_into { add_additional_variables($3, false); ! $$ = cat_str(3, make_str("fetch"), $2, $3); } ! | FETCH name ecpg_into { add_additional_variables($2, false); ! $$ = cat2_str(make_str("fetch"), $2); } ! | FETCH fetch_direction name { add_additional_variables($3, false); ! $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3); } ! | FETCH from_in name { add_additional_variables($3, false); ! $$ = cat_str(3, make_str("fetch"), $2, $3); } ECPG: SpecialRuleRelationOLD addon if (!QueryIsRule) --- 341,442 ---- mmerror(PARSE_ERROR, ET_ERROR, "SHOW ALL is not implemented"); $$ = EMPTY; } ! ECPG: FetchStmtFETCHBACKWARDfrom_incursor_name block { + char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); ! $$ = cat_str(3, make_str("fetch backward"), $3, cursor_marker); } ! ECPG: FetchStmtFETCHFORWARDfrom_incursor_name block { + char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; + add_additional_variables($4, false); + $$ = cat_str(3, make_str("fetch forward"), $3, cursor_marker); + } + ECPG: FetchStmtFETCHfetch_directionfrom_incursor_name block + { + char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; + add_additional_variables($4, false); + $$ = cat_str(4, make_str("fetch"), $2, $3, cursor_marker); + } + ECPG: FetchStmtFETCHcursor_name block + { + char *cursor_marker = $2[0] == ':' ? make_str("$0") : $2; add_additional_variables($2, false); ! $$ = cat_str(2, make_str("fetch"), cursor_marker); } ! ECPG: FetchStmtMOVEcursor_name rule ! | FETCH BACKWARD from_in cursor_name ecpg_into { + char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); ! $$ = cat_str(3, make_str("fetch backward"), $3, cursor_marker); } ! | FETCH FORWARD from_in cursor_name ecpg_into { + char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; + add_additional_variables($4, false); + $$ = cat_str(3, make_str("fetch forward"), $3, cursor_marker); + } + | FETCH fetch_direction from_in cursor_name ecpg_into + { + char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; + add_additional_variables($4, false); + $$ = cat_str(4, make_str("fetch"), $2, $3, cursor_marker); + } + | FETCH BACKWARD cursor_name ecpg_into + { + char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); ! $$ = cat2_str(make_str("fetch backward from"), cursor_marker); } ! | FETCH FORWARD cursor_name ecpg_into { + char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); ! $$ = cat2_str(make_str("fetch forward from"), cursor_marker); } ! | FETCH fetch_direction cursor_name ecpg_into ! { ! char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; ! add_additional_variables($3, false); ! $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), cursor_marker); ! } ! | FETCH from_in cursor_name ecpg_into ! { ! char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; ! add_additional_variables($3, false); ! $$ = cat_str(3, make_str("fetch"), $2, cursor_marker); ! } ! | FETCH cursor_name ecpg_into { + char *cursor_marker = $2[0] == ':' ? make_str("$0") : $2; add_additional_variables($2, false); ! $$ = cat2_str(make_str("fetch"), cursor_marker); } ! | FETCH BACKWARD cursor_name { + char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); ! $$ = cat2_str(make_str("fetch backward from"), cursor_marker); } ! | FETCH FORWARD cursor_name { + char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); ! $$ = cat2_str(make_str("fetch forward from"), cursor_marker); ! } ! | FETCH fetch_direction cursor_name ! { ! char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; ! add_additional_variables($3, false); ! $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), cursor_marker); ! } ! | FETCH from_in cursor_name ! { ! char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; ! add_additional_variables($3, false); ! $$ = cat_str(3, make_str("fetch"), $2, cursor_marker); } ECPG: SpecialRuleRelationOLD addon if (!QueryIsRule) diff -dcrpN pgsql85dev.0orig/src/interfaces/ecpg/preproc/ecpg.trailer pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/ecpg.trailer *** pgsql85dev.0orig/src/interfaces/ecpg/preproc/ecpg.trailer 2009-06-13 18:25:05.000000000 +0200 --- pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/ecpg.trailer 2009-08-03 15:09:45.000000000 +0200 *************** prepared_name: name { *** 284,292 **** * Declare a prepared cursor. The syntax is different from the standard * declare statement, so we create a new rule. */ ! ECPGCursorStmt: DECLARE name cursor_options CURSOR opt_hold FOR prepared_name { struct cursor *ptr, *this; struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable)); const char *con = connection ? connection : "NULL"; --- 284,293 ---- * Declare a prepared cursor. The syntax is different from the standard * declare statement, so we create a new rule. */ ! ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_name { struct cursor *ptr, *this; + char *cursor_marker = $2[0] == ':' ? make_str("$0") : mm_strdup($2); struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable)); const char *con = connection ? connection : "NULL"; *************** ECPGCursorStmt: DECLARE name cursor_opt *** 303,309 **** this->next = cur; this->name = $2; this->connection = connection; ! this->command = cat_str(6, make_str("declare"), mm_strdup($2), $3, make_str("cursor"), $5, make_str("for $1")); this->argsresult = NULL; thisquery->type = &ecpg_query; --- 304,310 ---- this->next = cur; this->name = $2; this->connection = connection; ! this->command = cat_str(6, make_str("declare"), cursor_marker, $3, make_str("cursor"), $5, make_str("for $1")); this->argsresult = NULL; thisquery->type = &ecpg_query; *************** ECPGCursorStmt: DECLARE name cursor_opt *** 313,318 **** --- 314,325 ---- sprintf(thisquery->name, "ECPGprepared_statement(%s, %s, __LINE__)", con, $7); this->argsinsert = NULL; + if ($2[0] == ':') + { + struct variable *var = find_variable($2 + 1); + remove_variable_from_list(&argsinsert, var); + add_variable_to_head(&(this->argsinsert), var, &no_indicator); + } add_variable_to_head(&(this->argsinsert), thisquery, &no_indicator); cur = this; *************** ECPGFree: SQL_FREE name { $$ = $2; } *** 944,950 **** /* * open is an open cursor, at the moment this has to be removed */ ! ECPGOpen: SQL_OPEN name opt_ecpg_using { $$ = $2; }; opt_ecpg_using: /*EMPTY*/ { $$ = EMPTY; } | ecpg_using { $$ = $1; } --- 951,966 ---- /* * open is an open cursor, at the moment this has to be removed */ ! ECPGOpen: SQL_OPEN cursor_name opt_ecpg_using ! { ! if ($2[0] == ':') ! { ! struct variable *var = find_variable($2 + 1); ! remove_variable_from_list(&argsinsert, var); ! } ! $$ = $2; ! } ! ; opt_ecpg_using: /*EMPTY*/ { $$ = EMPTY; } | ecpg_using { $$ = $1; } *************** civarind: cvariable indicator *** 1768,1773 **** --- 1784,1796 ---- } ; + char_civar: char_variable + { + add_variable_to_head(&argsinsert, find_variable($1), &no_indicator); + $$ = $1; + } + ; + civar: cvariable { add_variable_to_head(&argsinsert, find_variable($1), &no_indicator); diff -dcrpN pgsql85dev.0orig/src/interfaces/ecpg/preproc/ecpg.type pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/ecpg.type *** pgsql85dev.0orig/src/interfaces/ecpg/preproc/ecpg.type 2008-11-14 11:03:33.000000000 +0100 --- pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/ecpg.type 2009-08-03 15:09:45.000000000 +0200 *************** *** 43,48 **** --- 43,49 ---- %type <str> c_term %type <str> c_thing %type <str> char_variable + %type <str> char_civar %type <str> civar %type <str> civarind %type <str> ColLabel diff -dcrpN pgsql85dev.0orig/src/interfaces/ecpg/preproc/extern.h pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/extern.h *** pgsql85dev.0orig/src/interfaces/ecpg/preproc/extern.h 2009-07-17 07:50:56.000000000 +0200 --- pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/extern.h 2009-08-03 15:09:45.000000000 +0200 *************** extern struct descriptor *lookup_descrip *** 91,96 **** --- 91,97 ---- extern struct variable *descriptor_variable(const char *name, int input); 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); extern void dump_variables(struct arguments *, int); extern struct typedefs *get_typedef(char *); extern void adjust_array(enum ECPGttype, char **, char **, char *, char *, int, bool); diff -dcrpN pgsql85dev.0orig/src/interfaces/ecpg/preproc/variable.c pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/variable.c *** pgsql85dev.0orig/src/interfaces/ecpg/preproc/variable.c 2009-06-13 18:25:05.000000000 +0200 --- pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/variable.c 2009-08-03 15:09:45.000000000 +0200 *************** add_variable_to_tail(struct arguments ** *** 401,406 **** --- 401,430 ---- *list = new; } + void + remove_variable_from_list(struct arguments ** list, struct variable * var) + { + struct arguments *p, *prev = NULL; + bool found = false; + + for (p = *list; p; p = p->next) + { + if (p->variable == var) + { + found = true; + break; + } + prev = p; + } + if (found) + { + if (prev) + prev->next = p->next; + else + *list = p->next; + } + } + /* Dump out a list of all the variable on this list. This is a recursive function that works from the end of the list and deletes the list as we go on. diff -dcrpN pgsql85dev.1dyncursor/src/interfaces/ecpg/ecpglib/execute.c pgsql85dev.2sqlda/src/interfaces/ecpg/ecpglib/execute.c *** pgsql85dev.1dyncursor/src/interfaces/ecpg/ecpglib/execute.c 2009-06-13 18:25:05.000000000 +0200 --- pgsql85dev.2sqlda/src/interfaces/ecpg/ecpglib/execute.c 2009-08-03 16:36:23.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 *** 1031,1036 **** --- 1032,1038 ---- break; case ECPGt_descriptor: + case ECPGt_sqlda: break; default: *************** ecpg_execute(struct statement * stmt) *** 1170,1175 **** --- 1172,1233 ---- 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) *** 1351,1356 **** --- 1409,1435 ---- } 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; + + if (!sqlda) + { + sqlda = ecpg_build_sqlda_for_PGresult(stmt->lineno, results); + if (!sqlda) + status = false; + else + *_sqlda = sqlda; + } + else if (!ecpg_compare_sqlda_with_PGresult(sqlda, results)) + status = false; + + if (status == true) + ecpg_set_sqlda_from_PGresult(stmt->lineno, _sqlda, results); + + var = var->next; + } else for (act_field = 0; act_field < nfields && status; act_field++) { diff -dcrpN pgsql85dev.1dyncursor/src/interfaces/ecpg/ecpglib/extern.h pgsql85dev.2sqlda/src/interfaces/ecpg/ecpglib/extern.h *** pgsql85dev.1dyncursor/src/interfaces/ecpg/ecpglib/extern.h 2009-05-25 12:08:48.000000000 +0200 --- pgsql85dev.2sqlda/src/interfaces/ecpg/ecpglib/extern.h 2009-08-03 15:25:02.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,161 ---- 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 *); + bool ecpg_compare_sqlda_with_PGresult(pg_sqlda_t *sqlda, const PGresult *results); + void ecpg_set_sqlda_from_PGresult(int, pg_sqlda_t **, const PGresult *); + /* SQLSTATE values generated or processed by ecpglib (intentionally * not exported -- users should refer to the codes directly) */ diff -dcrpN pgsql85dev.1dyncursor/src/interfaces/ecpg/ecpglib/Makefile pgsql85dev.2sqlda/src/interfaces/ecpg/ecpglib/Makefile *** pgsql85dev.1dyncursor/src/interfaces/ecpg/ecpglib/Makefile 2009-07-13 11:16:41.000000000 +0200 --- pgsql85dev.2sqlda/src/interfaces/ecpg/ecpglib/Makefile 2009-08-03 15:25:02.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 pgsql85dev.1dyncursor/src/interfaces/ecpg/ecpglib/sqlda.c pgsql85dev.2sqlda/src/interfaces/ecpg/ecpglib/sqlda.c *** pgsql85dev.1dyncursor/src/interfaces/ecpg/ecpglib/sqlda.c 1970-01-01 01:00:00.000000000 +0100 --- pgsql85dev.2sqlda/src/interfaces/ecpg/ecpglib/sqlda.c 2009-08-03 16:34:12.000000000 +0200 *************** *** 0 **** --- 1,272 ---- + /* + * 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. + * + * (C) 2009 Cybertec GmbH + * Zoltán Böszörményi <zb@cybertec.at> + * Hans-Jürgen Schönig <hs@cybertec.at> + * Placed under the same license as PostgreSQL. + */ + + #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" + + /* + * Build pg_sqlda_t (metadata only) from PGresult + */ + pg_sqlda_t * + ecpg_build_sqlda_for_PGresult(int line, PGresult *res) + { + pg_sqlda_t *sqlda; + pg_sqlvar_t*sqlvar; + char *fname; + long size; + int i; + + size = sizeof(pg_sqlda_t) + PQnfields(res) * sizeof(pg_sqlvar_t); + for (i = 0; i < PQnfields(res); i++) + size += strlen(PQfname(res, i)) + 1; + /* round allocated size up to the next multiple of 8 */ + if (size % 8) + size += 8 - (size % 8); + + sqlda = (pg_sqlda_t *)ecpg_alloc(size, line); + if (!sqlda) + { + ecpg_raise(line, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL); + return NULL; + } + memset(sqlda, 0, size); + sqlvar = (pg_sqlvar_t *)(sqlda + 1); + fname = (char *)(sqlvar + PQnfields(res)); + + sqlda->sqld = PQnfields(res); + 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; + } + + /* + * Check whether the supplied sqlda and PGresult + * both has the same metadata + */ + bool + ecpg_compare_sqlda_with_PGresult(pg_sqlda_t *sqlda, const PGresult *res) + { + int i; + + if (sqlda->sqld != PQnfields(res)) + return false; + + for (i = 0; i < sqlda->sqld; i++) + { + if (sqlda->sqlvar[i].sqltype != ecpg_dynamic_type(PQftype(res, i))) + return false; + if (strcmp(sqlda->sqlvar[i].sqlname, PQfname(res, i))) + return false; + if (sqlda->sqlvar[i].sqlformat != (char *)(long)PQfformat(res, i)) + return false; + if (sqlda->sqlvar[i].sqlxid != PQftype(res, i)) + return false; + if (sqlda->sqlvar[i].sqltypelen != PQfsize(res, i)) + return false; + } + + return true; + } + + static long + ecpg_sqlda_size_round_align(long size, int alignment, int round) + { + if (size % alignment) + size += alignment - (size % alignment); + size += round; + return size; + } + + static long + ecpg_sqlda_size_align(long size, int alignment) + { + if (size % alignment) + size += alignment - (size % alignment); + return size; + } + + /* + * Sets values from PGresult. + * Reallocates the memory area pointed by *_sqlda if needed + */ + void + ecpg_set_sqlda_from_PGresult(int lineno, pg_sqlda_t **_sqlda, const PGresult *res) + { + pg_sqlda_t *sqlda = (*_sqlda); + int i; + long size; + static int2 value_is_null = 1; + static int2 value_is_not_null = 0; + + /* Compute new structure size for allocation */ + size = sizeof(pg_sqlda_t) + sqlda->sqld * sizeof(pg_sqlvar_t); + for (i = 0; i < PQnfields(res); i++) + size += strlen(PQfname(res, i)) + 1; + + for (i = 0; i < sqlda->sqld; i++) + { + switch (sqlda->sqlvar[i].sqltype) + { + 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 + * 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: + break; + } + } + + if (sqlda->desc_occ < size) + { + sqlda = realloc(sqlda, size); + *_sqlda = sqlda; + sqlda->desc_occ = size; + } + + /* + * Set sqlvar[i]->sqldata pointers and convert values to correct format + */ + size = sizeof(pg_sqlda_t) + sqlda->sqld * sizeof(pg_sqlvar_t); + for (i = 0; i < PQnfields(res); i++) + size += strlen(PQfname(res, i)) + 1; + + for (i = 0; i < sqlda->sqld; i++) + { + switch (sqlda->sqlvar[i].sqltype) + { + case SQLSMINT: + size = ecpg_sqlda_size_align(size, sizeof(short)); + sscanf(PQgetvalue(res, 0, i), "%hd", (short *)((char *)sqlda + size)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + size += sizeof(short); + break; + case SQLINT: + case SQLSERIAL: + size = ecpg_sqlda_size_align(size, sizeof(int)); + sscanf(PQgetvalue(res, 0, i), "%d", (int *)((char *)sqlda + size)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + size += sizeof(int); + break; + case SQLFLOAT: + size = ecpg_sqlda_size_align(size, sizeof(double)); + sscanf(PQgetvalue(res, 0, i), "%lf", (double *)((char *)sqlda + size)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + size += sizeof(double); + break; + case SQLSMFLOAT: + size = ecpg_sqlda_size_align(size, sizeof(float)); + sscanf(PQgetvalue(res, 0, i), "%f", (float *)((char *)sqlda + size)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + size += sizeof(float); + break; + case SQLDECIMAL: + { + size = ecpg_sqlda_size_align(size, sizeof(int)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + + ecpg_get_data(res, 0, i, lineno, + ECPGt_decimal, ECPGt_NO_INDICATOR, + sqlda->sqlvar[i].sqldata, NULL, 0, 0, 0, + ECPG_ARRAY_NONE, ECPG_COMPAT_INFORMIX, false); + + size += sizeof(decimal); + break; + } + case SQLINT8: + case SQLSERIAL8: + size = ecpg_sqlda_size_align(size, sizeof(int64_t)); + sscanf(PQgetvalue(res, 0, i), "%" PRId64, (int64_t *)((char *)sqlda + size)); + sqlda->sqlvar[i].sqldata = (char *)sqlda + size; + size += sizeof(int64_t); + 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 = PQgetvalue(res, 0, i); + break; + } + + sqlda->sqlvar[i].sqlind = PQgetisnull(res, 0, i) ? &value_is_null : &value_is_not_null; + } + } diff -dcrpN pgsql85dev.1dyncursor/src/interfaces/ecpg/ecpglib/typename.c pgsql85dev.2sqlda/src/interfaces/ecpg/ecpglib/typename.c *** pgsql85dev.1dyncursor/src/interfaces/ecpg/ecpglib/typename.c 2007-11-15 22:14:45.000000000 +0100 --- pgsql85dev.2sqlda/src/interfaces/ecpg/ecpglib/typename.c 2009-08-03 16:38:16.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) *** 99,101 **** --- 100,189 ---- 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 pgsql85dev.1dyncursor/src/interfaces/ecpg/include/ecpgtype.h pgsql85dev.2sqlda/src/interfaces/ecpg/include/ecpgtype.h *** pgsql85dev.1dyncursor/src/interfaces/ecpg/include/ecpgtype.h 2007-08-14 12:01:52.000000000 +0200 --- pgsql85dev.2sqlda/src/interfaces/ecpg/include/ecpgtype.h 2009-08-03 15:25:02.000000000 +0200 *************** enum ECPGttype *** 61,67 **** ECPGt_const, /* a constant is needed sometimes */ ECPGt_EOIT, /* End of insert types. */ ECPGt_EORT, /* End of result types. */ ! ECPGt_NO_INDICATOR /* no indicator */ }; /* descriptor items */ --- 61,68 ---- ECPGt_const, /* a constant is needed sometimes */ ECPGt_EOIT, /* End of insert types. */ ECPGt_EORT, /* End of result types. */ ! ECPGt_NO_INDICATOR, /* no indicator */ ! ECPGt_sqlda /* INFORMIX-compatible sqlda_t descriptor */ }; /* descriptor items */ diff -dcrpN pgsql85dev.1dyncursor/src/interfaces/ecpg/include/sqlda.h pgsql85dev.2sqlda/src/interfaces/ecpg/include/sqlda.h *** pgsql85dev.1dyncursor/src/interfaces/ecpg/include/sqlda.h 2009-06-13 18:25:05.000000000 +0200 --- pgsql85dev.2sqlda/src/interfaces/ecpg/include/sqlda.h 2009-08-03 15:25:02.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 pgsql85dev.1dyncursor/src/interfaces/ecpg/include/sqltypes.h pgsql85dev.2sqlda/src/interfaces/ecpg/include/sqltypes.h *** pgsql85dev.1dyncursor/src/interfaces/ecpg/include/sqltypes.h 2009-06-13 18:25:05.000000000 +0200 --- pgsql85dev.2sqlda/src/interfaces/ecpg/include/sqltypes.h 2009-08-03 16:39:30.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 pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/descriptor.c pgsql85dev.2sqlda/src/interfaces/ecpg/preproc/descriptor.c *** pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/descriptor.c 2009-01-30 17:28:46.000000000 +0100 --- pgsql85dev.2sqlda/src/interfaces/ecpg/preproc/descriptor.c 2009-08-03 15:25:02.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 pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/ecpg.addons pgsql85dev.2sqlda/src/interfaces/ecpg/preproc/ecpg.addons *** pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/ecpg.addons 2009-08-03 15:09:45.000000000 +0200 --- pgsql85dev.2sqlda/src/interfaces/ecpg/preproc/ecpg.addons 2009-08-03 15:25:02.000000000 +0200 *************** ECPG: FetchStmtFETCHcursor_name block *** 366,414 **** $$ = cat_str(2, make_str("fetch"), cursor_marker); } ECPG: FetchStmtMOVEcursor_name rule ! | FETCH BACKWARD from_in cursor_name ecpg_into { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); $$ = cat_str(3, make_str("fetch backward"), $3, cursor_marker); } ! | FETCH FORWARD from_in cursor_name ecpg_into { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); $$ = cat_str(3, make_str("fetch forward"), $3, cursor_marker); } ! | FETCH fetch_direction from_in cursor_name ecpg_into { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); $$ = cat_str(4, make_str("fetch"), $2, $3, cursor_marker); } ! | FETCH BACKWARD cursor_name ecpg_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat2_str(make_str("fetch backward from"), cursor_marker); } ! | FETCH FORWARD cursor_name ecpg_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat2_str(make_str("fetch forward from"), cursor_marker); } ! | FETCH fetch_direction cursor_name ecpg_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), cursor_marker); } ! | FETCH from_in cursor_name ecpg_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat_str(3, make_str("fetch"), $2, cursor_marker); } ! | FETCH cursor_name ecpg_into { char *cursor_marker = $2[0] == ':' ? make_str("$0") : $2; add_additional_variables($2, false); --- 366,414 ---- $$ = cat_str(2, make_str("fetch"), cursor_marker); } ECPG: FetchStmtMOVEcursor_name rule ! | FETCH BACKWARD from_in cursor_name ecpg_fetch_into { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); $$ = cat_str(3, make_str("fetch backward"), $3, cursor_marker); } ! | FETCH FORWARD from_in cursor_name ecpg_fetch_into { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); $$ = cat_str(3, make_str("fetch forward"), $3, cursor_marker); } ! | FETCH fetch_direction from_in cursor_name ecpg_fetch_into { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); $$ = cat_str(4, make_str("fetch"), $2, $3, cursor_marker); } ! | FETCH BACKWARD cursor_name ecpg_fetch_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat2_str(make_str("fetch backward from"), cursor_marker); } ! | FETCH FORWARD cursor_name ecpg_fetch_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat2_str(make_str("fetch forward from"), cursor_marker); } ! | FETCH fetch_direction cursor_name ecpg_fetch_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), cursor_marker); } ! | FETCH from_in cursor_name ecpg_fetch_into { char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3; add_additional_variables($3, false); $$ = cat_str(3, make_str("fetch"), $2, cursor_marker); } ! | FETCH cursor_name ecpg_fetch_into { char *cursor_marker = $2[0] == ':' ? make_str("$0") : $2; add_additional_variables($2, false); diff -dcrpN pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/ecpg.trailer pgsql85dev.2sqlda/src/interfaces/ecpg/preproc/ecpg.trailer *** pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/ecpg.trailer 2009-08-03 15:09:45.000000000 +0200 --- pgsql85dev.2sqlda/src/interfaces/ecpg/preproc/ecpg.trailer 2009-08-03 15:25:02.000000000 +0200 *************** ecpg_using: USING using_list { $$ = EMP *** 972,990 **** 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; --- 972,1020 ---- 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; *** 2006,2011 **** --- 2036,2056 ---- | 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; + } + ; + %% void base_yyerror(const char *error) diff -dcrpN pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/ecpg.type pgsql85dev.2sqlda/src/interfaces/ecpg/preproc/ecpg.type *** pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/ecpg.type 2009-08-03 15:09:45.000000000 +0200 --- pgsql85dev.2sqlda/src/interfaces/ecpg/preproc/ecpg.type 2009-08-03 15:25:02.000000000 +0200 *************** *** 61,66 **** --- 61,67 ---- %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 *************** *** 85,90 **** --- 86,92 ---- %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 pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/extern.h pgsql85dev.2sqlda/src/interfaces/ecpg/preproc/extern.h *** pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/extern.h 2009-08-03 15:09:45.000000000 +0200 --- pgsql85dev.2sqlda/src/interfaces/ecpg/preproc/extern.h 2009-08-03 15:25:02.000000000 +0200 *************** extern void add_descriptor(char *, char *** 89,94 **** --- 89,95 ---- 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 pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/type.c pgsql85dev.2sqlda/src/interfaces/ecpg/preproc/type.c *** pgsql85dev.1dyncursor/src/interfaces/ecpg/preproc/type.c 2009-06-13 18:25:05.000000000 +0200 --- pgsql85dev.2sqlda/src/interfaces/ecpg/preproc/type.c 2009-08-03 15:25:02.000000000 +0200 *************** ECPGdump_a_simple(FILE *o, const char *n *** 325,330 **** --- 325,332 ---- 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 pgsql85dev.2sqlda/src/interfaces/ecpg/ecpglib/descriptor.c pgsql85dev.3describe/src/interfaces/ecpg/ecpglib/descriptor.c *** pgsql85dev.2sqlda/src/interfaces/ecpg/ecpglib/descriptor.c 2009-06-13 18:25:05.000000000 +0200 --- pgsql85dev.3describe/src/interfaces/ecpg/ecpglib/descriptor.c 2009-08-03 15:41:17.000000000 +0200 *************** *** 13,18 **** --- 13,19 ---- #include "ecpgerrno.h" #include "extern.h" #include "sqlca.h" + #include "sqlda.h" #include "sql3types.h" static void descriptor_free(struct descriptor * desc); *************** get_char_item(int lineno, void *var, enu *** 225,230 **** --- 226,237 ---- return (true); } + #define RETURN_IF_NO_DATA if (ntuples < 1) \ + { \ + ecpg_raise(lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL); \ + return (false); \ + } + bool ECPGget_desc(int lineno, const char *desc_name, int index,...) { *************** ECPGget_desc(int lineno, const char *des *** 243,253 **** return (false); ntuples = PQntuples(ECPGresult); - if (ntuples < 1) - { - ecpg_raise(lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL); - return (false); - } if (index < 1 || index > PQnfields(ECPGresult)) { --- 250,255 ---- *************** ECPGget_desc(int lineno, const char *des *** 282,287 **** --- 284,290 ---- switch (type) { case (ECPGd_indicator): + RETURN_IF_NO_DATA; data_var.ind_type = vartype; data_var.ind_pointer = var; data_var.ind_varcharsize = varcharsize; *************** ECPGget_desc(int lineno, const char *des *** 294,299 **** --- 297,303 ---- break; case ECPGd_data: + RETURN_IF_NO_DATA; data_var.type = vartype; data_var.pointer = var; data_var.varcharsize = varcharsize; *************** ECPGget_desc(int lineno, const char *des *** 376,381 **** --- 380,386 ---- case ECPGd_ret_length: case ECPGd_ret_octet: + RETURN_IF_NO_DATA; /* * this is like ECPGstore_result */ *************** ECPGget_desc(int lineno, const char *des *** 479,484 **** --- 484,490 ---- sqlca->sqlerrd[2] = ntuples; return (true); } + #undef RETURN_IF_NO_DATA bool ECPGset_desc_header(int lineno, const char *desc_name, int count) *************** ecpg_find_desc(int line, const char *nam *** 721,729 **** return NULL; /* not found */ } bool ! ECPGdescribe(int line, bool input, const char *statement,...) { ! ecpg_log("ECPGdescribe called on line %d for %s: %s\n", line, input ? "input" : "output", statement); ! return false; } --- 727,840 ---- return NULL; /* not found */ } + static pg_sqlda_t* + build_sqlda(int lineno, bool input, const char *connection_name, const char *stmt_name) + { + struct connection *con; + PGresult *res; + pg_sqlda_t *sqlda = NULL; + + con = ecpg_get_connection(connection_name); + res = PQdescribePrepared(con->connection, stmt_name); + if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_INFORMIX)) + return NULL; + + sqlda = ecpg_build_sqlda_for_PGresult(lineno, res); + + PQclear(res); + return sqlda; + } + bool ! ECPGdescribe(int line, bool input, const char *connection_name, const char *stmt_name, ...) { ! bool ret = false; ! va_list args; ! ! /* DESCRIBE INPUT is not yet supported */ ! if (input) ! return false; ! ! va_start(args, stmt_name); ! ! for (;;) ! { ! enum ECPGttype type, dummy_type; ! void *ptr, *dummy_ptr; ! long dummy; ! ! /* variable type */ ! type = va_arg(args, enum ECPGttype); ! ! if (type == ECPGt_EORT) ! break; ! ! /* rest of variable parameters*/ ! ptr = va_arg(args, void *); ! dummy = va_arg(args, long); ! dummy = va_arg(args, long); ! dummy = va_arg(args, long); ! ! /* variable indicator */ ! dummy_type = va_arg(args, enum ECPGttype); ! dummy_ptr = va_arg(args, void *); ! dummy = va_arg(args, long); ! dummy = va_arg(args, long); ! dummy = va_arg(args, long); ! ! switch (type) ! { ! case ECPGt_descriptor: ! { ! char *name = ptr; ! struct connection *con = ecpg_get_connection(connection_name); ! struct descriptor *desc = ecpg_find_desc(line, name); ! PGresult *res; ! ExecStatusType ret; ! ! if (con == NULL) ! break; ! if (desc == NULL) ! break; ! ! res = PQdescribePrepared(con->connection, stmt_name); ! ret = PQresultStatus(res); ! if (ecpg_check_PQresult(res, line, con->connection, ECPG_COMPAT_PGSQL)) ! { ! if (desc->result != NULL) ! PQclear(desc->result); ! desc->result = res; ! ret = true; ! } ! break; ! } ! case ECPGt_sqlda: ! { ! pg_sqlda_t **sqlda_ptr = ptr; ! pg_sqlda_t *sqlda_new; ! ! sqlda_new = build_sqlda(line, input, connection_name, stmt_name); ! if (sqlda_new) ! { ! #if 0 ! /* ! * We should free the old pointer but we can't be sure ! * if the pointer is valid. Only the calling application can. ! */ ! pg_sqlda_t *sqlda_old = *sqlda_ptr; ! if (sqlda_old) ! free(sqlda_old); ! #endif ! *sqlda_ptr = sqlda_new; ! ret = true; ! } ! break; ! } ! default: ! /* nothing else may come */ ! ; ! } ! } ! ! return ret; } diff -dcrpN pgsql85dev.2sqlda/src/interfaces/ecpg/ecpglib/execute.c pgsql85dev.3describe/src/interfaces/ecpg/ecpglib/execute.c *** pgsql85dev.2sqlda/src/interfaces/ecpg/ecpglib/execute.c 2009-08-03 16:36:23.000000000 +0200 --- pgsql85dev.3describe/src/interfaces/ecpg/ecpglib/execute.c 2009-08-03 16:37:09.000000000 +0200 *************** ecpg_store_input(const int lineno, const *** 1032,1037 **** --- 1032,1039 ---- break; case ECPGt_descriptor: + break; + case ECPGt_sqlda: break; diff -dcrpN pgsql85dev.2sqlda/src/interfaces/ecpg/include/ecpglib.h pgsql85dev.3describe/src/interfaces/ecpg/include/ecpglib.h *** pgsql85dev.2sqlda/src/interfaces/ecpg/include/ecpglib.h 2009-06-13 18:25:05.000000000 +0200 --- pgsql85dev.3describe/src/interfaces/ecpg/include/ecpglib.h 2009-08-03 16:10:33.000000000 +0200 *************** bool ECPGset_desc(int, const char *, in *** 83,89 **** void ECPGset_noind_null(enum ECPGttype, void *); bool ECPGis_noind_null(enum ECPGttype, void *); ! bool ECPGdescribe(int, bool, const char *,...); /* dynamic result allocation */ void ECPGfree_auto_mem(void); --- 83,89 ---- void ECPGset_noind_null(enum ECPGttype, void *); bool ECPGis_noind_null(enum ECPGttype, void *); ! bool ECPGdescribe(int, bool, const char *, const char *, ...); /* dynamic result allocation */ void ECPGfree_auto_mem(void); diff -dcrpN pgsql85dev.2sqlda/src/interfaces/ecpg/preproc/ecpg.addons pgsql85dev.3describe/src/interfaces/ecpg/preproc/ecpg.addons *** pgsql85dev.2sqlda/src/interfaces/ecpg/preproc/ecpg.addons 2009-08-03 15:25:02.000000000 +0200 --- pgsql85dev.3describe/src/interfaces/ecpg/preproc/ecpg.addons 2009-08-03 15:37:11.000000000 +0200 *************** ECPG: VariableShowStmtSHOWALL block *** 341,347 **** mmerror(PARSE_ERROR, ET_ERROR, "SHOW ALL is not implemented"); $$ = EMPTY; } ! ECPG: FetchStmtFETCHBACKWARDfrom_incursor_name block { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); --- 341,347 ---- mmerror(PARSE_ERROR, ET_ERROR, "SHOW ALL is not implemented"); $$ = EMPTY; } ! ECPG: FetchStmtFETCHBACKWARDfrom_incursor_name block { char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4; add_additional_variables($4, false); diff -dcrpN pgsql85dev.2sqlda/src/interfaces/ecpg/preproc/ecpg.trailer pgsql85dev.3describe/src/interfaces/ecpg/preproc/ecpg.trailer *** pgsql85dev.2sqlda/src/interfaces/ecpg/preproc/ecpg.trailer 2009-08-03 15:25:02.000000000 +0200 --- pgsql85dev.3describe/src/interfaces/ecpg/preproc/ecpg.trailer 2009-08-03 15:28:36.000000000 +0200 *************** ECPGCursorStmt: DECLARE cursor_name cur *** 321,327 **** add_variable_to_head(&(this->argsinsert), var, &no_indicator); } add_variable_to_head(&(this->argsinsert), thisquery, &no_indicator); - cur = this; $$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/")); --- 321,326 ---- *************** into_descriptor: INTO opt_sql SQL_DESCRI *** 1012,1017 **** --- 1011,1023 ---- } ; + into_sqlda: INTO name + { + add_variable_to_head(&argsresult, sqlda_variable($2), &no_indicator); + $$ = EMPTY; + } + ; + opt_sql: /*EMPTY*/ { $$ = EMPTY; } | SQL_SQL { $$ = make_str("sql"); } ; *************** ECPGDescribe: SQL_DESCRIBE INPUT_P name *** 1047,1068 **** { const char *con = connection ? connection : "NULL"; mmerror(PARSE_ERROR, ET_WARNING, "using unsupported DESCRIBE statement"); ! $$ = (char *) mm_alloc(sizeof("1, ECPGprepared_statement(, \"\", __LINE__)") + strlen(con) + strlen($3)); ! sprintf($$, "1, ECPGprepared_statement(%s, \"%s\", __LINE__)", con, $3); } | SQL_DESCRIBE opt_output name using_descriptor { const char *con = connection ? connection : "NULL"; ! mmerror(PARSE_ERROR, ET_WARNING, "using unsupported DESCRIBE statement"); ! $$ = (char *) mm_alloc(sizeof("0, ECPGprepared_statement(, \"\", __LINE__)") + strlen(con) + strlen($3)); ! sprintf($$, "0, ECPGprepared_statement(%s, \"%s\", __LINE__)", con, $3); } | SQL_DESCRIBE opt_output name into_descriptor { const char *con = connection ? connection : "NULL"; mmerror(PARSE_ERROR, ET_WARNING, "using unsupported DESCRIBE statement"); ! $$ = (char *) mm_alloc(sizeof("0, ECPGprepared_statement(, \"\", __LINE__)") + strlen(con) + strlen($3)); ! sprintf($$, "0, ECPGprepared_statement(%s, \"%s\", __LINE__)", con, $3); } ; --- 1053,1085 ---- { const char *con = connection ? connection : "NULL"; mmerror(PARSE_ERROR, ET_WARNING, "using unsupported DESCRIBE statement"); ! $$ = (char *) mm_alloc(sizeof("1, , \"\"") + strlen(con) + strlen($3)); ! sprintf($$, "1, %s, \"%s\"", con, $3); } | SQL_DESCRIBE opt_output name using_descriptor { const char *con = connection ? connection : "NULL"; ! $$ = (char *) mm_alloc(sizeof("0, , \"\"") + strlen(con) + strlen($3)); ! sprintf($$, "0, %s, \"%s\"", con, $3); } | SQL_DESCRIBE opt_output name into_descriptor { const char *con = connection ? connection : "NULL"; + $$ = (char *) mm_alloc(sizeof("0, , \"\"") + strlen(con) + strlen($3)); + sprintf($$, "0, %s, \"%s\"", con, $3); + } + | SQL_DESCRIBE INPUT_P name into_sqlda + { + const char *con = connection ? connection : "NULL"; mmerror(PARSE_ERROR, ET_WARNING, "using unsupported DESCRIBE statement"); ! $$ = (char *) mm_alloc(sizeof("1, , \"\"") + strlen(con) + strlen($3)); ! sprintf($$, "1, %s, \"%s\"", con, $3); ! } ! | SQL_DESCRIBE opt_output name into_sqlda ! { ! const char *con = connection ? connection : "NULL"; ! $$ = (char *) mm_alloc(sizeof("0, , \"\"") + strlen(con) + strlen($3)); ! sprintf($$, "0, %s, \"%s\"", con, $3); } ; diff -dcrpN pgsql85dev.2sqlda/src/interfaces/ecpg/preproc/ecpg.type pgsql85dev.3describe/src/interfaces/ecpg/preproc/ecpg.type *** pgsql85dev.2sqlda/src/interfaces/ecpg/preproc/ecpg.type 2009-08-03 15:25:02.000000000 +0200 --- pgsql85dev.3describe/src/interfaces/ecpg/preproc/ecpg.type 2009-08-03 15:28:36.000000000 +0200 *************** *** 72,77 **** --- 72,78 ---- %type <str> execute_rest %type <str> indicator %type <str> into_descriptor + %type <str> into_sqlda %type <str> Iresult %type <str> on_off %type <str> opt_bit_field *************** *** 86,92 **** %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 --- 87,93 ---- %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 pgsql85dev.3describe/doc/src/sgml/ecpg.sgml pgsql85dev.4string/doc/src/sgml/ecpg.sgml *** pgsql85dev.3describe/doc/src/sgml/ecpg.sgml 2009-07-13 11:16:15.000000000 +0200 --- pgsql85dev.4string/doc/src/sgml/ecpg.sgml 2009-08-03 18:03:36.000000000 +0200 *************** void PGTYPESdecimal_free(decimal *var); *** 2418,2423 **** --- 2418,2428 ---- know about ranges like for example <literal>YEAR TO MINUTE</> so you won't find support in ecpg for that either. </para> + <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> + </para> <sect2> <title>Additional embedded SQL statements</title> diff -dcrpN pgsql85dev.3describe/src/interfaces/ecpg/ecpglib/data.c pgsql85dev.4string/src/interfaces/ecpg/ecpglib/data.c *** pgsql85dev.3describe/src/interfaces/ecpg/ecpglib/data.c 2009-01-16 11:45:04.000000000 +0100 --- pgsql85dev.4string/src/interfaces/ecpg/ecpglib/data.c 2009-08-03 17:01:19.000000000 +0200 *************** ecpg_get_data(const PGresult *results, i *** 138,143 **** --- 138,144 ---- case ECPGt_char: case ECPGt_unsigned_char: case ECPGt_varchar: + case ECPGt_string: break; default: *************** ecpg_get_data(const PGresult *results, i *** 389,394 **** --- 390,396 ---- case ECPGt_char: case ECPGt_unsigned_char: + case ECPGt_string: if (pval) { if (varcharsize == 0 || varcharsize > size) *************** ecpg_get_data(const PGresult *results, i *** 426,431 **** --- 428,454 ---- sqlca->sqlwarn[0] = sqlca->sqlwarn[1] = 'W'; } } + /* Do the rtrim() */ + if (type == ECPGt_string) + { + char *str = (char *) ((long) var + offset * act_tuple); + char *last; + int len = strlen(str); + + last = str + len; + while (last > str) + { + if (*last == '\0') + last--; + else if (*last == ' ') + { + *last = '\0'; + last--; + } + else + break; + } + } pval += size; } break; diff -dcrpN pgsql85dev.3describe/src/interfaces/ecpg/ecpglib/descriptor.c pgsql85dev.4string/src/interfaces/ecpg/ecpglib/descriptor.c *** pgsql85dev.3describe/src/interfaces/ecpg/ecpglib/descriptor.c 2009-08-03 15:41:17.000000000 +0200 --- pgsql85dev.4string/src/interfaces/ecpg/ecpglib/descriptor.c 2009-08-03 17:01:19.000000000 +0200 *************** get_char_item(int lineno, void *var, enu *** 201,206 **** --- 201,207 ---- { case ECPGt_char: case ECPGt_unsigned_char: + case ECPGt_string: strncpy((char *) var, value, varcharsize); break; case ECPGt_varchar: diff -dcrpN pgsql85dev.3describe/src/interfaces/ecpg/ecpglib/execute.c pgsql85dev.4string/src/interfaces/ecpg/ecpglib/execute.c *** pgsql85dev.3describe/src/interfaces/ecpg/ecpglib/execute.c 2009-08-03 16:37:09.000000000 +0200 --- pgsql85dev.4string/src/interfaces/ecpg/ecpglib/execute.c 2009-08-03 17:01:19.000000000 +0200 *************** ecpg_store_result(const PGresult *result *** 360,365 **** --- 360,366 ---- { case ECPGt_char: case ECPGt_unsigned_char: + case ECPGt_string: if (!var->varcharsize && !var->arrsize) { /* special mode for handling char**foo=0 */ *************** ecpg_store_result(const PGresult *result *** 419,425 **** /* fill the variable with the tuple(s) */ if (!var->varcharsize && !var->arrsize && ! (var->type == ECPGt_char || var->type == ECPGt_unsigned_char)) { /* special mode for handling char**foo=0 */ --- 420,426 ---- /* fill the variable with the tuple(s) */ if (!var->varcharsize && !var->arrsize && ! (var->type == ECPGt_char || var->type == ECPGt_unsigned_char || var->type == ECPGt_string)) { /* special mode for handling char**foo=0 */ *************** ecpg_store_input(const int lineno, const *** 758,763 **** --- 759,765 ---- case ECPGt_char: case ECPGt_unsigned_char: + case ECPGt_string: { /* set slen to string length if type is char * */ int slen = (var->varcharsize == 0) ? strlen((char *) var->value) : (unsigned int) var->varcharsize; *************** ecpg_execute(struct statement * stmt) *** 1196,1201 **** --- 1198,1204 ---- { case ECPGt_char: case ECPGt_varchar: + case ECPGt_string: desc_inlist.varcharsize = strlen(sqlda->sqlvar[i].sqldata); break; default: diff -dcrpN pgsql85dev.3describe/src/interfaces/ecpg/ecpglib/misc.c pgsql85dev.4string/src/interfaces/ecpg/ecpglib/misc.c *** pgsql85dev.3describe/src/interfaces/ecpg/ecpglib/misc.c 2009-06-13 18:25:05.000000000 +0200 --- pgsql85dev.4string/src/interfaces/ecpg/ecpglib/misc.c 2009-08-03 17:01:19.000000000 +0200 *************** ECPGset_noind_null(enum ECPGttype type, *** 295,300 **** --- 295,301 ---- { case ECPGt_char: case ECPGt_unsigned_char: + case ECPGt_string: *((char *) ptr) = '\0'; break; case ECPGt_short: *************** ECPGis_noind_null(enum ECPGttype type, v *** 361,366 **** --- 362,368 ---- { case ECPGt_char: case ECPGt_unsigned_char: + case ECPGt_string: if (*((char *) ptr) == '\0') return true; break; diff -dcrpN pgsql85dev.3describe/src/interfaces/ecpg/ecpglib/typename.c pgsql85dev.4string/src/interfaces/ecpg/ecpglib/typename.c *** pgsql85dev.3describe/src/interfaces/ecpg/ecpglib/typename.c 2009-08-03 15:28:36.000000000 +0200 --- pgsql85dev.4string/src/interfaces/ecpg/ecpglib/typename.c 2009-08-03 17:01:19.000000000 +0200 *************** ecpg_type_name(enum ECPGttype typ) *** 20,25 **** --- 20,26 ---- switch (typ) { case ECPGt_char: + case ECPGt_string: return "char"; case ECPGt_unsigned_char: return "unsigned char"; diff -dcrpN pgsql85dev.3describe/src/interfaces/ecpg/include/ecpgtype.h pgsql85dev.4string/src/interfaces/ecpg/include/ecpgtype.h *** pgsql85dev.3describe/src/interfaces/ecpg/include/ecpgtype.h 2009-08-03 15:25:02.000000000 +0200 --- pgsql85dev.4string/src/interfaces/ecpg/include/ecpgtype.h 2009-08-03 17:01:19.000000000 +0200 *************** enum ECPGttype *** 62,68 **** ECPGt_EOIT, /* End of insert types. */ ECPGt_EORT, /* End of result types. */ ECPGt_NO_INDICATOR, /* no indicator */ ! ECPGt_sqlda /* INFORMIX-compatible sqlda_t descriptor */ }; /* descriptor items */ --- 62,69 ---- ECPGt_EOIT, /* End of insert types. */ ECPGt_EORT, /* End of result types. */ ECPGt_NO_INDICATOR, /* no indicator */ ! ECPGt_sqlda, /* INFORMIX-compatible sqlda_t descriptor */ ! ECPGt_string /* trimmed (char *) type */ }; /* descriptor items */ *************** enum ECPGdtype *** 87,93 **** ECPGd_cardinality }; ! #define IS_SIMPLE_TYPE(type) ((type) >= ECPGt_char && (type) <= ECPGt_interval) /* we also have to handle different statement types */ enum ECPG_statement_type --- 88,94 ---- ECPGd_cardinality }; ! #define IS_SIMPLE_TYPE(type) (((type) >= ECPGt_char && (type) <= ECPGt_interval) || ((type) == ECPGt_string)) /* we also have to handle different statement types */ enum ECPG_statement_type diff -dcrpN pgsql85dev.3describe/src/interfaces/ecpg/preproc/ecpg.header pgsql85dev.4string/src/interfaces/ecpg/preproc/ecpg.header *** pgsql85dev.3describe/src/interfaces/ecpg/preproc/ecpg.header 2009-06-13 18:25:05.000000000 +0200 --- pgsql85dev.4string/src/interfaces/ecpg/preproc/ecpg.header 2009-08-03 18:02:40.000000000 +0200 *************** adjust_informix(struct arguments *list) *** 256,267 **** original_var = ptr->variable->name; sprintf(temp, "%d))", ecpg_informix_var); ! if ((ptr->variable->type->type != ECPGt_varchar && ptr->variable->type->type != ECPGt_char && ptr->variable->type->type!= ECPGt_unsigned_char) && atoi(ptr->variable->type->size) > 1) { ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)),make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)),ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type, make_str("1"), ptr->variable->type->u.element->lineno),ptr->variable->type->size), 0); sprintf(temp, "%d, (", ecpg_informix_var++); } ! else if ((ptr->variable->type->type == ECPGt_varchar || ptr->variable->type->type == ECPGt_char || ptr->variable->type->type== ECPGt_unsigned_char) && atoi(ptr->variable->type->size) > 1) { ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->type)),make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->variable->type->type,ptr->variable->type->size, ptr->variable->type->lineno), 0); sprintf(temp, "%d, (", ecpg_informix_var++); --- 256,267 ---- original_var = ptr->variable->name; sprintf(temp, "%d))", ecpg_informix_var); ! if ((ptr->variable->type->type != ECPGt_varchar && ptr->variable->type->type != ECPGt_char && ptr->variable->type->type!= ECPGt_unsigned_char && ptr->variable->type->type != ECPGt_string) && atoi(ptr->variable->type->size)> 1) { ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)),make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)),ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type, make_str("1"), ptr->variable->type->u.element->lineno),ptr->variable->type->size), 0); sprintf(temp, "%d, (", ecpg_informix_var++); } ! else if ((ptr->variable->type->type == ECPGt_varchar || ptr->variable->type->type == ECPGt_char || ptr->variable->type->type== ECPGt_unsigned_char || ptr->variable->type->type == ECPGt_string) && atoi(ptr->variable->type->size)> 1) { ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->type)),make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->variable->type->type,ptr->variable->type->size, ptr->variable->type->lineno), 0); sprintf(temp, "%d, (", ecpg_informix_var++); *************** add_typedef(char *name, char * dimension *** 343,348 **** --- 343,350 ---- type_enum == ECPGt_union) && initializer == 1) mmerror(PARSE_ERROR, ET_ERROR, "initializer not allowed in type definition"); + else if (INFORMIX_MODE && strcmp(name, "string") == 0) + mmerror(PARSE_ERROR, ET_ERROR, "type name \"string\" is reserved in Informix mode"); else { for (ptr = types; ptr != NULL; ptr = ptr->next) *************** add_typedef(char *name, char * dimension *** 371,376 **** --- 373,379 ---- if (type_enum != ECPGt_varchar && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && + type_enum != ECPGt_string && atoi(this->type->type_index) >= 0) mmerror(PARSE_ERROR, ET_ERROR, "multidimensional arrays for simple data types are not supported"); diff -dcrpN pgsql85dev.3describe/src/interfaces/ecpg/preproc/ecpg.trailer pgsql85dev.4string/src/interfaces/ecpg/preproc/ecpg.trailer *** pgsql85dev.3describe/src/interfaces/ecpg/preproc/ecpg.trailer 2009-08-03 16:42:28.000000000 +0200 --- pgsql85dev.4string/src/interfaces/ecpg/preproc/ecpg.trailer 2009-08-03 17:11:57.000000000 +0200 *************** char_variable: cvariable *** 213,218 **** --- 213,219 ---- { case ECPGt_char: case ECPGt_unsigned_char: + case ECPGt_string: $$ = $1; break; case ECPGt_varchar: *************** var_type: simple_type *** 597,614 **** else { /* this is for typedef'ed types */ ! struct typedefs *this = get_typedef($1); ! $$.type_str = (this->type->type_enum == ECPGt_varchar) ? EMPTY : mm_strdup(this->name); ! $$.type_enum = this->type->type_enum; ! $$.type_dimension = this->type->type_dimension; ! $$.type_index = this->type->type_index; ! if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0) ! $$.type_sizeof = this->type->type_sizeof; ! else ! $$.type_sizeof = cat_str(3, make_str("sizeof("), mm_strdup(this->name), make_str(")")); ! struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list); } } | s_struct_union_symbol --- 598,632 ---- else { /* this is for typedef'ed types */ ! struct typedefs *this = get_typedef($1, FALSE); ! if (this == NULL) ! { ! if ((strcmp($1, "string") == 0) && INFORMIX_MODE) ! { ! $$.type_enum = ECPGt_string; ! $$.type_str = make_str("char"); ! $$.type_dimension = make_str("-1"); ! $$.type_index = make_str("-1"); ! $$.type_sizeof = NULL; ! } ! else ! /* Emit the same error as get_typedef() */ ! mmerror(PARSE_ERROR, ET_FATAL, "unrecognized data type name \"%s\"", $1); ! } ! else ! { ! $$.type_str = (this->type->type_enum == ECPGt_varchar) ? EMPTY : mm_strdup(this->name); ! $$.type_enum = this->type->type_enum; ! $$.type_dimension = this->type->type_dimension; ! $$.type_index = this->type->type_index; ! if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0) ! $$.type_sizeof = this->type->type_sizeof; ! else ! $$.type_sizeof = cat_str(3, make_str("sizeof("), mm_strdup(this->name), make_str(")")); ! struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list); ! } } } | s_struct_union_symbol *************** var_type: simple_type *** 624,630 **** { /* No */ ! this = get_typedef(name); $$.type_str = mm_strdup(this->name); $$.type_enum = this->type->type_enum; $$.type_dimension = this->type->type_dimension; --- 642,648 ---- { /* No */ ! this = get_typedef(name, TRUE); $$.type_str = mm_strdup(this->name); $$.type_enum = this->type->type_enum; $$.type_dimension = this->type->type_dimension; *************** variable: opt_pointer ECPGColLabel opt_a *** 856,861 **** --- 874,880 ---- case ECPGt_char: case ECPGt_unsigned_char: + case ECPGt_string: if (atoi(dimension) == -1) { int i = strlen($5); *************** ECPGVar: SQL_VAR *** 1333,1338 **** --- 1352,1358 ---- case ECPGt_char: case ECPGt_unsigned_char: + case ECPGt_string: if (atoi(dimension) == -1) type = ECPGmake_simple_type($5.type_enum, length, 0); else diff -dcrpN pgsql85dev.3describe/src/interfaces/ecpg/preproc/extern.h pgsql85dev.4string/src/interfaces/ecpg/preproc/extern.h *** pgsql85dev.3describe/src/interfaces/ecpg/preproc/extern.h 2009-08-03 15:25:02.000000000 +0200 --- pgsql85dev.4string/src/interfaces/ecpg/preproc/extern.h 2009-08-03 17:01:19.000000000 +0200 *************** extern void add_variable_to_head(struct *** 94,100 **** extern void add_variable_to_tail(struct arguments **, struct variable *, struct variable *); extern void remove_variable_from_list(struct arguments ** list, struct variable * var); extern void dump_variables(struct arguments *, int); ! extern struct typedefs *get_typedef(char *); extern void adjust_array(enum ECPGttype, char **, char **, char *, char *, int, bool); extern void reset_variables(void); extern void check_indicator(struct ECPGtype *); --- 94,100 ---- extern void add_variable_to_tail(struct arguments **, struct variable *, struct variable *); extern void remove_variable_from_list(struct arguments ** list, struct variable * var); extern void dump_variables(struct arguments *, int); ! extern struct typedefs *get_typedef(char *, int); extern void adjust_array(enum ECPGttype, char **, char **, char *, char *, int, bool); extern void reset_variables(void); extern void check_indicator(struct ECPGtype *); diff -dcrpN pgsql85dev.3describe/src/interfaces/ecpg/preproc/type.c pgsql85dev.4string/src/interfaces/ecpg/preproc/type.c *** pgsql85dev.3describe/src/interfaces/ecpg/preproc/type.c 2009-08-03 15:25:02.000000000 +0200 --- pgsql85dev.4string/src/interfaces/ecpg/preproc/type.c 2009-08-03 17:01:19.000000000 +0200 *************** get_type(enum ECPGttype type) *** 200,205 **** --- 200,208 ---- case ECPGt_timestamp: return ("ECPGt_timestamp"); break; + case ECPGt_string: + return ("ECPGt_string"); + break; default: mmerror(PARSE_ERROR, ET_ERROR, "unrecognized variable type code %d", type); } *************** ECPGdump_a_simple(FILE *o, const char *n *** 368,373 **** --- 371,377 ---- case ECPGt_char: case ECPGt_unsigned_char: case ECPGt_char_variable: + case ECPGt_string: /* * we have to use the pointer except for arrays with given diff -dcrpN pgsql85dev.3describe/src/interfaces/ecpg/preproc/variable.c pgsql85dev.4string/src/interfaces/ecpg/preproc/variable.c *** pgsql85dev.3describe/src/interfaces/ecpg/preproc/variable.c 2009-08-03 15:09:45.000000000 +0200 --- pgsql85dev.4string/src/interfaces/ecpg/preproc/variable.c 2009-08-03 17:01:19.000000000 +0200 *************** check_indicator(struct ECPGtype * var) *** 486,497 **** } struct typedefs * ! get_typedef(char *name) { struct typedefs *this; for (this = types; this && strcmp(this->name, name); this = this->next); ! if (!this) mmerror(PARSE_ERROR, ET_FATAL, "unrecognized data type name \"%s\"", name); return (this); --- 486,497 ---- } struct typedefs * ! get_typedef(char *name, int error) { struct typedefs *this; for (this = types; this && strcmp(this->name, name); this = this->next); ! if (!this && error) mmerror(PARSE_ERROR, ET_FATAL, "unrecognized data type name \"%s\"", name); return (this); *************** adjust_array(enum ECPGttype type_enum, c *** 524,530 **** "multilevel pointers (more than 2 levels) are not supported; found %d levels",pointer_len), pointer_len); ! if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char) mmerror(PARSE_ERROR, ET_FATAL, "pointer to pointer is not supported for this data type"); if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0)) --- 524,530 ---- "multilevel pointers (more than 2 levels) are not supported; found %d levels",pointer_len), pointer_len); ! if (pointer_len > 1 && type_enum != ECPGt_char && type_enum != ECPGt_unsigned_char && type_enum != ECPGt_string) mmerror(PARSE_ERROR, ET_FATAL, "pointer to pointer is not supported for this data type"); if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0)) *************** adjust_array(enum ECPGttype type_enum, c *** 563,568 **** --- 563,569 ---- break; case ECPGt_char: case ECPGt_unsigned_char: + case ECPGt_string: /* char ** */ if (pointer_len == 2) { diff -dcrpN pgsql85dev.4string/src/interfaces/ecpg/preproc/ecpg.header pgsql85dev.5struct/src/interfaces/ecpg/preproc/ecpg.header *** pgsql85dev.4string/src/interfaces/ecpg/preproc/ecpg.header 2009-07-15 11:19:06.000000000 +0200 --- pgsql85dev.5struct/src/interfaces/ecpg/preproc/ecpg.header 2009-07-31 11:38:50.000000000 +0200 *************** adjust_informix(struct arguments *list) *** 266,271 **** --- 266,273 ---- ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->type)),make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->variable->type->type,ptr->variable->type->size, ptr->variable->type->lineno), 0); sprintf(temp, "%d, (", ecpg_informix_var++); } + else if (ptr->variable->type->type == ECPGt_struct || ptr->variable->type->type == ECPGt_union) + continue; else { ptr->variable = new_variable(cat_str(4, make_str("*("), mm_strdup(ecpg_type_name(ptr->variable->type->type)),make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->variable->type->type,ptr->variable->type->size, ptr->variable->type->lineno), 0);
pgsql-hackers by date: