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  (Tom Lane <tgl@sss.pgh.pa.us>)
Re: Split-up ECPG patches  (Michael Meskes <meskes@postgresql.org>)
Re: Split-up ECPG patches  (Michael Meskes <meskes@postgresql.org>)
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:

Previous
From: Robert Haas
Date:
Subject: Re: CommitFest Status Summary - 2009-08-03
Next
From: David Fetter
Date:
Subject: Re: Alpha releases: How to tag