Thread: Split-up ECPG patches

Split-up ECPG patches

From
Böszörményi Zoltán
Date:
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


Attachment

Re: Split-up ECPG patches

From
Michael Meskes
Date:
On Wed, Jul 15, 2009 at 07:17:17PM +0200, Böszörményi Zoltán wrote:
> as asked by Michael Meskes, I have split up our ECPG patchset:

Just a couple quick comments.

It appears to me (without much testing) that the patches still partly rely on
each other. But I cannot see a reason for this.

> 1. dynamic cursorname (DECLARE :cursorname ..., etc)
> 2. SQLDA support in Informix compat mode (C structure used for
>     descriptor and data query)

One file has this:
 * (C) 2009 Cybertec GmbH *     Zolt??n B??sz??rm??nyi <zb@cybertec.at> *     Hans-J??rgen Sch??nig <hs@cybertec.at>

Shouldn't this also list a license? In general I wonder whether we need some
statement for every patch submitted? Anyone more into licensing might comment
here.

> 3. DESCRIBE OUTPUT support for named and sqlda descriptors

I don't think we have to add ECPGdescribe2 to keep the old API. The old
ECPGdescribe function does nothing, so it's not worth being kept.

> 4. "string" pseudo-type in Informix compat mode

There is still a lot of stuff being done when not in compatibility mode. I
thought you wanted to change that?

Michael
-- 
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Wed, Jul 15, 2009 at 07:17:17PM +0200, Böszörményi Zoltán wrote:
>   
>> as asked by Michael Meskes, I have split up our ECPG patchset:
>>     
>
> Just a couple quick comments.
>
> It appears to me (without much testing) that the patches still partly rely on
> each other. But I cannot see a reason for this.
>   

There are three reasons:

1. sqlda and string type support both add one constant in ecptypes.h
2. dynamic cursorname and DESCRIBE support both modify the  FetchStmt rule.
3. DESCRIBE support partially builds on sqlda support

I saw no point creating patches that are applicable standalone
when they would conflict each other. The point would be to have
all patches upstreamed, reviewed and applied in the order
indicated by the patch filenames.

Another point was that where to split features?
SQLDA and DESCRIBE [OUTPUT] features overlap.

>> 1. dynamic cursorname (DECLARE :cursorname ..., etc)
>> 2. SQLDA support in Informix compat mode (C structure used for
>>     descriptor and data query)
>>     
>
> One file has this:
>
>   * (C) 2009 Cybertec GmbH
>   *     Zolt??n B??sz??rm??nyi <zb@cybertec.at>
>   *     Hans-J??rgen Sch??nig <hs@cybertec.at>
>
> Shouldn't this also list a license? In general I wonder whether we need some
> statement for every patch submitted? Anyone more into licensing might comment
> here.
>   

What is the correct way to indicate that the licence is the same
as the PostgreSQL licence but we are the authors? We aren't
license experts. :-)

>> 3. DESCRIBE OUTPUT support for named and sqlda descriptors
>>     
>
> I don't think we have to add ECPGdescribe2 to keep the old API. The old
> ECPGdescribe function does nothing, so it's not worth being kept.
>   

I thought about easing transition and letting old binaries work as is.
IIRC a common wisdom is that if you add API calls, you only need to
increase the minor library version. But if you modify an existing
call you create an incompatibility (even when the usage of said call
was unlikely) and the major library version need to be increased.

>> 4. "string" pseudo-type in Informix compat mode
>>     
>
> There is still a lot of stuff being done when not in compatibility mode. I
> thought you wanted to change that?
>   

The things is that in Informix mode, the patch refuses
"typedef ... string;", in native mode it lets "string"
typename through. "make check" under ecpg passes. Isn't that
enough? Is there a particular place you didn't like?

Thanks for the review so far.

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/


Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
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); 

Re: Split-up ECPG patches

From
Tom Lane
Date:
Boszormenyi Zoltan <zb@cybertec.at> writes:
> new versions attached, updated to apply to the current CVS cleanly.

Why is this messing with the core grammar?
        regards, tom lane


Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Tom Lane írta:
> Boszormenyi Zoltan <zb@cybertec.at> writes:
>   
>> new versions attached, updated to apply to the current CVS cleanly.
>>     
>
> Why is this messing with the core grammar?
>
>             regards, tom lane
>   

It was explained in earlier mails, let me explain it again
but a bit more verbosely.

This was the evolution of my approaches adding the
dynamic cursorname:

At first, I changed ECPG grammar only. This meant adding
one new rule for every rule dealing with FETCH or
MOVE in the ECPG grammar. It turned out quickly,
that these two rules below:   FETCH fetch_direction from_in cursor_name ecpg_into   MOVE fetch_direction from_in
cursor_name
created shift/reduce conflicts in fetch_direction. This conflict
could have been solved by decreasing factorization of
"fetch_direction", pulling "BACKWARD" and "FORWARD"
(without the row number indicator) up to the rules using
"fetch_direction". Which could be solved by two ways.

1. Leave the original (auto-generated) rules alone and add
the new ones together with a new fetch_direction2 rule
used by the dynamic cursorname FETCH/MOVE rules.
At this point the FETCH/MOVE ruleset was so proliferated
that my eyes started aching just by looking at it. And as
Michael Meskes said, it was a great step back in the ECPG
auto-generated grammar introduced in 8.4.

2. With the first approach being a dead-end, I tried to unify
the two ruleset (FETCH/MOVE with and without dynamic
cursorname variable). But it only worked if I add these changes:
- add the "cursor_name" rule to the main grammar, so it can be picked up by the auto-generated ECPG grammar
- "cursor_name" has a new subrule dealing with host variables in ECPG
- the above solution for solving the shift/reduce problems in *ECPG*, needed the  change in the main grammar, so
auto-generationstill works, and both the main grammar and the ECPG grammar are clean.
 

I hope I explained it well, the first approach would have made
the autogenerated ECPG grammar very unclean, you would have
rejected immediately seeing that proposed.

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/



Re: Split-up ECPG patches

From
Michael Meskes
Date:
On Mon, Aug 03, 2009 at 06:12:43PM +0200, Boszormenyi Zoltan wrote:
> - 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.

I took the freedom to rewrite some parts of this patch and the commit it. Not
having read the Informix specs I might have broken something, so please test.

Michael
-- 
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Mon, Aug 03, 2009 at 06:12:43PM +0200, Boszormenyi Zoltan wrote:
>   
>> - 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.
>>     
>
> I took the freedom to rewrite some parts of this patch and the commit it. Not
> having read the Informix specs I might have broken something, so please test.
>   

Hey, thanks. Did you only commit this, or all of
those in the patchset? Exluding the nonfix for
the struct problem of course.

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/



Re: Split-up ECPG patches

From
Michael Meskes
Date:
On Fri, Aug 07, 2009 at 01:05:33PM +0200, Boszormenyi Zoltan wrote:
> Hey, thanks. Did you only commit this, or all of
> those in the patchset? Exluding the nonfix for
> the struct problem of course.

So far only this. So there are three more left to go. :-)

Did you take care of the copyright/licensing issue with sqlda?

Michael
-- 
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Fri, Aug 07, 2009 at 01:05:33PM +0200, Boszormenyi Zoltan wrote:
>   
>> Hey, thanks. Did you only commit this, or all of
>> those in the patchset? Exluding the nonfix for
>> the struct problem of course.
>>     
>
> So far only this. So there are three more left to go. :-)
>   

Okay :-)

> Did you take care of the copyright/licensing issue with sqlda?
>   

I added notice about the PostgreSQL license. Is it ok?
Or should I resend without indicating the authors?

Thanks,
Zoltán Böszörményi

-- 
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/



Re: Split-up ECPG patches

From
Alvaro Herrera
Date:
Boszormenyi Zoltan wrote:
> Michael Meskes írta:

> > Did you take care of the copyright/licensing issue with sqlda?
> 
> I added notice about the PostgreSQL license. Is it ok?
> Or should I resend without indicating the authors?

I think we're normally OK with mentioning the authors, i.e. "Author:
such and such", but the (C) line should attribute copyright to UCB/PGDG.
Michael is free to dictate something else for ECPG of course ...

-- 
Alvaro Herrera                                http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.


Re: Split-up ECPG patches

From
Michael Meskes
Date:
On Fri, Aug 07, 2009 at 04:03:38PM +0200, Boszormenyi Zoltan wrote:
> I added notice about the PostgreSQL license. Is it ok?
> Or should I resend without indicating the authors?

Normally all our source files are "Copyright PostgreSQL Global Development
Group" and I don't see a reason why this should be handled differently.

Michael
-- 
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: Split-up ECPG patches

From
Michael Meskes
Date:
On Fri, Aug 07, 2009 at 12:08:00PM -0400, Alvaro Herrera wrote:
> I think we're normally OK with mentioning the authors, i.e. "Author:

Yes, it's OK, but I think we normally only acknowledge the author in our commit
messages, don't we?

> such and such", but the (C) line should attribute copyright to UCB/PGDG.
> Michael is free to dictate something else for ECPG of course ...

No special rule for ecpg, I absolutely agree.

Michael
-- 
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Fri, Aug 07, 2009 at 12:08:00PM -0400, Alvaro Herrera wrote:
>   
>> I think we're normally OK with mentioning the authors, i.e. "Author:
>>     
>
> Yes, it's OK, but I think we normally only acknowledge the author in our commit
> messages, don't we?
>
>   
>> such and such", but the (C) line should attribute copyright to UCB/PGDG.
>> Michael is free to dictate something else for ECPG of course ...
>>     
>
> No special rule for ecpg, I absolutely agree.
>
> Michael
>   

OK, I can resend if you want. Or feel free
to delete the (C) lines from the sqlda.c file.

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/



Re: Split-up ECPG patches

From
Michael Meskes
Date:
On Mon, Aug 03, 2009 at 06:59:30PM +0200, Boszormenyi Zoltan wrote:
> > Why is this messing with the core grammar?
> ...

Zoltan, could you please explain why you unrolled FORWARD and BACKWARD? I tried
applying the rest of your patch, without this unrolling but didn't get any
shift/reduce problem. Might have been that I missed something, so could you please try again?

Tom, AFAICT we only need one core grammar change, moving the cursor name to
it's own rule that only resolves back to name. This rule should be eliminated
by bison during the build process anyway, so I see no problem adding it. It
does make the ecpg changes way smaller though. Is this okay with you?

Zoltan, two more things about this patch need to be cleared:
- I don't think your code is able to handle varchars.
- There is no test. Please add this to some of our test cases or write a new one.

Some variable handling commands look suspicious to me, a test case might
alleviate my concerns.

Michael

-- 
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: Split-up ECPG patches

From
Tom Lane
Date:
Michael Meskes <meskes@postgresql.org> writes:
> Tom, AFAICT we only need one core grammar change, moving the cursor name to
> it's own rule that only resolves back to name. This rule should be eliminated
> by bison during the build process anyway, so I see no problem adding it. It
> does make the ecpg changes way smaller though. Is this okay with you?

Sure, that one didn't bother me.  It was the FORWARD/BACKWARD decomposition
that looked unnecessary (as your tests seem to bear out).
        regards, tom lane


Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Mon, Aug 03, 2009 at 06:59:30PM +0200, Boszormenyi Zoltan wrote:
>
>>> Why is this messing with the core grammar?
>>>
>> ...
>>
>
> Zoltan, could you please explain why you unrolled FORWARD and BACKWARD? I tried
> applying the rest of your patch, without this unrolling but didn't get any
> shift/reduce problem. Might have been that I missed something, so could you please try again?
>

Without a re-quoted explanation, please, compare
your modified patch with the attached one. I rolled
FORWARD and BACKWARD back into fetch_direction
in the core grammar, deleting the newly introduced FETCH
and MOVE rules from the core and ECPG grammar and
again I got this during the ECPG grammar compilation:

...
"/usr/bin/perl" ./parse.pl . < ../../../../src/backend/parser/gram.y >
preproc.y
/usr/bin/bison -d  -o preproc.c preproc.y
preproc.y: conflicts: 2 shift/reduce
preproc.y: expected 0 shift/reduce conflicts
make[4]: *** [preproc.c] Error 1
make[4]: Leaving directory
`/home/zozo/Schönig-számlák/leoni/2/pgsql/src/interfaces/ecpg/preproc'
...

FYI:

$ rpm -q bison flex
bison-2.3-5.fc9.x86_64
flex-2.5.35-2.fc9.x86_64

> Tom, AFAICT we only need one core grammar change, moving the cursor name to
> it's own rule that only resolves back to name. This rule should be eliminated
> by bison during the build process anyway, so I see no problem adding it. It
> does make the ecpg changes way smaller though. Is this okay with you?
>
> Zoltan, two more things about this patch need to be cleared:
> - I don't think your code is able to handle varchars.
>

I will test that, thanks.

> - There is no test. Please add this to some of our test cases or write a new one.
>

I will write some regression tests, of course.

> Some variable handling commands look suspicious to me, a test case might
> alleviate my concerns.
>

Best regards,
Zoltán Böszörményi

--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/

diff -dcrpN pgsql.orig/src/backend/parser/gram.y pgsql/src/backend/parser/gram.y
*** pgsql.orig/src/backend/parser/gram.y    2009-08-03 10:38:28.000000000 +0200
--- pgsql/src/backend/parser/gram.y    2009-08-08 17:26:00.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,4095 ----
   *
   *****************************************************************************/

! FetchStmt:    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;
--- 4098,4111 ----
                      n->ismove = FALSE;
                      $$ = (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;
*************** set_target_list:
*** 6847,6853 ****
   *                CURSOR STATEMENTS
   *
   *****************************************************************************/
! DeclareCursorStmt: DECLARE name cursor_options CURSOR opt_hold FOR SelectStmt
                  {
                      DeclareCursorStmt *n = makeNode(DeclareCursorStmt);
                      n->portalname = $2;
--- 6847,6853 ----
   *                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 ****
--- 6858,6866 ----
                  }
          ;

+ 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 pgsql.orig/src/interfaces/ecpg/preproc/ecpg.addons pgsql/src/interfaces/ecpg/preproc/ecpg.addons
*** pgsql.orig/src/interfaces/ecpg/preproc/ecpg.addons    2009-01-30 17:28:46.000000000 +0100
--- pgsql/src/interfaces/ecpg/preproc/ecpg.addons    2009-08-08 17:28:02.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,394 ----
          mmerror(PARSE_ERROR, ET_ERROR, "SHOW ALL is not implemented");
          $$ = EMPTY;
      }
! 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 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 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 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 pgsql.orig/src/interfaces/ecpg/preproc/ecpg.trailer pgsql/src/interfaces/ecpg/preproc/ecpg.trailer
*** pgsql.orig/src/interfaces/ecpg/preproc/ecpg.trailer    2009-08-07 13:06:28.000000000 +0200
--- pgsql/src/interfaces/ecpg/preproc/ecpg.trailer    2009-08-08 17:23:11.000000000 +0200
*************** prepared_name: name             {
*** 285,293 ****
   * 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";

--- 285,294 ----
   * 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
*** 304,310 ****
              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;
--- 305,311 ----
              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
*** 314,319 ****
--- 315,326 ----
              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; }
*** 954,960 ****
  /*
   * 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; }
--- 961,976 ----
  /*
   * 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
*** 1779,1784 ****
--- 1795,1807 ----
          }
          ;

+ 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 pgsql.orig/src/interfaces/ecpg/preproc/ecpg.type pgsql/src/interfaces/ecpg/preproc/ecpg.type
*** pgsql.orig/src/interfaces/ecpg/preproc/ecpg.type    2008-11-14 11:03:33.000000000 +0100
--- pgsql/src/interfaces/ecpg/preproc/ecpg.type    2009-08-08 17:23:11.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 pgsql.orig/src/interfaces/ecpg/preproc/extern.h pgsql/src/interfaces/ecpg/preproc/extern.h
*** pgsql.orig/src/interfaces/ecpg/preproc/extern.h    2009-07-17 07:50:56.000000000 +0200
--- pgsql/src/interfaces/ecpg/preproc/extern.h    2009-08-08 17:23:11.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 pgsql.orig/src/interfaces/ecpg/preproc/variable.c pgsql/src/interfaces/ecpg/preproc/variable.c
*** pgsql.orig/src/interfaces/ecpg/preproc/variable.c    2009-08-07 13:06:28.000000000 +0200
--- pgsql/src/interfaces/ecpg/preproc/variable.c    2009-08-08 17:23:11.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.

Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Tom Lane írta:
> Michael Meskes <meskes@postgresql.org> writes:
>   
>> Tom, AFAICT we only need one core grammar change, moving the cursor name to
>> it's own rule that only resolves back to name. This rule should be eliminated
>> by bison during the build process anyway, so I see no problem adding it. It
>> does make the ecpg changes way smaller though. Is this okay with you?
>>     
>
> Sure, that one didn't bother me.  It was the FORWARD/BACKWARD decomposition
> that looked unnecessary (as your tests seem to bear out).
>   

Of course, that one bothered me as well.
Please, test the attached patch in my other mail.

I would like to know what bison version does
Michael use, maybe some difference from my
bison-2.3 might explain his test result. Tom,
you surely know more about bison releases
and its grammar changes than me, you might
give me some enlightenment on this issue.
It might turn out that my Fedora 9 bison is not bugfree.

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/



Re: Split-up ECPG patches

From
Michael Meskes
Date:
On Sat, Aug 08, 2009 at 05:48:57PM +0200, Boszormenyi Zoltan wrote:
> ...
> "/usr/bin/perl" ./parse.pl . < ../../../../src/backend/parser/gram.y >
> preproc.y
> /usr/bin/bison -d  -o preproc.c preproc.y
> preproc.y: conflicts: 2 shift/reduce
> preproc.y: expected 0 shift/reduce conflicts
> make[4]: *** [preproc.c] Error 1
> make[4]: Leaving directory
> `/home/zozo/Schönig-számlák/leoni/2/pgsql/src/interfaces/ecpg/preproc'
> ...

Right, I missed this one. But it's ecpg specific and should not be fixed by
changing gram.y. The problem is that SignedIconst might be a char variable,
too. So how shall the parser know whether str in "FETCH BACKWARD :str" carries
the number of records to move backwards ot the cursor name. A possible solution
would be to force a numeric variable for numeric data. Also keep in mind that a
fetch statement without from/in is an addition on top of the standard. I'm not
sure if any other dbms still allows this construct, so we might we well remove
it for 8.5. Or move it to a special compatibility mode.

Michael
-- 
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Sat, Aug 08, 2009 at 05:48:57PM +0200, Boszormenyi Zoltan wrote:
>   
>> ...
>> "/usr/bin/perl" ./parse.pl . < ../../../../src/backend/parser/gram.y >
>> preproc.y
>> /usr/bin/bison -d  -o preproc.c preproc.y
>> preproc.y: conflicts: 2 shift/reduce
>> preproc.y: expected 0 shift/reduce conflicts
>> make[4]: *** [preproc.c] Error 1
>> make[4]: Leaving directory
>> `/home/zozo/Schönig-számlák/leoni/2/pgsql/src/interfaces/ecpg/preproc'
>> ...
>>     
>
> Right, I missed this one. But it's ecpg specific and should not be fixed by
> changing gram.y.

Debatable. :-)

>  The problem is that SignedIconst might be a char variable,
> too. So how shall the parser know whether str in "FETCH BACKWARD :str" carries
> the number of records to move backwards ot the cursor name.

This was the problem, yes.

>  A possible solution
> would be to force a numeric variable for numeric data.

By which you would remove a feature.
With the proposed core grammar change,
the feature where you can pass the number of
records to be fetched in a string variable
can be kept.

>  Also keep in mind that a
> fetch statement without from/in is an addition on top of the standard.

It seems to be Informix-specific, I just looked it up in
their guide_to_sql_syntax.pdf.

>  I'm not
> sure if any other dbms still allows this construct, so we might we well remove
> it for 8.5. Or move it to a special compatibility mode.
>   

How would you do that? With a completely
different parser for Informix-compatibility?
It would reduce maintainability. Or does bison
allow conditionally enabled rules somehow?
It sure  would come in handy in this case.

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/



Re: Split-up ECPG patches

From
Michael Meskes
Date:
On Sat, Aug 08, 2009 at 07:21:59PM +0200, Boszormenyi Zoltan wrote:
> >  A possible solution
> > would be to force a numeric variable for numeric data.
> 
> By which you would remove a feature.
> With the proposed core grammar change,
> the feature where you can pass the number of
> records to be fetched in a string variable
> can be kept.

Somehow I doubt this. Yes, your patch originally didn't come with a
shift/reduce problem, but I cannot see how this solved this. The same rule
still has the same problem.

> It seems to be Informix-specific, I just looked it up in
> their guide_to_sql_syntax.pdf.

The questin is, does Oracle so somthing similar?

> >  I'm not
> > sure if any other dbms still allows this construct, so we might we well remove
> > it for 8.5. Or move it to a special compatibility mode.
> >   
> 
> How would you do that? With a completely
> different parser for Informix-compatibility?

No.

> It would reduce maintainability. Or does bison
> allow conditionally enabled rules somehow?
> It sure  would come in handy in this case.

No. You have to code around it. What I meant was, that other dbms should have
the same problem. So they solved it one way or the other. And we could create
both solutions just depending on the mode we're in. Informix e.g. doesn't seem
to allow a variable to carry the number of records. Heck, I don't even see
FORWARD/BACKWARD. A number is only given in ABSOLUTE and RELATIVE but no
variable.

Michael
-- 
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Sat, Aug 08, 2009 at 07:21:59PM +0200, Boszormenyi Zoltan wrote:
>   
>>>  A possible solution
>>> would be to force a numeric variable for numeric data.
>>>       
>> By which you would remove a feature.
>> With the proposed core grammar change,
>> the feature where you can pass the number of
>> records to be fetched in a string variable
>> can be kept.
>>     
>
> Somehow I doubt this. Yes, your patch originally didn't come with a
> shift/reduce problem, but I cannot see how this solved this. The same rule
> still has the same problem.
>   

Err, no. E.g. if the whole statement is    FETCH BACKWARD cursor_name
then it can only carry a cursor name, as always did.
No matter if cursor_name is now a static or dynamic name.
The problem is with the original factorization of
"fetch_direction", now with dynamic cursor name
the grammar cannot decide between    "FETCH BACKWARD :no_of_rec ..."
and   "FETCH BACKWARD :cursor"
Same with the FORWARD rule. And _that_ can be solved
by decreasing factorization, i.e. pulling FORWARD and
BACKWARD up into the FetchStmt rule in the core grammar.

>> It seems to be Informix-specific, I just looked it up in
>> their guide_to_sql_syntax.pdf.
>>     
>
> The questin is, does Oracle so somthing similar?
>   

No idea. I can look up though.

>>>  I'm not
>>> sure if any other dbms still allows this construct, so we might we well remove
>>> it for 8.5. Or move it to a special compatibility mode.
>>>   
>>>       
>> How would you do that? With a completely
>> different parser for Informix-compatibility?
>>     
>
> No.
>
>   
>> It would reduce maintainability. Or does bison
>> allow conditionally enabled rules somehow?
>> It sure  would come in handy in this case.
>>     
>
> No. You have to code around it. What I meant was, that other dbms should have
> the same problem. So they solved it one way or the other. And we could create
> both solutions just depending on the mode we're in. Informix e.g. doesn't seem
> to allow a variable to carry the number of records. Heck, I don't even see
> FORWARD/BACKWARD. A number is only given in ABSOLUTE and RELATIVE but no
> variable.
>
> Michael
>   


-- 
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/



Re: Split-up ECPG patches

From
Tom Lane
Date:
Boszormenyi Zoltan <zb@cybertec.at> writes:
> Michael Meskes írta:
>> The problem is that SignedIconst might be a char variable,
>> too. So how shall the parser know whether str in "FETCH BACKWARD :str" carries
>> the number of records to move backwards ot the cursor name.

> This was the problem, yes.

>> A possible solution
>> would be to force a numeric variable for numeric data.

> By which you would remove a feature.

If you ask me, the real problem here is the productions ecpg adds to
make "from_in" optional.  If a CVARIABLE can be either a fetch_count
or a cursor_name, then removing from_in makes the grammar fundamentally
ambiguous; no amount of rearrangement will fix that.

I'd look at requiring from_in as being the least-bad alternative.  What
I now see is that Zoltan's previous patch is removing a different subset
of the possible parses (and has to modify the core grammar in order to
be able to do that); to wit, it's arbitrarily deciding that "FETCH
FORWARD variable" must be a cursor name variable and not a row count
variable.  That strikes me as a non-orthogonal, error-prone kluge.
        regards, tom lane


Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Tom Lane írta:
> Boszormenyi Zoltan <zb@cybertec.at> writes:
>   
>> Michael Meskes Ă­rta:
>>     
>>> The problem is that SignedIconst might be a char variable,
>>> too. So how shall the parser know whether str in "FETCH BACKWARD :str" carries
>>> the number of records to move backwards ot the cursor name.
>>>       
>
>   
>> This was the problem, yes.
>>     
>
>   
>>> A possible solution
>>> would be to force a numeric variable for numeric data.
>>>       
>
>   
>> By which you would remove a feature.
>>     
>
> If you ask me, the real problem here is the productions ecpg adds to
> make "from_in" optional.  If a CVARIABLE can be either a fetch_count
> or a cursor_name, then removing from_in makes the grammar fundamentally
> ambiguous; no amount of rearrangement will fix that.
>
> I'd look at requiring from_in as being the least-bad alternative.  What
> I now see is that Zoltan's previous patch is removing a different subset
> of the possible parses (and has to modify the core grammar in order to
> be able to do that); to wit, it's arbitrarily deciding that "FETCH
> FORWARD variable" must be a cursor name variable and not a row count
> variable.  That strikes me as a non-orthogonal, error-prone kluge.
>   

Hm. "FETCH FORWARD variable" can only be a rowcount var
only if there's something afterwards, no? With the proposed
change in fetch_direction (moving FORWARD and BACKWARD
without the rowcount upper to the parent rules) now the parser is
able to look behind "FORWARD variable"...

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/



Re: Split-up ECPG patches

From
Tom Lane
Date:
Boszormenyi Zoltan <zb@cybertec.at> writes:
> Tom Lane �rta:
>> I'd look at requiring from_in as being the least-bad alternative.

> Hm. "FETCH FORWARD variable" can only be a rowcount var
> only if there's something afterwards, no? With the proposed
> change in fetch_direction (moving FORWARD and BACKWARD
> without the rowcount upper to the parent rules) now the parser is
> able to look behind "FORWARD variable"...

The fundamental reason that there's a problem here is that ecpg has
decided to accept a syntax that the backend doesn't (ie, FETCH with a
fetch direction but no FROM/IN).  I think that that's basically a bad
idea: it's not helpful to users to be inconsistent, and it requires ugly
hacks in ecpg, and now ugly hacks in the core grammar as well.  We
should resolve it either by taking out that syntax from ecpg, or by
making the backend accept it too.  Not by uglifying the grammars some
more in order to keep them inconsistent.

If we were going to allow it in the core, I think moving the cursor
name into the fetch_direction production might work, ie, change
fetch_direction to fetch_args and make it cover everything that
FETCH and MOVE share.  Probably from_in could become opt_from_in,
since the alternatives for it are fully reserved words already, and we
wouldn't need to double up any of the fetch_direction productions.
        regards, tom lane


Re: Split-up ECPG patches

From
Tom Lane
Date:
I wrote:
> The fundamental reason that there's a problem here is that ecpg has
> decided to accept a syntax that the backend doesn't (ie, FETCH with a
> fetch direction but no FROM/IN).  I think that that's basically a bad
> idea: it's not helpful to users to be inconsistent, and it requires ugly
> hacks in ecpg, and now ugly hacks in the core grammar as well.  We
> should resolve it either by taking out that syntax from ecpg, or by
> making the backend accept it too.  Not by uglifying the grammars some
> more in order to keep them inconsistent.

On looking a bit closer at this: I think the reason the core grammar
requires FROM/IN after fetch_direction is to leave the door open for
someday generalizing the fetch count to be an expression, not just an
integer constant.  If we made FROM/IN optional, then doing that would
require some ugly syntax hack or other, such as requiring parentheses
around nontrivial expressions.  So I'd like to see an actual case made
that there's a strong reason for not requiring FROM/IN in ecpg.
        regards, tom lane


Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Tom Lane írta:
> Boszormenyi Zoltan <zb@cybertec.at> writes:
>   
>> Tom Lane írta:
>>     
>>> I'd look at requiring from_in as being the least-bad alternative.
>>>       
>
>   
>> Hm. "FETCH FORWARD variable" can only be a rowcount var
>> only if there's something afterwards, no? With the proposed
>> change in fetch_direction (moving FORWARD and BACKWARD
>> without the rowcount upper to the parent rules) now the parser is
>> able to look behind "FORWARD variable"...
>>     
>
> The fundamental reason that there's a problem here is that ecpg has
> decided to accept a syntax that the backend doesn't (ie, FETCH with a
> fetch direction but no FROM/IN).  I think that that's basically a bad
> idea: it's not helpful to users to be inconsistent, and it requires ugly
> hacks in ecpg, and now ugly hacks in the core grammar as well.  We
> should resolve it either by taking out that syntax from ecpg, or by
> making the backend accept it too.  Not by uglifying the grammars some
> more in order to keep them inconsistent.
>
> If we were going to allow it in the core, I think moving the cursor
> name into the fetch_direction production might work, ie, change
> fetch_direction to fetch_args and make it cover everything that
> FETCH and MOVE share.  Probably from_in could become opt_from_in,
> since the alternatives for it are fully reserved words already, and we
> wouldn't need to double up any of the fetch_direction productions.
>   

And maybe, possibly with this change as a start, someday
we can support dynamic cursorname in plain SQL, too.
DECLARE $1 CURSOR FOR SELECT ...
It would be a much cleaner solution in ECPG, too.

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/



Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Tom Lane írta:
> I wrote:
>   
>> The fundamental reason that there's a problem here is that ecpg has
>> decided to accept a syntax that the backend doesn't (ie, FETCH with a
>> fetch direction but no FROM/IN).  I think that that's basically a bad
>> idea: it's not helpful to users to be inconsistent, and it requires ugly
>> hacks in ecpg, and now ugly hacks in the core grammar as well.  We
>> should resolve it either by taking out that syntax from ecpg, or by
>> making the backend accept it too.  Not by uglifying the grammars some
>> more in order to keep them inconsistent.
>>     
>
> On looking a bit closer at this: I think the reason the core grammar
> requires FROM/IN after fetch_direction is to leave the door open for
> someday generalizing the fetch count to be an expression, not just an
> integer constant.  If we made FROM/IN optional, then doing that would
> require some ugly syntax hack or other, such as requiring parentheses
> around nontrivial expressions.  So I'd like to see an actual case made
> that there's a strong reason for not requiring FROM/IN in ecpg.
>
>             regards, tom lane
>   

The only reason is I think was the Informix-compatible mode.
I don't know if it's strong enough, though.

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/



Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Boszormenyi Zoltan írta:
> Tom Lane írta:
>   
>> I wrote:
>>   
>>     
>>> The fundamental reason that there's a problem here is that ecpg has
>>> decided to accept a syntax that the backend doesn't (ie, FETCH with a
>>> fetch direction but no FROM/IN).  I think that that's basically a bad
>>> idea: it's not helpful to users to be inconsistent, and it requires ugly
>>> hacks in ecpg, and now ugly hacks in the core grammar as well.  We
>>> should resolve it either by taking out that syntax from ecpg, or by
>>> making the backend accept it too.  Not by uglifying the grammars some
>>> more in order to keep them inconsistent.
>>>     
>>>       
>> On looking a bit closer at this: I think the reason the core grammar
>> requires FROM/IN after fetch_direction is to leave the door open for
>> someday generalizing the fetch count to be an expression, not just an
>> integer constant.  If we made FROM/IN optional, then doing that would
>> require some ugly syntax hack or other, such as requiring parentheses
>> around nontrivial expressions.  So I'd like to see an actual case made
>> that there's a strong reason for not requiring FROM/IN in ecpg.
>>
>>             regards, tom lane
>>   
>>     
>
> The only reason is I think was the Informix-compatible mode.
> I don't know if it's strong enough, though.
>   

I am looking at the original gram.y and there's a special cased
"optional FROM/IN" case already for FETCH and MOVE:
"FETCH name" and "MOVE name". Which can be seen
as optional FORWARD (already in fetch_direction, as its
first rule) and optional FROM/IN.

> 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/



Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Tom Lane írta:
> Boszormenyi Zoltan <zb@cybertec.at> writes:
>   
>> Tom Lane írta:
>>     
>>> I'd look at requiring from_in as being the least-bad alternative.
>>>       
>
>   
>> Hm. "FETCH FORWARD variable" can only be a rowcount var
>> only if there's something afterwards, no? With the proposed
>> change in fetch_direction (moving FORWARD and BACKWARD
>> without the rowcount upper to the parent rules) now the parser is
>> able to look behind "FORWARD variable"...
>>     
>
> The fundamental reason that there's a problem here is that ecpg has
> decided to accept a syntax that the backend doesn't (ie, FETCH with a
> fetch direction but no FROM/IN).  I think that that's basically a bad
> idea: it's not helpful to users to be inconsistent, and it requires ugly
> hacks in ecpg, and now ugly hacks in the core grammar as well.  We
> should resolve it either by taking out that syntax from ecpg, or by
> making the backend accept it too.  Not by uglifying the grammars some
> more in order to keep them inconsistent.
>
> If we were going to allow it in the core, I think moving the cursor
> name into the fetch_direction production might work, ie, change
> fetch_direction to fetch_args and make it cover everything that
> FETCH and MOVE share.  Probably from_in could become opt_from_in,
> since the alternatives for it are fully reserved words already, and we
> wouldn't need to double up any of the fetch_direction productions.
>
>             regards, tom lane
>   

Your guess about making from_in into opt_from_in
seems good, mostly. I tried doing exactly that and simply
adding an empty match into from_in, I got shift/reduce conflicts
only in "opt_from_in cursor_name". So, this rule has to be
unrolled into 3 rules, or keeping a separate "from_in" just for
having a separate "cursor_name" and "from_in cursor_name".
I decided that I use the second method, it's shorter.

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/



Re: Split-up ECPG patches

From
Michael Meskes
Date:
On Sat, Aug 08, 2009 at 04:57:57PM -0400, Tom Lane wrote:
> The fundamental reason that there's a problem here is that ecpg has
> decided to accept a syntax that the backend doesn't (ie, FETCH with a
> fetch direction but no FROM/IN).  I think that that's basically a bad

Which was added because most if not all other precompilers allow this syntax
and of course it didn't do any harm until now.

> idea: it's not helpful to users to be inconsistent, and it requires ugly
> hacks in ecpg, and now ugly hacks in the core grammar as well.  We
> should resolve it either by taking out that syntax from ecpg, or by
> making the backend accept it too.  Not by uglifying the grammars some
> more in order to keep them inconsistent.

Couldn't agree more.

I'd like to figure out exactly what syntax other DBMSes accept. It appears
Informix allows the cursor name as a variable but has neither FORWARD/BACKWARD
nor FROM/IN. Zoltan, could you please check whether my docs are right? 

A quick google search seems to suggest that the same holds for Oracle that
apparently allows less options.

Michael
-- 
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: Split-up ECPG patches

From
Michael Meskes
Date:
On Sat, Aug 08, 2009 at 05:29:06PM -0400, Tom Lane wrote:
> around nontrivial expressions.  So I'd like to see an actual case made
> that there's a strong reason for not requiring FROM/IN in ecpg.

I guess there's only one, compatibility. 

Michael
-- 
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: Split-up ECPG patches

From
Tom Lane
Date:
Michael Meskes <meskes@postgresql.org> writes:
> On Sat, Aug 08, 2009 at 05:29:06PM -0400, Tom Lane wrote:
>> around nontrivial expressions.  So I'd like to see an actual case made
>> that there's a strong reason for not requiring FROM/IN in ecpg.

> I guess there's only one, compatibility. 

Yeah.  Are there any other precompilers that actively reject FROM/IN
here?  If we're just a bit more strict than they are, it's not as bad
as if there is no common syntax subset.
        regards, tom lane


Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Sat, Aug 08, 2009 at 04:57:57PM -0400, Tom Lane wrote:
>   
>> The fundamental reason that there's a problem here is that ecpg has
>> decided to accept a syntax that the backend doesn't (ie, FETCH with a
>> fetch direction but no FROM/IN).  I think that that's basically a bad
>>     
>
> Which was added because most if not all other precompilers allow this syntax
> and of course it didn't do any harm until now.
>   

:-( Why me? ;-)

>> idea: it's not helpful to users to be inconsistent, and it requires ugly
>> hacks in ecpg, and now ugly hacks in the core grammar as well.  We
>> should resolve it either by taking out that syntax from ecpg, or by
>> making the backend accept it too.  Not by uglifying the grammars some
>> more in order to keep them inconsistent.
>>     
>
> Couldn't agree more.
>
> I'd like to figure out exactly what syntax other DBMSes accept. It appears
> Informix allows the cursor name as a variable but has neither FORWARD/BACKWARD
> nor FROM/IN. Zoltan, could you please check whether my docs are right? 
>   

Yes, your docs seems to be right. From my docs, Informix allows these:

FETCH   { [NEXT] | PRIOR | PREVIOUS | FIRST | LAST | CURRENT |       ABSOLUTE pos_var_or_const |       RELATIVE {
[+]pos_var_or_const| -pos_const }   }   { cursor_id | cursor_var }   { USING [SQL] DESCRIPTOR ... | INTO
host_var_list...}
 

There's no FROM or IN anywhere in the syntax snake maze graph.

> A quick google search seems to suggest that the same holds for Oracle that
> apparently allows less options.
>
> Michael
>   

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/



Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Boszormenyi Zoltan írta:
> Tom Lane írta:
>
>> Boszormenyi Zoltan <zb@cybertec.at> writes:
>>
>>
>>> Tom Lane írta:
>>>
>>>
>>>> I'd look at requiring from_in as being the least-bad alternative.
>>>>
>>>>
>>
>>
>>> Hm. "FETCH FORWARD variable" can only be a rowcount var
>>> only if there's something afterwards, no? With the proposed
>>> change in fetch_direction (moving FORWARD and BACKWARD
>>> without the rowcount upper to the parent rules) now the parser is
>>> able to look behind "FORWARD variable"...
>>>
>>>
>> The fundamental reason that there's a problem here is that ecpg has
>> decided to accept a syntax that the backend doesn't (ie, FETCH with a
>> fetch direction but no FROM/IN).  I think that that's basically a bad
>> idea: it's not helpful to users to be inconsistent, and it requires ugly
>> hacks in ecpg, and now ugly hacks in the core grammar as well.  We
>> should resolve it either by taking out that syntax from ecpg, or by
>> making the backend accept it too.  Not by uglifying the grammars some
>> more in order to keep them inconsistent.
>>
>> If we were going to allow it in the core, I think moving the cursor
>> name into the fetch_direction production might work, ie, change
>> fetch_direction to fetch_args and make it cover everything that
>> FETCH and MOVE share.  Probably from_in could become opt_from_in,
>> since the alternatives for it are fully reserved words already, and we
>> wouldn't need to double up any of the fetch_direction productions.
>>
>>             regards, tom lane
>>
>>
>
> Your guess about making from_in into opt_from_in
> seems good, mostly. I tried doing exactly that and simply
> adding an empty match into from_in, I got shift/reduce conflicts
> only in "opt_from_in cursor_name". So, this rule has to be
> unrolled into 3 rules, or keeping a separate "from_in" just for
> having a separate "cursor_name" and "from_in cursor_name".
> I decided that I use the second method, it's shorter.
>

OK, here's the WIP patch for the unified core/ecpg grammar,
with opt_from_in. But I am still getting the 2 shift/reduce
conflicts exactly for the FORWARD and BACKWARD rules
that I was getting originally. Can you look at this patch and
point me to the right direction in solving it? Thanks in advance.

> Best regards,
> Zoltán Böszörményi
>
>


--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/

diff -dcrpN pgsql.orig/src/backend/parser/gram.y pgsql/src/backend/parser/gram.y
*** pgsql.orig/src/backend/parser/gram.y    2009-08-03 10:38:28.000000000 +0200
--- pgsql/src/backend/parser/gram.y    2009-08-09 17:48:36.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
*************** static TypeName *TableFuncTypeName(List
*** 331,337 ****
  %type <ival>    opt_column event cursor_options opt_hold opt_set_data
  %type <objtype>    reindex_type drop_type comment_type

! %type <node>    fetch_direction select_limit_value select_offset_value
                  select_offset_value2 opt_select_fetch_first_value
  %type <ival>    row_or_rows first_or_next

--- 331,337 ----
  %type <ival>    opt_column event cursor_options opt_hold opt_set_data
  %type <objtype>    reindex_type drop_type comment_type

! %type <node>    fetch_args select_limit_value select_offset_value
                  select_offset_value2 opt_select_fetch_first_value
  %type <ival>    row_or_rows first_or_next

*************** 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,4223 ****
   *
   *****************************************************************************/

! 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;
-                     n->howMany = 1;
-                     n->portalname = $2;
                      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;
                      n->howMany = 1;
-                     n->portalname = $2;
-                     n->ismove = TRUE;
                      $$ = (Node *)n;
                  }
!         ;
!
! fetch_direction:
!             /*EMPTY*/
                  {
                      FetchStmt *n = makeNode(FetchStmt);
                      n->direction = FETCH_FORWARD;
                      n->howMany = 1;
                      $$ = (Node *)n;
                  }
!             | NEXT
                  {
                      FetchStmt *n = makeNode(FetchStmt);
                      n->direction = FETCH_FORWARD;
                      n->howMany = 1;
                      $$ = (Node *)n;
                  }
!             | PRIOR
                  {
                      FetchStmt *n = makeNode(FetchStmt);
                      n->direction = FETCH_BACKWARD;
                      n->howMany = 1;
                      $$ = (Node *)n;
                  }
!             | FIRST_P
                  {
                      FetchStmt *n = makeNode(FetchStmt);
                      n->direction = FETCH_ABSOLUTE;
                      n->howMany = 1;
                      $$ = (Node *)n;
                  }
!             | LAST_P
                  {
                      FetchStmt *n = makeNode(FetchStmt);
                      n->direction = FETCH_ABSOLUTE;
                      n->howMany = -1;
                      $$ = (Node *)n;
                  }
!             | ABSOLUTE_P SignedIconst
                  {
                      FetchStmt *n = makeNode(FetchStmt);
                      n->direction = FETCH_ABSOLUTE;
                      n->howMany = $2;
                      $$ = (Node *)n;
                  }
!             | RELATIVE_P SignedIconst
                  {
                      FetchStmt *n = makeNode(FetchStmt);
                      n->direction = FETCH_RELATIVE;
                      n->howMany = $2;
                      $$ = (Node *)n;
                  }
!             | SignedIconst
                  {
                      FetchStmt *n = makeNode(FetchStmt);
                      n->direction = FETCH_FORWARD;
                      n->howMany = $1;
                      $$ = (Node *)n;
                  }
!             | ALL
                  {
                      FetchStmt *n = makeNode(FetchStmt);
                      n->direction = FETCH_FORWARD;
                      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);
                      n->direction = FETCH_FORWARD;
                      n->howMany = $2;
                      $$ = (Node *)n;
                  }
!             | FORWARD ALL
                  {
                      FetchStmt *n = makeNode(FetchStmt);
                      n->direction = FETCH_FORWARD;
                      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);
                      n->direction = FETCH_BACKWARD;
                      n->howMany = $2;
                      $$ = (Node *)n;
                  }
!             | BACKWARD ALL
                  {
                      FetchStmt *n = makeNode(FetchStmt);
                      n->direction = FETCH_BACKWARD;
                      n->howMany = FETCH_ALL;
                      $$ = (Node *)n;
--- 4082,4226 ----
   *
   *****************************************************************************/

! FetchStmt:    FETCH fetch_args
                  {
                      FetchStmt *n = (FetchStmt *) $2;
                      n->ismove = FALSE;
                      $$ = (Node *)n;
                  }
!             | MOVE fetch_args
                  {
                      FetchStmt *n = (FetchStmt *) $2;
                      n->ismove = TRUE;
                      $$ = (Node *)n;
                  }
!         ;
!
! fetch_args:
!             cursor_name
                  {
                      FetchStmt *n = makeNode(FetchStmt);
+                     n->portalname = $1;
                      n->direction = FETCH_FORWARD;
                      n->howMany = 1;
                      $$ = (Node *)n;
                  }
!             | from_in cursor_name
                  {
                      FetchStmt *n = makeNode(FetchStmt);
+                     n->portalname = $2;
                      n->direction = FETCH_FORWARD;
                      n->howMany = 1;
                      $$ = (Node *)n;
                  }
!             | NEXT opt_from_in cursor_name
                  {
                      FetchStmt *n = makeNode(FetchStmt);
+                     n->portalname = $3;
                      n->direction = FETCH_FORWARD;
                      n->howMany = 1;
                      $$ = (Node *)n;
                  }
!             | PRIOR opt_from_in cursor_name
                  {
                      FetchStmt *n = makeNode(FetchStmt);
+                     n->portalname = $3;
                      n->direction = FETCH_BACKWARD;
                      n->howMany = 1;
                      $$ = (Node *)n;
                  }
!             | FIRST_P opt_from_in cursor_name
                  {
                      FetchStmt *n = makeNode(FetchStmt);
+                     n->portalname = $3;
                      n->direction = FETCH_ABSOLUTE;
                      n->howMany = 1;
                      $$ = (Node *)n;
                  }
!             | LAST_P opt_from_in cursor_name
                  {
                      FetchStmt *n = makeNode(FetchStmt);
+                     n->portalname = $3;
                      n->direction = FETCH_ABSOLUTE;
                      n->howMany = -1;
                      $$ = (Node *)n;
                  }
!             | ABSOLUTE_P SignedIconst opt_from_in cursor_name
                  {
                      FetchStmt *n = makeNode(FetchStmt);
+                     n->portalname = $4;
                      n->direction = FETCH_ABSOLUTE;
                      n->howMany = $2;
                      $$ = (Node *)n;
                  }
!             | RELATIVE_P SignedIconst opt_from_in cursor_name
                  {
                      FetchStmt *n = makeNode(FetchStmt);
+                     n->portalname = $4;
                      n->direction = FETCH_RELATIVE;
                      n->howMany = $2;
                      $$ = (Node *)n;
                  }
!             | SignedIconst opt_from_in cursor_name
                  {
                      FetchStmt *n = makeNode(FetchStmt);
+                     n->portalname = $3;
                      n->direction = FETCH_FORWARD;
                      n->howMany = $1;
                      $$ = (Node *)n;
                  }
!             | ALL opt_from_in cursor_name
                  {
                      FetchStmt *n = makeNode(FetchStmt);
+                     n->portalname = $3;
                      n->direction = FETCH_FORWARD;
                      n->howMany = FETCH_ALL;
                      $$ = (Node *)n;
                  }
!             | FORWARD opt_from_in cursor_name
                  {
                      FetchStmt *n = makeNode(FetchStmt);
+                     n->portalname = $3;
                      n->direction = FETCH_FORWARD;
                      n->howMany = 1;
                      $$ = (Node *)n;
                  }
!             | FORWARD SignedIconst opt_from_in cursor_name
                  {
                      FetchStmt *n = makeNode(FetchStmt);
+                     n->portalname = $4;
                      n->direction = FETCH_FORWARD;
                      n->howMany = $2;
                      $$ = (Node *)n;
                  }
!             | FORWARD ALL opt_from_in cursor_name
                  {
                      FetchStmt *n = makeNode(FetchStmt);
+                     n->portalname = $4;
                      n->direction = FETCH_FORWARD;
                      n->howMany = FETCH_ALL;
                      $$ = (Node *)n;
                  }
!             | BACKWARD opt_from_in cursor_name
                  {
                      FetchStmt *n = makeNode(FetchStmt);
+                     n->portalname = $3;
                      n->direction = FETCH_BACKWARD;
                      n->howMany = 1;
                      $$ = (Node *)n;
                  }
!             | BACKWARD SignedIconst opt_from_in cursor_name
                  {
                      FetchStmt *n = makeNode(FetchStmt);
+                     n->portalname = $4;
                      n->direction = FETCH_BACKWARD;
                      n->howMany = $2;
                      $$ = (Node *)n;
                  }
!             | BACKWARD ALL opt_from_in cursor_name
                  {
                      FetchStmt *n = makeNode(FetchStmt);
+                     n->portalname = $4;
                      n->direction = FETCH_BACKWARD;
                      n->howMany = FETCH_ALL;
                      $$ = (Node *)n;
*************** from_in:    FROM                                    {}
*** 4228,4233 ****
--- 4231,4241 ----
              | IN_P                                    {}
          ;

+ opt_from_in:    FROM                                    {}
+             | IN_P                                    {}
+             | /* EMPTY */                                {}
+         ;
+

  /*****************************************************************************
   *
*************** set_target_list:
*** 6847,6853 ****
   *                CURSOR STATEMENTS
   *
   *****************************************************************************/
! DeclareCursorStmt: DECLARE name cursor_options CURSOR opt_hold FOR SelectStmt
                  {
                      DeclareCursorStmt *n = makeNode(DeclareCursorStmt);
                      n->portalname = $2;
--- 6855,6861 ----
   *                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 ****
--- 6866,6874 ----
                  }
          ;

+ 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 pgsql.orig/src/interfaces/ecpg/preproc/ecpg.addons pgsql/src/interfaces/ecpg/preproc/ecpg.addons
*** pgsql.orig/src/interfaces/ecpg/preproc/ecpg.addons    2009-01-30 17:28:46.000000000 +0100
--- pgsql/src/interfaces/ecpg/preproc/ecpg.addons    2009-08-09 19:50:07.000000000 +0200
*************** ECPG: ConstraintAttributeSpecConstraintT
*** 206,226 ****
              if (strcmp($2, "deferrable") != 0 && strcmp($1, "initially deferrable") == 0 )
                  mmerror(PARSE_ERROR, ET_ERROR, "constraint declared INITIALLY DEFERRED must be DEFERRABLE");
  ECPG: var_valueNumericOnly addon
- ECPG: fetch_directionSignedIconst addon
          if ($1[0] == '$')
          {
              free($1);
              $1 = make_str("$0");
          }
! ECPG: fetch_directionABSOLUTE_PSignedIconst addon
! ECPG: fetch_directionRELATIVE_PSignedIconst addon
! ECPG: fetch_directionFORWARDSignedIconst addon
! ECPG: fetch_directionBACKWARDSignedIconst addon
          if ($2[0] == '$')
          {
              free($2);
              $2 = make_str("$0");
          }
  ECPG: PrepareStmtPREPAREprepared_nameprep_type_clauseASPreparableStmt block
      {
          $$.name = $2;
--- 206,287 ----
              if (strcmp($2, "deferrable") != 0 && strcmp($1, "initially deferrable") == 0 )
                  mmerror(PARSE_ERROR, ET_ERROR, "constraint declared INITIALLY DEFERRED must be DEFERRABLE");
  ECPG: var_valueNumericOnly addon
          if ($1[0] == '$')
          {
              free($1);
              $1 = make_str("$0");
          }
! ECPG: fetch_argscursor_name addon
!         current_cursor = mm_strdup($1);
!         if ($1[0] == ':')
!         {
!             free($1);
!             $1 = make_str("$0");
!         }
! ECPG: fetch_argsfrom_incursor_name addon
!         current_cursor = mm_strdup($2);
!         if ($2[0] == ':')
!         {
!             free($2);
!             $2 = make_str("$0");
!         }
! ECPG: fetch_argsNEXTopt_from_incursor_name addon
! ECPG: fetch_argsPRIORopt_from_incursor_name addon
! ECPG: fetch_argsFIRST_Popt_from_incursor_name addon
! ECPG: fetch_argsLAST_Popt_from_incursor_name addon
! ECPG: fetch_argsALLopt_from_incursor_name addon
! ECPG: fetch_argsFORWARDopt_from_incursor_name addon
! ECPG: fetch_argsBACKWARDopt_from_incursor_name addon
!         current_cursor = mm_strdup($3);
!         if ($3[0] == ':')
!         {
!             free($3);
!             $3 = make_str("$0");
!         }
! ECPG: fetch_argsSignedIconstopt_from_incursor_name addon
!         if ($1[0] == '$')
!         {
!             free($1);
!             $1 = make_str("$0");
!         }
!         current_cursor = mm_strdup($3);
!         if ($3[0] == ':')
!         {
!             free($3);
!             $3 = make_str("$0");
!         }
! ECPG: fetch_argsFORWARDALLopt_from_incursor_name addon
! ECPG: fetch_argsBACKWARDALLopt_from_incursor_name addon
!         current_cursor = mm_strdup($4);
!         if ($4[0] == ':')
!         {
!             free($4);
!             $4 = make_str("$0");
!         }
! ECPG: fetch_argsABSOLUTE_PSignedIconstopt_from_incursor_name addon
! ECPG: fetch_argsRELATIVE_PSignedIconstopt_from_incursor_name addon
! ECPG: fetch_argsFORWARDSignedIconstopt_from_incursor_name addon
! ECPG: fetch_argsBACKWARDSignedIconstopt_from_incursor_name addon
          if ($2[0] == '$')
          {
              free($2);
              $2 = make_str("$0");
          }
+         current_cursor = mm_strdup($4);
+         if ($4[0] == ':')
+         {
+             free($4);
+             $4 = 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)
          {
--- 296,305 ----
      }
  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;
--- 313,319 ----
          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 ****
--- 324,334 ----
          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,372 ****
          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)
              mmerror(PARSE_ERROR, ET_ERROR, "OLD used in query that is not in a rule");
--- 393,412 ----
          mmerror(PARSE_ERROR, ET_ERROR, "SHOW ALL is not implemented");
          $$ = EMPTY;
      }
! ECPG: FetchStmtFETCHfetch_args block
      {
!         add_additional_variables(current_cursor, false);
!         free(current_cursor);
!         current_cursor = NULL;
!         $$ = cat2_str(2, make_str("fetch"), $2);
      }
! ECPG: FetchStmtMOVEfetch_args block
      {
!         add_additional_variables(current_cursor, false);
!         free(current_cursor);
!         current_cursor = NULL;
!         $$ = cat2_str(2, make_str("move"), $2);
      }
  ECPG: SpecialRuleRelationOLD addon
          if (!QueryIsRule)
              mmerror(PARSE_ERROR, ET_ERROR, "OLD used in query that is not in a rule");
diff -dcrpN pgsql.orig/src/interfaces/ecpg/preproc/ecpg.c pgsql/src/interfaces/ecpg/preproc/ecpg.c
*** pgsql.orig/src/interfaces/ecpg/preproc/ecpg.c    2009-08-07 13:06:28.000000000 +0200
--- pgsql/src/interfaces/ecpg/preproc/ecpg.c    2009-08-09 18:13:08.000000000 +0200
*************** enum COMPAT_MODE compat = ECPG_COMPAT_PG
*** 26,31 ****
--- 26,32 ----

  struct _include_path *include_paths = NULL;
  struct cursor *cur = NULL;
+ char *current_cursor = NULL;
  struct typedefs *types = NULL;
  struct _defines *defines = NULL;

diff -dcrpN pgsql.orig/src/interfaces/ecpg/preproc/ecpg.trailer pgsql/src/interfaces/ecpg/preproc/ecpg.trailer
*** pgsql.orig/src/interfaces/ecpg/preproc/ecpg.trailer    2009-08-07 13:06:28.000000000 +0200
--- pgsql/src/interfaces/ecpg/preproc/ecpg.trailer    2009-08-09 15:42:06.000000000 +0200
*************** prepared_name: name             {
*** 285,293 ****
   * 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";

--- 285,294 ----
   * 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
*** 304,310 ****
              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;
--- 305,311 ----
              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
*** 314,319 ****
--- 315,326 ----
              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; }
*** 954,960 ****
  /*
   * 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; }
--- 961,976 ----
  /*
   * 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
*** 1779,1784 ****
--- 1795,1807 ----
          }
          ;

+ 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 pgsql.orig/src/interfaces/ecpg/preproc/ecpg.type pgsql/src/interfaces/ecpg/preproc/ecpg.type
*** pgsql.orig/src/interfaces/ecpg/preproc/ecpg.type    2008-11-14 11:03:33.000000000 +0100
--- pgsql/src/interfaces/ecpg/preproc/ecpg.type    2009-08-09 15:42:06.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 pgsql.orig/src/interfaces/ecpg/preproc/extern.h pgsql/src/interfaces/ecpg/preproc/extern.h
*** pgsql.orig/src/interfaces/ecpg/preproc/extern.h    2009-07-17 07:50:56.000000000 +0200
--- pgsql/src/interfaces/ecpg/preproc/extern.h    2009-08-09 18:13:31.000000000 +0200
*************** extern char *output_filename;
*** 47,52 ****
--- 47,53 ----

  extern struct _include_path *include_paths;
  extern struct cursor *cur;
+ extern char *current_cursor;
  extern struct typedefs *types;
  extern struct _defines *defines;
  extern struct ECPGtype ecpg_no_indicator;
*************** extern struct descriptor *lookup_descrip
*** 91,96 ****
--- 92,98 ----
  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 pgsql.orig/src/interfaces/ecpg/preproc/parse.pl pgsql/src/interfaces/ecpg/preproc/parse.pl
*** pgsql.orig/src/interfaces/ecpg/preproc/parse.pl    2009-01-30 17:28:46.000000000 +0100
--- pgsql/src/interfaces/ecpg/preproc/parse.pl    2009-08-09 17:53:11.000000000 +0200
*************** $replace_types{'unreserved_keyword'} = '
*** 57,63 ****
  $replace_types{'Sconst'} = 'ignore';

  # some production rules have to be ignored or replaced
! $replace_line{'fetch_direction'} = 'ignore';
  $replace_line{"opt_array_boundsopt_array_bounds'['Iconst']'"} = 'ignore';
  $replace_line{'col_name_keywordCHAR_P'} = 'ignore';
  $replace_line{'col_name_keywordINT_P'} = 'ignore';
--- 57,63 ----
  $replace_types{'Sconst'} = 'ignore';

  # some production rules have to be ignored or replaced
! $replace_line{'fetch_args'} = 'ignore';
  $replace_line{"opt_array_boundsopt_array_bounds'['Iconst']'"} = 'ignore';
  $replace_line{'col_name_keywordCHAR_P'} = 'ignore';
  $replace_line{'col_name_keywordINT_P'} = 'ignore';
diff -dcrpN pgsql.orig/src/interfaces/ecpg/preproc/variable.c pgsql/src/interfaces/ecpg/preproc/variable.c
*** pgsql.orig/src/interfaces/ecpg/preproc/variable.c    2009-08-07 13:06:28.000000000 +0200
--- pgsql/src/interfaces/ecpg/preproc/variable.c    2009-08-09 15:42:06.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.

Re: Split-up ECPG patches

From
"Albe Laurenz"
Date:
Tom Lane wrote:
>>> So I'd like to see an actual case made
>>> that there's a strong reason for not requiring FROM/IN in ecpg.
>>
>> I guess there's only one, compatibility.
>
> Yeah.  Are there any other precompilers that actively reject FROM/IN
> here?  If we're just a bit more strict than they are, it's not as bad
> as if there is no common syntax subset.

Oracle:

http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28427/pc_afemb.htm#i9340

Yours,
Laurenz Albe


Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Boszormenyi Zoltan írta:
> OK, here's the WIP patch for the unified core/ecpg grammar,
> with opt_from_in. But I am still getting the 2 shift/reduce
> conflicts exactly for the FORWARD and BACKWARD rules
> that I was getting originally. Can you look at this patch and
> point me to the right direction in solving it? Thanks in advance.

Okay, I seem to start to succeed with the following strategy.
In ECPG, there's the possibility to ignore certain rules.
I just added these two lines to parse.pl:

$replace_line{'fetch_argsFORWARDopt_from_incursor_name'} = 'ignore';
$replace_line{'fetch_argsBACKWARDopt_from_incursor_name'} = 'ignore';

And I needed to pull up these into FetchStmt as:
    FETCH fetch_args FORWARD cursor_name
    FETCH fetch_args FORWARD from_in cursor_name
    FETCH fetch_args BACKWARD cursor_name
    FETCH fetch_args BACKWARD from_in cursor_name
    MOVE fetch_args FORWARD cursor_name
    MOVE fetch_args FORWARD from_in cursor_name
    MOVE fetch_args BACKWARD cursor_name
    MOVE fetch_args BACKWARD from_in cursor_name

But I have the following problem. When this is in ecpg.addon:
===============================
...
ECPG: FetchStmtFETCHfetch_args addon
ECPG: FetchStmtMOVEfetch_args addon
                add_additional_variables(current_cursor, false);
                free(current_cursor);
                current_cursor = NULL;
...
ECPG: FetchStmtMOVEfetch_args rule
        | FETCH fetch_args ecpg_into
        {
                add_additional_variables(current_cursor, false);
                free(current_cursor);
                current_cursor = NULL;
                $$ = cat2_str(make_str("fetch"), $2);
        }
...
===============================

After running parse.pl, I get this in preproc.y for FetchStmt:

===============================
  FetchStmt:
 FETCH fetch_args
 {
                add_additional_variables(current_cursor, false);
                free(current_cursor);
                current_cursor = NULL;

 $$ = cat_str(2,make_str("fetch"),$2);
}
|  MOVE fetch_args
 {
                add_additional_variables(current_cursor, false);
                free(current_cursor);
                current_cursor = NULL;
 { // THIS IS AN EXTRA "{"
 $$ = cat_str(2,make_str("move"),$2);
}
...
===============================

With this code, I can prevent the extra "{" emitted:

===============================
ECPG: FetchStmtMOVEfetch_args block
        {
                add_additional_variables(current_cursor, false);
                free(current_cursor);
                current_cursor = NULL;
                $$ = cat2_str(make_str("move"), $2);
        }
        | FETCH fetch_args ecpg_into
        {
                add_additional_variables(current_cursor, false);
                free(current_cursor);
                current_cursor = NULL;
                $$ = cat2_str(make_str("fetch"), $2);
        }
...
===============================

And it bothers me, it looks illegal, but at least ugly.

With the first code, if I delete that extra "{" manually,
preproc.y compiles fine, and "make check" in ecpg fails
only one test, and the "failure" is only in the generated source
as now there's no "from" emitted in the ECPG-created
statements where FROM or IN doesn't appear in the
*.pgc code, but the stdout/stderr results are the same
as what's expected. Michael, can you give me some help here?
The attached patch uses the second variation, at least it
produces usable preproc.y that compiles into what I wanted.

In the attached patch I added a regression test, as well.
Actually, two, but they are the same, one copy under preproc,
one copy under compat_informix, so the difference in
ECPG runs an be observed.

You had a comment in a previous mail: "Some variable
handling commands look suspicious to me, a test case
might alleviate my concerns." I suspect you meant
introducing remove_variable_from_list(). The regression
tesst may help me prove the usefulness of this function,
especially in the FETCH :count FROM :curname; where
multiple $0 references occur, or the PREPARED statement
cases, where the order of the parameters passed to ECPGdo()
would come out reversed, or the dynamic cursor name would
get duplicated in some other statements.

I also tried to test this new code with a varchar cursor,
you're right, it didn't work with cursor name in a varchar
variable. I fixed this case now, reflected in the regression test.

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/


Attachment

Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Boszormenyi Zoltan írta:
> But I have the following problem. When this is in ecpg.addon:
> ===============================
> ...
> ECPG: FetchStmtFETCHfetch_args addon
> ECPG: FetchStmtMOVEfetch_args addon
>                 add_additional_variables(current_cursor, false);
>                 free(current_cursor);
>                 current_cursor = NULL;
> ...
> ECPG: FetchStmtMOVEfetch_args rule
>         | FETCH fetch_args ecpg_into
>         {
>                 add_additional_variables(current_cursor, false);
>                 free(current_cursor);
>                 current_cursor = NULL;
>                 $$ = cat2_str(make_str("fetch"), $2);
>         }
> ...
> ===============================
>
> After running parse.pl, I get this in preproc.y for FetchStmt:
>
> ===============================
>   FetchStmt:
>  FETCH fetch_args
>  {
>                 add_additional_variables(current_cursor, false);
>                 free(current_cursor);
>                 current_cursor = NULL;
>
>  $$ = cat_str(2,make_str("fetch"),$2);
> }
> |  MOVE fetch_args
>  {
>                 add_additional_variables(current_cursor, false);
>                 free(current_cursor);
>                 current_cursor = NULL;
>  { // THIS IS AN EXTRA "{"
>  $$ = cat_str(2,make_str("move"),$2);
> }
> ...
> ===============================
>
> With this code, I can prevent the extra "{" emitted:
>
> ===============================
> ECPG: FetchStmtMOVEfetch_args block
>         {
>                 add_additional_variables(current_cursor, false);
>                 free(current_cursor);
>                 current_cursor = NULL;
>                 $$ = cat2_str(make_str("move"), $2);
>         }
>         | FETCH fetch_args ecpg_into
>         {
>                 add_additional_variables(current_cursor, false);
>                 free(current_cursor);
>                 current_cursor = NULL;
>                 $$ = cat2_str(make_str("fetch"), $2);
>         }
> ...
> ===============================
>

Any word on the above? If no, I can accept this construct being legal...

Anyway, I adapted the remaining two patches (SQLDA and
DESCRIBE) to the previously sent dynamic cursor code
and also added regression tests. Please, review.

Best regards,
Zoltán Böszörményi


--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/

diff -dcrpN pgsql/src/interfaces/ecpg/ecpglib/execute.c pgsql.sqlda/src/interfaces/ecpg/ecpglib/execute.c
*** pgsql/src/interfaces/ecpg/ecpglib/execute.c    2009-08-07 13:06:28.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/ecpglib/execute.c    2009-08-11 14:23:30.000000000 +0200
***************
*** 25,30 ****
--- 25,31 ----
  #include "ecpgerrno.h"
  #include "extern.h"
  #include "sqlca.h"
+ #include "sqlda.h"
  #include "sql3types.h"
  #include "pgtypes_numeric.h"
  #include "pgtypes_date.h"
*************** ecpg_store_input(const int lineno, const
*** 1033,1038 ****
--- 1034,1040 ----
                  break;

              case ECPGt_descriptor:
+             case ECPGt_sqlda:
                  break;

              default:
*************** ecpg_execute(struct statement * stmt)
*** 1172,1177 ****
--- 1174,1235 ----
              if (desc->count == desc_counter)
                  desc_counter = 0;
          }
+         else if (var->type == ECPGt_sqlda)
+         {
+             pg_sqlda_t      **_sqlda = (pg_sqlda_t **)var->pointer;
+             pg_sqlda_t       *sqlda = *_sqlda;
+             struct variable    desc_inlist;
+             int        i;
+
+             if (sqlda == NULL)
+                 return false;
+
+             desc_counter++;
+             for (i = 0; i < sqlda->sqld; i++)
+             {
+                 if (i + 1 == desc_counter)
+                 {
+                     desc_inlist.type = ecpg_sqlda_type(sqlda->sqlvar[i].sqltype);
+                     desc_inlist.value = sqlda->sqlvar[i].sqldata;
+                     desc_inlist.pointer = &(sqlda->sqlvar[i].sqldata);
+                     switch (desc_inlist.type)
+                     {
+                         case ECPGt_char:
+                         case ECPGt_varchar:
+                             desc_inlist.varcharsize = strlen(sqlda->sqlvar[i].sqldata);
+                             break;
+                         default:
+                             desc_inlist.varcharsize = 0;
+                             break;
+                     }
+                     desc_inlist.arrsize = 1;
+                     desc_inlist.offset = 0;
+                     if (sqlda->sqlvar[i].sqlind)
+                     {
+                         desc_inlist.ind_type = ECPGt_short;
+                         /* ECPG expects indicator value < 0 */
+                         if (*(sqlda->sqlvar[i].sqlind))
+                             *(sqlda->sqlvar[i].sqlind) = -1;
+                         desc_inlist.ind_value = sqlda->sqlvar[i].sqlind;
+                         desc_inlist.ind_pointer = &(sqlda->sqlvar[i].sqlind);
+                         desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = 1;
+                         desc_inlist.ind_offset = 0;
+                     }
+                     else
+                     {
+                         desc_inlist.ind_type = ECPGt_NO_INDICATOR;
+                         desc_inlist.ind_value = desc_inlist.ind_pointer = NULL;
+                         desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = desc_inlist.ind_offset = 0;
+                     }
+                     if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, &desc_inlist, &tobeinserted, false))
+                         return false;
+
+                     break;
+                 }
+             }
+             if (sqlda->sqld == desc_counter)
+                 desc_counter = 0;
+         }
          else
          {
              if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, var, &tobeinserted, false))
*************** ecpg_execute(struct statement * stmt)
*** 1353,1358 ****
--- 1411,1445 ----
                  }
                  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
+                 {
+                     status = ecpg_compare_sqlda_with_PGresult(sqlda, results);
+                     ecpg_log("ecpg_execute on line %d: called ecpg_compare_sqlda_with_PGresult, status %d\n",
+                             stmt->lineno, status);
+                 }
+
+                 if (status == true)
+                 {
+                     ecpg_set_sqlda_from_PGresult(stmt->lineno, _sqlda, results);
+                     ecpg_log("ecpg_execute on line %d: putting result (%d tuples) into sqlda descriptor\n",
+                             stmt->lineno, PQntuples(results));
+                 }
+
+                 var = var->next;
+             }
              else
                  for (act_field = 0; act_field < nfields && status; act_field++)
                  {
diff -dcrpN pgsql/src/interfaces/ecpg/ecpglib/extern.h pgsql.sqlda/src/interfaces/ecpg/ecpglib/extern.h
*** pgsql/src/interfaces/ecpg/ecpglib/extern.h    2009-05-25 12:08:48.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/ecpglib/extern.h    2009-08-11 10:32:34.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 pgsql/src/interfaces/ecpg/ecpglib/Makefile pgsql.sqlda/src/interfaces/ecpg/ecpglib/Makefile
*** pgsql/src/interfaces/ecpg/ecpglib/Makefile    2009-07-13 11:16:41.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/ecpglib/Makefile    2009-08-11 10:32:34.000000000 +0200
*************** override CFLAGS += $(PTHREAD_CFLAGS)
*** 24,30 ****
  # Need to recompile any libpgport object files
  LIBS := $(filter-out -lpgport, $(LIBS))

! OBJS= execute.o typename.o descriptor.o data.o error.o prepare.o memory.o \
      connect.o misc.o path.o pgstrcasecmp.o \
      $(filter snprintf.o strlcpy.o, $(LIBOBJS))

--- 24,30 ----
  # Need to recompile any libpgport object files
  LIBS := $(filter-out -lpgport, $(LIBS))

! OBJS= execute.o typename.o descriptor.o sqlda.o data.o error.o prepare.o memory.o \
      connect.o misc.o path.o pgstrcasecmp.o \
      $(filter snprintf.o strlcpy.o, $(LIBOBJS))

diff -dcrpN pgsql/src/interfaces/ecpg/ecpglib/sqlda.c pgsql.sqlda/src/interfaces/ecpg/ecpglib/sqlda.c
*** pgsql/src/interfaces/ecpg/ecpglib/sqlda.c    1970-01-01 01:00:00.000000000 +0100
--- pgsql.sqlda/src/interfaces/ecpg/ecpglib/sqlda.c    2009-08-11 17:41:47.000000000 +0200
***************
*** 0 ****
--- 1,300 ----
+ /*
+  * Crude SQLDA support routines
+  * Only supports fetching 1 record at a time
+  *
+  * The allocated memory area pointed by an sqlda pointer
+  * contains both the metadata and the data, so freeing up
+  * is a simple free(sqlda) as expected by the ESQL/C examples.
+  */
+
+ #define POSTGRES_ECPG_INTERNAL
+ #include "postgres_fe.h"
+ #include "pg_type.h"
+
+ #include <inttypes.h>
+ #include <dlfcn.h>
+
+ #include "ecpg-pthread-win32.h"
+ #include "decimal.h"
+ #include "ecpgtype.h"
+ #include "ecpglib.h"
+ #include "ecpgerrno.h"
+ #include "extern.h"
+ #include "sqlca.h"
+ #include "sqlda.h"
+ #include "sqltypes.h"
+
+ /*
+  * 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))
+     {
+         ecpg_log("ecpg_compare_sqlda_with_PGresult: sqld differ %d %d\n",
+                                                 sqlda->sqld, PQnfields(res));
+         return false;
+     }
+
+     for (i = 0; i < sqlda->sqld; i++)
+     {
+         if (sqlda->sqlvar[i].sqltype != ecpg_to_sqlda_type(PQftype(res, i)))
+         {
+             ecpg_log("ecpg_compare_sqlda_with_PGresult: field %d sqltype differ %d %d\n",
+                     i, sqlda->sqlvar[i].sqltype, ecpg_to_sqlda_type(PQftype(res, i)));
+             return false;
+         }
+         if (strcmp(sqlda->sqlvar[i].sqlname, PQfname(res, i)))
+         {
+             ecpg_log("ecpg_compare_sqlda_with_PGresult: field %d sqlname differ '%s' '%s'\n",
+                     i, sqlda->sqlvar[i].sqlname, PQfname(res, i));
+             return false;
+         }
+         if (sqlda->sqlvar[i].sqlformat != (char *)(long)PQfformat(res, i))
+         {
+             ecpg_log("ecpg_compare_sqlda_with_PGresult: field %d sqlformat differ %d %d\n",
+                     i, sqlda->sqlvar[i].sqlformat, PQfformat(res, i));
+             return false;
+         }
+         if (sqlda->sqlvar[i].sqlxid != PQftype(res, i))
+         {
+             ecpg_log("ecpg_compare_sqlda_with_PGresult: field %d sqlxid differ %d %d\n",
+                     i, sqlda->sqlvar[i].sqlxid, PQftype(res, i));
+             return false;
+         }
+         if (sqlda->sqlvar[i].sqltypelen != PQfsize(res, i))
+         {
+             ecpg_log("ecpg_compare_sqlda_with_PGresult: field %d sqltypelen differ %d %d\n",
+                     i, 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++)
+     {
+         int type = -1, isnull;
+         int use_getdata = true;
+
+         switch (sqlda->sqlvar[i].sqltype)
+         {
+             case SQLSMINT:
+                 size = ecpg_sqlda_size_align(size, sizeof(short));
+                 sqlda->sqlvar[i].sqldata = (char *)sqlda + size;
+                 size += sizeof(short);
+                 type = ECPGt_short;
+                 break;
+             case SQLINT:
+             case SQLSERIAL:
+                 size = ecpg_sqlda_size_align(size, sizeof(int));
+                 sqlda->sqlvar[i].sqldata = (char *)sqlda + size;
+                 size += sizeof(int);
+                 type = ECPGt_int;
+                 break;
+             case SQLFLOAT:
+                 size = ecpg_sqlda_size_align(size, sizeof(double));
+                 sqlda->sqlvar[i].sqldata = (char *)sqlda + size;
+                 size += sizeof(double);
+                 type = ECPGt_double;
+                 break;
+             case SQLSMFLOAT:
+                 size = ecpg_sqlda_size_align(size, sizeof(float));
+                 sqlda->sqlvar[i].sqldata = (char *)sqlda + size;
+                 size += sizeof(float);
+                 type = ECPGt_float;
+                 break;
+             case SQLDECIMAL:
+             {
+                 size = ecpg_sqlda_size_align(size, sizeof(int));
+                 sqlda->sqlvar[i].sqldata = (char *)sqlda + size;
+                 size += sizeof(decimal);
+                 type = ECPGt_decimal;
+                 break;
+             }
+             case SQLINT8:
+             case SQLSERIAL8:
+                 size = ecpg_sqlda_size_align(size, sizeof(int64_t));
+                 sqlda->sqlvar[i].sqldata = (char *)sqlda + size;
+                 size += sizeof(int64_t);
+                 type = ECPGt_long_long;
+                 break;
+
+             /*
+              * These types will be passed as character strings until
+              * it's known what to do with them. We use sqlvar->sqldata
+              * in all cases regardless of length, don't care about
+              * sqlvar->sqlilongdata.
+              */
+             case SQLCHAR:
+             case SQLTEXT:
+             case SQLVCHAR:
+             case SQLNCHAR:
+             case SQLNVCHAR:
+             case SQLMONEY:
+             case SQLDATE:
+             case SQLDTIME:
+             case SQLINTERVAL:
+             default:
+                 use_getdata = false;
+                 break;
+         }
+
+         isnull = PQgetisnull(res, 0, i);
+         sqlda->sqlvar[i].sqlind = isnull ? &value_is_null : &value_is_not_null;
+         if (!isnull)
+         {
+             if (use_getdata)
+                 ecpg_get_data(res, 0, i, lineno,
+                         type, ECPGt_NO_INDICATOR,
+                         sqlda->sqlvar[i].sqldata, NULL, 0, 0, 0,
+                         ECPG_ARRAY_NONE, ECPG_COMPAT_INFORMIX, false);
+             else
+                 sqlda->sqlvar[i].sqldata = PQgetvalue(res, 0, i);
+         }
+     }
+ }
diff -dcrpN pgsql/src/interfaces/ecpg/ecpglib/typename.c pgsql.sqlda/src/interfaces/ecpg/ecpglib/typename.c
*** pgsql/src/interfaces/ecpg/ecpglib/typename.c    2009-08-07 13:06:28.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/ecpglib/typename.c    2009-08-11 10:32:34.000000000 +0200
***************
*** 7,12 ****
--- 7,13 ----
  #include "ecpgtype.h"
  #include "ecpglib.h"
  #include "extern.h"
+ #include "sqltypes.h"
  #include "sql3types.h"
  #include "pg_type.h"

*************** ecpg_dynamic_type(Oid type)
*** 100,102 ****
--- 101,190 ----
              return -(int) type;
      }
  }
+
+ int
+ ecpg_sqlda_type(int type)
+ {
+     switch (type)
+     {
+         case SQLCHAR:
+         case SQLNCHAR:
+             return ECPGt_char;
+         case SQLSMINT:
+             return ECPGt_short;
+         case SQLINT:
+             return ECPGt_int;
+         case SQLFLOAT:
+             return ECPGt_double;
+         case SQLSMFLOAT:
+             return ECPGt_float;
+         case SQLDECIMAL:
+             return ECPGt_decimal;
+         case SQLSERIAL:
+             return ECPGt_int;
+         case SQLDATE:
+             return ECPGt_date;
+ #if 0
+         case SQLMONEY:
+             return ???;
+         case SQLNULL:
+             return ???;
+ #endif
+         case SQLDTIME:
+             return ECPGt_timestamp;
+ #if 0
+         case SQLBYTES:
+             return ???;
+ #endif
+         case SQLTEXT:
+             return ECPGt_char;
+         case SQLVCHAR:
+         case SQLNVCHAR:
+             return ECPGt_varchar;
+         case SQLINTERVAL:
+             return ECPGt_interval;
+         case SQLINT8:
+         case SQLSERIAL8:
+             return ECPGt_long_long;
+         default:
+             return (-type);
+     }
+ }
+
+ int
+ ecpg_to_sqlda_type(Oid type)
+ {
+     switch (type)
+     {
+         case CHAROID:
+         case BPCHAROID:
+             return SQLCHAR;
+         case INT2OID:
+             return SQLSMINT;
+         case INT4OID:
+             return SQLINT;
+         case FLOAT8OID:
+             return SQLFLOAT;
+         case FLOAT4OID:
+             return SQLSMFLOAT;
+         case NUMERICOID:
+             return SQLDECIMAL;
+         case DATEOID:
+             return SQLDATE;
+         case CASHOID:
+             return SQLMONEY;
+         case TIMESTAMPOID:
+         case TIMESTAMPTZOID:
+             return SQLDTIME;
+         case TEXTOID:
+             return SQLTEXT;
+         case VARCHAROID:
+             return SQLVCHAR;
+         case INTERVALOID:
+             return SQLINTERVAL;
+         case INT8OID:
+             return SQLINT8;
+         default:
+             return (-type);
+     }
+ }
diff -dcrpN pgsql/src/interfaces/ecpg/include/ecpgtype.h pgsql.sqlda/src/interfaces/ecpg/include/ecpgtype.h
*** pgsql/src/interfaces/ecpg/include/ecpgtype.h    2009-08-07 13:06:28.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/include/ecpgtype.h    2009-08-11 10:34:24.000000000 +0200
*************** enum ECPGttype
*** 62,68 ****
      ECPGt_EOIT,                    /* End of insert types. */
      ECPGt_EORT,                    /* End of result types. */
      ECPGt_NO_INDICATOR,            /* no indicator */
!     ECPGt_string                            /* trimmed (char *) type */
  };

   /* descriptor items */
--- 62,69 ----
      ECPGt_EOIT,                    /* End of insert types. */
      ECPGt_EORT,                    /* End of result types. */
      ECPGt_NO_INDICATOR,            /* no indicator */
!     ECPGt_string,                /* trimmed (char *) type */
!     ECPGt_sqlda                /* C struct descriptor */
  };

   /* descriptor items */
diff -dcrpN pgsql/src/interfaces/ecpg/include/sqlda.h pgsql.sqlda/src/interfaces/ecpg/include/sqlda.h
*** pgsql/src/interfaces/ecpg/include/sqlda.h    2009-06-13 18:25:05.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/include/sqlda.h    2009-08-11 10:32:34.000000000 +0200
***************
*** 1,3 ****
--- 1,74 ----
  /*
   * $PostgreSQL: pgsql/src/interfaces/ecpg/include/sqlda.h,v 1.4 2009/06/11 14:49:13 momjian Exp $
   */
+
+ #ifndef POSTGRES_SQLDA_H
+ #define POSTGRES_SQLDA_H
+
+ /* Define Informix "standard" types */
+ #ifndef C_H
+ typedef int        int4;
+ typedef    short        int2;
+ #endif
+ typedef    char        int1;
+
+ typedef    int        mint;
+ typedef    long        mlong;
+
+ typedef    short        MSHORT;
+ typedef    char        MCHAR;
+
+ typedef    unsigned int    uint4;
+ typedef    unsigned short    uint2;
+ typedef    unsigned char    uint1;
+
+ typedef    unsigned int    muint;
+ typedef    unsigned long    mulong;
+
+ typedef    unsigned short    MUSHORT;
+ typedef    unsigned char    MUCHAR;
+
+ #define MI_INT_SIZE     (sizeof(int)    * 8)
+ #define MI_LONG_SIZE    (sizeof(long)   * 8)
+ #define MI_PTR_SIZE     (sizeof(char *) * 8)
+
+ typedef struct sqlvar_struct
+ {
+     int2    sqltype;        /* variable type                */
+     int4    sqllen;            /* length in bytes              */
+     char       *sqldata;        /* pointer to data              */
+     int2       *sqlind;        /* pointer to indicator         */
+     char       *sqlname;        /* variable name                */
+     char       *sqlformat;        /* reserved for future use      */
+     int2    sqlitype;        /* ind variable type            */
+     int2    sqlilen;        /* ind length in bytes          */
+     char       *sqlidata;        /* ind data pointer             */
+     int4    sqlxid;            /* extended id type             */
+     char       *sqltypename;    /* extended type name           */
+     int2    sqltypelen;        /* length of extended type name */
+     int2    sqlownerlen;        /* length of owner name         */
+     int2    sqlsourcetype;        /* source type for distinct of built-ins */
+     char       *sqlownername;    /* owner name                   */
+     int4    sqlsourceid;        /* extended id of source type   */
+
+     /*
+      * sqlilongdata is new.  It supports data that exceeds the 32k
+      * limit.  sqlilen and sqlidata are for backward compatibility
+      * and they have maximum value of <32K.
+      */
+     char       *sqlilongdata;    /* for data field beyond 32K    */
+     int4    sqlflags;        /* for internal use only        */
+     void       *sqlreserved;    /* reserved for future use      */
+ } pg_sqlvar_t;
+
+ typedef struct sqlda
+ {
+     int2        sqld;
+     pg_sqlvar_t       *sqlvar;
+     char        desc_name[19];    /* descriptor name              */
+     int2        desc_occ;    /* size of sqlda structure      */
+     struct sqlda       *desc_next;    /* pointer to next sqlda struct */
+     void           *reserved;    /* reserved for future use */
+ } pg_sqlda_t;
+
+ #endif /* POSTGRES_SQLDA_H */
diff -dcrpN pgsql/src/interfaces/ecpg/include/sqltypes.h pgsql.sqlda/src/interfaces/ecpg/include/sqltypes.h
*** pgsql/src/interfaces/ecpg/include/sqltypes.h    2009-06-13 18:25:05.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/include/sqltypes.h    2009-08-11 10:32:34.000000000 +0200
***************
*** 30,33 ****
--- 30,55 ----
  #define CLVCHARPTRTYPE    124
  #define CTYPEMAX    25

+ /*
+  * Values used in sqlda->sqlvar[i]->sqltype
+  */
+ #define    SQLCHAR        0
+ #define    SQLSMINT    1
+ #define    SQLINT        2
+ #define    SQLFLOAT    3
+ #define    SQLSMFLOAT    4
+ #define    SQLDECIMAL    5
+ #define    SQLSERIAL    6
+ #define    SQLDATE        7
+ #define    SQLMONEY    8
+ #define    SQLDTIME    10
+ #define    SQLBYTES    11
+ #define    SQLTEXT        12
+ #define    SQLVCHAR    13
+ #define    SQLINTERVAL    14
+ #define    SQLNCHAR    15
+ #define    SQLNVCHAR    16
+ #define    SQLINT8        17
+ #define    SQLSERIAL8    18
+
  #endif   /* ndef ECPG_SQLTYPES_H */
diff -dcrpN pgsql/src/interfaces/ecpg/preproc/descriptor.c pgsql.sqlda/src/interfaces/ecpg/preproc/descriptor.c
*** pgsql/src/interfaces/ecpg/preproc/descriptor.c    2009-01-30 17:28:46.000000000 +0100
--- pgsql.sqlda/src/interfaces/ecpg/preproc/descriptor.c    2009-08-11 10:32:34.000000000 +0200
*************** descriptor_variable(const char *name, in
*** 326,328 ****
--- 326,347 ----
      strlcpy(descriptor_names[input], name, sizeof(descriptor_names[input]));
      return (struct variable *) & varspace[input];
  }
+
+ struct variable *
+ sqlda_variable(const char *name)
+ {
+     struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable));
+
+     p->name = mm_strdup(name);
+     p->type = (struct ECPGtype *) mm_alloc(sizeof(struct ECPGtype));
+     p->type->type = ECPGt_sqlda;
+     p->type->size = NULL;
+     p->type->struct_sizeof = NULL;
+     p->type->u.element = NULL;
+     p->type->lineno = 0;
+     p->brace_level = 0;
+     p->next = NULL;
+
+     return p;
+ }
+
diff -dcrpN pgsql/src/interfaces/ecpg/preproc/ecpg.addons pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.addons
*** pgsql/src/interfaces/ecpg/preproc/ecpg.addons    2009-08-10 15:18:04.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.addons    2009-08-11 10:42:00.000000000 +0200
*************** ECPG: FetchStmtMOVEfetch_args block
*** 405,424 ****
          current_cursor = NULL;
          $$ = cat2_str(make_str("move"), $2);
      }
!     | FETCH fetch_args ecpg_into
      {
          add_additional_variables(current_cursor, false);
          free(current_cursor);
          current_cursor = NULL;
          $$ = cat2_str(make_str("fetch"), $2);
      }
!     | FETCH FORWARD cursor_name opt_ecpg_into
      {
          char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3;
          add_additional_variables($3, false);
          $$ = cat_str(2, make_str("fetch forward"), cursor_marker);
      }
!     | FETCH FORWARD from_in cursor_name opt_ecpg_into
      {
          char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4;
          add_additional_variables($4, false);
--- 405,424 ----
          current_cursor = NULL;
          $$ = cat2_str(make_str("move"), $2);
      }
!     | FETCH fetch_args ecpg_fetch_into
      {
          add_additional_variables(current_cursor, false);
          free(current_cursor);
          current_cursor = NULL;
          $$ = cat2_str(make_str("fetch"), $2);
      }
!     | FETCH FORWARD cursor_name opt_ecpg_fetch_into
      {
          char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3;
          add_additional_variables($3, false);
          $$ = cat_str(2, make_str("fetch forward"), cursor_marker);
      }
!     | FETCH FORWARD from_in cursor_name opt_ecpg_fetch_into
      {
          char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4;
          add_additional_variables($4, false);
diff -dcrpN pgsql/src/interfaces/ecpg/preproc/ecpg.trailer pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.trailer
*** pgsql/src/interfaces/ecpg/preproc/ecpg.trailer    2009-08-10 18:01:47.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.trailer    2009-08-11 10:41:02.000000000 +0200
*************** ecpg_using:    USING using_list     { $$ = EMP
*** 1014,1032 ****

  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;

--- 1014,1062 ----

  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;
*** 2050,2057 ****
      ;


! opt_ecpg_into:    /* EMPTY */    { $$ = EMPTY; }
!     | ecpg_into        { $$ = $1; }

  %%

--- 2080,2103 ----
      ;


! ecpg_fetch_into: ecpg_into    { $$ = $1; }
!     | using_descriptor
!     {
!         struct variable *var;
!
!         if (!INFORMIX_MODE)
!             mmerror(PARSE_ERROR, ET_ERROR, "Not in Informix compatibility mode");
!
!         var = argsinsert->variable;
!         remove_variable_from_list(&argsinsert, var);
!         add_variable_to_head(&argsresult, var, &no_indicator);
!         $$ = $1;
!     }
!     ;
!
! opt_ecpg_fetch_into: /* EMPTY */    { $$ = EMPTY; }
!     | ecpg_fetch_into        { $$ = $1; }
!     ;

  %%

diff -dcrpN pgsql/src/interfaces/ecpg/preproc/ecpg.type pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.type
*** pgsql/src/interfaces/ecpg/preproc/ecpg.type    2009-08-10 18:02:24.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.type    2009-08-11 10:44:52.000000000 +0200
***************
*** 62,67 ****
--- 62,68 ----
  %type <str> ecpg_ident
  %type <str> ecpg_interval
  %type <str> ecpg_into
+ %type <str> ecpg_fetch_into
  %type <str> ecpg_param
  %type <str> ecpg_sconst
  %type <str> ecpg_using
***************
*** 77,83 ****
  %type <str> opt_bit_field
  %type <str> opt_connection_name
  %type <str> opt_database_name
! %type <str> opt_ecpg_into
  %type <str> opt_ecpg_using
  %type <str> opt_initializer
  %type <str> opt_options
--- 78,84 ----
  %type <str> opt_bit_field
  %type <str> opt_connection_name
  %type <str> opt_database_name
! %type <str> opt_ecpg_fetch_into
  %type <str> opt_ecpg_using
  %type <str> opt_initializer
  %type <str> opt_options
***************
*** 87,92 ****
--- 88,94 ----
  %type <str> opt_reference
  %type <str> opt_scale
  %type <str> opt_server
+ %type <str> opt_sql
  %type <str> opt_user
  %type <str> opt_opt_value
  %type <str> ora_user
diff -dcrpN pgsql/src/interfaces/ecpg/preproc/extern.h pgsql.sqlda/src/interfaces/ecpg/preproc/extern.h
*** pgsql/src/interfaces/ecpg/preproc/extern.h    2009-08-09 18:13:31.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/preproc/extern.h    2009-08-11 10:32:34.000000000 +0200
*************** extern void add_descriptor(char *, char
*** 90,95 ****
--- 90,96 ----
  extern void drop_descriptor(char *, char *);
  extern struct descriptor *lookup_descriptor(char *, char *);
  extern struct variable *descriptor_variable(const char *name, int input);
+ extern struct variable *sqlda_variable(const char *name);
  extern void add_variable_to_head(struct arguments **, struct variable *, struct variable *);
  extern void add_variable_to_tail(struct arguments **, struct variable *, struct variable *);
  extern void remove_variable_from_list(struct arguments ** list, struct variable * var);
diff -dcrpN pgsql/src/interfaces/ecpg/preproc/type.c pgsql.sqlda/src/interfaces/ecpg/preproc/type.c
*** pgsql/src/interfaces/ecpg/preproc/type.c    2009-08-07 13:06:28.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/preproc/type.c    2009-08-11 11:46:04.000000000 +0200
*************** get_type(enum ECPGttype type)
*** 194,199 ****
--- 194,202 ----
          case ECPGt_descriptor:
              return ("ECPGt_descriptor");
              break;
+         case ECPGt_sqlda:
+             return ("ECPGt_sqlda");
+             break;
          case ECPGt_date:
              return ("ECPGt_date");
              break;
*************** ECPGdump_a_simple(FILE *o, const char *n
*** 328,333 ****
--- 331,338 ----
      else if (type == ECPGt_descriptor)
          /* remember that name here already contains quotes (if needed) */
          fprintf(o, "\n\tECPGt_descriptor, %s, 0L, 0L, 0L, ", name);
+     else if (type == ECPGt_sqlda)
+         fprintf(o, "\n\tECPGt_sqlda, &%s, 0L, 0L, 0L, ", name);
      else
      {
          char       *variable = (char *) mm_alloc(strlen(name) + ((prefix == NULL) ? 0 : strlen(prefix)) + 4);
diff -dcrpN pgsql/src/interfaces/ecpg/test/compat_informix/Makefile
pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/Makefile
*** pgsql/src/interfaces/ecpg/test/compat_informix/Makefile    2009-08-10 18:05:33.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/Makefile    2009-08-11 10:51:42.000000000 +0200
*************** TESTS = test_informix test_informix.c \
*** 17,22 ****
--- 17,23 ----
          rfmtdate rfmtdate.c \
          rfmtlong rfmtlong.c \
          rnull rnull.c \
+         sqlda sqlda.c \
          charfuncs charfuncs.c

  all: $(TESTS)
*************** test_informix2.c: test_informix2.pgc ../
*** 30,35 ****
--- 31,39 ----
  cursor.c: cursor.pgc ../regression.h
      $(ECPG) -o $@ -I$(srcdir) $<

+ sqlda.c: sqlda.pgc ../regression.h
+     $(ECPG) -o $@ -I$(srcdir) $<
+
  dec_test.c: dec_test.pgc ../regression.h
      $(ECPG) -o $@ -I$(srcdir) $<

diff -dcrpN pgsql/src/interfaces/ecpg/test/compat_informix/sqlda.pgc
pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/sqlda.pgc
*** pgsql/src/interfaces/ecpg/test/compat_informix/sqlda.pgc    1970-01-01 01:00:00.000000000 +0100
--- pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/sqlda.pgc    2009-08-11 13:44:07.000000000 +0200
***************
*** 0 ****
--- 1,207 ----
+ #include <stdlib.h>
+ #include <string.h>
+ #include <inttypes.h>
+
+ exec sql include ../regression;
+
+ exec sql include sqlda.h;
+ exec sql include sqltypes.h;
+
+ exec sql whenever sqlerror stop;
+
+ /* These shouldn't be under DECLARE SECTION */
+ pg_sqlda_t    *inp_sqlda, *outp_sqlda;
+
+ static void
+ dump_sqlda(pg_sqlda_t *sqlda)
+ {
+     int    i;
+
+     for (i = 0; i < sqlda->sqld; i++)
+     {
+         if (outp_sqlda->sqlvar[i].sqlind && *(outp_sqlda->sqlvar[i].sqlind) == -1)
+             printf("name sqlda descriptor: '%s' value NULL'\n", outp_sqlda->sqlvar[i].sqlname);
+         else
+         switch (sqlda->sqlvar[i].sqltype)
+         {
+         case SQLCHAR:
+         case SQLVCHAR:
+         case SQLTEXT:
+             printf("name sqlda descriptor: '%s' value '%s'\n", sqlda->sqlvar[i].sqlname, sqlda->sqlvar[i].sqldata);
+             break;
+         case SQLSERIAL:
+         case SQLINT:
+             printf("name sqlda descriptor: '%s' value %d\n", sqlda->sqlvar[i].sqlname, *(int
*)sqlda->sqlvar[i].sqldata);
+             break;
+         case SQLSERIAL8:
+         case SQLINT8:
+             printf("name sqlda descriptor: '%s' value %" PRId64 "\n", sqlda->sqlvar[i].sqlname, *(int64_t
*)sqlda->sqlvar[i].sqldata);
+             break;
+         case SQLFLOAT:
+             printf("name sqlda descriptor: '%s' value %lf\n", sqlda->sqlvar[i].sqlname, *(double
*)sqlda->sqlvar[i].sqldata);
+             break;
+         case SQLDECIMAL:
+             {
+                 char    val[64];
+                 dectoasc((dec_t *)sqlda->sqlvar[i].sqldata, val, 64, -1);
+                 printf("name sqlda descriptor: '%s' value DECIMAL '%s'\n", sqlda->sqlvar[i].sqlname, val);
+                 break;
+             }
+         }
+     }
+ }
+
+ int
+ main (void)
+ {
+ exec sql begin declare section;
+     char    *stmt1 = "SELECT * FROM t1";
+     char    *stmt2 = "SELECT * FROM t1 WHERE id = ?";
+     int    rec;
+     int    id;
+ exec sql end declare section;
+
+     char msg[128];
+
+     ECPGdebug(1, stderr);
+
+     strcpy(msg, "connect");
+     exec sql connect to REGRESSDB1;
+
+     strcpy(msg, "set");
+     exec sql set datestyle to iso;
+
+     strcpy(msg, "create");
+     exec sql create table t1(
+         id integer,
+         t text,
+         d1 numeric,
+         d2 float8,
+         c char(10));
+
+     strcpy(msg, "insert");
+     exec sql insert into t1 values
+         (1, 'a', 1.0, 1, 'a'),
+         (2, null, null, null, null),
+         (3, '"c"', -3, 'nan'::float8, 'c'),
+         (4, 'd', 4.0, 4, 'd');
+
+     strcpy(msg, "commit");
+     exec sql commit;
+
+     /* SQLDA test for getting all records from a table */
+
+     outp_sqlda = NULL;
+
+     strcpy(msg, "prepare");
+     exec sql prepare st_id1 from :stmt1;
+
+     strcpy(msg, "declare");
+     exec sql declare mycur1 cursor for st_id1;
+
+     strcpy(msg, "open");
+     exec sql open mycur1;
+
+     exec sql whenever not found do break;
+
+     rec = 0;
+     while (1)
+     {
+         strcpy(msg, "fetch");
+         exec sql fetch 1 from mycur1 into descriptor outp_sqlda;
+
+         printf("FETCH RECORD %d\n", ++rec);
+         dump_sqlda(outp_sqlda);
+     }
+
+     exec sql whenever not found continue;
+
+     strcpy(msg, "close");
+     exec sql close mycur1;
+
+     strcpy(msg, "deallocate");
+     exec sql deallocate prepare st_id1;
+
+     free(outp_sqlda);
+
+     /* SQLDA test for getting all records from a table
+        using the Informix-specific FETCH ... USING DESCRIPTOR
+      */
+
+     outp_sqlda = NULL;
+
+     strcpy(msg, "prepare");
+     exec sql prepare st_id2 from :stmt1;
+
+     strcpy(msg, "declare");
+     exec sql declare mycur2 cursor for st_id2;
+
+     strcpy(msg, "open");
+     exec sql open mycur2;
+
+     exec sql whenever not found do break;
+
+     rec = 0;
+     while (1)
+     {
+         strcpy(msg, "fetch");
+         exec sql fetch from mycur2 using descriptor outp_sqlda;
+
+         printf("FETCH RECORD %d\n", ++rec);
+         dump_sqlda(outp_sqlda);
+     }
+
+     exec sql whenever not found continue;
+
+     strcpy(msg, "close");
+     exec sql close mycur2;
+
+     strcpy(msg, "deallocate");
+     exec sql deallocate prepare st_id2;
+
+     free(outp_sqlda);
+
+     /* SQLDA test for getting one record using an input descriptor */
+
+     /* Input sqlda has to be built manually */
+     inp_sqlda = (pg_sqlda_t *)malloc(sizeof(pg_sqlda_t));
+     memset(inp_sqlda, 0, sizeof(pg_sqlda_t));
+     inp_sqlda->sqld = 1;
+     inp_sqlda->sqlvar = malloc(sizeof(pg_sqlvar_t));
+     memset(inp_sqlda->sqlvar, 0, sizeof(pg_sqlvar_t));
+
+     inp_sqlda->sqlvar[0].sqltype = SQLINT;
+     inp_sqlda->sqlvar[0].sqldata = (char *)&id;
+
+     printf("EXECUTE RECORD 4\n");
+
+     id = 4;
+
+     outp_sqlda = NULL;
+
+     strcpy(msg, "prepare");
+     exec sql prepare st_id3 FROM :stmt2;
+
+     strcpy(msg, "execute");
+     exec sql execute st_id3 using descriptor inp_sqlda into descriptor outp_sqlda;
+
+     dump_sqlda(outp_sqlda);
+
+     strcpy(msg, "deallocate");
+     exec sql deallocate prepare st_id3;
+
+     free(outp_sqlda);
+
+     /* End test */
+
+     strcpy(msg, "drop");
+     exec sql drop table t1;
+
+     strcpy(msg, "commit");
+     exec sql commit;
+
+     strcpy(msg, "disconnect");
+     exec sql disconnect;
+
+     return (0);
+ }
diff -dcrpN pgsql/src/interfaces/ecpg/test/ecpg_schedule pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule
*** pgsql/src/interfaces/ecpg/test/ecpg_schedule    2009-08-10 18:06:06.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule    2009-08-11 11:19:52.000000000 +0200
*************** test: compat_informix/rfmtdate
*** 4,9 ****
--- 4,10 ----
  test: compat_informix/rfmtlong
  test: compat_informix/rnull
  test: compat_informix/cursor
+ test: compat_informix/sqlda
  test: compat_informix/test_informix
  test: compat_informix/test_informix2
  test: connect/test2
diff -dcrpN pgsql/src/interfaces/ecpg/test/ecpg_schedule_tcp pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule_tcp
*** pgsql/src/interfaces/ecpg/test/ecpg_schedule_tcp    2009-08-10 18:06:11.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule_tcp    2009-08-11 11:19:59.000000000 +0200
*************** test: compat_informix/rfmtdate
*** 4,9 ****
--- 4,10 ----
  test: compat_informix/rfmtlong
  test: compat_informix/rnull
  test: compat_informix/cursor
+ test: compat_informix/sqlda
  test: compat_informix/test_informix
  test: compat_informix/test_informix2
  test: connect/test2
diff -dcrpN pgsql/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c
pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c
*** pgsql/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c    1970-01-01 01:00:00.000000000 +0100
--- pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c    2009-08-11 14:24:20.000000000 +0200
***************
*** 0 ****
--- 1,506 ----
+ /* Processed by ecpg (regression mode) */
+ /* These include files are added by the preprocessor */
+ #include <ecpglib.h>
+ #include <ecpgerrno.h>
+ #include <sqlca.h>
+ /* Needed for informix compatibility */
+ #include <ecpg_informix.h>
+ /* End of automatic include section */
+ #define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+ #line 1 "sqlda.pgc"
+ #include <stdlib.h>
+ #include <string.h>
+ #include <inttypes.h>
+
+
+ #line 1 "regression.h"
+
+
+
+
+
+
+ #line 5 "sqlda.pgc"
+
+
+
+ #line 1 "sqlda.h"
+ /*
+  * $PostgreSQL: pgsql/src/interfaces/ecpg/include/sqlda.h,v 1.4 2009/06/11 14:49:13 momjian Exp $
+  */
+
+ #ifndef POSTGRES_SQLDA_H
+ #define POSTGRES_SQLDA_H
+
+ /* Define Informix "standard" types */
+ #ifndef C_H
+ typedef int        int4;
+ typedef    short        int2;
+ #endif
+ typedef    char        int1;
+
+ typedef    int        mint;
+ typedef    long        mlong;
+
+ typedef    short        MSHORT;
+ typedef    char        MCHAR;
+
+ typedef    unsigned int    uint4;
+ typedef    unsigned short    uint2;
+ typedef    unsigned char    uint1;
+
+ typedef    unsigned int    muint;
+ typedef    unsigned long    mulong;
+
+ typedef    unsigned short    MUSHORT;
+ typedef    unsigned char    MUCHAR;
+
+ #define MI_INT_SIZE     (sizeof(int)    * 8)
+ #define MI_LONG_SIZE    (sizeof(long)   * 8)
+ #define MI_PTR_SIZE     (sizeof(char *) * 8)
+
+ typedef struct sqlvar_struct
+ {
+     int2    sqltype;        /* variable type                */
+     int4    sqllen;            /* length in bytes              */
+     char       *sqldata;        /* pointer to data              */
+     int2       *sqlind;        /* pointer to indicator         */
+     char       *sqlname;        /* variable name                */
+     char       *sqlformat;        /* reserved for future use      */
+     int2    sqlitype;        /* ind variable type            */
+     int2    sqlilen;        /* ind length in bytes          */
+     char       *sqlidata;        /* ind data pointer             */
+     int4    sqlxid;            /* extended id type             */
+     char       *sqltypename;    /* extended type name           */
+     int2    sqltypelen;        /* length of extended type name */
+     int2    sqlownerlen;        /* length of owner name         */
+     int2    sqlsourcetype;        /* source type for distinct of built-ins */
+     char       *sqlownername;    /* owner name                   */
+     int4    sqlsourceid;        /* extended id of source type   */
+
+     /*
+      * sqlilongdata is new.  It supports data that exceeds the 32k
+      * limit.  sqlilen and sqlidata are for backward compatibility
+      * and they have maximum value of <32K.
+      */
+     char       *sqlilongdata;    /* for data field beyond 32K    */
+     int4    sqlflags;        /* for internal use only        */
+     void       *sqlreserved;    /* reserved for future use      */
+ } pg_sqlvar_t;
+
+ typedef struct sqlda
+ {
+     int2        sqld;
+     pg_sqlvar_t       *sqlvar;
+     char        desc_name[19];    /* descriptor name              */
+     int2        desc_occ;    /* size of sqlda structure      */
+     struct sqlda       *desc_next;    /* pointer to next sqlda struct */
+     void           *reserved;    /* reserved for future use */
+ } pg_sqlda_t;
+
+ #endif /* POSTGRES_SQLDA_H */
+
+ #line 7 "sqlda.pgc"
+
+
+ #line 1 "sqltypes.h"
+ /*
+  * $PostgreSQL: pgsql/src/interfaces/ecpg/include/sqltypes.h,v 1.9 2009/06/11 14:49:13 momjian Exp $
+  */
+ #ifndef ECPG_SQLTYPES_H
+ #define ECPG_SQLTYPES_H
+
+ #define CCHARTYPE    ECPGt_char
+ #define CSHORTTYPE    ECPGt_short
+ #define CINTTYPE    ECPGt_int
+ #define CLONGTYPE    ECPGt_long
+ #define CFLOATTYPE    ECPGt_float
+ #define CDOUBLETYPE ECPGt_double
+ #define CDECIMALTYPE    ECPGt_decimal
+ #define CFIXCHARTYPE    108
+ #define CSTRINGTYPE ECPGt_char
+ #define CDATETYPE    ECPGt_date
+ #define CMONEYTYPE    111
+ #define CDTIMETYPE    ECPGt_timestamp
+ #define CLOCATORTYPE    113
+ #define CVCHARTYPE    ECPGt_varchar
+ #define CINVTYPE    115
+ #define CFILETYPE    116
+ #define CINT8TYPE    ECPGt_long_long
+ #define CCOLLTYPE        118
+ #define CLVCHARTYPE        119
+ #define CFIXBINTYPE        120
+ #define CVARBINTYPE        121
+ #define CBOOLTYPE        ECPGt_bool
+ #define CROWTYPE        123
+ #define CLVCHARPTRTYPE    124
+ #define CTYPEMAX    25
+
+ /*
+  * Values used in sqlda->sqlvar[i]->sqltype
+  */
+ #define    SQLCHAR        0
+ #define    SQLSMINT    1
+ #define    SQLINT        2
+ #define    SQLFLOAT    3
+ #define    SQLSMFLOAT    4
+ #define    SQLDECIMAL    5
+ #define    SQLSERIAL    6
+ #define    SQLDATE        7
+ #define    SQLMONEY    8
+ #define    SQLDTIME    10
+ #define    SQLBYTES    11
+ #define    SQLTEXT        12
+ #define    SQLVCHAR    13
+ #define    SQLINTERVAL    14
+ #define    SQLNCHAR    15
+ #define    SQLNVCHAR    16
+ #define    SQLINT8        17
+ #define    SQLSERIAL8    18
+
+ #endif   /* ndef ECPG_SQLTYPES_H */
+
+ #line 8 "sqlda.pgc"
+
+
+ /* exec sql whenever sqlerror  stop ; */
+ #line 10 "sqlda.pgc"
+
+
+ /* These shouldn't be under DECLARE SECTION */
+ pg_sqlda_t    *inp_sqlda, *outp_sqlda;
+
+ static void
+ dump_sqlda(pg_sqlda_t *sqlda)
+ {
+     int    i;
+
+     for (i = 0; i < sqlda->sqld; i++)
+     {
+         if (outp_sqlda->sqlvar[i].sqlind && *(outp_sqlda->sqlvar[i].sqlind) == -1)
+             printf("name sqlda descriptor: '%s' value NULL'\n", outp_sqlda->sqlvar[i].sqlname);
+         else
+         switch (sqlda->sqlvar[i].sqltype)
+         {
+         case SQLCHAR:
+         case SQLVCHAR:
+         case SQLTEXT:
+             printf("name sqlda descriptor: '%s' value '%s'\n", sqlda->sqlvar[i].sqlname, sqlda->sqlvar[i].sqldata);
+             break;
+         case SQLSERIAL:
+         case SQLINT:
+             printf("name sqlda descriptor: '%s' value %d\n", sqlda->sqlvar[i].sqlname, *(int
*)sqlda->sqlvar[i].sqldata);
+             break;
+         case SQLSERIAL8:
+         case SQLINT8:
+             printf("name sqlda descriptor: '%s' value %" PRId64 "\n", sqlda->sqlvar[i].sqlname, *(int64_t
*)sqlda->sqlvar[i].sqldata);
+             break;
+         case SQLFLOAT:
+             printf("name sqlda descriptor: '%s' value %lf\n", sqlda->sqlvar[i].sqlname, *(double
*)sqlda->sqlvar[i].sqldata);
+             break;
+         case SQLDECIMAL:
+             {
+                 char    val[64];
+                 dectoasc((decimal *)sqlda->sqlvar[i].sqldata, val, 64, -1);
+                 printf("name sqlda descriptor: '%s' value DECIMAL '%s'\n", sqlda->sqlvar[i].sqlname, val);
+                 break;
+             }
+         }
+     }
+ }
+
+ int
+ main (void)
+ {
+ /* exec sql begin declare section */
+
+
+
+
+
+ #line 58 "sqlda.pgc"
+  char * stmt1 = "SELECT * FROM t1" ;
+
+ #line 59 "sqlda.pgc"
+  char * stmt2 = "SELECT * FROM t1 WHERE id = ?" ;
+
+ #line 60 "sqlda.pgc"
+  int rec ;
+
+ #line 61 "sqlda.pgc"
+  int id ;
+ /* exec sql end declare section */
+ #line 62 "sqlda.pgc"
+
+
+     char msg[128];
+
+     ECPGdebug(1, stderr);
+
+     strcpy(msg, "connect");
+     { ECPGconnect(__LINE__, 1, "regress1" , NULL, NULL , NULL, 0);
+ #line 69 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 69 "sqlda.pgc"
+
+
+     strcpy(msg, "set");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "set datestyle to iso", ECPGt_EOIT, ECPGt_EORT);
+ #line 72 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 72 "sqlda.pgc"
+
+
+     strcpy(msg, "create");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "create table t1 ( id integer , t text , d1 numeric , d2 float8
,c char ( 10 ) )", ECPGt_EOIT, ECPGt_EORT); 
+ #line 80 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 80 "sqlda.pgc"
+
+
+     strcpy(msg, "insert");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "insert into t1 values ( 1 , 'a' , 1.0 , 1 , 'a' ) , ( 2 , null
,null , null , null ) , ( 3 , '\"c\"' , - 3 , 'nan' :: float8 , 'c' ) , ( 4 , 'd' , 4.0 , 4 , 'd' )", ECPGt_EOIT,
ECPGt_EORT);
+ #line 87 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 87 "sqlda.pgc"
+
+
+     strcpy(msg, "commit");
+     { ECPGtrans(__LINE__, NULL, "commit");
+ #line 90 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 90 "sqlda.pgc"
+
+
+     /* SQLDA test for getting all records from a table */
+
+     outp_sqlda = NULL;
+
+     strcpy(msg, "prepare");
+     { ECPGprepare(__LINE__, NULL, 0, "st_id1", stmt1);
+ #line 97 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 97 "sqlda.pgc"
+
+
+     strcpy(msg, "declare");
+     /* declare mycur1 cursor for $1 */
+ #line 100 "sqlda.pgc"
+
+
+     strcpy(msg, "open");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "declare mycur1 cursor for $1",
+     ECPGt_char_variable,(ECPGprepared_statement(NULL, "st_id1", __LINE__)),(long)1,(long)1,(1)*sizeof(char),
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+ #line 103 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 103 "sqlda.pgc"
+
+
+     /* exec sql whenever not found  break ; */
+ #line 105 "sqlda.pgc"
+
+
+     rec = 0;
+     while (1)
+     {
+         strcpy(msg, "fetch");
+         { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch 1 from mycur1", ECPGt_EOIT,
+     ECPGt_sqlda, & outp_sqlda , 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 111 "sqlda.pgc"
+
+ if (sqlca.sqlcode == ECPG_NOT_FOUND) break;
+ #line 111 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 111 "sqlda.pgc"
+
+
+         printf("FETCH RECORD %d\n", ++rec);
+         dump_sqlda(outp_sqlda);
+     }
+
+     /* exec sql whenever not found  continue ; */
+ #line 117 "sqlda.pgc"
+
+
+     strcpy(msg, "close");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "close mycur1", ECPGt_EOIT, ECPGt_EORT);
+ #line 120 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 120 "sqlda.pgc"
+
+
+     strcpy(msg, "deallocate");
+     { ECPGdeallocate(__LINE__, 1, NULL, "st_id1");
+ #line 123 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 123 "sqlda.pgc"
+
+
+     free(outp_sqlda);
+
+     /* SQLDA test for getting all records from a table
+        using the Informix-specific FETCH ... USING DESCRIPTOR
+      */
+
+     outp_sqlda = NULL;
+
+     strcpy(msg, "prepare");
+     { ECPGprepare(__LINE__, NULL, 0, "st_id2", stmt1);
+ #line 134 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 134 "sqlda.pgc"
+
+
+     strcpy(msg, "declare");
+     /* declare mycur2 cursor for $1 */
+ #line 137 "sqlda.pgc"
+
+
+     strcpy(msg, "open");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "declare mycur2 cursor for $1",
+     ECPGt_char_variable,(ECPGprepared_statement(NULL, "st_id2", __LINE__)),(long)1,(long)1,(1)*sizeof(char),
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+ #line 140 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 140 "sqlda.pgc"
+
+
+     /* exec sql whenever not found  break ; */
+ #line 142 "sqlda.pgc"
+
+
+     rec = 0;
+     while (1)
+     {
+         strcpy(msg, "fetch");
+         { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch from mycur2", ECPGt_EOIT,
+     ECPGt_sqlda, & outp_sqlda , 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 148 "sqlda.pgc"
+
+ if (sqlca.sqlcode == ECPG_NOT_FOUND) break;
+ #line 148 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 148 "sqlda.pgc"
+
+
+         printf("FETCH RECORD %d\n", ++rec);
+         dump_sqlda(outp_sqlda);
+     }
+
+     /* exec sql whenever not found  continue ; */
+ #line 154 "sqlda.pgc"
+
+
+     strcpy(msg, "close");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "close mycur2", ECPGt_EOIT, ECPGt_EORT);
+ #line 157 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 157 "sqlda.pgc"
+
+
+     strcpy(msg, "deallocate");
+     { ECPGdeallocate(__LINE__, 1, NULL, "st_id2");
+ #line 160 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 160 "sqlda.pgc"
+
+
+     free(outp_sqlda);
+
+     /* SQLDA test for getting one record using an input descriptor */
+
+     /* Input sqlda has to be built manually */
+     inp_sqlda = (pg_sqlda_t *)malloc(sizeof(pg_sqlda_t));
+     memset(inp_sqlda, 0, sizeof(pg_sqlda_t));
+     inp_sqlda->sqld = 1;
+     inp_sqlda->sqlvar = malloc(sizeof(pg_sqlvar_t));
+     memset(inp_sqlda->sqlvar, 0, sizeof(pg_sqlvar_t));
+
+     inp_sqlda->sqlvar[0].sqltype = SQLINT;
+     inp_sqlda->sqlvar[0].sqldata = (char *)&id;
+
+     printf("EXECUTE RECORD 4\n");
+
+     id = 4;
+
+     outp_sqlda = NULL;
+
+     strcpy(msg, "prepare");
+     { ECPGprepare(__LINE__, NULL, 0, "st_id3", stmt2);
+ #line 183 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 183 "sqlda.pgc"
+
+
+     strcpy(msg, "execute");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, 1, "st_id3",
+     ECPGt_sqlda, & inp_sqlda , 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
+     ECPGt_sqlda, & outp_sqlda , 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 186 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 186 "sqlda.pgc"
+
+
+     dump_sqlda(outp_sqlda);
+
+     strcpy(msg, "deallocate");
+     { ECPGdeallocate(__LINE__, 1, NULL, "st_id3");
+ #line 191 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 191 "sqlda.pgc"
+
+
+     free(outp_sqlda);
+
+     /* End test */
+
+     strcpy(msg, "drop");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "drop table t1", ECPGt_EOIT, ECPGt_EORT);
+ #line 198 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 198 "sqlda.pgc"
+
+
+     strcpy(msg, "commit");
+     { ECPGtrans(__LINE__, NULL, "commit");
+ #line 201 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 201 "sqlda.pgc"
+
+
+     strcpy(msg, "disconnect");
+     { ECPGdisconnect(__LINE__, "CURRENT");
+ #line 204 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 204 "sqlda.pgc"
+
+
+     return (0);
+ }
diff -dcrpN pgsql/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr
pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr
*** pgsql/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr    1970-01-01 01:00:00.000000000 +0100
--- pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr    2009-08-11 14:24:21.000000000 +0200
***************
*** 0 ****
--- 1,218 ----
+ [NO_PID]: ECPGdebug: set to 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGconnect: opening database regress1 on <DEFAULT> port <DEFAULT>
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 72: query: set datestyle to iso; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 72: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 72: OK: SET
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 75: query: create table t1 ( id integer , t text , d1 numeric , d2 float8 , c char (
10) ); with 0 parameter(s) on connection regress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 75: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 75: OK: CREATE TABLE
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 83: query: insert into t1 values ( 1 , 'a' , 1.0 , 1 , 'a' ) , ( 2 , null , null ,
null, null ) , ( 3 , '"c"' , - 3 , 'nan' :: float8 , 'c' ) , ( 4 , 'd' , 4.0 , 4 , 'd' ); with 0 parameter(s) on
connectionregress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 83: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 83: OK: INSERT 0 4
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGtrans on line 90: action "commit"; connection "regress1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGprepare on line 97: name st_id1; query: "SELECT * FROM t1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 103: query: declare mycur1 cursor for SELECT * FROM t1; with 0 parameter(s) on
connectionregress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 103: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 103: OK: DECLARE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: 1 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: 1.0 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: 1 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: putting result (1 tuples) into sqlda descriptor
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: called ecpg_compare_sqlda_with_PGresult, status 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: 2 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: putting result (1 tuples) into sqlda descriptor
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: called ecpg_compare_sqlda_with_PGresult, status 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: 3 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: -3 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: NaN offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: putting result (1 tuples) into sqlda descriptor
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: called ecpg_compare_sqlda_with_PGresult, status 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: 4 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: 4.0 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: 4 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: putting result (1 tuples) into sqlda descriptor
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: correctly got 0 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: raising sqlcode 100 on line 111: no data found on line 111
+ [NO_PID]: sqlca: code: 100, state: 02000
+ [NO_PID]: ecpg_execute on line 120: query: close mycur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 120: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 120: OK: CLOSE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGdeallocate on line 123: name st_id1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGprepare on line 134: name st_id2; query: "SELECT * FROM t1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 140: query: declare mycur2 cursor for SELECT * FROM t1; with 0 parameter(s) on
connectionregress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 140: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 140: OK: DECLARE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: 1 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: 1.0 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: 1 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: putting result (1 tuples) into sqlda descriptor
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: called ecpg_compare_sqlda_with_PGresult, status 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: 2 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: putting result (1 tuples) into sqlda descriptor
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: called ecpg_compare_sqlda_with_PGresult, status 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: 3 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: -3 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: NaN offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: putting result (1 tuples) into sqlda descriptor
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: called ecpg_compare_sqlda_with_PGresult, status 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: 4 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: 4.0 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: 4 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: putting result (1 tuples) into sqlda descriptor
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: correctly got 0 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: raising sqlcode 100 on line 148: no data found on line 148
+ [NO_PID]: sqlca: code: 100, state: 02000
+ [NO_PID]: ecpg_execute on line 157: query: close mycur2; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 157: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 157: OK: CLOSE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGdeallocate on line 160: name st_id2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGprepare on line 183: name st_id3; query: "SELECT * FROM t1 WHERE id = $1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 186: query: SELECT * FROM t1 WHERE id = $1; with 1 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 186: using PQexecPrepared for "SELECT * FROM t1 WHERE id = $1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: free_params on line 186: parameter 1 = 4
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 186: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 186: RESULT: 4 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 186: RESULT: 4.0 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 186: RESULT: 4 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 186: putting result (1 tuples) into sqlda descriptor
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGdeallocate on line 191: name st_id3
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 198: query: drop table t1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 198: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 198: OK: DROP TABLE
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGtrans on line 201: action "commit"; connection "regress1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_finish: connection regress1 closed
+ [NO_PID]: sqlca: code: 0, state: 00000
diff -dcrpN pgsql/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout
pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout
*** pgsql/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout    1970-01-01 01:00:00.000000000 +0100
--- pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout    2009-08-11 14:24:21.000000000 +0200
***************
*** 0 ****
--- 1,54 ----
+ FETCH RECORD 1
+ name sqlda descriptor: 'id' value 1
+ name sqlda descriptor: 't' value 'a'
+ name sqlda descriptor: 'd1' value DECIMAL '1.0'
+ name sqlda descriptor: 'd2' value 1.000000
+ name sqlda descriptor: 'c' value 'a         '
+ FETCH RECORD 2
+ name sqlda descriptor: 'id' value 2
+ name sqlda descriptor: 't' value NULL'
+ name sqlda descriptor: 'd1' value NULL'
+ name sqlda descriptor: 'd2' value NULL'
+ name sqlda descriptor: 'c' value NULL'
+ FETCH RECORD 3
+ name sqlda descriptor: 'id' value 3
+ name sqlda descriptor: 't' value '"c"'
+ name sqlda descriptor: 'd1' value DECIMAL '-3'
+ name sqlda descriptor: 'd2' value nan
+ name sqlda descriptor: 'c' value 'c         '
+ FETCH RECORD 4
+ name sqlda descriptor: 'id' value 4
+ name sqlda descriptor: 't' value 'd'
+ name sqlda descriptor: 'd1' value DECIMAL '4.0'
+ name sqlda descriptor: 'd2' value 4.000000
+ name sqlda descriptor: 'c' value 'd         '
+ FETCH RECORD 1
+ name sqlda descriptor: 'id' value 1
+ name sqlda descriptor: 't' value 'a'
+ name sqlda descriptor: 'd1' value DECIMAL '1.0'
+ name sqlda descriptor: 'd2' value 1.000000
+ name sqlda descriptor: 'c' value 'a         '
+ FETCH RECORD 2
+ name sqlda descriptor: 'id' value 2
+ name sqlda descriptor: 't' value NULL'
+ name sqlda descriptor: 'd1' value NULL'
+ name sqlda descriptor: 'd2' value NULL'
+ name sqlda descriptor: 'c' value NULL'
+ FETCH RECORD 3
+ name sqlda descriptor: 'id' value 3
+ name sqlda descriptor: 't' value '"c"'
+ name sqlda descriptor: 'd1' value DECIMAL '-3'
+ name sqlda descriptor: 'd2' value nan
+ name sqlda descriptor: 'c' value 'c         '
+ FETCH RECORD 4
+ name sqlda descriptor: 'id' value 4
+ name sqlda descriptor: 't' value 'd'
+ name sqlda descriptor: 'd1' value DECIMAL '4.0'
+ name sqlda descriptor: 'd2' value 4.000000
+ name sqlda descriptor: 'c' value 'd         '
+ EXECUTE RECORD 4
+ name sqlda descriptor: 'id' value 4
+ name sqlda descriptor: 't' value 'd'
+ name sqlda descriptor: 'd1' value DECIMAL '4.0'
+ name sqlda descriptor: 'd2' value 4.000000
+ name sqlda descriptor: 'c' value 'd         '
diff -dcrpN pgsql.sqlda/src/interfaces/ecpg/ecpglib/descriptor.c
pgsql.describe/src/interfaces/ecpg/ecpglib/descriptor.c
*** pgsql.sqlda/src/interfaces/ecpg/ecpglib/descriptor.c    2009-08-07 13:06:28.000000000 +0200
--- pgsql.describe/src/interfaces/ecpg/ecpglib/descriptor.c    2009-08-11 14:34:03.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
*** 226,231 ****
--- 227,238 ----
      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
*** 244,254 ****
          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))
      {
--- 251,256 ----
*************** ECPGget_desc(int lineno, const char *des
*** 283,288 ****
--- 285,291 ----
          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
*** 295,300 ****
--- 298,304 ----
                  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
*** 377,382 ****
--- 381,387 ----
              case ECPGd_ret_length:
              case ECPGd_ret_octet:

+                 RETURN_IF_NO_DATA;
                  /*
                   * this is like ECPGstore_result
                   */
*************** ECPGget_desc(int lineno, const char *des
*** 480,485 ****
--- 485,491 ----
      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
*** 722,730 ****
      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;
  }
--- 728,841 ----
      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 pgsql.sqlda/src/interfaces/ecpg/ecpglib/execute.c pgsql.describe/src/interfaces/ecpg/ecpglib/execute.c
*** pgsql.sqlda/src/interfaces/ecpg/ecpglib/execute.c    2009-08-11 14:23:30.000000000 +0200
--- pgsql.describe/src/interfaces/ecpg/ecpglib/execute.c    2009-08-11 14:34:03.000000000 +0200
*************** ecpg_store_input(const int lineno, const
*** 1034,1039 ****
--- 1034,1041 ----
                  break;

              case ECPGt_descriptor:
+                 break;
+
              case ECPGt_sqlda:
                  break;

diff -dcrpN pgsql.sqlda/src/interfaces/ecpg/include/ecpglib.h pgsql.describe/src/interfaces/ecpg/include/ecpglib.h
*** pgsql.sqlda/src/interfaces/ecpg/include/ecpglib.h    2009-06-13 18:25:05.000000000 +0200
--- pgsql.describe/src/interfaces/ecpg/include/ecpglib.h    2009-08-11 14:34:03.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 pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.trailer
pgsql.describe/src/interfaces/ecpg/preproc/ecpg.trailer
*** pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.trailer    2009-08-11 10:41:02.000000000 +0200
--- pgsql.describe/src/interfaces/ecpg/preproc/ecpg.trailer    2009-08-11 17:18:31.000000000 +0200
*************** ECPGCursorStmt:  DECLARE cursor_name cur
*** 354,360 ****
                  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("*/"));
--- 354,359 ----
*************** into_descriptor: INTO opt_sql SQL_DESCRI
*** 1054,1059 ****
--- 1053,1065 ----
          }
          ;

+ 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
*** 1089,1110 ****
      {
          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);
      }
      ;

--- 1095,1137 ----
      {
          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";
!         struct variable *var;
!
!         var = argsinsert->variable;
!         remove_variable_from_list(&argsinsert, var);
!         add_variable_to_head(&argsresult, var, &no_indicator);
!
!         $$ = (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");
!         if (!INFORMIX_MODE)
!             mmerror(PARSE_ERROR, ET_ERROR, "Not in Informix compatibility mode");
!         $$ = (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";
!         if (!INFORMIX_MODE)
!             mmerror(PARSE_ERROR, ET_ERROR, "Not in Informix compatibility mode");
!         $$ = (char *) mm_alloc(sizeof("0, , \"\"") + strlen(con) + strlen($3));
!         sprintf($$, "0, %s, \"%s\"", con, $3);
      }
      ;

diff -dcrpN pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.type pgsql.describe/src/interfaces/ecpg/preproc/ecpg.type
*** pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.type    2009-08-11 10:44:52.000000000 +0200
--- pgsql.describe/src/interfaces/ecpg/preproc/ecpg.type    2009-08-11 14:34:03.000000000 +0200
***************
*** 73,78 ****
--- 73,79 ----
  %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
***************
*** 88,94 ****
  %type <str> opt_reference
  %type <str> opt_scale
  %type <str> opt_server
! %type <str> opt_sql
  %type <str> opt_user
  %type <str> opt_opt_value
  %type <str> ora_user
--- 89,95 ----
  %type <str> opt_reference
  %type <str> opt_scale
  %type <str> opt_server
! %type <str> opt_sql
  %type <str> opt_user
  %type <str> opt_opt_value
  %type <str> ora_user
diff -dcrpN pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/describe.pgc
pgsql.describe/src/interfaces/ecpg/test/compat_informix/describe.pgc
*** pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/describe.pgc    1970-01-01 01:00:00.000000000 +0100
--- pgsql.describe/src/interfaces/ecpg/test/compat_informix/describe.pgc    2009-08-11 17:13:35.000000000 +0200
***************
*** 0 ****
--- 1,166 ----
+ #include <stdlib.h>
+ #include <string.h>
+
+ exec sql include ../regression;
+ exec sql include sqlda.h;
+
+ exec sql whenever sqlerror stop;
+
+ pg_sqlda_t    *sqlda1, *sqlda2, *sqlda3;
+
+ int
+ main (void)
+ {
+ exec sql begin declare section;
+     char    *stmt1 = "SELECT id, t FROM t1";
+     char    *stmt2 = "SELECT id, t FROM t1 WHERE id = -1";
+     int    i, count1, count2;
+     char    field_name1[30] = "not set";
+     char    field_name2[30] = "not set";
+ exec sql end declare section;
+
+     char msg[128];
+
+     ECPGdebug(1, stderr);
+
+     strcpy(msg, "connect");
+     exec sql connect to REGRESSDB1;
+
+     strcpy(msg, "set");
+     exec sql set datestyle to iso;
+
+     strcpy(msg, "create");
+     exec sql create table t1(id serial primary key, t text);
+
+     strcpy(msg, "insert");
+     exec sql insert into t1(id, t) values (default, 'a');
+     exec sql insert into t1(id, t) values (default, 'b');
+     exec sql insert into t1(id, t) values (default, 'c');
+     exec sql insert into t1(id, t) values (default, 'd');
+
+     strcpy(msg, "commit");
+     exec sql commit;
+
+     /*
+      * Test DESCRIBE with a query producing tuples.
+      * DESCRIPTOR and SQL DESCRIPTOR are NOT the same in
+      * Informix-compat mode.
+      */
+
+     strcpy(msg, "allocate");
+     exec sql allocate descriptor desc1;
+     exec sql allocate descriptor desc2;
+
+     strcpy(msg, "prepare");
+     exec sql prepare st_id1 FROM :stmt1;
+
+     sqlda1 = sqlda2 = sqlda3 = NULL;
+
+     strcpy(msg, "describe");
+     exec sql describe st_id1 into sql descriptor desc1;
+     exec sql describe st_id1 using sql descriptor desc2;
+
+     exec sql describe st_id1 into descriptor sqlda1;
+     exec sql describe st_id1 using descriptor sqlda2;
+     exec sql describe st_id1 into sqlda3;
+
+     if (sqlda1 == NULL || sqlda1 == NULL || sqlda2 == NULL)
+         exit(1);
+
+     strcpy(msg, "get descriptor");
+     exec sql get descriptor desc1 :count1 = count;
+     exec sql get descriptor desc1 :count2 = count;
+
+     if (!(    count1 == count2 &&
+         count1 == sqlda1->sqld &&
+         count1 == sqlda2->sqld &&
+         count1 == sqlda3->sqld))
+         exit(1);
+
+     for (i = 1; i <= count1; i++)
+     {
+         exec sql get descriptor desc1 value :i :field_name1 = name;
+         exec sql get descriptor desc2 value :i :field_name2 = name;
+         printf("%d\n\tfield_name1 '%s'\n\tfield_name2 '%s'\n\t"
+             "sqlda1 '%s'\n\tsqlda2 '%s'\n\tsqlda3 '%s'\n",
+             i, field_name1, field_name2,
+             sqlda1->sqlvar[i-1].sqlname,
+             sqlda2->sqlvar[i-1].sqlname,
+             sqlda3->sqlvar[i-1].sqlname);
+     }
+
+     strcpy(msg, "deallocate");
+     exec sql deallocate descriptor desc1;
+     exec sql deallocate descriptor desc2;
+     free(sqlda1);
+     free(sqlda2);
+     free(sqlda3);
+
+     exec sql deallocate prepare st_id1;
+
+     /* Test DESCRIBE with a query not producing tuples */
+
+     strcpy(msg, "allocate");
+     exec sql allocate descriptor desc1;
+     exec sql allocate descriptor desc2;
+
+     strcpy(msg, "prepare");
+     exec sql prepare st_id2 FROM :stmt2;
+
+     sqlda1 = sqlda2 = sqlda3 = NULL;
+
+     strcpy(msg, "describe");
+     exec sql describe st_id2 into sql descriptor desc1;
+     exec sql describe st_id2 using sql descriptor desc2;
+
+     exec sql describe st_id2 into descriptor sqlda1;
+     exec sql describe st_id2 using descriptor sqlda2;
+     exec sql describe st_id2 into sqlda3;
+
+     if (sqlda1 == NULL || sqlda1 == NULL || sqlda2 == NULL)
+         exit(1);
+
+     strcpy(msg, "get descriptor");
+     exec sql get descriptor desc1 :count1 = count;
+     exec sql get descriptor desc1 :count2 = count;
+
+     if (!(    count1 == count2 &&
+         count1 == sqlda1->sqld &&
+         count1 == sqlda2->sqld &&
+         count1 == sqlda3->sqld))
+         exit(1);
+
+     for (i = 1; i <= count1; i++)
+     {
+         exec sql get descriptor desc1 value :i :field_name1 = name;
+         exec sql get descriptor desc2 value :i :field_name2 = name;
+         printf("%d\n\tfield_name1 '%s'\n\tfield_name2 '%s'\n\t"
+             "sqlda1 '%s'\n\tsqlda2 '%s'\n\tsqlda3 '%s'\n",
+             i, field_name1, field_name2,
+             sqlda1->sqlvar[i-1].sqlname,
+             sqlda2->sqlvar[i-1].sqlname,
+             sqlda3->sqlvar[i-1].sqlname);
+     }
+
+     strcpy(msg, "deallocate");
+     exec sql deallocate descriptor desc1;
+     exec sql deallocate descriptor desc2;
+     free(sqlda1);
+     free(sqlda2);
+     free(sqlda3);
+
+     exec sql deallocate prepare st_id2;
+
+     /* End test */
+
+     strcpy(msg, "drop");
+     exec sql drop table t1;
+
+     strcpy(msg, "commit");
+     exec sql commit;
+
+     strcpy(msg, "disconnect");
+     exec sql disconnect;
+
+     return (0);
+ }
diff -dcrpN pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/Makefile
pgsql.describe/src/interfaces/ecpg/test/compat_informix/Makefile
*** pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/Makefile    2009-08-11 10:51:42.000000000 +0200
--- pgsql.describe/src/interfaces/ecpg/test/compat_informix/Makefile    2009-08-11 16:56:15.000000000 +0200
*************** override LIBS := -lecpg_compat $(LIBS)
*** 13,18 ****
--- 13,19 ----
  TESTS = test_informix test_informix.c \
          test_informix2 test_informix2.c \
          cursor cursor.c \
+         describe describe.c \
          dec_test dec_test.c \
          rfmtdate rfmtdate.c \
          rfmtlong rfmtlong.c \
*************** test_informix2.c: test_informix2.pgc ../
*** 31,36 ****
--- 32,40 ----
  cursor.c: cursor.pgc ../regression.h
      $(ECPG) -o $@ -I$(srcdir) $<

+ describe.c: describe.pgc ../regression.h
+     $(ECPG) -o $@ -I$(srcdir) $<
+
  sqlda.c: sqlda.pgc ../regression.h
      $(ECPG) -o $@ -I$(srcdir) $<

diff -dcrpN pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule pgsql.describe/src/interfaces/ecpg/test/ecpg_schedule
*** pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule    2009-08-11 11:19:52.000000000 +0200
--- pgsql.describe/src/interfaces/ecpg/test/ecpg_schedule    2009-08-11 17:00:27.000000000 +0200
*************** test: compat_informix/rfmtlong
*** 5,10 ****
--- 5,11 ----
  test: compat_informix/rnull
  test: compat_informix/cursor
  test: compat_informix/sqlda
+ test: compat_informix/describe
  test: compat_informix/test_informix
  test: compat_informix/test_informix2
  test: connect/test2
*************** test: preproc/array_of_struct
*** 19,24 ****
--- 20,26 ----
  test: preproc/autoprep
  test: preproc/comment
  test: preproc/cursor
+ test: preproc/describe
  test: preproc/define
  test: preproc/init
  test: preproc/strings
diff -dcrpN pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule_tcp
pgsql.describe/src/interfaces/ecpg/test/ecpg_schedule_tcp
*** pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule_tcp    2009-08-11 11:19:59.000000000 +0200
--- pgsql.describe/src/interfaces/ecpg/test/ecpg_schedule_tcp    2009-08-11 17:00:33.000000000 +0200
*************** test: compat_informix/rfmtlong
*** 5,10 ****
--- 5,11 ----
  test: compat_informix/rnull
  test: compat_informix/cursor
  test: compat_informix/sqlda
+ test: compat_informix/describe
  test: compat_informix/test_informix
  test: compat_informix/test_informix2
  test: connect/test2
*************** test: preproc/array_of_struct
*** 19,24 ****
--- 20,26 ----
  test: preproc/autoprep
  test: preproc/comment
  test: preproc/cursor
+ test: preproc/describe
  test: preproc/define
  test: preproc/init
  test: preproc/strings
diff -dcrpN pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-describe.c
pgsql.describe/src/interfaces/ecpg/test/expected/compat_informix-describe.c
*** pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-describe.c    1970-01-01 01:00:00.000000000 +0100
--- pgsql.describe/src/interfaces/ecpg/test/expected/compat_informix-describe.c    2009-08-11 17:23:04.000000000 +0200
***************
*** 0 ****
--- 1,490 ----
+ /* Processed by ecpg (regression mode) */
+ /* These include files are added by the preprocessor */
+ #include <ecpglib.h>
+ #include <ecpgerrno.h>
+ #include <sqlca.h>
+ /* Needed for informix compatibility */
+ #include <ecpg_informix.h>
+ /* End of automatic include section */
+ #define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+ #line 1 "describe.pgc"
+ #include <stdlib.h>
+ #include <string.h>
+
+
+ #line 1 "regression.h"
+
+
+
+
+
+
+ #line 4 "describe.pgc"
+
+
+ #line 1 "sqlda.h"
+ /*
+  * $PostgreSQL: pgsql/src/interfaces/ecpg/include/sqlda.h,v 1.4 2009/06/11 14:49:13 momjian Exp $
+  */
+
+ #ifndef POSTGRES_SQLDA_H
+ #define POSTGRES_SQLDA_H
+
+ /* Define Informix "standard" types */
+ #ifndef C_H
+ typedef int        int4;
+ typedef    short        int2;
+ #endif
+ typedef    char        int1;
+
+ typedef    int        mint;
+ typedef    long        mlong;
+
+ typedef    short        MSHORT;
+ typedef    char        MCHAR;
+
+ typedef    unsigned int    uint4;
+ typedef    unsigned short    uint2;
+ typedef    unsigned char    uint1;
+
+ typedef    unsigned int    muint;
+ typedef    unsigned long    mulong;
+
+ typedef    unsigned short    MUSHORT;
+ typedef    unsigned char    MUCHAR;
+
+ #define MI_INT_SIZE     (sizeof(int)    * 8)
+ #define MI_LONG_SIZE    (sizeof(long)   * 8)
+ #define MI_PTR_SIZE     (sizeof(char *) * 8)
+
+ typedef struct sqlvar_struct
+ {
+     int2    sqltype;        /* variable type                */
+     int4    sqllen;            /* length in bytes              */
+     char       *sqldata;        /* pointer to data              */
+     int2       *sqlind;        /* pointer to indicator         */
+     char       *sqlname;        /* variable name                */
+     char       *sqlformat;        /* reserved for future use      */
+     int2    sqlitype;        /* ind variable type            */
+     int2    sqlilen;        /* ind length in bytes          */
+     char       *sqlidata;        /* ind data pointer             */
+     int4    sqlxid;            /* extended id type             */
+     char       *sqltypename;    /* extended type name           */
+     int2    sqltypelen;        /* length of extended type name */
+     int2    sqlownerlen;        /* length of owner name         */
+     int2    sqlsourcetype;        /* source type for distinct of built-ins */
+     char       *sqlownername;    /* owner name                   */
+     int4    sqlsourceid;        /* extended id of source type   */
+
+     /*
+      * sqlilongdata is new.  It supports data that exceeds the 32k
+      * limit.  sqlilen and sqlidata are for backward compatibility
+      * and they have maximum value of <32K.
+      */
+     char       *sqlilongdata;    /* for data field beyond 32K    */
+     int4    sqlflags;        /* for internal use only        */
+     void       *sqlreserved;    /* reserved for future use      */
+ } pg_sqlvar_t;
+
+ typedef struct sqlda
+ {
+     int2        sqld;
+     pg_sqlvar_t       *sqlvar;
+     char        desc_name[19];    /* descriptor name              */
+     int2        desc_occ;    /* size of sqlda structure      */
+     struct sqlda       *desc_next;    /* pointer to next sqlda struct */
+     void           *reserved;    /* reserved for future use */
+ } pg_sqlda_t;
+
+ #endif /* POSTGRES_SQLDA_H */
+
+ #line 5 "describe.pgc"
+
+
+ /* exec sql whenever sqlerror  stop ; */
+ #line 7 "describe.pgc"
+
+
+ pg_sqlda_t    *sqlda1, *sqlda2, *sqlda3;
+
+ int
+ main (void)
+ {
+ /* exec sql begin declare section */
+
+
+
+
+
+
+ #line 15 "describe.pgc"
+  char * stmt1 = "SELECT id, t FROM t1" ;
+
+ #line 16 "describe.pgc"
+  char * stmt2 = "SELECT id, t FROM t1 WHERE id = -1" ;
+
+ #line 17 "describe.pgc"
+  int i , count1 , count2 ;
+
+ #line 18 "describe.pgc"
+  char field_name1 [ 30 ] = "not set" ;
+
+ #line 19 "describe.pgc"
+  char field_name2 [ 30 ] = "not set" ;
+ /* exec sql end declare section */
+ #line 20 "describe.pgc"
+
+
+     char msg[128];
+
+     ECPGdebug(1, stderr);
+
+     strcpy(msg, "connect");
+     { ECPGconnect(__LINE__, 1, "regress1" , NULL, NULL , NULL, 0);
+ #line 27 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 27 "describe.pgc"
+
+
+     strcpy(msg, "set");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "set datestyle to iso", ECPGt_EOIT, ECPGt_EORT);
+ #line 30 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 30 "describe.pgc"
+
+
+     strcpy(msg, "create");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "create table t1 ( id serial primary key , t text )",
ECPGt_EOIT,ECPGt_EORT); 
+ #line 33 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 33 "describe.pgc"
+
+
+     strcpy(msg, "insert");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "insert into t1 ( id , t ) values ( default , 'a' )",
ECPGt_EOIT,ECPGt_EORT); 
+ #line 36 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 36 "describe.pgc"
+
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "insert into t1 ( id , t ) values ( default , 'b' )",
ECPGt_EOIT,ECPGt_EORT); 
+ #line 37 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 37 "describe.pgc"
+
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "insert into t1 ( id , t ) values ( default , 'c' )",
ECPGt_EOIT,ECPGt_EORT); 
+ #line 38 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 38 "describe.pgc"
+
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "insert into t1 ( id , t ) values ( default , 'd' )",
ECPGt_EOIT,ECPGt_EORT); 
+ #line 39 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 39 "describe.pgc"
+
+
+     strcpy(msg, "commit");
+     { ECPGtrans(__LINE__, NULL, "commit");
+ #line 42 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 42 "describe.pgc"
+
+
+     /*
+      * Test DESCRIBE with a query producing tuples.
+      * DESCRIPTOR and SQL DESCRIPTOR are NOT the same in
+      * Informix-compat mode.
+      */
+
+     strcpy(msg, "allocate");
+     ECPGallocate_desc(__LINE__, "desc1");
+ #line 51 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 51 "describe.pgc"
+
+     ECPGallocate_desc(__LINE__, "desc2");
+ #line 52 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 52 "describe.pgc"
+
+
+     strcpy(msg, "prepare");
+     { ECPGprepare(__LINE__, NULL, 0, "st_id1", stmt1);
+ #line 55 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 55 "describe.pgc"
+
+
+     sqlda1 = sqlda2 = sqlda3 = NULL;
+
+     strcpy(msg, "describe");
+     { ECPGdescribe(__LINE__, 0, NULL, "st_id1",
+     ECPGt_descriptor, "desc1", 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+ #line 60 "describe.pgc"
+
+     { ECPGdescribe(__LINE__, 0, NULL, "st_id1",
+     ECPGt_descriptor, "desc2", 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+ #line 61 "describe.pgc"
+
+
+     { ECPGdescribe(__LINE__, 0, NULL, "st_id1",
+     ECPGt_sqlda, & sqlda1 , 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+ #line 63 "describe.pgc"
+
+     { ECPGdescribe(__LINE__, 0, NULL, "st_id1",
+     ECPGt_sqlda, & sqlda2 , 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+ #line 64 "describe.pgc"
+
+     { ECPGdescribe(__LINE__, 0, NULL, "st_id1",
+     ECPGt_sqlda, &sqlda3, 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+ #line 65 "describe.pgc"
+
+
+     if (sqlda1 == NULL || sqlda1 == NULL || sqlda2 == NULL)
+         exit(1);
+
+     strcpy(msg, "get descriptor");
+     { ECPGget_desc_header(__LINE__, "desc1", &(count1));
+
+ #line 71 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 71 "describe.pgc"
+
+     { ECPGget_desc_header(__LINE__, "desc1", &(count2));
+
+ #line 72 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 72 "describe.pgc"
+
+
+     if (!(    count1 == count2 &&
+         count1 == sqlda1->sqld &&
+         count1 == sqlda2->sqld &&
+         count1 == sqlda3->sqld))
+         exit(1);
+
+     for (i = 1; i <= count1; i++)
+     {
+         { ECPGget_desc(__LINE__, "desc1", i,ECPGd_name,
+     ECPGt_char,(field_name1),(long)30,(long)1,(30)*sizeof(char), ECPGd_EODT);
+
+ #line 82 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 82 "describe.pgc"
+
+         { ECPGget_desc(__LINE__, "desc2", i,ECPGd_name,
+     ECPGt_char,(field_name2),(long)30,(long)1,(30)*sizeof(char), ECPGd_EODT);
+
+ #line 83 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 83 "describe.pgc"
+
+         printf("%d\n\tfield_name1 '%s'\n\tfield_name2 '%s'\n\t"
+             "sqlda1 '%s'\n\tsqlda2 '%s'\n\tsqlda3 '%s'\n",
+             i, field_name1, field_name2,
+             sqlda1->sqlvar[i-1].sqlname,
+             sqlda2->sqlvar[i-1].sqlname,
+             sqlda3->sqlvar[i-1].sqlname);
+     }
+
+     strcpy(msg, "deallocate");
+     ECPGdeallocate_desc(__LINE__, "desc1");
+ #line 93 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 93 "describe.pgc"
+
+     ECPGdeallocate_desc(__LINE__, "desc2");
+ #line 94 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 94 "describe.pgc"
+
+     free(sqlda1);
+     free(sqlda2);
+     free(sqlda3);
+
+     { ECPGdeallocate(__LINE__, 1, NULL, "st_id1");
+ #line 99 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 99 "describe.pgc"
+
+
+     /* Test DESCRIBE with a query not producing tuples */
+
+     strcpy(msg, "allocate");
+     ECPGallocate_desc(__LINE__, "desc1");
+ #line 104 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 104 "describe.pgc"
+
+     ECPGallocate_desc(__LINE__, "desc2");
+ #line 105 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 105 "describe.pgc"
+
+
+     strcpy(msg, "prepare");
+     { ECPGprepare(__LINE__, NULL, 0, "st_id2", stmt2);
+ #line 108 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 108 "describe.pgc"
+
+
+     sqlda1 = sqlda2 = sqlda3 = NULL;
+
+     strcpy(msg, "describe");
+     { ECPGdescribe(__LINE__, 0, NULL, "st_id2",
+     ECPGt_descriptor, "desc1", 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+ #line 113 "describe.pgc"
+
+     { ECPGdescribe(__LINE__, 0, NULL, "st_id2",
+     ECPGt_descriptor, "desc2", 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+ #line 114 "describe.pgc"
+
+
+     { ECPGdescribe(__LINE__, 0, NULL, "st_id2",
+     ECPGt_sqlda, & sqlda1 , 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+ #line 116 "describe.pgc"
+
+     { ECPGdescribe(__LINE__, 0, NULL, "st_id2",
+     ECPGt_sqlda, & sqlda2 , 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+ #line 117 "describe.pgc"
+
+     { ECPGdescribe(__LINE__, 0, NULL, "st_id2",
+     ECPGt_sqlda, &sqlda3, 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+ #line 118 "describe.pgc"
+
+
+     if (sqlda1 == NULL || sqlda1 == NULL || sqlda2 == NULL)
+         exit(1);
+
+     strcpy(msg, "get descriptor");
+     { ECPGget_desc_header(__LINE__, "desc1", &(count1));
+
+ #line 124 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 124 "describe.pgc"
+
+     { ECPGget_desc_header(__LINE__, "desc1", &(count2));
+
+ #line 125 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 125 "describe.pgc"
+
+
+     if (!(    count1 == count2 &&
+         count1 == sqlda1->sqld &&
+         count1 == sqlda2->sqld &&
+         count1 == sqlda3->sqld))
+         exit(1);
+
+     for (i = 1; i <= count1; i++)
+     {
+         { ECPGget_desc(__LINE__, "desc1", i,ECPGd_name,
+     ECPGt_char,(field_name1),(long)30,(long)1,(30)*sizeof(char), ECPGd_EODT);
+
+ #line 135 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 135 "describe.pgc"
+
+         { ECPGget_desc(__LINE__, "desc2", i,ECPGd_name,
+     ECPGt_char,(field_name2),(long)30,(long)1,(30)*sizeof(char), ECPGd_EODT);
+
+ #line 136 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 136 "describe.pgc"
+
+         printf("%d\n\tfield_name1 '%s'\n\tfield_name2 '%s'\n\t"
+             "sqlda1 '%s'\n\tsqlda2 '%s'\n\tsqlda3 '%s'\n",
+             i, field_name1, field_name2,
+             sqlda1->sqlvar[i-1].sqlname,
+             sqlda2->sqlvar[i-1].sqlname,
+             sqlda3->sqlvar[i-1].sqlname);
+     }
+
+     strcpy(msg, "deallocate");
+     ECPGdeallocate_desc(__LINE__, "desc1");
+ #line 146 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 146 "describe.pgc"
+
+     ECPGdeallocate_desc(__LINE__, "desc2");
+ #line 147 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 147 "describe.pgc"
+
+     free(sqlda1);
+     free(sqlda2);
+     free(sqlda3);
+
+     { ECPGdeallocate(__LINE__, 1, NULL, "st_id2");
+ #line 152 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 152 "describe.pgc"
+
+
+     /* End test */
+
+     strcpy(msg, "drop");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "drop table t1", ECPGt_EOIT, ECPGt_EORT);
+ #line 157 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 157 "describe.pgc"
+
+
+     strcpy(msg, "commit");
+     { ECPGtrans(__LINE__, NULL, "commit");
+ #line 160 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 160 "describe.pgc"
+
+
+     strcpy(msg, "disconnect");
+     { ECPGdisconnect(__LINE__, "CURRENT");
+ #line 163 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 163 "describe.pgc"
+
+
+     return (0);
+ }
diff -dcrpN pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-describe.stderr
pgsql.describe/src/interfaces/ecpg/test/expected/compat_informix-describe.stderr
*** pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-describe.stderr    1970-01-01 01:00:00.000000000
+0100
--- pgsql.describe/src/interfaces/ecpg/test/expected/compat_informix-describe.stderr    2009-08-11 17:23:04.000000000
+0200
***************
*** 0 ****
--- 1,100 ----
+ [NO_PID]: ECPGdebug: set to 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGconnect: opening database regress1 on <DEFAULT> port <DEFAULT>
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 30: query: set datestyle to iso; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 30: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 30: OK: SET
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 33: query: create table t1 ( id serial primary key , t text ); with 0 parameter(s) on
connectionregress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 33: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 33: OK: CREATE TABLE
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 36: query: insert into t1 ( id , t ) values ( default , 'a' ); with 0 parameter(s) on
connectionregress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 36: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 36: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 37: query: insert into t1 ( id , t ) values ( default , 'b' ); with 0 parameter(s) on
connectionregress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 37: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 37: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 38: query: insert into t1 ( id , t ) values ( default , 'c' ); with 0 parameter(s) on
connectionregress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 38: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 38: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 39: query: insert into t1 ( id , t ) values ( default , 'd' ); with 0 parameter(s) on
connectionregress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 39: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 39: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGtrans on line 42: action "commit"; connection "regress1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGprepare on line 55: name st_id1; query: "SELECT id, t FROM t1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc_header: found 2 attributes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc_header: found 2 attributes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = id
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = id
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = t
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = t
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGdeallocate on line 99: name st_id1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGprepare on line 108: name st_id2; query: "SELECT id, t FROM t1 WHERE id = -1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc_header: found 2 attributes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc_header: found 2 attributes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = id
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = id
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = t
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = t
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGdeallocate on line 152: name st_id2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 157: query: drop table t1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 157: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 157: OK: DROP TABLE
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGtrans on line 160: action "commit"; connection "regress1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_finish: connection regress1 closed
+ [NO_PID]: sqlca: code: 0, state: 00000
diff -dcrpN pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-describe.stdout
pgsql.describe/src/interfaces/ecpg/test/expected/compat_informix-describe.stdout
*** pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-describe.stdout    1970-01-01 01:00:00.000000000
+0100
--- pgsql.describe/src/interfaces/ecpg/test/expected/compat_informix-describe.stdout    2009-08-11 17:23:04.000000000
+0200
***************
*** 0 ****
--- 1,24 ----
+ 1
+     field_name1 'id'
+     field_name2 'id'
+     sqlda1 'id'
+     sqlda2 'id'
+     sqlda3 'id'
+ 2
+     field_name1 't'
+     field_name2 't'
+     sqlda1 't'
+     sqlda2 't'
+     sqlda3 't'
+ 1
+     field_name1 'id'
+     field_name2 'id'
+     sqlda1 'id'
+     sqlda2 'id'
+     sqlda3 'id'
+ 2
+     field_name1 't'
+     field_name2 't'
+     sqlda1 't'
+     sqlda2 't'
+     sqlda3 't'
diff -dcrpN pgsql.sqlda/src/interfaces/ecpg/test/expected/preproc-describe.c
pgsql.describe/src/interfaces/ecpg/test/expected/preproc-describe.c
*** pgsql.sqlda/src/interfaces/ecpg/test/expected/preproc-describe.c    1970-01-01 01:00:00.000000000 +0100
--- pgsql.describe/src/interfaces/ecpg/test/expected/preproc-describe.c    2009-08-11 17:29:53.000000000 +0200
***************
*** 0 ****
--- 1,481 ----
+ /* Processed by ecpg (regression mode) */
+ /* These include files are added by the preprocessor */
+ #include <ecpglib.h>
+ #include <ecpgerrno.h>
+ #include <sqlca.h>
+ /* End of automatic include section */
+ #define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+ #line 1 "describe.pgc"
+ #include <stdlib.h>
+ #include <string.h>
+
+
+ #line 1 "regression.h"
+
+
+
+
+
+
+ #line 4 "describe.pgc"
+
+
+ /* exec sql whenever sqlerror  stop ; */
+ #line 6 "describe.pgc"
+
+
+ int
+ main (void)
+ {
+ /* exec sql begin declare section */
+
+
+
+
+
+
+
+
+ #line 12 "describe.pgc"
+  char * stmt1 = "SELECT id, t FROM t1" ;
+
+ #line 13 "describe.pgc"
+  char * stmt2 = "SELECT id, t FROM t1 WHERE id = -1" ;
+
+ #line 14 "describe.pgc"
+  int i , count1 , count2 , count3 , count4 ;
+
+ #line 15 "describe.pgc"
+  char field_name1 [ 30 ] = "not set" ;
+
+ #line 16 "describe.pgc"
+  char field_name2 [ 30 ] = "not set" ;
+
+ #line 17 "describe.pgc"
+  char field_name3 [ 30 ] = "not set" ;
+
+ #line 18 "describe.pgc"
+  char field_name4 [ 30 ] = "not set" ;
+ /* exec sql end declare section */
+ #line 19 "describe.pgc"
+
+
+     char msg[128];
+
+     ECPGdebug(1, stderr);
+
+     strcpy(msg, "connect");
+     { ECPGconnect(__LINE__, 0, "regress1" , NULL, NULL , NULL, 0);
+ #line 26 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 26 "describe.pgc"
+
+
+     strcpy(msg, "set");
+     { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "set datestyle to iso", ECPGt_EOIT, ECPGt_EORT);
+ #line 29 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 29 "describe.pgc"
+
+
+     strcpy(msg, "create");
+     { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table t1 ( id serial primary key , t text )",
ECPGt_EOIT,ECPGt_EORT); 
+ #line 32 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 32 "describe.pgc"
+
+
+     strcpy(msg, "insert");
+     { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into t1 ( id , t ) values ( default , 'a' )",
ECPGt_EOIT,ECPGt_EORT); 
+ #line 35 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 35 "describe.pgc"
+
+     { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into t1 ( id , t ) values ( default , 'b' )",
ECPGt_EOIT,ECPGt_EORT); 
+ #line 36 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 36 "describe.pgc"
+
+     { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into t1 ( id , t ) values ( default , 'c' )",
ECPGt_EOIT,ECPGt_EORT); 
+ #line 37 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 37 "describe.pgc"
+
+     { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into t1 ( id , t ) values ( default , 'd' )",
ECPGt_EOIT,ECPGt_EORT); 
+ #line 38 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 38 "describe.pgc"
+
+
+     strcpy(msg, "commit");
+     { ECPGtrans(__LINE__, NULL, "commit");
+ #line 41 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 41 "describe.pgc"
+
+
+     /*
+      * Test DESCRIBE with a query producing tuples.
+      * DESCRIPTOR and SQL DESCRIPTOR are the same in native mode.
+      */
+
+     strcpy(msg, "allocate");
+     ECPGallocate_desc(__LINE__, "desc1");
+ #line 49 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 49 "describe.pgc"
+
+     ECPGallocate_desc(__LINE__, "desc2");
+ #line 50 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 50 "describe.pgc"
+
+     ECPGallocate_desc(__LINE__, "desc3");
+ #line 51 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 51 "describe.pgc"
+
+     ECPGallocate_desc(__LINE__, "desc4");
+ #line 52 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 52 "describe.pgc"
+
+
+     strcpy(msg, "prepare");
+     { ECPGprepare(__LINE__, NULL, 0, "st_id1", stmt1);
+ #line 55 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 55 "describe.pgc"
+
+
+     strcpy(msg, "describe");
+     { ECPGdescribe(__LINE__, 0, NULL, "st_id1",
+     ECPGt_descriptor, "desc1", 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+ #line 58 "describe.pgc"
+
+     { ECPGdescribe(__LINE__, 0, NULL, "st_id1",
+     ECPGt_descriptor, "desc2", 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+ #line 59 "describe.pgc"
+
+     { ECPGdescribe(__LINE__, 0, NULL, "st_id1",
+     ECPGt_descriptor, "desc3", 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+ #line 60 "describe.pgc"
+
+     { ECPGdescribe(__LINE__, 0, NULL, "st_id1",
+     ECPGt_descriptor, "desc4", 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+ #line 61 "describe.pgc"
+
+
+     strcpy(msg, "get descriptor");
+     { ECPGget_desc_header(__LINE__, "desc1", &(count1));
+
+ #line 64 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 64 "describe.pgc"
+
+     { ECPGget_desc_header(__LINE__, "desc2", &(count2));
+
+ #line 65 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 65 "describe.pgc"
+
+     { ECPGget_desc_header(__LINE__, "desc3", &(count3));
+
+ #line 66 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 66 "describe.pgc"
+
+     { ECPGget_desc_header(__LINE__, "desc4", &(count4));
+
+ #line 67 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 67 "describe.pgc"
+
+
+     if (!(count1 == count2 && count1 == count3 && count1 == count4))
+         exit(1);
+
+     for (i = 1; i <= count1; i++)
+     {
+         { ECPGget_desc(__LINE__, "desc1", i,ECPGd_name,
+     ECPGt_char,(field_name1),(long)30,(long)1,(30)*sizeof(char), ECPGd_EODT);
+
+ #line 74 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 74 "describe.pgc"
+
+         { ECPGget_desc(__LINE__, "desc2", i,ECPGd_name,
+     ECPGt_char,(field_name2),(long)30,(long)1,(30)*sizeof(char), ECPGd_EODT);
+
+ #line 75 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 75 "describe.pgc"
+
+         { ECPGget_desc(__LINE__, "desc3", i,ECPGd_name,
+     ECPGt_char,(field_name3),(long)30,(long)1,(30)*sizeof(char), ECPGd_EODT);
+
+ #line 76 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 76 "describe.pgc"
+
+         { ECPGget_desc(__LINE__, "desc4", i,ECPGd_name,
+     ECPGt_char,(field_name4),(long)30,(long)1,(30)*sizeof(char), ECPGd_EODT);
+
+ #line 77 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 77 "describe.pgc"
+
+         printf("field_name 1 '%s' 2 '%s' 3 '%s' 4 '%s'\n",
+             field_name1, field_name2, field_name3, field_name4);
+     }
+
+     strcpy(msg, "deallocate");
+     ECPGdeallocate_desc(__LINE__, "desc1");
+ #line 83 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 83 "describe.pgc"
+
+     ECPGdeallocate_desc(__LINE__, "desc2");
+ #line 84 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 84 "describe.pgc"
+
+     ECPGdeallocate_desc(__LINE__, "desc3");
+ #line 85 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 85 "describe.pgc"
+
+     ECPGdeallocate_desc(__LINE__, "desc4");
+ #line 86 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 86 "describe.pgc"
+
+
+     { ECPGdeallocate(__LINE__, 0, NULL, "st_id1");
+ #line 88 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 88 "describe.pgc"
+
+
+     /* Test DESCRIBE with a query not producing tuples */
+
+     strcpy(msg, "allocate");
+     ECPGallocate_desc(__LINE__, "desc1");
+ #line 93 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 93 "describe.pgc"
+
+     ECPGallocate_desc(__LINE__, "desc2");
+ #line 94 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 94 "describe.pgc"
+
+     ECPGallocate_desc(__LINE__, "desc3");
+ #line 95 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 95 "describe.pgc"
+
+     ECPGallocate_desc(__LINE__, "desc4");
+ #line 96 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 96 "describe.pgc"
+
+
+     strcpy(msg, "prepare");
+     { ECPGprepare(__LINE__, NULL, 0, "st_id2", stmt2);
+ #line 99 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 99 "describe.pgc"
+
+
+     strcpy(msg, "describe");
+     { ECPGdescribe(__LINE__, 0, NULL, "st_id2",
+     ECPGt_descriptor, "desc1", 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+ #line 102 "describe.pgc"
+
+     { ECPGdescribe(__LINE__, 0, NULL, "st_id2",
+     ECPGt_descriptor, "desc2", 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+ #line 103 "describe.pgc"
+
+     { ECPGdescribe(__LINE__, 0, NULL, "st_id2",
+     ECPGt_descriptor, "desc3", 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+ #line 104 "describe.pgc"
+
+     { ECPGdescribe(__LINE__, 0, NULL, "st_id2",
+     ECPGt_descriptor, "desc4", 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+ #line 105 "describe.pgc"
+
+
+     strcpy(msg, "get descriptor");
+     { ECPGget_desc_header(__LINE__, "desc1", &(count1));
+
+ #line 108 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 108 "describe.pgc"
+
+     { ECPGget_desc_header(__LINE__, "desc2", &(count2));
+
+ #line 109 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 109 "describe.pgc"
+
+     { ECPGget_desc_header(__LINE__, "desc3", &(count3));
+
+ #line 110 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 110 "describe.pgc"
+
+     { ECPGget_desc_header(__LINE__, "desc4", &(count4));
+
+ #line 111 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 111 "describe.pgc"
+
+
+     if (!(count1 == count2 && count1 == count3 && count1 == count4))
+         exit(1);
+
+     for (i = 1; i <= count1; i++)
+     {
+         { ECPGget_desc(__LINE__, "desc1", i,ECPGd_name,
+     ECPGt_char,(field_name1),(long)30,(long)1,(30)*sizeof(char), ECPGd_EODT);
+
+ #line 118 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 118 "describe.pgc"
+
+         { ECPGget_desc(__LINE__, "desc2", i,ECPGd_name,
+     ECPGt_char,(field_name2),(long)30,(long)1,(30)*sizeof(char), ECPGd_EODT);
+
+ #line 119 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 119 "describe.pgc"
+
+         { ECPGget_desc(__LINE__, "desc3", i,ECPGd_name,
+     ECPGt_char,(field_name3),(long)30,(long)1,(30)*sizeof(char), ECPGd_EODT);
+
+ #line 120 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 120 "describe.pgc"
+
+         { ECPGget_desc(__LINE__, "desc4", i,ECPGd_name,
+     ECPGt_char,(field_name4),(long)30,(long)1,(30)*sizeof(char), ECPGd_EODT);
+
+ #line 121 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 121 "describe.pgc"
+
+         printf("field_name 1 '%s' 2 '%s' 3 '%s' 4 '%s'\n",
+             field_name1, field_name2, field_name3, field_name4);
+     }
+
+     strcpy(msg, "deallocate");
+     ECPGdeallocate_desc(__LINE__, "desc1");
+ #line 127 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 127 "describe.pgc"
+
+     ECPGdeallocate_desc(__LINE__, "desc2");
+ #line 128 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 128 "describe.pgc"
+
+     ECPGdeallocate_desc(__LINE__, "desc3");
+ #line 129 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 129 "describe.pgc"
+
+     ECPGdeallocate_desc(__LINE__, "desc4");
+ #line 130 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);
+ #line 130 "describe.pgc"
+
+
+     { ECPGdeallocate(__LINE__, 0, NULL, "st_id2");
+ #line 132 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 132 "describe.pgc"
+
+
+
+     /* End test */
+
+     strcpy(msg, "drop");
+     { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table t1", ECPGt_EOIT, ECPGt_EORT);
+ #line 138 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 138 "describe.pgc"
+
+
+     strcpy(msg, "commit");
+     { ECPGtrans(__LINE__, NULL, "commit");
+ #line 141 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 141 "describe.pgc"
+
+
+     strcpy(msg, "disconnect");
+     { ECPGdisconnect(__LINE__, "CURRENT");
+ #line 144 "describe.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 144 "describe.pgc"
+
+
+     return (0);
+ }
diff -dcrpN pgsql.sqlda/src/interfaces/ecpg/test/expected/preproc-describe.stderr
pgsql.describe/src/interfaces/ecpg/test/expected/preproc-describe.stderr
*** pgsql.sqlda/src/interfaces/ecpg/test/expected/preproc-describe.stderr    1970-01-01 01:00:00.000000000 +0100
--- pgsql.describe/src/interfaces/ecpg/test/expected/preproc-describe.stderr    2009-08-11 17:29:53.000000000 +0200
***************
*** 0 ****
--- 1,140 ----
+ [NO_PID]: ECPGdebug: set to 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGconnect: opening database regress1 on <DEFAULT> port <DEFAULT>
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 29: query: set datestyle to iso; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 29: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 29: OK: SET
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 32: query: create table t1 ( id serial primary key , t text ); with 0 parameter(s) on
connectionregress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 32: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 32: OK: CREATE TABLE
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 35: query: insert into t1 ( id , t ) values ( default , 'a' ); with 0 parameter(s) on
connectionregress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 35: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 35: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 36: query: insert into t1 ( id , t ) values ( default , 'b' ); with 0 parameter(s) on
connectionregress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 36: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 36: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 37: query: insert into t1 ( id , t ) values ( default , 'c' ); with 0 parameter(s) on
connectionregress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 37: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 37: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 38: query: insert into t1 ( id , t ) values ( default , 'd' ); with 0 parameter(s) on
connectionregress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 38: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 38: OK: INSERT 0 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGtrans on line 41: action "commit"; connection "regress1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGprepare on line 55: name st_id1; query: "SELECT id, t FROM t1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc_header: found 2 attributes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc_header: found 2 attributes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc_header: found 2 attributes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc_header: found 2 attributes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = id
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = id
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = id
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = id
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = t
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = t
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = t
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = t
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGdeallocate on line 88: name st_id1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGprepare on line 99: name st_id2; query: "SELECT id, t FROM t1 WHERE id = -1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc_header: found 2 attributes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc_header: found 2 attributes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc_header: found 2 attributes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc_header: found 2 attributes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = id
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = id
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = id
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = id
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = t
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = t
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = t
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: reading items for tuple 2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGget_desc: NAME = t
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGdeallocate on line 132: name st_id2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 138: query: drop table t1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 138: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 138: OK: DROP TABLE
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGtrans on line 141: action "commit"; connection "regress1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_finish: connection regress1 closed
+ [NO_PID]: sqlca: code: 0, state: 00000
diff -dcrpN pgsql.sqlda/src/interfaces/ecpg/test/expected/preproc-describe.stdout
pgsql.describe/src/interfaces/ecpg/test/expected/preproc-describe.stdout
*** pgsql.sqlda/src/interfaces/ecpg/test/expected/preproc-describe.stdout    1970-01-01 01:00:00.000000000 +0100
--- pgsql.describe/src/interfaces/ecpg/test/expected/preproc-describe.stdout    2009-08-11 17:29:53.000000000 +0200
***************
*** 0 ****
--- 1,4 ----
+ field_name 1 'id' 2 'id' 3 'id' 4 'id'
+ field_name 1 't' 2 't' 3 't' 4 't'
+ field_name 1 'id' 2 'id' 3 'id' 4 'id'
+ field_name 1 't' 2 't' 3 't' 4 't'
diff -dcrpN pgsql.sqlda/src/interfaces/ecpg/test/preproc/describe.pgc
pgsql.describe/src/interfaces/ecpg/test/preproc/describe.pgc
*** pgsql.sqlda/src/interfaces/ecpg/test/preproc/describe.pgc    1970-01-01 01:00:00.000000000 +0100
--- pgsql.describe/src/interfaces/ecpg/test/preproc/describe.pgc    2009-08-11 17:26:13.000000000 +0200
***************
*** 0 ****
--- 1,147 ----
+ #include <stdlib.h>
+ #include <string.h>
+
+ exec sql include ../regression;
+
+ exec sql whenever sqlerror stop;
+
+ int
+ main (void)
+ {
+ exec sql begin declare section;
+     char    *stmt1 = "SELECT id, t FROM t1";
+     char    *stmt2 = "SELECT id, t FROM t1 WHERE id = -1";
+     int    i, count1, count2, count3, count4;
+     char    field_name1[30] = "not set";
+     char    field_name2[30] = "not set";
+     char    field_name3[30] = "not set";
+     char    field_name4[30] = "not set";
+ exec sql end declare section;
+
+     char msg[128];
+
+     ECPGdebug(1, stderr);
+
+     strcpy(msg, "connect");
+     exec sql connect to REGRESSDB1;
+
+     strcpy(msg, "set");
+     exec sql set datestyle to iso;
+
+     strcpy(msg, "create");
+     exec sql create table t1(id serial primary key, t text);
+
+     strcpy(msg, "insert");
+     exec sql insert into t1(id, t) values (default, 'a');
+     exec sql insert into t1(id, t) values (default, 'b');
+     exec sql insert into t1(id, t) values (default, 'c');
+     exec sql insert into t1(id, t) values (default, 'd');
+
+     strcpy(msg, "commit");
+     exec sql commit;
+
+     /*
+      * Test DESCRIBE with a query producing tuples.
+      * DESCRIPTOR and SQL DESCRIPTOR are the same in native mode.
+      */
+
+     strcpy(msg, "allocate");
+     exec sql allocate descriptor desc1;
+     exec sql allocate descriptor desc2;
+     exec sql allocate descriptor desc3;
+     exec sql allocate descriptor desc4;
+
+     strcpy(msg, "prepare");
+     exec sql prepare st_id1 FROM :stmt1;
+
+     strcpy(msg, "describe");
+     exec sql describe st_id1 into descriptor desc1;
+     exec sql describe st_id1 into sql descriptor desc2;
+     exec sql describe st_id1 using descriptor desc3;
+     exec sql describe st_id1 using sql descriptor desc4;
+
+     strcpy(msg, "get descriptor");
+     exec sql get descriptor desc1 :count1 = count;
+     exec sql get descriptor desc2 :count2 = count;
+     exec sql get descriptor desc3 :count3 = count;
+     exec sql get descriptor desc4 :count4 = count;
+
+     if (!(count1 == count2 && count1 == count3 && count1 == count4))
+         exit(1);
+
+     for (i = 1; i <= count1; i++)
+     {
+         exec sql get descriptor desc1 value :i :field_name1 = name;
+         exec sql get descriptor desc2 value :i :field_name2 = name;
+         exec sql get descriptor desc3 value :i :field_name3 = name;
+         exec sql get descriptor desc4 value :i :field_name4 = name;
+         printf("field_name 1 '%s' 2 '%s' 3 '%s' 4 '%s'\n",
+             field_name1, field_name2, field_name3, field_name4);
+     }
+
+     strcpy(msg, "deallocate");
+     exec sql deallocate descriptor desc1;
+     exec sql deallocate descriptor desc2;
+     exec sql deallocate descriptor desc3;
+     exec sql deallocate descriptor desc4;
+
+     exec sql deallocate prepare st_id1;
+
+     /* Test DESCRIBE with a query not producing tuples */
+
+     strcpy(msg, "allocate");
+     exec sql allocate descriptor desc1;
+     exec sql allocate descriptor desc2;
+     exec sql allocate descriptor desc3;
+     exec sql allocate descriptor desc4;
+
+     strcpy(msg, "prepare");
+     exec sql prepare st_id2 FROM :stmt2;
+
+     strcpy(msg, "describe");
+     exec sql describe st_id2 into descriptor desc1;
+     exec sql describe st_id2 into sql descriptor desc2;
+     exec sql describe st_id2 using descriptor desc3;
+     exec sql describe st_id2 using sql descriptor desc4;
+
+     strcpy(msg, "get descriptor");
+     exec sql get descriptor desc1 :count1 = count;
+     exec sql get descriptor desc2 :count2 = count;
+     exec sql get descriptor desc3 :count3 = count;
+     exec sql get descriptor desc4 :count4 = count;
+
+     if (!(count1 == count2 && count1 == count3 && count1 == count4))
+         exit(1);
+
+     for (i = 1; i <= count1; i++)
+     {
+         exec sql get descriptor desc1 value :i :field_name1 = name;
+         exec sql get descriptor desc2 value :i :field_name2 = name;
+         exec sql get descriptor desc3 value :i :field_name3 = name;
+         exec sql get descriptor desc4 value :i :field_name4 = name;
+         printf("field_name 1 '%s' 2 '%s' 3 '%s' 4 '%s'\n",
+             field_name1, field_name2, field_name3, field_name4);
+     }
+
+     strcpy(msg, "deallocate");
+     exec sql deallocate descriptor desc1;
+     exec sql deallocate descriptor desc2;
+     exec sql deallocate descriptor desc3;
+     exec sql deallocate descriptor desc4;
+
+     exec sql deallocate prepare st_id2;
+
+
+     /* End test */
+
+     strcpy(msg, "drop");
+     exec sql drop table t1;
+
+     strcpy(msg, "commit");
+     exec sql commit;
+
+     strcpy(msg, "disconnect");
+     exec sql disconnect;
+
+     return (0);
+ }
diff -dcrpN pgsql.sqlda/src/interfaces/ecpg/test/preproc/Makefile
pgsql.describe/src/interfaces/ecpg/test/preproc/Makefile
*** pgsql.sqlda/src/interfaces/ecpg/test/preproc/Makefile    2009-08-09 23:14:23.000000000 +0200
--- pgsql.describe/src/interfaces/ecpg/test/preproc/Makefile    2009-08-11 15:30:38.000000000 +0200
*************** TESTS = array_of_struct array_of_struct.
*** 8,13 ****
--- 8,14 ----
      autoprep autoprep.c \
      comment comment.c \
      cursor cursor.c \
+     describe describe.c \
      define define.c \
      init init.c \
      strings strings.c \

Re: Split-up ECPG patches

From
Michael Meskes
Date:
On Mon, Aug 03, 2009 at 06:12:43PM +0200, Boszormenyi Zoltan wrote:
> - sqlda support:
>   - sqlda.c now indicates license
>   - #defines inside #if 0 ... #endif are now omitted from sqltypes.h
>   (both per comments from Jaime Casanova)

I still owe you some first thoughts about this part of the patch, although I
didn't run it yet

> *************** 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);

Please add some ecpg_log output here. The same is doen for a descriptor and for
variables, so it should be doen for sqlda too. Also please add some meaningful
comment as to what the code is supposed to do.

> + 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);

Same here, the question is not *what* does the code accomplish, but *why*.

> + 
> +     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;
> +     }

ecpg_alloc is being used because it already checks for ENOMEM, no need to do it again.

> + static long
> + ecpg_sqlda_size_round_align(long size, int alignment, int round)
> + {
> +     if (size % alignment)
> +         size += alignment - (size % alignment);
> +     size += round;
> +     return size;
> + }

Another implementation of the same code we saw a few lines ago?

> + static long
> + ecpg_sqlda_size_align(long size, int alignment)
> + {
> +     if (size % alignment)
> +         size += alignment - (size % alignment);
> +     return size;
> + }

And yet another one? Sure I see that the above function has an additional add
command, I just wonder why we need the alignment three times.

> +         sqlda = realloc(sqlda, size);

We have ecpg_realloc().

> *************** 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); \
> +                 }
> + 

Could you please explain why you removed this test for some queries? Is there a
bug in there?

Michael
-- 
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Mon, Aug 03, 2009 at 06:12:43PM +0200, Boszormenyi Zoltan wrote:
>   
>> - sqlda support:
>>   - sqlda.c now indicates license
>>   - #defines inside #if 0 ... #endif are now omitted from sqltypes.h
>>   (both per comments from Jaime Casanova)
>>     
>
> I still owe you some first thoughts about this part of the patch, although I
> didn't run it yet
>   

Okay, answers below...

>> *************** 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);
>>     
>
> Please add some ecpg_log output here. The same is doen for a descriptor and for
> variables, so it should be doen for sqlda too. Also please add some meaningful
> comment as to what the code is supposed to do.
>   

Will add the ecpg_log(). What the code does is:
- sets up a minimal SQLDA on the first call (called with NULL ptr), so the field types and field names and some other
propertiesare in place. doesn't do further work if out of memory
 
- upon subsequent calls it checks whether a "compatible" sqlda was
passed in, i.e. same number of fields, same types, etc. Sanity check. Doesn't do
further work if the check fails.
- fills in the field values

>> + 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);
>>     
>
> Same here, the question is not *what* does the code accomplish, but *why*.
>   

Arbitrary alignment, maybe not needed, Will check.

>> + 
>> +     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;
>> +     }
>>     
>
> ecpg_alloc is being used because it already checks for ENOMEM, no need to do it again.
>   

Okay, thanks.

>> + static long
>> + ecpg_sqlda_size_round_align(long size, int alignment, int round)
>> + {
>> +     if (size % alignment)
>> +         size += alignment - (size % alignment);
>>     

Padding to the position of the "current" variable.

>> +     size += round;
>>     

Position to the next variable.

>> +     return size;
>> + }
>>     
>
> Another implementation of the same code we saw a few lines ago?
>   

It's called with different alignments and padding at several places.
Used for computing the offset of the next variable.

>> + static long
>> + ecpg_sqlda_size_align(long size, int alignment)
>> + {
>> +     if (size % alignment)
>> +         size += alignment - (size % alignment);
>>     

Padding only.

>> +     return size;
>> + }
>>     
>
> And yet another one? Sure I see that the above function has an additional add
> command, I just wonder why we need the alignment three times.
>   

The fixed size alignment can be done with a call
to ecpg_sqlda_size_round_align(), sure.

>> +         sqlda = realloc(sqlda, size);
>>     
>
> We have ecpg_realloc().
>   

Okay, thanks.

>> *************** 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); \
>> +                 }
>> + 
>>     
>
> Could you please explain why you removed this test for some queries? Is there a
> bug in there?
>   

DESCRIBE can be used on queries not returning tuples.
This check at the beginning of the function prevented it.
I only added the check back to two or three places where
tuples were actually processed. Maybe I missed places.

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/



Re: Split-up ECPG patches

From
Michael Meskes
Date:
On Fri, Aug 14, 2009 at 10:12:24PM +0200, Boszormenyi Zoltan wrote:
> Will add the ecpg_log(). What the code does is:
> - sets up a minimal SQLDA on the first call (called with NULL ptr),
>   so the field types and field names and some other properties are in place.
>   doesn't do further work if out of memory

So this is an empty but compatible sqlda, right? 

> - upon subsequent calls it checks whether a "compatible" sqlda was
> passed in,
>   i.e. same number of fields, same types, etc. Sanity check. Doesn't do
> further
>   work if the check fails.

What heppens if the sqlda is incompatible?

Michael
-- 
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Fri, Aug 14, 2009 at 10:12:24PM +0200, Boszormenyi Zoltan wrote:
>   
>> Will add the ecpg_log(). What the code does is:
>> - sets up a minimal SQLDA on the first call (called with NULL ptr),
>>   so the field types and field names and some other properties are in place.
>>   doesn't do further work if out of memory
>>     
>
> So this is an empty but compatible sqlda, right? 
>   

Yes. Is's the same sqlda as DESCRIBE would create.

>> - upon subsequent calls it checks whether a "compatible" sqlda was
>> passed in,
>>   i.e. same number of fields, same types, etc. Sanity check. Doesn't do
>> further
>>   work if the check fails.
>>     
>
> What heppens if the sqlda is incompatible?
>   

Returns false?

> Michael
>   


-- 
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/



Re: Split-up ECPG patches

From
Michael Meskes
Date:
On Sun, Aug 16, 2009 at 05:59:46PM +0200, Boszormenyi Zoltan wrote:
> > What heppens if the sqlda is incompatible?
> 
> Returns false?

I wasn't talking about this one function but about the flow of the resulting
program. How can it happen that sqlda is incompatible and what happens then?

Michael
-- 
Michael Meskes
Michael at Fam-Meskes dot De, Michael at Meskes dot (De|Com|Net|Org)
Michael at BorussiaFan dot De, Meskes at (Debian|Postgresql) dot Org
ICQ: 179140304, AIM/Yahoo/Skype: michaelmeskes, Jabber: meskes@jabber.org
Go VfL Borussia! Go SF 49ers! Use Debian GNU/Linux! Use PostgreSQL!


Re: Split-up ECPG patches

From
Boszormenyi Zoltan
Date:
Michael Meskes írta:
> On Sun, Aug 16, 2009 at 05:59:46PM +0200, Boszormenyi Zoltan wrote:
>
>>> What heppens if the sqlda is incompatible?
>>>
>> Returns false?
>>
>
> I wasn't talking about this one function but about the flow of the resulting
> program. How can it happen that sqlda is incompatible and what happens then?
>

Hm. The following may occur. One may pass the same
sqlda ptr to two different cursors in DECLARE or FETCH
in the same loop. In this case it's wrong to not process the
"incompatible" call. Modified patch is attached:
- fixed flow, frees up the "incompatible" sqlda and creates a new one
- added ecpg_log() calls
- no more realloc(), an "empty" sqlda is allocated for full size.
  realloc() can destroy internal pointers (like the ones pointing to
  field names and ->sqlvar.)

The previous pg85-describe-5-ctxdiff.patch still applies cleanly.

Best regards,
Zoltán Böszörményi

--
Bible has answers for everything. Proof:
"But let your communication be, Yea, yea; Nay, nay: for whatsoever is more
than these cometh of evil." (Matthew 5:37) - basics of digital technology.
"May your kingdom come" - superficial description of plate tectonics

----------------------------------
Zoltán Böszörményi
Cybertec Schönig & Schönig GmbH
http://www.postgresql.at/

diff -dcrpN pgsql/src/interfaces/ecpg/ecpglib/execute.c pgsql.sqlda/src/interfaces/ecpg/ecpglib/execute.c
*** pgsql/src/interfaces/ecpg/ecpglib/execute.c    2009-08-07 13:06:28.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/ecpglib/execute.c    2009-08-17 11:13:42.000000000 +0200
***************
*** 25,30 ****
--- 25,31 ----
  #include "ecpgerrno.h"
  #include "extern.h"
  #include "sqlca.h"
+ #include "sqlda.h"
  #include "sql3types.h"
  #include "pgtypes_numeric.h"
  #include "pgtypes_date.h"
*************** ecpg_store_input(const int lineno, const
*** 1033,1038 ****
--- 1034,1040 ----
                  break;

              case ECPGt_descriptor:
+             case ECPGt_sqlda:
                  break;

              default:
*************** ecpg_execute(struct statement * stmt)
*** 1172,1177 ****
--- 1174,1235 ----
              if (desc->count == desc_counter)
                  desc_counter = 0;
          }
+         else if (var->type == ECPGt_sqlda)
+         {
+             pg_sqlda_t      **_sqlda = (pg_sqlda_t **)var->pointer;
+             pg_sqlda_t       *sqlda = *_sqlda;
+             struct variable    desc_inlist;
+             int        i;
+
+             if (sqlda == NULL)
+                 return false;
+
+             desc_counter++;
+             for (i = 0; i < sqlda->sqld; i++)
+             {
+                 if (i + 1 == desc_counter)
+                 {
+                     desc_inlist.type = ecpg_sqlda_type(sqlda->sqlvar[i].sqltype);
+                     desc_inlist.value = sqlda->sqlvar[i].sqldata;
+                     desc_inlist.pointer = &(sqlda->sqlvar[i].sqldata);
+                     switch (desc_inlist.type)
+                     {
+                         case ECPGt_char:
+                         case ECPGt_varchar:
+                             desc_inlist.varcharsize = strlen(sqlda->sqlvar[i].sqldata);
+                             break;
+                         default:
+                             desc_inlist.varcharsize = 0;
+                             break;
+                     }
+                     desc_inlist.arrsize = 1;
+                     desc_inlist.offset = 0;
+                     if (sqlda->sqlvar[i].sqlind)
+                     {
+                         desc_inlist.ind_type = ECPGt_short;
+                         /* ECPG expects indicator value < 0 */
+                         if (*(sqlda->sqlvar[i].sqlind))
+                             *(sqlda->sqlvar[i].sqlind) = -1;
+                         desc_inlist.ind_value = sqlda->sqlvar[i].sqlind;
+                         desc_inlist.ind_pointer = &(sqlda->sqlvar[i].sqlind);
+                         desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = 1;
+                         desc_inlist.ind_offset = 0;
+                     }
+                     else
+                     {
+                         desc_inlist.ind_type = ECPGt_NO_INDICATOR;
+                         desc_inlist.ind_value = desc_inlist.ind_pointer = NULL;
+                         desc_inlist.ind_varcharsize = desc_inlist.ind_arrsize = desc_inlist.ind_offset = 0;
+                     }
+                     if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, &desc_inlist, &tobeinserted, false))
+                         return false;
+
+                     break;
+                 }
+             }
+             if (sqlda->sqld == desc_counter)
+                 desc_counter = 0;
+         }
          else
          {
              if (!ecpg_store_input(stmt->lineno, stmt->force_indicator, var, &tobeinserted, false))
*************** ecpg_execute(struct statement * stmt)
*** 1353,1358 ****
--- 1411,1453 ----
                  }
                  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 we are passed in a non-compatible sqlda then free it. */
+                 if (sqlda)
+                 {
+                     int    compat_sqlda;
+                     compat_sqlda = ecpg_compare_sqlda_with_PGresult(sqlda, results);
+                     ecpg_log("ecpg_execute on line %d: called ecpg_compare_sqlda_with_PGresult, status %d\n",
+                             stmt->lineno, compat_sqlda);
+                     if (!compat_sqlda)
+                     {
+                         free(sqlda);
+                         sqlda = NULL;
+                     }
+                 }
+                 /* Build a new sqlda structure */
+                 if (!sqlda)
+                 {
+                     sqlda = ecpg_build_sqlda_for_PGresult(stmt->lineno, results);
+                     ecpg_log("ecpg_execute on line %d: new sqlda was built\n", stmt->lineno);
+                     if (!sqlda)
+                         status = false;
+                     *_sqlda = sqlda;
+                 }
+                 /* If the sqlda was allocated then fill it. */
+                 if (status == true)
+                 {
+                     ecpg_set_sqlda_from_PGresult(stmt->lineno, _sqlda, results);
+                     ecpg_log("ecpg_execute on line %d: putting result (1 tuple %d fields) into sqlda descriptor\n",
+                             stmt->lineno, PQnfields(results));
+                 }
+
+                 var = var->next;
+             }
              else
                  for (act_field = 0; act_field < nfields && status; act_field++)
                  {
diff -dcrpN pgsql/src/interfaces/ecpg/ecpglib/extern.h pgsql.sqlda/src/interfaces/ecpg/ecpglib/extern.h
*** pgsql/src/interfaces/ecpg/ecpglib/extern.h    2009-05-25 12:08:48.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/ecpglib/extern.h    2009-08-11 10:32:34.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 pgsql/src/interfaces/ecpg/ecpglib/Makefile pgsql.sqlda/src/interfaces/ecpg/ecpglib/Makefile
*** pgsql/src/interfaces/ecpg/ecpglib/Makefile    2009-07-13 11:16:41.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/ecpglib/Makefile    2009-08-11 10:32:34.000000000 +0200
*************** override CFLAGS += $(PTHREAD_CFLAGS)
*** 24,30 ****
  # Need to recompile any libpgport object files
  LIBS := $(filter-out -lpgport, $(LIBS))

! OBJS= execute.o typename.o descriptor.o data.o error.o prepare.o memory.o \
      connect.o misc.o path.o pgstrcasecmp.o \
      $(filter snprintf.o strlcpy.o, $(LIBOBJS))

--- 24,30 ----
  # Need to recompile any libpgport object files
  LIBS := $(filter-out -lpgport, $(LIBS))

! OBJS= execute.o typename.o descriptor.o sqlda.o data.o error.o prepare.o memory.o \
      connect.o misc.o path.o pgstrcasecmp.o \
      $(filter snprintf.o strlcpy.o, $(LIBOBJS))

diff -dcrpN pgsql/src/interfaces/ecpg/ecpglib/sqlda.c pgsql.sqlda/src/interfaces/ecpg/ecpglib/sqlda.c
*** pgsql/src/interfaces/ecpg/ecpglib/sqlda.c    1970-01-01 01:00:00.000000000 +0100
--- pgsql.sqlda/src/interfaces/ecpg/ecpglib/sqlda.c    2009-08-17 11:10:32.000000000 +0200
***************
*** 0 ****
--- 1,329 ----
+ /*
+  * Crude SQLDA support routines
+  * Only supports fetching 1 record at a time
+  *
+  * The allocated memory area pointed by an sqlda pointer
+  * contains both the metadata and the data, so freeing up
+  * is a simple free(sqlda) as expected by the ESQL/C examples.
+  */
+
+ #define POSTGRES_ECPG_INTERNAL
+ #include "postgres_fe.h"
+ #include "pg_type.h"
+
+ #include <inttypes.h>
+ #include <dlfcn.h>
+
+ #include "ecpg-pthread-win32.h"
+ #include "decimal.h"
+ #include "ecpgtype.h"
+ #include "ecpglib.h"
+ #include "ecpgerrno.h"
+ #include "extern.h"
+ #include "sqlca.h"
+ #include "sqlda.h"
+ #include "sqltypes.h"
+
+ /*
+  * Compute the next variable's offset with
+  * the current variable's size and alignment.
+  */
+ static long
+ ecpg_sqlda_size_round_align(long offset, int alignment, int size)
+ {
+     if (offset % alignment)
+         offset += alignment - (offset % alignment);
+     offset += size;
+     return offset;
+ }
+
+ /*
+  * Compute the current variable's offset with alignment.
+  */
+ static long
+ ecpg_sqlda_size_align(long offset, int alignment)
+ {
+     if (offset % alignment)
+         offset += alignment - (offset % alignment);
+     return offset;
+ }
+
+ static long
+ ecpg_sqlda_empty_size(const PGresult *res)
+ {
+     long    size;
+     int    i;
+     int    sqld = PQnfields(res);
+
+
+     /* Initial size to store main structure and field structures */
+     size = sizeof(pg_sqlda_t) + sqld * sizeof(pg_sqlvar_t);
+
+     /* Add space for field names */
+     for (i = 0; i < sqld; i++)
+         size += strlen(PQfname(res, i)) + 1;
+
+     /* Add padding to the first field value */
+     size = ecpg_sqlda_size_align(size, sizeof(int));
+
+     return size;
+ }
+
+ static long
+ ecpg_sqlda_total_size(const PGresult *res)
+ {
+     int    i;
+     int    sqld = PQnfields(res);
+     long    size;
+
+     size = ecpg_sqlda_empty_size(res);
+
+     /* Add space for the field values */
+     for (i = 0; i < sqld; i++)
+     {
+         switch (ecpg_to_sqlda_type(PQftype(res, i)))
+         {
+             case SQLSMINT:
+                 size = ecpg_sqlda_size_round_align(size, sizeof(short), sizeof(short));
+                 break;
+             case SQLINT:
+             case SQLSERIAL:
+                 size = ecpg_sqlda_size_round_align(size, sizeof(int), sizeof(int));
+                 break;
+             case SQLFLOAT:
+                 size = ecpg_sqlda_size_round_align(size, sizeof(double), sizeof(double));
+                 break;
+             case SQLSMFLOAT:
+                 size = ecpg_sqlda_size_round_align(size, sizeof(float), sizeof(float));
+                 break;
+             case SQLDECIMAL:
+                 size = ecpg_sqlda_size_round_align(size, sizeof(int), sizeof(decimal));
+                 break;
+             case SQLINT8:
+             case SQLSERIAL8:
+                 size = ecpg_sqlda_size_round_align(size, sizeof(int64_t), sizeof(int64_t));
+                 break;
+
+             /*
+              * These types will be passed as character strings
+              * as is from the PGresult until we know what to do with them.
+              */
+             case SQLCHAR:
+             case SQLTEXT:
+             case SQLVCHAR:
+             case SQLNCHAR:
+             case SQLNVCHAR:
+             case SQLMONEY:
+             case SQLDATE:
+             case SQLDTIME:
+             case SQLINTERVAL:
+             default:
+                 break;
+         }
+     }
+     return size;
+ }
+
+ /*
+  * 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        sqld;
+     int        i;
+
+     size = ecpg_sqlda_total_size(res);
+     sqlda = (pg_sqlda_t *)ecpg_alloc(size, line);
+     if (!sqlda)
+         return NULL;
+
+     memset(sqlda, 0, size);
+     sqlvar = (pg_sqlvar_t *)(sqlda + 1);
+     sqld = PQnfields(res);
+     fname = (char *)(sqlvar + sqld);
+
+     sqlda->sqld = sqld;
+     sqlda->desc_occ = size; /* cheat here, keep the full allocated size */
+     sqlda->sqlvar = sqlvar;
+
+     for (i = 0; i < sqlda->sqld; i++)
+     {
+         sqlda->sqlvar[i].sqltype = ecpg_to_sqlda_type(PQftype(res, i));
+         strcpy(fname, PQfname(res, i));
+         sqlda->sqlvar[i].sqlname = fname;
+         fname += strlen(sqlda->sqlvar[i].sqlname) + 1;
+         sqlda->sqlvar[i].sqlformat = (char *)(long)PQfformat(res, i);
+         sqlda->sqlvar[i].sqlxid = PQftype(res, i);
+         sqlda->sqlvar[i].sqltypelen = PQfsize(res, i);
+     }
+
+     return sqlda;
+ }
+
+ /*
+  * 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;
+     long    size;
+
+     if (sqlda->sqld != PQnfields(res))
+     {
+         ecpg_log("ecpg_compare_sqlda_with_PGresult: sqld differ %d %d\n",
+                                                 sqlda->sqld, PQnfields(res));
+         return false;
+     }
+
+     size = ecpg_sqlda_total_size(res);
+     if (sqlda->desc_occ != size)
+     {
+         ecpg_log("ecpg_compare_sqlda_with_PGresult: structure size differ %d %d\n",
+                             sqlda->desc_occ, size);
+         return false;
+     }
+
+     for (i = 0; i < sqlda->sqld; i++)
+     {
+         if (sqlda->sqlvar[i].sqltype != ecpg_to_sqlda_type(PQftype(res, i)))
+         {
+             ecpg_log("ecpg_compare_sqlda_with_PGresult: field %d sqltype differ %d %d\n",
+                     i, sqlda->sqlvar[i].sqltype, ecpg_to_sqlda_type(PQftype(res, i)));
+             return false;
+         }
+         if (strncmp(sqlda->sqlvar[i].sqlname, PQfname(res, i), strlen(PQfname(res, i))))
+         {
+             ecpg_log("ecpg_compare_sqlda_with_PGresult: field %d sqlname differ '%s' '%s'\n",
+                     i, sqlda->sqlvar[i].sqlname, PQfname(res, i));
+             return false;
+         }
+         if (sqlda->sqlvar[i].sqlformat != (char *)(long)PQfformat(res, i))
+         {
+             ecpg_log("ecpg_compare_sqlda_with_PGresult: field %d sqlformat differ %d %d\n",
+                     i, sqlda->sqlvar[i].sqlformat, PQfformat(res, i));
+             return false;
+         }
+         if (sqlda->sqlvar[i].sqlxid != PQftype(res, i))
+         {
+             ecpg_log("ecpg_compare_sqlda_with_PGresult: field %d sqlxid differ %d %d\n",
+                     i, sqlda->sqlvar[i].sqlxid, PQftype(res, i));
+             return false;
+         }
+         if (sqlda->sqlvar[i].sqltypelen != PQfsize(res, i))
+         {
+             ecpg_log("ecpg_compare_sqlda_with_PGresult: field %d sqltypelen differ %d %d\n",
+                     i, sqlda->sqlvar[i].sqltypelen, PQfsize(res, i));
+             return false;
+         }
+     }
+
+     return true;
+ }
+
+ /*
+  * Sets values from PGresult.
+  */
+ 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;
+
+     /* Offset for the first field value */
+     size = ecpg_sqlda_empty_size(res);
+
+     /*
+      * Set sqlvar[i]->sqldata pointers and convert values to correct format
+      */
+     for (i = 0; i < sqlda->sqld; i++)
+     {
+         int type = -1, isnull;
+         int use_getdata = true;
+
+         switch (sqlda->sqlvar[i].sqltype)
+         {
+             case SQLSMINT:
+                 size = ecpg_sqlda_size_align(size, sizeof(short));
+                 sqlda->sqlvar[i].sqldata = (char *)sqlda + size;
+                 size += sizeof(short);
+                 type = ECPGt_short;
+                 break;
+             case SQLINT:
+             case SQLSERIAL:
+                 size = ecpg_sqlda_size_align(size, sizeof(int));
+                 sqlda->sqlvar[i].sqldata = (char *)sqlda + size;
+                 size += sizeof(int);
+                 type = ECPGt_int;
+                 break;
+             case SQLFLOAT:
+                 size = ecpg_sqlda_size_align(size, sizeof(double));
+                 sqlda->sqlvar[i].sqldata = (char *)sqlda + size;
+                 size += sizeof(double);
+                 type = ECPGt_double;
+                 break;
+             case SQLSMFLOAT:
+                 size = ecpg_sqlda_size_align(size, sizeof(float));
+                 sqlda->sqlvar[i].sqldata = (char *)sqlda + size;
+                 size += sizeof(float);
+                 type = ECPGt_float;
+                 break;
+             case SQLDECIMAL:
+             {
+                 size = ecpg_sqlda_size_align(size, sizeof(int));
+                 sqlda->sqlvar[i].sqldata = (char *)sqlda + size;
+                 size += sizeof(decimal);
+                 type = ECPGt_decimal;
+                 break;
+             }
+             case SQLINT8:
+             case SQLSERIAL8:
+                 size = ecpg_sqlda_size_align(size, sizeof(int64_t));
+                 sqlda->sqlvar[i].sqldata = (char *)sqlda + size;
+                 size += sizeof(int64_t);
+                 type = ECPGt_long_long;
+                 break;
+
+             /*
+              * These types will be passed as character strings until
+              * it's known what to do with them. We use sqlvar->sqldata
+              * in all cases regardless of length, don't care about
+              * sqlvar->sqlilongdata.
+              */
+             case SQLCHAR:
+             case SQLTEXT:
+             case SQLVCHAR:
+             case SQLNCHAR:
+             case SQLNVCHAR:
+             case SQLMONEY:
+             case SQLDATE:
+             case SQLDTIME:
+             case SQLINTERVAL:
+             default:
+                 use_getdata = false;
+                 break;
+         }
+
+         isnull = PQgetisnull(res, 0, i);
+         sqlda->sqlvar[i].sqlind = isnull ? &value_is_null : &value_is_not_null;
+         if (!isnull)
+         {
+             if (use_getdata)
+                 ecpg_get_data(res, 0, i, lineno,
+                         type, ECPGt_NO_INDICATOR,
+                         sqlda->sqlvar[i].sqldata, NULL, 0, 0, 0,
+                         ECPG_ARRAY_NONE, ECPG_COMPAT_INFORMIX, false);
+             else
+                 sqlda->sqlvar[i].sqldata = PQgetvalue(res, 0, i);
+         }
+     }
+ }
diff -dcrpN pgsql/src/interfaces/ecpg/ecpglib/typename.c pgsql.sqlda/src/interfaces/ecpg/ecpglib/typename.c
*** pgsql/src/interfaces/ecpg/ecpglib/typename.c    2009-08-07 13:06:28.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/ecpglib/typename.c    2009-08-11 10:32:34.000000000 +0200
***************
*** 7,12 ****
--- 7,13 ----
  #include "ecpgtype.h"
  #include "ecpglib.h"
  #include "extern.h"
+ #include "sqltypes.h"
  #include "sql3types.h"
  #include "pg_type.h"

*************** ecpg_dynamic_type(Oid type)
*** 100,102 ****
--- 101,190 ----
              return -(int) type;
      }
  }
+
+ int
+ ecpg_sqlda_type(int type)
+ {
+     switch (type)
+     {
+         case SQLCHAR:
+         case SQLNCHAR:
+             return ECPGt_char;
+         case SQLSMINT:
+             return ECPGt_short;
+         case SQLINT:
+             return ECPGt_int;
+         case SQLFLOAT:
+             return ECPGt_double;
+         case SQLSMFLOAT:
+             return ECPGt_float;
+         case SQLDECIMAL:
+             return ECPGt_decimal;
+         case SQLSERIAL:
+             return ECPGt_int;
+         case SQLDATE:
+             return ECPGt_date;
+ #if 0
+         case SQLMONEY:
+             return ???;
+         case SQLNULL:
+             return ???;
+ #endif
+         case SQLDTIME:
+             return ECPGt_timestamp;
+ #if 0
+         case SQLBYTES:
+             return ???;
+ #endif
+         case SQLTEXT:
+             return ECPGt_char;
+         case SQLVCHAR:
+         case SQLNVCHAR:
+             return ECPGt_varchar;
+         case SQLINTERVAL:
+             return ECPGt_interval;
+         case SQLINT8:
+         case SQLSERIAL8:
+             return ECPGt_long_long;
+         default:
+             return (-type);
+     }
+ }
+
+ int
+ ecpg_to_sqlda_type(Oid type)
+ {
+     switch (type)
+     {
+         case CHAROID:
+         case BPCHAROID:
+             return SQLCHAR;
+         case INT2OID:
+             return SQLSMINT;
+         case INT4OID:
+             return SQLINT;
+         case FLOAT8OID:
+             return SQLFLOAT;
+         case FLOAT4OID:
+             return SQLSMFLOAT;
+         case NUMERICOID:
+             return SQLDECIMAL;
+         case DATEOID:
+             return SQLDATE;
+         case CASHOID:
+             return SQLMONEY;
+         case TIMESTAMPOID:
+         case TIMESTAMPTZOID:
+             return SQLDTIME;
+         case TEXTOID:
+             return SQLTEXT;
+         case VARCHAROID:
+             return SQLVCHAR;
+         case INTERVALOID:
+             return SQLINTERVAL;
+         case INT8OID:
+             return SQLINT8;
+         default:
+             return (-type);
+     }
+ }
diff -dcrpN pgsql/src/interfaces/ecpg/include/ecpgtype.h pgsql.sqlda/src/interfaces/ecpg/include/ecpgtype.h
*** pgsql/src/interfaces/ecpg/include/ecpgtype.h    2009-08-07 13:06:28.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/include/ecpgtype.h    2009-08-11 10:34:24.000000000 +0200
*************** enum ECPGttype
*** 62,68 ****
      ECPGt_EOIT,                    /* End of insert types. */
      ECPGt_EORT,                    /* End of result types. */
      ECPGt_NO_INDICATOR,            /* no indicator */
!     ECPGt_string                            /* trimmed (char *) type */
  };

   /* descriptor items */
--- 62,69 ----
      ECPGt_EOIT,                    /* End of insert types. */
      ECPGt_EORT,                    /* End of result types. */
      ECPGt_NO_INDICATOR,            /* no indicator */
!     ECPGt_string,                /* trimmed (char *) type */
!     ECPGt_sqlda                /* C struct descriptor */
  };

   /* descriptor items */
diff -dcrpN pgsql/src/interfaces/ecpg/include/sqlda.h pgsql.sqlda/src/interfaces/ecpg/include/sqlda.h
*** pgsql/src/interfaces/ecpg/include/sqlda.h    2009-06-13 18:25:05.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/include/sqlda.h    2009-08-11 10:32:34.000000000 +0200
***************
*** 1,3 ****
--- 1,74 ----
  /*
   * $PostgreSQL: pgsql/src/interfaces/ecpg/include/sqlda.h,v 1.4 2009/06/11 14:49:13 momjian Exp $
   */
+
+ #ifndef POSTGRES_SQLDA_H
+ #define POSTGRES_SQLDA_H
+
+ /* Define Informix "standard" types */
+ #ifndef C_H
+ typedef int        int4;
+ typedef    short        int2;
+ #endif
+ typedef    char        int1;
+
+ typedef    int        mint;
+ typedef    long        mlong;
+
+ typedef    short        MSHORT;
+ typedef    char        MCHAR;
+
+ typedef    unsigned int    uint4;
+ typedef    unsigned short    uint2;
+ typedef    unsigned char    uint1;
+
+ typedef    unsigned int    muint;
+ typedef    unsigned long    mulong;
+
+ typedef    unsigned short    MUSHORT;
+ typedef    unsigned char    MUCHAR;
+
+ #define MI_INT_SIZE     (sizeof(int)    * 8)
+ #define MI_LONG_SIZE    (sizeof(long)   * 8)
+ #define MI_PTR_SIZE     (sizeof(char *) * 8)
+
+ typedef struct sqlvar_struct
+ {
+     int2    sqltype;        /* variable type                */
+     int4    sqllen;            /* length in bytes              */
+     char       *sqldata;        /* pointer to data              */
+     int2       *sqlind;        /* pointer to indicator         */
+     char       *sqlname;        /* variable name                */
+     char       *sqlformat;        /* reserved for future use      */
+     int2    sqlitype;        /* ind variable type            */
+     int2    sqlilen;        /* ind length in bytes          */
+     char       *sqlidata;        /* ind data pointer             */
+     int4    sqlxid;            /* extended id type             */
+     char       *sqltypename;    /* extended type name           */
+     int2    sqltypelen;        /* length of extended type name */
+     int2    sqlownerlen;        /* length of owner name         */
+     int2    sqlsourcetype;        /* source type for distinct of built-ins */
+     char       *sqlownername;    /* owner name                   */
+     int4    sqlsourceid;        /* extended id of source type   */
+
+     /*
+      * sqlilongdata is new.  It supports data that exceeds the 32k
+      * limit.  sqlilen and sqlidata are for backward compatibility
+      * and they have maximum value of <32K.
+      */
+     char       *sqlilongdata;    /* for data field beyond 32K    */
+     int4    sqlflags;        /* for internal use only        */
+     void       *sqlreserved;    /* reserved for future use      */
+ } pg_sqlvar_t;
+
+ typedef struct sqlda
+ {
+     int2        sqld;
+     pg_sqlvar_t       *sqlvar;
+     char        desc_name[19];    /* descriptor name              */
+     int2        desc_occ;    /* size of sqlda structure      */
+     struct sqlda       *desc_next;    /* pointer to next sqlda struct */
+     void           *reserved;    /* reserved for future use */
+ } pg_sqlda_t;
+
+ #endif /* POSTGRES_SQLDA_H */
diff -dcrpN pgsql/src/interfaces/ecpg/include/sqltypes.h pgsql.sqlda/src/interfaces/ecpg/include/sqltypes.h
*** pgsql/src/interfaces/ecpg/include/sqltypes.h    2009-06-13 18:25:05.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/include/sqltypes.h    2009-08-11 10:32:34.000000000 +0200
***************
*** 30,33 ****
--- 30,55 ----
  #define CLVCHARPTRTYPE    124
  #define CTYPEMAX    25

+ /*
+  * Values used in sqlda->sqlvar[i]->sqltype
+  */
+ #define    SQLCHAR        0
+ #define    SQLSMINT    1
+ #define    SQLINT        2
+ #define    SQLFLOAT    3
+ #define    SQLSMFLOAT    4
+ #define    SQLDECIMAL    5
+ #define    SQLSERIAL    6
+ #define    SQLDATE        7
+ #define    SQLMONEY    8
+ #define    SQLDTIME    10
+ #define    SQLBYTES    11
+ #define    SQLTEXT        12
+ #define    SQLVCHAR    13
+ #define    SQLINTERVAL    14
+ #define    SQLNCHAR    15
+ #define    SQLNVCHAR    16
+ #define    SQLINT8        17
+ #define    SQLSERIAL8    18
+
  #endif   /* ndef ECPG_SQLTYPES_H */
diff -dcrpN pgsql/src/interfaces/ecpg/preproc/descriptor.c pgsql.sqlda/src/interfaces/ecpg/preproc/descriptor.c
*** pgsql/src/interfaces/ecpg/preproc/descriptor.c    2009-01-30 17:28:46.000000000 +0100
--- pgsql.sqlda/src/interfaces/ecpg/preproc/descriptor.c    2009-08-11 10:32:34.000000000 +0200
*************** descriptor_variable(const char *name, in
*** 326,328 ****
--- 326,347 ----
      strlcpy(descriptor_names[input], name, sizeof(descriptor_names[input]));
      return (struct variable *) & varspace[input];
  }
+
+ struct variable *
+ sqlda_variable(const char *name)
+ {
+     struct variable *p = (struct variable *) mm_alloc(sizeof(struct variable));
+
+     p->name = mm_strdup(name);
+     p->type = (struct ECPGtype *) mm_alloc(sizeof(struct ECPGtype));
+     p->type->type = ECPGt_sqlda;
+     p->type->size = NULL;
+     p->type->struct_sizeof = NULL;
+     p->type->u.element = NULL;
+     p->type->lineno = 0;
+     p->brace_level = 0;
+     p->next = NULL;
+
+     return p;
+ }
+
diff -dcrpN pgsql/src/interfaces/ecpg/preproc/ecpg.addons pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.addons
*** pgsql/src/interfaces/ecpg/preproc/ecpg.addons    2009-08-10 15:18:04.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.addons    2009-08-11 10:42:00.000000000 +0200
*************** ECPG: FetchStmtMOVEfetch_args block
*** 405,424 ****
          current_cursor = NULL;
          $$ = cat2_str(make_str("move"), $2);
      }
!     | FETCH fetch_args ecpg_into
      {
          add_additional_variables(current_cursor, false);
          free(current_cursor);
          current_cursor = NULL;
          $$ = cat2_str(make_str("fetch"), $2);
      }
!     | FETCH FORWARD cursor_name opt_ecpg_into
      {
          char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3;
          add_additional_variables($3, false);
          $$ = cat_str(2, make_str("fetch forward"), cursor_marker);
      }
!     | FETCH FORWARD from_in cursor_name opt_ecpg_into
      {
          char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4;
          add_additional_variables($4, false);
--- 405,424 ----
          current_cursor = NULL;
          $$ = cat2_str(make_str("move"), $2);
      }
!     | FETCH fetch_args ecpg_fetch_into
      {
          add_additional_variables(current_cursor, false);
          free(current_cursor);
          current_cursor = NULL;
          $$ = cat2_str(make_str("fetch"), $2);
      }
!     | FETCH FORWARD cursor_name opt_ecpg_fetch_into
      {
          char *cursor_marker = $3[0] == ':' ? make_str("$0") : $3;
          add_additional_variables($3, false);
          $$ = cat_str(2, make_str("fetch forward"), cursor_marker);
      }
!     | FETCH FORWARD from_in cursor_name opt_ecpg_fetch_into
      {
          char *cursor_marker = $4[0] == ':' ? make_str("$0") : $4;
          add_additional_variables($4, false);
diff -dcrpN pgsql/src/interfaces/ecpg/preproc/ecpg.trailer pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.trailer
*** pgsql/src/interfaces/ecpg/preproc/ecpg.trailer    2009-08-10 18:01:47.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.trailer    2009-08-11 10:41:02.000000000 +0200
*************** ecpg_using:    USING using_list     { $$ = EMP
*** 1014,1032 ****

  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;

--- 1014,1062 ----

  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;
*** 2050,2057 ****
      ;


! opt_ecpg_into:    /* EMPTY */    { $$ = EMPTY; }
!     | ecpg_into        { $$ = $1; }

  %%

--- 2080,2103 ----
      ;


! ecpg_fetch_into: ecpg_into    { $$ = $1; }
!     | using_descriptor
!     {
!         struct variable *var;
!
!         if (!INFORMIX_MODE)
!             mmerror(PARSE_ERROR, ET_ERROR, "Not in Informix compatibility mode");
!
!         var = argsinsert->variable;
!         remove_variable_from_list(&argsinsert, var);
!         add_variable_to_head(&argsresult, var, &no_indicator);
!         $$ = $1;
!     }
!     ;
!
! opt_ecpg_fetch_into: /* EMPTY */    { $$ = EMPTY; }
!     | ecpg_fetch_into        { $$ = $1; }
!     ;

  %%

diff -dcrpN pgsql/src/interfaces/ecpg/preproc/ecpg.type pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.type
*** pgsql/src/interfaces/ecpg/preproc/ecpg.type    2009-08-10 18:02:24.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/preproc/ecpg.type    2009-08-11 10:44:52.000000000 +0200
***************
*** 62,67 ****
--- 62,68 ----
  %type <str> ecpg_ident
  %type <str> ecpg_interval
  %type <str> ecpg_into
+ %type <str> ecpg_fetch_into
  %type <str> ecpg_param
  %type <str> ecpg_sconst
  %type <str> ecpg_using
***************
*** 77,83 ****
  %type <str> opt_bit_field
  %type <str> opt_connection_name
  %type <str> opt_database_name
! %type <str> opt_ecpg_into
  %type <str> opt_ecpg_using
  %type <str> opt_initializer
  %type <str> opt_options
--- 78,84 ----
  %type <str> opt_bit_field
  %type <str> opt_connection_name
  %type <str> opt_database_name
! %type <str> opt_ecpg_fetch_into
  %type <str> opt_ecpg_using
  %type <str> opt_initializer
  %type <str> opt_options
***************
*** 87,92 ****
--- 88,94 ----
  %type <str> opt_reference
  %type <str> opt_scale
  %type <str> opt_server
+ %type <str> opt_sql
  %type <str> opt_user
  %type <str> opt_opt_value
  %type <str> ora_user
diff -dcrpN pgsql/src/interfaces/ecpg/preproc/extern.h pgsql.sqlda/src/interfaces/ecpg/preproc/extern.h
*** pgsql/src/interfaces/ecpg/preproc/extern.h    2009-08-09 18:13:31.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/preproc/extern.h    2009-08-11 10:32:34.000000000 +0200
*************** extern void add_descriptor(char *, char
*** 90,95 ****
--- 90,96 ----
  extern void drop_descriptor(char *, char *);
  extern struct descriptor *lookup_descriptor(char *, char *);
  extern struct variable *descriptor_variable(const char *name, int input);
+ extern struct variable *sqlda_variable(const char *name);
  extern void add_variable_to_head(struct arguments **, struct variable *, struct variable *);
  extern void add_variable_to_tail(struct arguments **, struct variable *, struct variable *);
  extern void remove_variable_from_list(struct arguments ** list, struct variable * var);
diff -dcrpN pgsql/src/interfaces/ecpg/preproc/type.c pgsql.sqlda/src/interfaces/ecpg/preproc/type.c
*** pgsql/src/interfaces/ecpg/preproc/type.c    2009-08-07 13:06:28.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/preproc/type.c    2009-08-11 11:46:04.000000000 +0200
*************** get_type(enum ECPGttype type)
*** 194,199 ****
--- 194,202 ----
          case ECPGt_descriptor:
              return ("ECPGt_descriptor");
              break;
+         case ECPGt_sqlda:
+             return ("ECPGt_sqlda");
+             break;
          case ECPGt_date:
              return ("ECPGt_date");
              break;
*************** ECPGdump_a_simple(FILE *o, const char *n
*** 328,333 ****
--- 331,338 ----
      else if (type == ECPGt_descriptor)
          /* remember that name here already contains quotes (if needed) */
          fprintf(o, "\n\tECPGt_descriptor, %s, 0L, 0L, 0L, ", name);
+     else if (type == ECPGt_sqlda)
+         fprintf(o, "\n\tECPGt_sqlda, &%s, 0L, 0L, 0L, ", name);
      else
      {
          char       *variable = (char *) mm_alloc(strlen(name) + ((prefix == NULL) ? 0 : strlen(prefix)) + 4);
diff -dcrpN pgsql/src/interfaces/ecpg/test/compat_informix/Makefile
pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/Makefile
*** pgsql/src/interfaces/ecpg/test/compat_informix/Makefile    2009-08-10 18:05:33.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/Makefile    2009-08-11 10:51:42.000000000 +0200
*************** TESTS = test_informix test_informix.c \
*** 17,22 ****
--- 17,23 ----
          rfmtdate rfmtdate.c \
          rfmtlong rfmtlong.c \
          rnull rnull.c \
+         sqlda sqlda.c \
          charfuncs charfuncs.c

  all: $(TESTS)
*************** test_informix2.c: test_informix2.pgc ../
*** 30,35 ****
--- 31,39 ----
  cursor.c: cursor.pgc ../regression.h
      $(ECPG) -o $@ -I$(srcdir) $<

+ sqlda.c: sqlda.pgc ../regression.h
+     $(ECPG) -o $@ -I$(srcdir) $<
+
  dec_test.c: dec_test.pgc ../regression.h
      $(ECPG) -o $@ -I$(srcdir) $<

diff -dcrpN pgsql/src/interfaces/ecpg/test/compat_informix/sqlda.pgc
pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/sqlda.pgc
*** pgsql/src/interfaces/ecpg/test/compat_informix/sqlda.pgc    1970-01-01 01:00:00.000000000 +0100
--- pgsql.sqlda/src/interfaces/ecpg/test/compat_informix/sqlda.pgc    2009-08-11 13:44:07.000000000 +0200
***************
*** 0 ****
--- 1,207 ----
+ #include <stdlib.h>
+ #include <string.h>
+ #include <inttypes.h>
+
+ exec sql include ../regression;
+
+ exec sql include sqlda.h;
+ exec sql include sqltypes.h;
+
+ exec sql whenever sqlerror stop;
+
+ /* These shouldn't be under DECLARE SECTION */
+ pg_sqlda_t    *inp_sqlda, *outp_sqlda;
+
+ static void
+ dump_sqlda(pg_sqlda_t *sqlda)
+ {
+     int    i;
+
+     for (i = 0; i < sqlda->sqld; i++)
+     {
+         if (outp_sqlda->sqlvar[i].sqlind && *(outp_sqlda->sqlvar[i].sqlind) == -1)
+             printf("name sqlda descriptor: '%s' value NULL'\n", outp_sqlda->sqlvar[i].sqlname);
+         else
+         switch (sqlda->sqlvar[i].sqltype)
+         {
+         case SQLCHAR:
+         case SQLVCHAR:
+         case SQLTEXT:
+             printf("name sqlda descriptor: '%s' value '%s'\n", sqlda->sqlvar[i].sqlname, sqlda->sqlvar[i].sqldata);
+             break;
+         case SQLSERIAL:
+         case SQLINT:
+             printf("name sqlda descriptor: '%s' value %d\n", sqlda->sqlvar[i].sqlname, *(int
*)sqlda->sqlvar[i].sqldata);
+             break;
+         case SQLSERIAL8:
+         case SQLINT8:
+             printf("name sqlda descriptor: '%s' value %" PRId64 "\n", sqlda->sqlvar[i].sqlname, *(int64_t
*)sqlda->sqlvar[i].sqldata);
+             break;
+         case SQLFLOAT:
+             printf("name sqlda descriptor: '%s' value %lf\n", sqlda->sqlvar[i].sqlname, *(double
*)sqlda->sqlvar[i].sqldata);
+             break;
+         case SQLDECIMAL:
+             {
+                 char    val[64];
+                 dectoasc((dec_t *)sqlda->sqlvar[i].sqldata, val, 64, -1);
+                 printf("name sqlda descriptor: '%s' value DECIMAL '%s'\n", sqlda->sqlvar[i].sqlname, val);
+                 break;
+             }
+         }
+     }
+ }
+
+ int
+ main (void)
+ {
+ exec sql begin declare section;
+     char    *stmt1 = "SELECT * FROM t1";
+     char    *stmt2 = "SELECT * FROM t1 WHERE id = ?";
+     int    rec;
+     int    id;
+ exec sql end declare section;
+
+     char msg[128];
+
+     ECPGdebug(1, stderr);
+
+     strcpy(msg, "connect");
+     exec sql connect to REGRESSDB1;
+
+     strcpy(msg, "set");
+     exec sql set datestyle to iso;
+
+     strcpy(msg, "create");
+     exec sql create table t1(
+         id integer,
+         t text,
+         d1 numeric,
+         d2 float8,
+         c char(10));
+
+     strcpy(msg, "insert");
+     exec sql insert into t1 values
+         (1, 'a', 1.0, 1, 'a'),
+         (2, null, null, null, null),
+         (3, '"c"', -3, 'nan'::float8, 'c'),
+         (4, 'd', 4.0, 4, 'd');
+
+     strcpy(msg, "commit");
+     exec sql commit;
+
+     /* SQLDA test for getting all records from a table */
+
+     outp_sqlda = NULL;
+
+     strcpy(msg, "prepare");
+     exec sql prepare st_id1 from :stmt1;
+
+     strcpy(msg, "declare");
+     exec sql declare mycur1 cursor for st_id1;
+
+     strcpy(msg, "open");
+     exec sql open mycur1;
+
+     exec sql whenever not found do break;
+
+     rec = 0;
+     while (1)
+     {
+         strcpy(msg, "fetch");
+         exec sql fetch 1 from mycur1 into descriptor outp_sqlda;
+
+         printf("FETCH RECORD %d\n", ++rec);
+         dump_sqlda(outp_sqlda);
+     }
+
+     exec sql whenever not found continue;
+
+     strcpy(msg, "close");
+     exec sql close mycur1;
+
+     strcpy(msg, "deallocate");
+     exec sql deallocate prepare st_id1;
+
+     free(outp_sqlda);
+
+     /* SQLDA test for getting all records from a table
+        using the Informix-specific FETCH ... USING DESCRIPTOR
+      */
+
+     outp_sqlda = NULL;
+
+     strcpy(msg, "prepare");
+     exec sql prepare st_id2 from :stmt1;
+
+     strcpy(msg, "declare");
+     exec sql declare mycur2 cursor for st_id2;
+
+     strcpy(msg, "open");
+     exec sql open mycur2;
+
+     exec sql whenever not found do break;
+
+     rec = 0;
+     while (1)
+     {
+         strcpy(msg, "fetch");
+         exec sql fetch from mycur2 using descriptor outp_sqlda;
+
+         printf("FETCH RECORD %d\n", ++rec);
+         dump_sqlda(outp_sqlda);
+     }
+
+     exec sql whenever not found continue;
+
+     strcpy(msg, "close");
+     exec sql close mycur2;
+
+     strcpy(msg, "deallocate");
+     exec sql deallocate prepare st_id2;
+
+     free(outp_sqlda);
+
+     /* SQLDA test for getting one record using an input descriptor */
+
+     /* Input sqlda has to be built manually */
+     inp_sqlda = (pg_sqlda_t *)malloc(sizeof(pg_sqlda_t));
+     memset(inp_sqlda, 0, sizeof(pg_sqlda_t));
+     inp_sqlda->sqld = 1;
+     inp_sqlda->sqlvar = malloc(sizeof(pg_sqlvar_t));
+     memset(inp_sqlda->sqlvar, 0, sizeof(pg_sqlvar_t));
+
+     inp_sqlda->sqlvar[0].sqltype = SQLINT;
+     inp_sqlda->sqlvar[0].sqldata = (char *)&id;
+
+     printf("EXECUTE RECORD 4\n");
+
+     id = 4;
+
+     outp_sqlda = NULL;
+
+     strcpy(msg, "prepare");
+     exec sql prepare st_id3 FROM :stmt2;
+
+     strcpy(msg, "execute");
+     exec sql execute st_id3 using descriptor inp_sqlda into descriptor outp_sqlda;
+
+     dump_sqlda(outp_sqlda);
+
+     strcpy(msg, "deallocate");
+     exec sql deallocate prepare st_id3;
+
+     free(outp_sqlda);
+
+     /* End test */
+
+     strcpy(msg, "drop");
+     exec sql drop table t1;
+
+     strcpy(msg, "commit");
+     exec sql commit;
+
+     strcpy(msg, "disconnect");
+     exec sql disconnect;
+
+     return (0);
+ }
diff -dcrpN pgsql/src/interfaces/ecpg/test/ecpg_schedule pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule
*** pgsql/src/interfaces/ecpg/test/ecpg_schedule    2009-08-10 18:06:06.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule    2009-08-11 11:19:52.000000000 +0200
*************** test: compat_informix/rfmtdate
*** 4,9 ****
--- 4,10 ----
  test: compat_informix/rfmtlong
  test: compat_informix/rnull
  test: compat_informix/cursor
+ test: compat_informix/sqlda
  test: compat_informix/test_informix
  test: compat_informix/test_informix2
  test: connect/test2
diff -dcrpN pgsql/src/interfaces/ecpg/test/ecpg_schedule_tcp pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule_tcp
*** pgsql/src/interfaces/ecpg/test/ecpg_schedule_tcp    2009-08-10 18:06:11.000000000 +0200
--- pgsql.sqlda/src/interfaces/ecpg/test/ecpg_schedule_tcp    2009-08-11 11:19:59.000000000 +0200
*************** test: compat_informix/rfmtdate
*** 4,9 ****
--- 4,10 ----
  test: compat_informix/rfmtlong
  test: compat_informix/rnull
  test: compat_informix/cursor
+ test: compat_informix/sqlda
  test: compat_informix/test_informix
  test: compat_informix/test_informix2
  test: connect/test2
diff -dcrpN pgsql/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c
pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c
*** pgsql/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c    1970-01-01 01:00:00.000000000 +0100
--- pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c    2009-08-11 14:24:20.000000000 +0200
***************
*** 0 ****
--- 1,506 ----
+ /* Processed by ecpg (regression mode) */
+ /* These include files are added by the preprocessor */
+ #include <ecpglib.h>
+ #include <ecpgerrno.h>
+ #include <sqlca.h>
+ /* Needed for informix compatibility */
+ #include <ecpg_informix.h>
+ /* End of automatic include section */
+ #define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+ #line 1 "sqlda.pgc"
+ #include <stdlib.h>
+ #include <string.h>
+ #include <inttypes.h>
+
+
+ #line 1 "regression.h"
+
+
+
+
+
+
+ #line 5 "sqlda.pgc"
+
+
+
+ #line 1 "sqlda.h"
+ /*
+  * $PostgreSQL: pgsql/src/interfaces/ecpg/include/sqlda.h,v 1.4 2009/06/11 14:49:13 momjian Exp $
+  */
+
+ #ifndef POSTGRES_SQLDA_H
+ #define POSTGRES_SQLDA_H
+
+ /* Define Informix "standard" types */
+ #ifndef C_H
+ typedef int        int4;
+ typedef    short        int2;
+ #endif
+ typedef    char        int1;
+
+ typedef    int        mint;
+ typedef    long        mlong;
+
+ typedef    short        MSHORT;
+ typedef    char        MCHAR;
+
+ typedef    unsigned int    uint4;
+ typedef    unsigned short    uint2;
+ typedef    unsigned char    uint1;
+
+ typedef    unsigned int    muint;
+ typedef    unsigned long    mulong;
+
+ typedef    unsigned short    MUSHORT;
+ typedef    unsigned char    MUCHAR;
+
+ #define MI_INT_SIZE     (sizeof(int)    * 8)
+ #define MI_LONG_SIZE    (sizeof(long)   * 8)
+ #define MI_PTR_SIZE     (sizeof(char *) * 8)
+
+ typedef struct sqlvar_struct
+ {
+     int2    sqltype;        /* variable type                */
+     int4    sqllen;            /* length in bytes              */
+     char       *sqldata;        /* pointer to data              */
+     int2       *sqlind;        /* pointer to indicator         */
+     char       *sqlname;        /* variable name                */
+     char       *sqlformat;        /* reserved for future use      */
+     int2    sqlitype;        /* ind variable type            */
+     int2    sqlilen;        /* ind length in bytes          */
+     char       *sqlidata;        /* ind data pointer             */
+     int4    sqlxid;            /* extended id type             */
+     char       *sqltypename;    /* extended type name           */
+     int2    sqltypelen;        /* length of extended type name */
+     int2    sqlownerlen;        /* length of owner name         */
+     int2    sqlsourcetype;        /* source type for distinct of built-ins */
+     char       *sqlownername;    /* owner name                   */
+     int4    sqlsourceid;        /* extended id of source type   */
+
+     /*
+      * sqlilongdata is new.  It supports data that exceeds the 32k
+      * limit.  sqlilen and sqlidata are for backward compatibility
+      * and they have maximum value of <32K.
+      */
+     char       *sqlilongdata;    /* for data field beyond 32K    */
+     int4    sqlflags;        /* for internal use only        */
+     void       *sqlreserved;    /* reserved for future use      */
+ } pg_sqlvar_t;
+
+ typedef struct sqlda
+ {
+     int2        sqld;
+     pg_sqlvar_t       *sqlvar;
+     char        desc_name[19];    /* descriptor name              */
+     int2        desc_occ;    /* size of sqlda structure      */
+     struct sqlda       *desc_next;    /* pointer to next sqlda struct */
+     void           *reserved;    /* reserved for future use */
+ } pg_sqlda_t;
+
+ #endif /* POSTGRES_SQLDA_H */
+
+ #line 7 "sqlda.pgc"
+
+
+ #line 1 "sqltypes.h"
+ /*
+  * $PostgreSQL: pgsql/src/interfaces/ecpg/include/sqltypes.h,v 1.9 2009/06/11 14:49:13 momjian Exp $
+  */
+ #ifndef ECPG_SQLTYPES_H
+ #define ECPG_SQLTYPES_H
+
+ #define CCHARTYPE    ECPGt_char
+ #define CSHORTTYPE    ECPGt_short
+ #define CINTTYPE    ECPGt_int
+ #define CLONGTYPE    ECPGt_long
+ #define CFLOATTYPE    ECPGt_float
+ #define CDOUBLETYPE ECPGt_double
+ #define CDECIMALTYPE    ECPGt_decimal
+ #define CFIXCHARTYPE    108
+ #define CSTRINGTYPE ECPGt_char
+ #define CDATETYPE    ECPGt_date
+ #define CMONEYTYPE    111
+ #define CDTIMETYPE    ECPGt_timestamp
+ #define CLOCATORTYPE    113
+ #define CVCHARTYPE    ECPGt_varchar
+ #define CINVTYPE    115
+ #define CFILETYPE    116
+ #define CINT8TYPE    ECPGt_long_long
+ #define CCOLLTYPE        118
+ #define CLVCHARTYPE        119
+ #define CFIXBINTYPE        120
+ #define CVARBINTYPE        121
+ #define CBOOLTYPE        ECPGt_bool
+ #define CROWTYPE        123
+ #define CLVCHARPTRTYPE    124
+ #define CTYPEMAX    25
+
+ /*
+  * Values used in sqlda->sqlvar[i]->sqltype
+  */
+ #define    SQLCHAR        0
+ #define    SQLSMINT    1
+ #define    SQLINT        2
+ #define    SQLFLOAT    3
+ #define    SQLSMFLOAT    4
+ #define    SQLDECIMAL    5
+ #define    SQLSERIAL    6
+ #define    SQLDATE        7
+ #define    SQLMONEY    8
+ #define    SQLDTIME    10
+ #define    SQLBYTES    11
+ #define    SQLTEXT        12
+ #define    SQLVCHAR    13
+ #define    SQLINTERVAL    14
+ #define    SQLNCHAR    15
+ #define    SQLNVCHAR    16
+ #define    SQLINT8        17
+ #define    SQLSERIAL8    18
+
+ #endif   /* ndef ECPG_SQLTYPES_H */
+
+ #line 8 "sqlda.pgc"
+
+
+ /* exec sql whenever sqlerror  stop ; */
+ #line 10 "sqlda.pgc"
+
+
+ /* These shouldn't be under DECLARE SECTION */
+ pg_sqlda_t    *inp_sqlda, *outp_sqlda;
+
+ static void
+ dump_sqlda(pg_sqlda_t *sqlda)
+ {
+     int    i;
+
+     for (i = 0; i < sqlda->sqld; i++)
+     {
+         if (outp_sqlda->sqlvar[i].sqlind && *(outp_sqlda->sqlvar[i].sqlind) == -1)
+             printf("name sqlda descriptor: '%s' value NULL'\n", outp_sqlda->sqlvar[i].sqlname);
+         else
+         switch (sqlda->sqlvar[i].sqltype)
+         {
+         case SQLCHAR:
+         case SQLVCHAR:
+         case SQLTEXT:
+             printf("name sqlda descriptor: '%s' value '%s'\n", sqlda->sqlvar[i].sqlname, sqlda->sqlvar[i].sqldata);
+             break;
+         case SQLSERIAL:
+         case SQLINT:
+             printf("name sqlda descriptor: '%s' value %d\n", sqlda->sqlvar[i].sqlname, *(int
*)sqlda->sqlvar[i].sqldata);
+             break;
+         case SQLSERIAL8:
+         case SQLINT8:
+             printf("name sqlda descriptor: '%s' value %" PRId64 "\n", sqlda->sqlvar[i].sqlname, *(int64_t
*)sqlda->sqlvar[i].sqldata);
+             break;
+         case SQLFLOAT:
+             printf("name sqlda descriptor: '%s' value %lf\n", sqlda->sqlvar[i].sqlname, *(double
*)sqlda->sqlvar[i].sqldata);
+             break;
+         case SQLDECIMAL:
+             {
+                 char    val[64];
+                 dectoasc((decimal *)sqlda->sqlvar[i].sqldata, val, 64, -1);
+                 printf("name sqlda descriptor: '%s' value DECIMAL '%s'\n", sqlda->sqlvar[i].sqlname, val);
+                 break;
+             }
+         }
+     }
+ }
+
+ int
+ main (void)
+ {
+ /* exec sql begin declare section */
+
+
+
+
+
+ #line 58 "sqlda.pgc"
+  char * stmt1 = "SELECT * FROM t1" ;
+
+ #line 59 "sqlda.pgc"
+  char * stmt2 = "SELECT * FROM t1 WHERE id = ?" ;
+
+ #line 60 "sqlda.pgc"
+  int rec ;
+
+ #line 61 "sqlda.pgc"
+  int id ;
+ /* exec sql end declare section */
+ #line 62 "sqlda.pgc"
+
+
+     char msg[128];
+
+     ECPGdebug(1, stderr);
+
+     strcpy(msg, "connect");
+     { ECPGconnect(__LINE__, 1, "regress1" , NULL, NULL , NULL, 0);
+ #line 69 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 69 "sqlda.pgc"
+
+
+     strcpy(msg, "set");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "set datestyle to iso", ECPGt_EOIT, ECPGt_EORT);
+ #line 72 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 72 "sqlda.pgc"
+
+
+     strcpy(msg, "create");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "create table t1 ( id integer , t text , d1 numeric , d2 float8
,c char ( 10 ) )", ECPGt_EOIT, ECPGt_EORT); 
+ #line 80 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 80 "sqlda.pgc"
+
+
+     strcpy(msg, "insert");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "insert into t1 values ( 1 , 'a' , 1.0 , 1 , 'a' ) , ( 2 , null
,null , null , null ) , ( 3 , '\"c\"' , - 3 , 'nan' :: float8 , 'c' ) , ( 4 , 'd' , 4.0 , 4 , 'd' )", ECPGt_EOIT,
ECPGt_EORT);
+ #line 87 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 87 "sqlda.pgc"
+
+
+     strcpy(msg, "commit");
+     { ECPGtrans(__LINE__, NULL, "commit");
+ #line 90 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 90 "sqlda.pgc"
+
+
+     /* SQLDA test for getting all records from a table */
+
+     outp_sqlda = NULL;
+
+     strcpy(msg, "prepare");
+     { ECPGprepare(__LINE__, NULL, 0, "st_id1", stmt1);
+ #line 97 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 97 "sqlda.pgc"
+
+
+     strcpy(msg, "declare");
+     /* declare mycur1 cursor for $1 */
+ #line 100 "sqlda.pgc"
+
+
+     strcpy(msg, "open");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "declare mycur1 cursor for $1",
+     ECPGt_char_variable,(ECPGprepared_statement(NULL, "st_id1", __LINE__)),(long)1,(long)1,(1)*sizeof(char),
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+ #line 103 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 103 "sqlda.pgc"
+
+
+     /* exec sql whenever not found  break ; */
+ #line 105 "sqlda.pgc"
+
+
+     rec = 0;
+     while (1)
+     {
+         strcpy(msg, "fetch");
+         { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch 1 from mycur1", ECPGt_EOIT,
+     ECPGt_sqlda, & outp_sqlda , 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 111 "sqlda.pgc"
+
+ if (sqlca.sqlcode == ECPG_NOT_FOUND) break;
+ #line 111 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 111 "sqlda.pgc"
+
+
+         printf("FETCH RECORD %d\n", ++rec);
+         dump_sqlda(outp_sqlda);
+     }
+
+     /* exec sql whenever not found  continue ; */
+ #line 117 "sqlda.pgc"
+
+
+     strcpy(msg, "close");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "close mycur1", ECPGt_EOIT, ECPGt_EORT);
+ #line 120 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 120 "sqlda.pgc"
+
+
+     strcpy(msg, "deallocate");
+     { ECPGdeallocate(__LINE__, 1, NULL, "st_id1");
+ #line 123 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 123 "sqlda.pgc"
+
+
+     free(outp_sqlda);
+
+     /* SQLDA test for getting all records from a table
+        using the Informix-specific FETCH ... USING DESCRIPTOR
+      */
+
+     outp_sqlda = NULL;
+
+     strcpy(msg, "prepare");
+     { ECPGprepare(__LINE__, NULL, 0, "st_id2", stmt1);
+ #line 134 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 134 "sqlda.pgc"
+
+
+     strcpy(msg, "declare");
+     /* declare mycur2 cursor for $1 */
+ #line 137 "sqlda.pgc"
+
+
+     strcpy(msg, "open");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "declare mycur2 cursor for $1",
+     ECPGt_char_variable,(ECPGprepared_statement(NULL, "st_id2", __LINE__)),(long)1,(long)1,(1)*sizeof(char),
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+ #line 140 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 140 "sqlda.pgc"
+
+
+     /* exec sql whenever not found  break ; */
+ #line 142 "sqlda.pgc"
+
+
+     rec = 0;
+     while (1)
+     {
+         strcpy(msg, "fetch");
+         { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "fetch from mycur2", ECPGt_EOIT,
+     ECPGt_sqlda, & outp_sqlda , 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 148 "sqlda.pgc"
+
+ if (sqlca.sqlcode == ECPG_NOT_FOUND) break;
+ #line 148 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 148 "sqlda.pgc"
+
+
+         printf("FETCH RECORD %d\n", ++rec);
+         dump_sqlda(outp_sqlda);
+     }
+
+     /* exec sql whenever not found  continue ; */
+ #line 154 "sqlda.pgc"
+
+
+     strcpy(msg, "close");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "close mycur2", ECPGt_EOIT, ECPGt_EORT);
+ #line 157 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 157 "sqlda.pgc"
+
+
+     strcpy(msg, "deallocate");
+     { ECPGdeallocate(__LINE__, 1, NULL, "st_id2");
+ #line 160 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 160 "sqlda.pgc"
+
+
+     free(outp_sqlda);
+
+     /* SQLDA test for getting one record using an input descriptor */
+
+     /* Input sqlda has to be built manually */
+     inp_sqlda = (pg_sqlda_t *)malloc(sizeof(pg_sqlda_t));
+     memset(inp_sqlda, 0, sizeof(pg_sqlda_t));
+     inp_sqlda->sqld = 1;
+     inp_sqlda->sqlvar = malloc(sizeof(pg_sqlvar_t));
+     memset(inp_sqlda->sqlvar, 0, sizeof(pg_sqlvar_t));
+
+     inp_sqlda->sqlvar[0].sqltype = SQLINT;
+     inp_sqlda->sqlvar[0].sqldata = (char *)&id;
+
+     printf("EXECUTE RECORD 4\n");
+
+     id = 4;
+
+     outp_sqlda = NULL;
+
+     strcpy(msg, "prepare");
+     { ECPGprepare(__LINE__, NULL, 0, "st_id3", stmt2);
+ #line 183 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 183 "sqlda.pgc"
+
+
+     strcpy(msg, "execute");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, 1, "st_id3",
+     ECPGt_sqlda, & inp_sqlda , 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
+     ECPGt_sqlda, & outp_sqlda , 0L, 0L, 0L,
+     ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 186 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 186 "sqlda.pgc"
+
+
+     dump_sqlda(outp_sqlda);
+
+     strcpy(msg, "deallocate");
+     { ECPGdeallocate(__LINE__, 1, NULL, "st_id3");
+ #line 191 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 191 "sqlda.pgc"
+
+
+     free(outp_sqlda);
+
+     /* End test */
+
+     strcpy(msg, "drop");
+     { ECPGdo(__LINE__, 1, 1, NULL, 0, ECPGst_normal, "drop table t1", ECPGt_EOIT, ECPGt_EORT);
+ #line 198 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 198 "sqlda.pgc"
+
+
+     strcpy(msg, "commit");
+     { ECPGtrans(__LINE__, NULL, "commit");
+ #line 201 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 201 "sqlda.pgc"
+
+
+     strcpy(msg, "disconnect");
+     { ECPGdisconnect(__LINE__, "CURRENT");
+ #line 204 "sqlda.pgc"
+
+ if (sqlca.sqlcode < 0) exit (1);}
+ #line 204 "sqlda.pgc"
+
+
+     return (0);
+ }
diff -dcrpN pgsql/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr
pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr
*** pgsql/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr    1970-01-01 01:00:00.000000000 +0100
--- pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stderr    2009-08-17 11:22:46.000000000 +0200
***************
*** 0 ****
--- 1,224 ----
+ [NO_PID]: ECPGdebug: set to 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGconnect: opening database regress1 on <DEFAULT> port <DEFAULT>
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 72: query: set datestyle to iso; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 72: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 72: OK: SET
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 75: query: create table t1 ( id integer , t text , d1 numeric , d2 float8 , c char (
10) ); with 0 parameter(s) on connection regress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 75: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 75: OK: CREATE TABLE
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 83: query: insert into t1 values ( 1 , 'a' , 1.0 , 1 , 'a' ) , ( 2 , null , null ,
null, null ) , ( 3 , '"c"' , - 3 , 'nan' :: float8 , 'c' ) , ( 4 , 'd' , 4.0 , 4 , 'd' ); with 0 parameter(s) on
connectionregress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 83: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 83: OK: INSERT 0 4
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGtrans on line 90: action "commit"; connection "regress1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGprepare on line 97: name st_id1; query: "SELECT * FROM t1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 103: query: declare mycur1 cursor for SELECT * FROM t1; with 0 parameter(s) on
connectionregress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 103: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 103: OK: DECLARE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: new sqlda was built
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: 1 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: 1.0 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: 1 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: putting result (1 tuple 5 fields) into sqlda descriptor
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: called ecpg_compare_sqlda_with_PGresult, status 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: 2 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: putting result (1 tuple 5 fields) into sqlda descriptor
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: called ecpg_compare_sqlda_with_PGresult, status 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: 3 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: -3 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: NaN offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: putting result (1 tuple 5 fields) into sqlda descriptor
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: called ecpg_compare_sqlda_with_PGresult, status 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: 4 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: 4.0 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 111: RESULT: 4 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: putting result (1 tuple 5 fields) into sqlda descriptor
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: query: fetch 1 from mycur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 111: correctly got 0 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: raising sqlcode 100 on line 111: no data found on line 111
+ [NO_PID]: sqlca: code: 100, state: 02000
+ [NO_PID]: ecpg_execute on line 120: query: close mycur1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 120: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 120: OK: CLOSE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGdeallocate on line 123: name st_id1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGprepare on line 134: name st_id2; query: "SELECT * FROM t1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 140: query: declare mycur2 cursor for SELECT * FROM t1; with 0 parameter(s) on
connectionregress1 
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 140: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 140: OK: DECLARE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: new sqlda was built
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: 1 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: 1.0 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: 1 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: putting result (1 tuple 5 fields) into sqlda descriptor
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: called ecpg_compare_sqlda_with_PGresult, status 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: 2 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: putting result (1 tuple 5 fields) into sqlda descriptor
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: called ecpg_compare_sqlda_with_PGresult, status 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: 3 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: -3 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: NaN offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: putting result (1 tuple 5 fields) into sqlda descriptor
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: called ecpg_compare_sqlda_with_PGresult, status 1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: 4 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: 4.0 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 148: RESULT: 4 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: putting result (1 tuple 5 fields) into sqlda descriptor
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: query: fetch from mycur2; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 148: correctly got 0 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: raising sqlcode 100 on line 148: no data found on line 148
+ [NO_PID]: sqlca: code: 100, state: 02000
+ [NO_PID]: ecpg_execute on line 157: query: close mycur2; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 157: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 157: OK: CLOSE CURSOR
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGdeallocate on line 160: name st_id2
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGprepare on line 183: name st_id3; query: "SELECT * FROM t1 WHERE id = $1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 186: query: SELECT * FROM t1 WHERE id = $1; with 1 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 186: using PQexecPrepared for "SELECT * FROM t1 WHERE id = $1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: free_params on line 186: parameter 1 = 4
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 186: correctly got 1 tuples with 5 fields
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 186: new sqlda was built
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 186: RESULT: 4 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 186: RESULT: 4.0 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_get_data on line 186: RESULT: 4 offset: -1; array: yes
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 186: putting result (1 tuple 5 fields) into sqlda descriptor
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGdeallocate on line 191: name st_id3
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 198: query: drop table t1; with 0 parameter(s) on connection regress1
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 198: using PQexec
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_execute on line 198: OK: DROP TABLE
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ECPGtrans on line 201: action "commit"; connection "regress1"
+ [NO_PID]: sqlca: code: 0, state: 00000
+ [NO_PID]: ecpg_finish: connection regress1 closed
+ [NO_PID]: sqlca: code: 0, state: 00000
diff -dcrpN pgsql/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout
pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout
*** pgsql/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout    1970-01-01 01:00:00.000000000 +0100
--- pgsql.sqlda/src/interfaces/ecpg/test/expected/compat_informix-sqlda.stdout    2009-08-11 14:24:21.000000000 +0200
***************
*** 0 ****
--- 1,54 ----
+ FETCH RECORD 1
+ name sqlda descriptor: 'id' value 1
+ name sqlda descriptor: 't' value 'a'
+ name sqlda descriptor: 'd1' value DECIMAL '1.0'
+ name sqlda descriptor: 'd2' value 1.000000
+ name sqlda descriptor: 'c' value 'a         '
+ FETCH RECORD 2
+ name sqlda descriptor: 'id' value 2
+ name sqlda descriptor: 't' value NULL'
+ name sqlda descriptor: 'd1' value NULL'
+ name sqlda descriptor: 'd2' value NULL'
+ name sqlda descriptor: 'c' value NULL'
+ FETCH RECORD 3
+ name sqlda descriptor: 'id' value 3
+ name sqlda descriptor: 't' value '"c"'
+ name sqlda descriptor: 'd1' value DECIMAL '-3'
+ name sqlda descriptor: 'd2' value nan
+ name sqlda descriptor: 'c' value 'c         '
+ FETCH RECORD 4
+ name sqlda descriptor: 'id' value 4
+ name sqlda descriptor: 't' value 'd'
+ name sqlda descriptor: 'd1' value DECIMAL '4.0'
+ name sqlda descriptor: 'd2' value 4.000000
+ name sqlda descriptor: 'c' value 'd         '
+ FETCH RECORD 1
+ name sqlda descriptor: 'id' value 1
+ name sqlda descriptor: 't' value 'a'
+ name sqlda descriptor: 'd1' value DECIMAL '1.0'
+ name sqlda descriptor: 'd2' value 1.000000
+ name sqlda descriptor: 'c' value 'a         '
+ FETCH RECORD 2
+ name sqlda descriptor: 'id' value 2
+ name sqlda descriptor: 't' value NULL'
+ name sqlda descriptor: 'd1' value NULL'
+ name sqlda descriptor: 'd2' value NULL'
+ name sqlda descriptor: 'c' value NULL'
+ FETCH RECORD 3
+ name sqlda descriptor: 'id' value 3
+ name sqlda descriptor: 't' value '"c"'
+ name sqlda descriptor: 'd1' value DECIMAL '-3'
+ name sqlda descriptor: 'd2' value nan
+ name sqlda descriptor: 'c' value 'c         '
+ FETCH RECORD 4
+ name sqlda descriptor: 'id' value 4
+ name sqlda descriptor: 't' value 'd'
+ name sqlda descriptor: 'd1' value DECIMAL '4.0'
+ name sqlda descriptor: 'd2' value 4.000000
+ name sqlda descriptor: 'c' value 'd         '
+ EXECUTE RECORD 4
+ name sqlda descriptor: 'id' value 4
+ name sqlda descriptor: 't' value 'd'
+ name sqlda descriptor: 'd1' value DECIMAL '4.0'
+ name sqlda descriptor: 'd2' value 4.000000
+ name sqlda descriptor: 'c' value 'd         '