Hi, here's the documentation patch for the new ECPG features.
- I changed the order of sections "Using Descriptor Areas" and "Informix compatibility mode" - split the "Using Descriptor Areas", so it now have two subsections: "Named SQL Descriptor Areas" and "SQLDA Descriptor Areas". The second one talks about the native mode SQLDA only. - Documented DESCRIBE and the USING/INTO quirks. - Documented the "string" pseudo-type in compat mode - Modified the section name "Additional embedded SQL statements", it now reads "Additional/missing embedded SQL statements" and documented the lack of "FREE cursor_name" statement and the behaviour of "FREE statement_name" statement. - Documented the Informix-compatible SQLDA under the "Informix compatibility mode" section. Best regards, Zoltán Böszörményi -- Bible has answers for everything. Proof: "But let your communication be, Yea, yea; Nay, nay: for whatsoever is more than these cometh of evil." (Matthew 5:37) - basics of digital technology. "May your kingdom come" - superficial description of plate tectonics ---------------------------------- Zoltán Böszörményi Cybertec Schönig & Schönig GmbH http://www.postgresql.at/
*** pgsql.orig/doc/src/sgml/ecpg.sgml 2009-12-08 09:23:19.000000000 +0100 --- pgsql.doc/doc/src/sgml/ecpg.sgml 2010-01-15 19:07:01.000000000 +0100 *************** *** 2376,2381 **** --- 2376,2853 ---- </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,2442 **** 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; </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 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> </variablelist> </para> </sect2> --- 2857,3229 ---- 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; ! </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> ! </listitem> ! </varlistentry> <varlistentry> ! <term><literal>sqlind</></term> <listitem> <para> ! Pointer to the NULL indicator. If returned by DESCRIBE or FETCH then it's always a valid pointer. ! If used as input for <literal>EXECUTE ... USING sqlda;</literal> then NULL-pointer value means ! that the value for this field is non-NULL. Otherwise a valid pointer and <literal>sqlitype</literal> ! has to be properly set. Example: <programlisting> ! if (*(int2 *)sqldata->sqlvar[i].sqlind != 0) ! printf("value is NULL\n"); </programlisting> </para> </listitem> </varlistentry> + + <varlistentry> + <term><literal>sqlname</></term> + <listitem> + <para> + Name of the field. 0-terminated string. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>sqlformat</></term> + <listitem> + <para> + Reserved in Informix, value of PQfformat() for the field. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>sqlitype</></term> + <listitem> + <para> + Type of the NULL indicator data. It's always SQLSMINT when returning data from the server. + When the <literal>SQLDA</literal> is used for a parametrized query, the data is treated + according to the set type. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>sqlilen</></term> + <listitem> + <para> + Length of the NULL indicator data. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>sqlxid</></term> + <listitem> + <para> + Extended type of the field, result of PQftype(). + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>sqltypename</></term> + <term><literal>sqltypelen</></term> + <term><literal>sqlownerlen</></term> + <term><literal>sqlsourcetype</></term> + <term><literal>sqlownername</></term> + <term><literal>sqlsourceid</></term> + <term><literal>sqlflags</></term> + <term><literal>sqlreserved</></term> + <listitem> + <para> + Unused. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>sqlilongdata</></term> + <listitem> + <para> + It equals to <literal>sqldata</literal> if <literal>sqllen</literal> is larger than 32KB. + </para> + </listitem> + </varlistentry> + </variablelist> + + Example: + <programlisting> + EXEC SQL INCLUDE sqlda.h; + + 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,3867 **** </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> --- 4447,4452 ----
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers