]> granicus.if.org Git - postgresql/commitdiff
Finally applied patch by Boszormenyi Zoltan <zb@cybertec.at> to add the new features...
authorMichael Meskes <meskes@postgresql.org>
Tue, 26 Jan 2010 09:10:11 +0000 (09:10 +0000)
committerMichael Meskes <meskes@postgresql.org>
Tue, 26 Jan 2010 09:10:11 +0000 (09:10 +0000)
doc/src/sgml/ecpg.sgml

index ebf8e73a8450957d0d67330b4d89784eced66a82..bb164e23e74d8e7e5a2bf5e569cfb94d24fcb922 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/ecpg.sgml,v 1.93 2009/12/02 14:07:25 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/ecpg.sgml,v 1.94 2010/01/26 09:10:11 meskes Exp $ -->
 
 <chapter id="ecpg">
  <title><application>ECPG</application> - Embedded <acronym>SQL</acronym> in C</title>
@@ -2376,6 +2376,478 @@ void PGTYPESdecimal_free(decimal *var);
   </sect2>
  </sect1>
 
+ <sect1 id="ecpg-descriptors">
+  <title>Using Descriptor Areas</title>
+
+  <para>
+   An SQL descriptor area is a more sophisticated method for processing
+   the result of a <command>SELECT</command>, <command>FETCH</command> or
+   a <command>DESCRIBE</command> statement. An SQL descriptor area groups
+   the data of one row of data together with metadata items into one
+   data structure.  The metadata is particularly useful when executing
+   dynamic SQL statements, where the nature of the result columns might
+   not be known ahead of time. PostgreSQL provides two ways to use
+   Descriptor Areas: the named SQL Descriptor Areas and the C-structure
+   SQLDAs.
+  </para>
+
+  <sect2 id="ecpg-named-descriptors">
+   <title>Named SQL Descriptor Areas</title>
+
+   <para>
+    A named SQL descriptor area consists of a header, which contains
+    information concerning the entire descriptor, and one or more item
+    descriptor areas, which basically each describe one column in the
+    result row.
+   </para>
+
+   <para>
+    Before you can use an SQL descriptor area, you need to allocate one:
+<programlisting>
+EXEC SQL ALLOCATE DESCRIPTOR <replaceable>identifier</replaceable>;
+</programlisting>
+    The identifier serves as the <quote>variable name</quote> of the
+    descriptor area.  <remark>The scope of the allocated descriptor is WHAT?.</remark>
+    When you don't need the descriptor anymore, you should deallocate
+    it:
+<programlisting>
+EXEC SQL DEALLOCATE DESCRIPTOR <replaceable>identifier</replaceable>;
+</programlisting>
+   </para>
+
+   <para>
+    To use a descriptor area, specify it as the storage target in an
+    <literal>INTO</literal> clause, instead of listing host variables:
+<programlisting>
+EXEC SQL FETCH NEXT FROM mycursor INTO SQL DESCRIPTOR mydesc;
+</programlisting>
+    If the resultset is empty, the Descriptor Area will still contain
+    the metadata from the query, i.e. the field names.
+   </para>
+
+   <para>
+    For not yet executed prepared queries, the <command>DESCRIBE</command>
+    statement can be used to get the metadata of the resultset:
+<programlisting> 
+EXEC SQL BEGIN DECLARE SECTION;
+char *sql_stmt = "SELECT * FROM table1";
+EXEC SQL END DECLARE SECTION;
+
+EXEC SQL PREPARE stmt1 FROM :sql_stmt;
+EXEC SQL DESCRIBE stmt1 INTO SQL DESCRIPTOR mydesc;
+</programlisting>
+   </para>
+
+   <para>
+    Before PostgreSQL 8.5, the <literal>SQL</literal> keyword was optional,
+    so using <literal>DESCRIPTOR</literal> and <literal>SQL DESCRIPTOR</literal>
+    produced named SQL Descriptor Areas. Now it is mandatory, omitting
+    the <literal>SQL</literal> keyword produces SQLDA Descriptor Areas,
+    see <xref linkend="ecpg-sqlda-descriptors">. 
+   </para>
+
+   <para>
+    In <command>DESCRIBE</command> and <command>FETCH</command> statements,
+    the <literal>INTO</literal> and <literal>USING</literal> keywords can be
+    used to similarly: they produce the resultset and the metadata in a
+    Descriptor Area.
+   </para>
+
+   <para>
+    Now how do you get the data out of the descriptor area?  You can
+    think of the descriptor area as a structure with named fields.  To
+    retrieve the value of a field from the header and store it into a
+    host variable, use the following command:
+<programlisting>
+EXEC SQL GET DESCRIPTOR <replaceable>name</replaceable> :<replaceable>hostvar</replaceable> = <replaceable>field</replaceable>;
+</programlisting>
+    Currently, there is only one header field defined:
+    <replaceable>COUNT</replaceable>, which tells how many item
+    descriptor areas exist (that is, how many columns are contained in
+    the result).  The host variable needs to be of an integer type.  To
+    get a field from the item descriptor area, use the following
+    command:
+<programlisting>
+EXEC SQL GET DESCRIPTOR <replaceable>name</replaceable> VALUE <replaceable>num</replaceable> :<replaceable>hostvar</replaceable> = <replaceable>field</replaceable>;
+</programlisting>
+    <replaceable>num</replaceable> can be a literal integer or a host
+    variable containing an integer. Possible fields are:
+
+    <variablelist>
+     <varlistentry>
+      <term><literal>CARDINALITY</literal> (integer)</term>
+      <listitem>
+       <para>
+        number of rows in the result set
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><literal>DATA</literal></term>
+      <listitem>
+       <para>
+        actual data item (therefore, the data type of this field
+        depends on the query)
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><literal>DATETIME_INTERVAL_CODE</literal> (integer)</term>
+      <listitem>
+       <para>
+        ?
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><literal>DATETIME_INTERVAL_PRECISION</literal> (integer)</term>
+      <listitem>
+       <para>
+        not implemented
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><literal>INDICATOR</literal> (integer)</term>
+      <listitem>
+       <para>
+        the indicator (indicating a null value or a value truncation)
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><literal>KEY_MEMBER</literal> (integer)</term>
+      <listitem>
+       <para>
+        not implemented
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><literal>LENGTH</literal> (integer)</term>
+      <listitem>
+       <para>
+        length of the datum in characters
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><literal>NAME</literal> (string)</term>
+      <listitem>
+       <para>
+        name of the column
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><literal>NULLABLE</literal> (integer)</term>
+      <listitem>
+       <para>
+        not implemented
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><literal>OCTET_LENGTH</literal> (integer)</term>
+      <listitem>
+       <para>
+        length of the character representation of the datum in bytes
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><literal>PRECISION</literal> (integer)</term>
+      <listitem>
+       <para>
+        precision (for type <type>numeric</type>)
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><literal>RETURNED_LENGTH</literal> (integer)</term>
+      <listitem>
+       <para>
+        length of the datum in characters
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><literal>RETURNED_OCTET_LENGTH</literal> (integer)</term>
+      <listitem>
+       <para>
+        length of the character representation of the datum in bytes
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><literal>SCALE</literal> (integer)</term>
+      <listitem>
+       <para>
+        scale (for type <type>numeric</type>)
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><literal>TYPE</literal> (integer)</term>
+      <listitem>
+       <para>
+        numeric code of the data type of the column
+       </para>
+      </listitem>
+     </varlistentry>
+    </variablelist>
+   </para>
+
+   <para>
+    In <command>EXECUTE</command>, <command>DECLARE</command> and <command>OPEN</command>
+    statements, the effect of the <literal>INTO</literal> and <literal>USING</literal>
+    keywords are different. A Descriptor Area can also be manually built to
+    provide the input parameters for a query or a cursor and
+    <literal>USING SQL DESCRIPTOR <replaceable>name</replaceable></literal>
+    is the way to pass the input parameters into a parametrized query. The statement
+    to build a named SQL Descriptor Area is below:
+<programlisting>
+EXEC SQL SET DESCRIPTOR <replaceable>name</replaceable> VALUE <replaceable>num</replaceable> <replaceable>field</replaceable> = :<replaceable>hostvar</replaceable>;
+</programlisting>
+   </para>
+
+   <para>
+    PostgreSQL supports retrieving more that one record in one <command>FETCH</command>
+    statement and storing the data in host variables in this case assumes that the
+    variable is an array. E.g.:
+<programlisting>
+EXEC SQL BEGIN DECLARE SECTION;
+int id[5];
+EXEC SQL END DECLARE SECTION;
+
+EXEC SQL FETCH 5 FROM mycursor INTO SQL DESCRIPTOR mydesc;
+
+EXEC SQL GET DESCRIPTOR mydesc VALUE 1 :id = DATA;
+</programlisting>
+
+   </para>
+
+  </sect2>
+
+  <sect2 id="ecpg-sqlda-descriptors">
+   <title>SQLDA Descriptor Areas</title>
+
+   <para>
+    An SQLDA Descriptor Area is a C language structure which can be also used
+    to get the resultset and the metadata of a query. One structure stores one
+    record from the resultset.
+<programlisting>
+EXEC SQL include sqlda.h;
+sqlda_t        *mysqlda;
+
+EXEC SQL FETCH 3 FROM mycursor INTO DESCRIPTOR mysqlda;
+</programlisting>
+    Note that the <literal>SQL</literal> keyword is omitted. The paragraphs about
+    the use cases of the <literal>INTO</literal> and <literal>USING</literal>
+    keywords in <xref linkend="ecpg-named-descriptors"> also apply here with an addition.
+    In a <command>DESCRIBE</command> statement the <literal>DESCRIPTOR</literal>
+    keyword can be completely omitted if the <literal>INTO</literal> keyword is used:
+<programlisting>
+EXEC SQL DESCRIBE prepared_statement INTO mysqlda;
+</programlisting>
+   </para>
+
+   <para>
+    The structure of SQLDA is:
+<programlisting>
+#define NAMEDATALEN 64
+
+struct sqlname
+{
+        short           length;
+        char            data[NAMEDATALEN];
+};
+
+struct sqlvar_struct
+{
+        short           sqltype;
+        short           sqllen;
+        char       *sqldata;
+        short      *sqlind;
+        struct sqlname sqlname;
+};
+
+struct sqlda_struct
+{
+        char            sqldaid[8];
+        long            sqldabc;
+        short           sqln;
+        short           sqld;
+        struct sqlda_struct *desc_next;
+        struct sqlvar_struct    sqlvar[1];
+};
+
+typedef struct sqlvar_struct    sqlvar_t;
+typedef struct sqlda_struct     sqlda_t;
+</programlisting>
+   </para>
+
+   <para>
+    The allocated data for an SQLDA structure is variable as it depends on the
+    number of fields in a resultset and also depends on the length of the string
+    data values in a record. The individual fields of the <literal>SQLDA</literal>
+    structure are:
+
+    <variablelist>
+     <varlistentry>
+      <term><literal>sqldaid</></term>
+      <listitem>
+       <para>
+        It contains the "<literal>SQLDA  </literal>" literal string.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><literal>sqldabc</></term>
+      <listitem>
+       <para>
+        It contains the size of the allocated space in bytes.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><literal>sqln</></term>
+      <listitem>
+       <para>
+        It contains the number of input parameters for a parametrized query
+        case it's passed into <command>OPEN</command>, <command>DECLARE</command> or
+        <command>EXECUTE</command> statements using the <literal>USING</literal>
+        keyword. In case it's used as output of <command>SELECT</command>,
+        <command>EXECUTE</command> or <command>FETCH</command> statements,
+        its value is the same as <literal>sqld</literal>
+        statement
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><literal>sqld</></term>
+      <listitem>
+       <para>
+        It contains the number of fields in a resultset.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><literal>desc_next</></term>
+      <listitem>
+       <para>
+        If the query returns more than one records, multiple linked SQLDA structures
+        are returned, the first record is stored in the SQLDA returned in the
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><literal>sqlvar</></term>
+      <listitem>
+       <para>
+        This is the array of the fields in the resultset. The fields are:
+
+        <variablelist>
+
+         <varlistentry>
+         <term><literal>sqltype</></term>
+          <listitem>
+           <para>
+            It contains the type identifier of the field. For values,
+            see <literal>enum ECPGttype</literal> in <literal>ecpgtype.h</literal>.
+           </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+         <term><literal>sqllen</></term>
+          <listitem>
+           <para>
+            It contains the binary length of the field. E.g. 4 bytes for ECPGt_int.
+           </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+         <term><literal>sqldata</></term>
+          <listitem>
+           <para>
+            <literal>(char *)sqldata</literal> points to the data.
+           </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+         <term><literal>sqlind</></term>
+          <listitem>
+           <para>
+            <literal>(char *)sqlind</literal> points to the NULL indicator for data.
+            0 means NOT NULL, -1 means NULL.
+           </para>
+          </listitem>
+         </varlistentry>
+
+         <varlistentry>
+         <term><literal>sqlname</></term>
+          <listitem>
+           <para>
+            <literal>struct sqlname sqlname</literal> contains the name of the field
+            in a structure:
+<programlisting>
+struct sqlname
+{
+        short           length;
+        char            data[NAMEDATALEN];
+};
+</programlisting>
+
+            <variablelist>
+             <varlistentry>
+              <term><literal>length</></term>
+               <listitem>
+                <para>
+                 <literal>sqlname.length</literal> contains the length of the field name.
+                </para>
+               </listitem>
+              </varlistentry>
+             <varlistentry>
+              <term><literal>data</></term>
+               <listitem>
+                <para>
+                 <literal>sqlname.data</literal> contains the actual field name.
+                </para>
+               </listitem>
+              </varlistentry>
+            </variablelist>
+           </para>
+          </listitem>
+         </varlistentry>
+
+        </variablelist>
+       </para>
+      </listitem>
+     </varlistentry>
+    </variablelist>
+   </para>
+
+  </sect2>
+
+ </sect1>
+
  <sect1 id="ecpg-informix-compat">
   <title><productname>Informix</productname> compatibility mode</title>
   <para>
@@ -2385,58 +2857,373 @@ void PGTYPESdecimal_free(decimal *var);
    the dollar sign instead of the <literal>EXEC SQL</> primitive to introduce
    embedded SQL commands.:
 <programlisting>
-   $int j = 3;
-   $CONNECT TO :dbname;
-   $CREATE TABLE test(i INT PRIMARY KEY, j INT);
-   $INSERT INTO test(i, j) VALUES (7, :j);
-   $COMMIT;
+   $int j = 3;
+   $CONNECT TO :dbname;
+   $CREATE TABLE test(i INT PRIMARY KEY, j INT);
+   $INSERT INTO test(i, j) VALUES (7, :j);
+   $COMMIT;
+</programlisting>
+  </para>
+  <para>
+   There are two compatiblity modes: INFORMIX, INFORMIX_SE
+  </para>
+  <para>
+   When linking programs that use this compatibility mode, remember to link
+   against <literal>libcompat</> that is shipped with ecpg.
+  </para>
+  <para>
+   Besides the previously explained syntactic sugar, the <productname>Informix</productname> compatibility
+   mode ports some functions for input, output and transformation of data as
+   well as embedded SQL statements known from E/SQL to ecpg.
+  </para>
+  <para>
+   <productname>Informix</productname> compatibility mode is closely connected to the pgtypeslib library
+   of ecpg. pgtypeslib maps SQL data types to data types within the C host
+   program and most of the additional functions of the <productname>Informix</productname> compatibility
+   mode allow you to operate on those C host program types. Note however that
+   the extent of the compatibility is limited. It does not try to copy <productname>Informix</productname>
+   behaviour; it allows you to do more or less the same operations and gives
+   you functions that have the same name and the same basic behavior but it is
+   no drop-in replacement if you are using <productname>Informix</productname> at the moment. Moreover,
+   some of the data types are different. For example,
+   <productname>PostgreSQL's</productname> datetime and interval types do not
+   know about ranges like for example <literal>YEAR TO MINUTE</> so you won't
+   find support in ecpg for that either.
+  </para>
+
+  <sect2>
+   <title>Additional types</title>
+   <para>
+    The Informix-special "string" pseudo-type for storing right-trimmed character string data is now
+    supported in Informix-mode without using <literal>typedef</literal>. In fact, in Informix-mode,
+    ECPG refuses to process source files that contain <literal>typedef sometype string;</literal>
+<programlisting>
+    EXEC SQL BEGIN DECLARE SECTION;
+    string userid; /* this variable will contain trimmed data */
+    EXEC SQL END DECLARE SECTION;
+
+    EXEC SQL FETCH MYCUR INTO :userid;
+</programlisting>
+   </para>
+  </sect2>
+
+  <sect2>
+   <title>Additional/missing embedded SQL statements</title>
+   <para>
+    <variablelist>
+     <varlistentry>
+      <term><literal>CLOSE DATABASE</></term>
+      <listitem>
+       <para>
+        This statement closes the current connection. In fact, this is a
+        synonym for ecpg's <literal>DISCONNECT CURRENT</>.:
+<programlisting>
+    $CLOSE DATABASE;                /* close the current connection */
+    EXEC SQL CLOSE DATABASE;
+</programlisting>
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><literal>FREE cursor_name</></term>
+      <listitem>
+       <para>
+        Due to the differences how ECPG works compared to Informix's ESQL/C (i.e. which steps
+        are purely grammar transformations and which steps rely on the underlying runtime library)
+        there is no <literal>FREE cursor_name</> statement in ECPG. This is because in ECPG,
+        <literal>DECLARE CURSOR</literal> doesn't translate to a function call into
+        the runtime library that uses to the cursor name. This means that there's no runtime
+       bookkeeping of SQL cursors in the ECPG runtime library, only in the PostgreSQL server.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><literal>FREE statement_name</></term>
+      <listitem>
+       <para>
+        <literal>FREE statement_name</> is a synonym for <literal>DEALLOCATE PREPARE statement_name</>.
+       </para>      
+      </listitem>   
+     </varlistentry>
+    </variablelist>
+   </para>
+  </sect2>
+
+  <sect2>
+   <title>Informix-compatible SQLDA Descriptor Areas</title>
+   <para>
+    Informix-compatible mode supports a different structure than the one described in
+    <xref linkend="ecpg-sqlda-descriptors">. See below:
+<programlisting>
+struct sqlvar_compat
+{
+        short   sqltype;
+        int     sqllen;
+        char       *sqldata;
+        short      *sqlind;
+        char       *sqlname;
+        char       *sqlformat;
+        short   sqlitype;
+        short   sqlilen;
+        char       *sqlidata;
+        int     sqlxid;
+        char       *sqltypename;
+        short   sqltypelen;
+        short   sqlownerlen;
+        short   sqlsourcetype;
+        char       *sqlownername;
+        int     sqlsourceid;
+
+        char       *sqlilongdata;
+        int     sqlflags;
+        void       *sqlreserved;
+};
+
+struct sqlda_compat
+{
+        short           sqld;
+        struct sqlvar_compat *sqlvar;
+        char            desc_name[19];
+        short           desc_occ;
+        struct sqlda_compat *desc_next;
+        void               *reserved;
+};
+
+typedef struct sqlvar_compat    sqlvar_t;
+typedef struct sqlda_compat     sqlda_t;
+</programlisting>
+   </para>
+
+   <para>
+    The global properties are:
+    <variablelist>  
+
+     <varlistentry>
+     <term><literal>sqld</></term>
+      <listitem>
+       <para>
+        The number of fields in the <literal>SQLDA</> descriptor.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+     <term><literal>sqlvar</></term>   
+      <listitem>
+       <para>
+        Pointer to the per-field properties.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+     <term><literal>desc_name</></term>
+      <listitem>
+       <para>
+        Unused, filled with zerobytes.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+     <term><literal>desc_occ</></term>
+      <listitem>
+       <para>
+        Size of the allocated structure.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+     <term><literal>desc_next</></term>
+      <listitem>
+       <para>
+        Pointer to the next SQLDA structure if the resultset contains more than one records.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+     <term><literal>reserved</></term>
+      <listitem>
+       <para>
+        Unused pointer, contains NULL. Kept for Informix-compatibility.
+       </para>
+      </listitem>
+     </varlistentry>
+
+    </variablelist>
+
+    The per-field properties are below, they are stored in the <literal>sqlvar</literal> array:
+
+    <variablelist>
+
+     <varlistentry>
+     <term><literal>sqltype</></term>
+      <listitem>
+       <para>
+        Type of the field. Constants are in <literal>sqltypes.h</literal>
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+     <term><literal>sqllen</></term>
+      <listitem>
+       <para>
+        Length of the field data.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+     <term><literal>sqldata</></term>
+      <listitem>
+       <para>
+        Pointer to the field data. The pointer is of <literal>char *</literal> type,
+        the data pointed by it is in a binary format. Example:
+<programlisting>
+    int intval; 
+
+    switch (sqldata->sqlvar[i].sqltype)
+    {
+      case SQLINTEGER:
+        intval = *(int *)sqldata->sqlvar[i].sqldata;
+        break;
+      ...
+    }
 </programlisting>
-  </para>
-  <para>
-   There are two compatiblity modes: INFORMIX, INFORMIX_SE
-  </para>
-  <para>
-   When linking programs that use this compatibility mode, remember to link
-   against <literal>libcompat</> that is shipped with ecpg.
-  </para>
-  <para>
-   Besides the previously explained syntactic sugar, the <productname>Informix</productname> compatibility
-   mode ports some functions for input, output and transformation of data as
-   well as embedded SQL statements known from E/SQL to ecpg.
-  </para>
-  <para>
-   <productname>Informix</productname> compatibility mode is closely connected to the pgtypeslib library
-   of ecpg. pgtypeslib maps SQL data types to data types within the C host
-   program and most of the additional functions of the <productname>Informix</productname> compatibility
-   mode allow you to operate on those C host program types. Note however that
-   the extent of the compatibility is limited. It does not try to copy <productname>Informix</productname>
-   behaviour; it allows you to do more or less the same operations and gives
-   you functions that have the same name and the same basic behavior but it is
-   no drop-in replacement if you are using <productname>Informix</productname> at the moment. Moreover,
-   some of the data types are different. For example,
-   <productname>PostgreSQL's</productname> datetime and interval types do not
-   know about ranges like for example <literal>YEAR TO MINUTE</> so you won't
-   find support in ecpg for that either.
-  </para>
+       </para>
+      </listitem>
+     </varlistentry>
 
-  <sect2>
-   <title>Additional embedded SQL statements</title>
-   <para>
-    <variablelist>
      <varlistentry>
-      <term><literal>CLOSE DATABASE</></term>
+     <term><literal>sqlind</></term>
       <listitem>
        <para>
-        This statement closes the current connection. In fact, this is a
-        synonym for ecpg's <literal>DISCONNECT CURRENT</>.:
+        Pointer to the NULL indicator. If returned by DESCRIBE or FETCH then it's always a valid pointer.
+        If used as input for <literal>EXECUTE ... USING sqlda;</literal> then NULL-pointer value means   
+        that the value for this field is non-NULL. Otherwise a valid pointer and <literal>sqlitype</literal>
+        has to be properly set. Example:
 <programlisting>
-    $CLOSE DATABASE;                /* close the current connection */
-    EXEC SQL CLOSE DATABASE;
+    if (*(int2 *)sqldata->sqlvar[i].sqlind != 0)
+      printf("value is NULL\n");
 </programlisting>
        </para>
       </listitem>
      </varlistentry>
+
+     <varlistentry>
+     <term><literal>sqlname</></term>
+      <listitem>
+       <para>
+        Name of the field. 0-terminated string.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+     <term><literal>sqlformat</></term>
+      <listitem>
+       <para>
+        Reserved in Informix, value of PQfformat() for the field.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+     <term><literal>sqlitype</></term>
+      <listitem>
+       <para>
+        Type of the NULL indicator data. It's always SQLSMINT when returning data from the server.
+        When the <literal>SQLDA</literal> is used for a parametrized query, the data is treated   
+        according to the set type.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+     <term><literal>sqlilen</></term>
+      <listitem>
+       <para>
+        Length of the NULL indicator data.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+     <term><literal>sqlxid</></term>
+      <listitem>
+       <para>
+        Extended type of the field, result of PQftype().
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+     <term><literal>sqltypename</></term>
+     <term><literal>sqltypelen</></term> 
+     <term><literal>sqlownerlen</></term>
+     <term><literal>sqlsourcetype</></term>
+     <term><literal>sqlownername</></term> 
+     <term><literal>sqlsourceid</></term>  
+     <term><literal>sqlflags</></term>     
+     <term><literal>sqlreserved</></term>  
+      <listitem>
+       <para>
+        Unused.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+     <term><literal>sqlilongdata</></term>
+      <listitem>
+       <para>
+        It equals to <literal>sqldata</literal> if <literal>sqllen</literal> is larger than 32KB.
+       </para>
+      </listitem>
+     </varlistentry>
+
     </variablelist>
+
+    Example:
+<programlisting>
+EXEC SQL INCLUDE sqlda.h;
+
+    sqlda_t        *sqlda; /* This doesn't need to be under embedded DECLARE SECTION */
+
+    EXEC SQL BEGIN DECLARE SECTION;
+    char *prep_stmt = "select * from table1";
+    int i;
+    EXEC SQL END DECLARE SECTION;
+
+    ...
+
+    EXEC SQL PREPARE mystmt FROM :prep_stmt;
+
+    EXEC SQL DESCRIBE mystmt INTO sqlda;
+
+    printf("# of fields: %d\n", sqlda->sqld);
+    for (i = 0; i < sqlda->sqld; i++)
+      printf("field %d: \"%s\"\n", sqlda->sqlvar[i]->sqlname);
+
+    EXEC SQL DECLARE mycursor CURSOR FOR mystmt;
+    EXEC SQL OPEN mycursor;
+    EXEC SQL WHENEVER NOT FOUND GOTO out;
+
+    while (1)
+    {
+      EXEC SQL FETCH mycursor USING sqlda;
+    }
+
+    EXEC SQL CLOSE mycursor;
+
+    free(sqlda); /* The main structure is all to be free(),
+                  * sqlda and sqlda->sqlvar is in one allocated area */
+</programlisting>
+    For more information, see the <literal>sqlda.h</> header and the
+    <literal>src/interfaces/ecpg/test/compat_informix/sqlda.pgc</literal> regression test.
    </para>
   </sect2>
 
@@ -3660,208 +4447,6 @@ risnull(CINTTYPE, (char *) &i);
   </sect2>
  </sect1>
 
- <sect1 id="ecpg-descriptors">
-  <title>Using SQL Descriptor Areas</title>
-
-  <para>
-   An SQL descriptor area is a more sophisticated method for
-   processing the result of a <command>SELECT</command> or
-   <command>FETCH</command> statement.  An SQL descriptor area groups
-   the data of one row of data together with metadata items into one
-   data structure.  The metadata is particularly useful when executing
-   dynamic SQL statements, where the nature of the result columns might
-   not be known ahead of time.
-  </para>
-
-  <para>
-   An SQL descriptor area consists of a header, which contains
-   information concerning the entire descriptor, and one or more item
-   descriptor areas, which basically each describe one column in the
-   result row.
-  </para>
-
-  <para>
-   Before you can use an SQL descriptor area, you need to allocate one:
-<programlisting>
-EXEC SQL ALLOCATE DESCRIPTOR <replaceable>identifier</replaceable>;
-</programlisting>
-   The identifier serves as the <quote>variable name</quote> of the
-   descriptor area.  <remark>The scope of the allocated descriptor is WHAT?.</remark>
-   When you don't need the descriptor anymore, you should deallocate
-   it:
-<programlisting>
-EXEC SQL DEALLOCATE DESCRIPTOR <replaceable>identifier</replaceable>;
-</programlisting>
-  </para>
-
-  <para>
-   To use a descriptor area, specify it as the storage target in an
-   <literal>INTO</literal> clause, instead of listing host variables:
-<programlisting>
-EXEC SQL FETCH NEXT FROM mycursor INTO DESCRIPTOR mydesc;
-</programlisting>
-  </para>
-
-  <para>
-   Now how do you get the data out of the descriptor area?  You can
-   think of the descriptor area as a structure with named fields.  To
-   retrieve the value of a field from the header and store it into a
-   host variable, use the following command:
-<programlisting>
-EXEC SQL GET DESCRIPTOR <replaceable>name</replaceable> :<replaceable>hostvar</replaceable> = <replaceable>field</replaceable>;
-</programlisting>
-   Currently, there is only one header field defined:
-   <replaceable>COUNT</replaceable>, which tells how many item
-   descriptor areas exist (that is, how many columns are contained in
-   the result).  The host variable needs to be of an integer type.  To
-   get a field from the item descriptor area, use the following
-   command:
-<programlisting>
-EXEC SQL GET DESCRIPTOR <replaceable>name</replaceable> VALUE <replaceable>num</replaceable> :<replaceable>hostvar</replaceable> = <replaceable>field</replaceable>;
-</programlisting>
-   <replaceable>num</replaceable> can be a literal integer or a host
-   variable containing an integer. Possible fields are:
-
-   <variablelist>
-    <varlistentry>
-     <term><literal>CARDINALITY</literal> (integer)</term>
-     <listitem>
-      <para>
-       number of rows in the result set
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term><literal>DATA</literal></term>
-     <listitem>
-      <para>
-       actual data item (therefore, the data type of this field
-       depends on the query)
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term><literal>DATETIME_INTERVAL_CODE</literal> (integer)</term>
-     <listitem>
-      <para>
-       ?
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term><literal>DATETIME_INTERVAL_PRECISION</literal> (integer)</term>
-     <listitem>
-      <para>
-       not implemented
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term><literal>INDICATOR</literal> (integer)</term>
-     <listitem>
-      <para>
-       the indicator (indicating a null value or a value truncation)
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term><literal>KEY_MEMBER</literal> (integer)</term>
-     <listitem>
-      <para>
-       not implemented
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term><literal>LENGTH</literal> (integer)</term>
-     <listitem>
-      <para>
-       length of the datum in characters
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term><literal>NAME</literal> (string)</term>
-     <listitem>
-      <para>
-       name of the column
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term><literal>NULLABLE</literal> (integer)</term>
-     <listitem>
-      <para>
-       not implemented
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term><literal>OCTET_LENGTH</literal> (integer)</term>
-     <listitem>
-      <para>
-       length of the character representation of the datum in bytes
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term><literal>PRECISION</literal> (integer)</term>
-     <listitem>
-      <para>
-       precision (for type <type>numeric</type>)
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term><literal>RETURNED_LENGTH</literal> (integer)</term>
-     <listitem>
-      <para>
-       length of the datum in characters
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term><literal>RETURNED_OCTET_LENGTH</literal> (integer)</term>
-     <listitem>
-      <para>
-       length of the character representation of the datum in bytes
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term><literal>SCALE</literal> (integer)</term>
-     <listitem>
-      <para>
-       scale (for type <type>numeric</type>)
-      </para>
-     </listitem>
-    </varlistentry>
-
-    <varlistentry>
-     <term><literal>TYPE</literal> (integer)</term>
-     <listitem>
-      <para>
-       numeric code of the data type of the column
-      </para>
-     </listitem>
-    </varlistentry>
-   </variablelist>
-  </para>
- </sect1>
-
  <sect1 id="ecpg-errors">
   <title>Error Handling</title>