-<!-- $PostgreSQL: pgsql/doc/src/sgml/ecpg.sgml,v 1.74 2006/09/16 00:30:12 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/ecpg.sgml,v 1.75 2006/09/21 09:10:27 meskes Exp $ -->
<chapter id="ecpg">
<title><application>ECPG</application> - Embedded <acronym>SQL</acronym> in C</title>
not really useful in real applications. This section explains in
detail how you can pass data between your C program and the
embedded SQL statements using a simple mechanism called
- <firstterm>host variables</firstterm>.
+ <firstterm>host variables</firstterm>. In an embedded SQL program we
+ consider the SQL statements to be <firstterm>guests</firstterm> in the C
+ program code which is the <firstterm>host language</firstterm>. Therefore
+ the variables of the C program are called <firstterm>host
+ variables</firstterm>.
</para>
<sect2>
<para>
This style of inserting C variables in SQL statements works
- anywhere a value expression is expected in an SQL statement. In
- the SQL environment we call the references to C variables
- <firstterm>host variables</firstterm>.
+ anywhere a value expression is expected in an SQL statement.
</para>
</sect2>
Between those lines, there must be normal C variable declarations,
such as
<programlisting>
-int x;
+int x = 4;
char foo[16], bar[16];
+</programlisting>
+ As you can see, you can optionally assign an initial value to the variable.
+ The variable's scope is determined by the location of its declaring
+ section within the program.
+ You can also declare variables with the following syntax which implicitly
+ creates a declare section:
+<programlisting>
+EXEC SQL int i = 4;
</programlisting>
You can have as many declare sections in a program as you like.
</para>
a <literal>DECLARE</> section. Otherwise the preprocessor cannot
handle these types since it does not know the definition.
</para>
+ </sect2>
+
+ <sect2>
+ <title>Different types of host variables</title>
+ <para>
+ As a host variable you can also use arrays, typedefs, structs and
+ pointers. Moreover there are special types of host variables that exist
+ only in ecpg.
+ </para>
<para>
- The special type <type>VARCHAR</type>
- is converted into a named <type>struct</> for every variable. A
- declaration like
+ A few examples on host variables:
+ <variablelist>
+ <varlistentry>
+ <term>Arrays</term>
+ <listitem>
+ <para>
+ One of the most common uses of an array declaration is probably the
+ allocation of a char array as in
+<programlisting>
+EXEC SQL BEGIN DECLARE SECTION;
+ char str[50];
+EXEC SQL END DECLARE SECTION;
+</programlisting>
+ Note that you have to take care of the length for yourself. If you use
+ this host variable as the target variable of a query which returns a
+ string with more than 49 characters, a buffer overflow occurs.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Typedefs</term>
+ <listitem>
+ <para>
+ Use the <literal>typedef</literal> keyword to map new types to already
+ existing types.
+<programlisting>
+EXEC SQL BEGIN DECLARE SECTION;
+ typedef char mychartype[40];
+ typedef long serial_t;
+EXEC SQL END DECLARE SECTION;
+</programlisting>
+ Note that you could also use
+<programlisting>
+EXEC SQL TYPE serial_t IS long;
+</programlisting>
+ This declaration does not need to be part of a declare section.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Pointers</term>
+ <listitem>
+ <para>
+ You can declare pointers to the most common types. Note however that
+ you can not use pointers as target variables of queries without
+ auto-allocation. See <xref linkend="ecpg-descriptors"> for more
+ information on auto-allocation.
+ </para>
+<programlisting>
+EXEC SQL BEGIN DECLARE SECTION;
+ int *intp;
+ char **charp;
+EXEC SQL END DECLARE SECTION;
+</programlisting>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Special types of variables</term>
+ <listitem>
+ <para>
+ ecpg contains some special types that help you to interact easily with
+ data from the SQL server. For example it has implemented support for
+ the varchar, numeric, date, timestamp and interval types.
+ <xref linkend="ecpg-pgtypes"> contains basic functions to deal with
+ those types, such that you do not need to send a query to the SQL
+ server just for adding an interval to a timestamp for example.
+ </para>
+ <para>
+ The special type <type>VARCHAR</type>
+ is converted into a named <type>struct</> for every variable. A
+ declaration like
<programlisting>
VARCHAR var[180];
</programlisting>
- is converted into
+ is converted into
<programlisting>
struct varchar_var { int len; char arr[180]; } var;
</programlisting>
- This structure is suitable for interfacing with SQL datums of type
- <type>varchar</type>.
+ This structure is suitable for interfacing with SQL datums of type
+ <type>varchar</type>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
</para>
</sect2>
</sect2>
<sect2>
- <title>Indicators</title>
-
+ <title>Indicators</title>
+
+ <para>
+ The examples above do not handle null values. In fact, the
+ retrieval examples will raise an error if they fetch a null value
+ from the database. To be able to pass null values to the database
+ or retrieve null values from the database, you need to append a
+ second host variable specification to each host variable that
+ contains data. This second host variable is called the
+ <firstterm>indicator</firstterm> and contains a flag that tells
+ whether the datum is null, in which case the value of the real
+ host variable is ignored. Here is an example that handles the
+ retrieval of null values correctly:
+<programlisting>
+EXEC SQL BEGIN DECLARE SECTION;
+VARCHAR val;
+int val_ind;
+EXEC SQL END DECLARE SECTION:
+
+ ...
+
+EXEC SQL SELECT b INTO :val :val_ind FROM test1;
+</programlisting>
+ The indicator variable <varname>val_ind</varname> will be zero if
+ the value was not null, and it will be negative if the value was
+ null.
+ </para>
+
+ <para>
+ The indicator has another function: if the indicator value is
+ positive, it means that the value is not null, but it was
+ truncated when it was stored in the host variable.
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1 id="ecpg-dynamic">
+ <title>Dynamic SQL</title>
+
+ <para>
+ In many cases, the particular SQL statements that an application
+ has to execute are known at the time the application is written.
+ In some cases, however, the SQL statements are composed at run time
+ or provided by an external source. In these cases you cannot embed
+ the SQL statements directly into the C source code, but there is a
+ facility that allows you to call arbitrary SQL statements that you
+ provide in a string variable.
+ </para>
+
+ <para>
+ The simplest way to execute an arbitrary SQL statement is to use
+ the command <command>EXECUTE IMMEDIATE</command>. For example:
+<programlisting>
+EXEC SQL BEGIN DECLARE SECTION;
+const char *stmt = "CREATE TABLE test1 (...);";
+EXEC SQL END DECLARE SECTION;
+
+EXEC SQL EXECUTE IMMEDIATE :stmt;
+</programlisting>
+ You may not execute statements that retrieve data (e.g.,
+ <command>SELECT</command>) this way.
+ </para>
+
+ <para>
+ A more powerful way to execute arbitrary SQL statements is to
+ prepare them once and execute the prepared statement as often as
+ you like. It is also possible to prepare a generalized version of
+ a statement and then execute specific versions of it by
+ substituting parameters. When preparing the statement, write
+ question marks where you want to substitute parameters later. For
+ example:
+<programlisting>
+EXEC SQL BEGIN DECLARE SECTION;
+const char *stmt = "INSERT INTO test1 VALUES(?, ?);";
+EXEC SQL END DECLARE SECTION;
+
+EXEC SQL PREPARE mystmt FROM :stmt;
+ ...
+EXEC SQL EXECUTE mystmt USING 42, 'foobar';
+</programlisting>
+ If the statement you are executing returns values, then add an
+ <literal>INTO</literal> clause:
+<programlisting>
+EXEC SQL BEGIN DECLARE SECTION;
+const char *stmt = "SELECT a, b, c FROM test1 WHERE a > ?";
+int v1, v2;
+VARCHAR v3;
+EXEC SQL END DECLARE SECTION;
+
+EXEC SQL PREPARE mystmt FROM :stmt;
+ ...
+EXEC SQL EXECUTE mystmt INTO v1, v2, v3 USING 37;
+</programlisting>
+ An <command>EXECUTE</command> command may have an
+ <literal>INTO</literal> clause, a <literal>USING</literal> clause,
+ both, or neither.
+ </para>
+
+ <para>
+ When you don't need the prepared statement anymore, you should
+ deallocate it:
+<programlisting>
+EXEC SQL DEALLOCATE PREPARE <replaceable>name</replaceable>;
+</programlisting>
+ </para>
+ </sect1>
+
+
+ <sect1 id="ecpg-pgtypes">
+ <title>pgtypes library</title>
+
+ <para>
+ The pgtypes library maps <productname>PostgreSQL</productname> database
+ types to C equivalents that can be used in C programs. It also offers
+ functions to do basic calculations with those types within C, i.e. without
+ the help of the <productname>PostgreSQL</productname> server. See the
+ following example:
+<programlisting>
+EXEC SQL BEGIN DECLARE SECTION;
+ date date1;
+ timestamp ts1, tsout;
+ interval iv1;
+ char *out;
+EXEC SQL END DECLARE SECTION;
+
+PGTYPESdate_today(&date1);
+EXEC SQL SELECT started, duration INTO :ts1, :iv1 FROM datetbl WHERE d=:date1;
+PGTYPEStimestamp_add_interval(&ts1, &iv1, &tsout);
+out = PGTYPEStimestamp_to_asc(&tsout);
+printf("Started + duration: %s\n", out);
+free(out);
+</programlisting>
+ </para>
+
+ <sect2>
+ <title>The numeric type</title>
+ <para>
+ The numeric type offers to do calculations with arbitrary precision. See
+ <xref linkend="datatype-numeric"> for the equivalent type in the
+ <productname>PostgreSQL</> server. Because of the arbitrary precision this
+ variable needs to be able to expand and shrink dynamically. That's why you
+ can only create variables on the heap by means of the
+ <function>PGTYPESnumeric_new</> and <function>PGTYPESnumeric_free</>
+ functions. The decimal type, which is similar but limited in the precision,
+ can be created on the stack as well as on the heap.
+ </para>
+ <para>
+ The following functions can be used to work with the numeric type:
+ <variablelist>
+ <varlistentry>
+ <term><function>PGTYPESnumeric_new</function></term>
+ <listitem>
+ <para>
+ Request a pointer to a newly allocated numeric variable.
+<synopsis>
+numeric *PGTYPESnumeric_new(void);
+</synopsis>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>PGTYPESnumeric_free</function></term>
+ <listitem>
+ <para>
+ Free a numeric type, release all of its memory.
+<synopsis>
+void PGTYPESnumeric_free(numeric *var);
+</synopsis>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>PGTYPESnumeric_from_asc</function></term>
+ <listitem>
+ <para>
+ Parse a numeric type from its string notation.
+<synopsis>
+numeric *PGTYPESnumeric_from_asc(char *str, char **endptr);
+</synopsis>
+ Valid formats are for example:
+ <literal>-2</literal>,
+ <literal>.794</literal>,
+ <literal>+3.44</literal>,
+ <literal>592.49E07</literal> or
+ <literal>-32.84e-4</literal>.
+ If the value could be parsed successfully, a valid pointer is returned,
+ else the NULL pointer. At the moment ecpg always parses the complete
+ string and so it currently does not support to store the address of the
+ first invalid character in <literal>*endptr</literal>. You can safely
+ set <literal>endptr</literal> to NULL.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>PGTYPESnumeric_to_asc</function></term>
+ <listitem>
+ <para>
+ Returns a pointer to a malloced string that contains the string
+ representation of the numeric type <literal>num</literal>.
+<synopsis>
+char *PGTYPESnumeric_to_asc(numeric *num, int dscale);
+</synopsis>
+ The numeric value will be printed with <literal>dscale</literal> decimal
+ digits, with rounding applied if necessary.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>PGTYPESnumeric_add</function></term>
+ <listitem>
+ <para>
+ Add two numeric variables into a third one.
+<synopsis>
+int PGTYPESnumeric_add(numeric *var1, numeric *var2, numeric *result);
+</synopsis>
+ The function adds the variables <literal>var1</literal> and
+ <literal>var2</literal> into the result variable
+ <literal>result</literal>.
+ The function returns 0 on success and -1 in case of error.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>PGTYPESnumeric_sub</function></term>
+ <listitem>
+ <para>
+ Subtract two numeric variables and return the result in a third one.
+<synopsis>
+int PGTYPESnumeric_sub(numeric *var1, numeric *var2, numeric *result);
+</synopsis>
+ The function subtracts the variable <literal>var2</literal> from
+ the variable <literal>var1</literal>. The result of the operation is
+ stored in the variable <literal>result</literal>.
+ The function returns 0 on success and -1 in case of error.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>PGTYPESnumeric_mul</function></term>
+ <listitem>
+ <para>
+ Multiply two numeric variables and return the result in a third one.
+<synopsis>
+int PGTYPESnumeric_mul(numeric *var1, numeric *var2, numeric *result);
+</synopsis>
+ The function multiplies the variables <literal>var1</literal> and
+ <literal>var2</literal>. The result of the operation is stored in the
+ variable <literal>result</literal>.
+ The function returns 0 on success and -1 in case of error.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>PGTYPESnumeric_div</function></term>
+ <listitem>
+ <para>
+ Divide two numeric variables and return the result in a third one.
+<synopsis>
+int PGTYPESnumeric_div(numeric *var1, numeric *var2, numeric *result);
+</synopsis>
+ The function divides the variables <literal>var1</literal> by
+ <literal>var2</literal>. The result of the operation is stored in the
+ variable <literal>result</literal>.
+ The function returns 0 on success and -1 in case of error.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>PGTYPESnumeric_cmp</function></term>
+ <listitem>
+ <para>
+ Compare two numeric variables.
+<synopsis>
+int PGTYPESnumeric_cmp(numeric *var1, numeric *var2)
+</synopsis>
+ This function compares two numeric variables. In case of error,
+ <literal>INT_MAX</literal> is returned. On success, the function
+ returns one of three possible results:
+ <itemizedlist>
+ <listitem>
+ <para>
+ 1, if <literal>var1</> is bigger than <literal>var2</>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ -1, if <literal>var1</> is smaller than <literal>var2</>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 0, if <literal>var1</> and <literal>var2</> are equal
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>PGTYPESnumeric_from_int</function></term>
+ <listitem>
+ <para>
+ Convert an int variable to a numeric variable.
+<synopsis>
+int PGTYPESnumeric_from_int(signed int int_val, numeric *var);
+</synopsis>
+ This function accepts a variable of type signed int and stores it
+ in the numeric variable <literal>var</>. Upon success, 0 is returned and
+ -1 in case of a failure.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>PGTYPESnumeric_from_long</function></term>
+ <listitem>
+ <para>
+ Convert a long int variable to a numeric variable.
+<synopsis>
+int PGTYPESnumeric_from_long(signed long int long_val, numeric *var);
+</synopsis>
+ This function accepts a variable of type signed long int and stores it
+ in the numeric variable <literal>var</>. Upon success, 0 is returned and
+ -1 in case of a failure.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>PGTYPESnumeric_copy</function></term>
+ <listitem>
+ <para>
+ Copy over one numeric variable into another one.
+<synopsis>
+int PGTYPESnumeric_copy(numeric *src, numeric *dst);
+</synopsis>
+ This function copies over the value of the variable that
+ <literal>src</literal> points to into the variable that <literal>dst</>
+ points to. It returns 0 on success and -1 if an error occurs.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>PGTYPESnumeric_from_double</function></term>
+ <listitem>
+ <para>
+ Convert a variable of type double to a numeric.
+<synopsis>
+int PGTYPESnumeric_from_double(double d, numeric *dst);
+</synopsis>
+ This function accepts a variable of type double and stores the result
+ in the variable that <literal>dst</> points to. It returns 0 on success
+ and -1 if an error occurs.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>PGTYPESnumeric_to_double</function></term>
+ <listitem>
+ <para>
+ Convert a variable of type numeric to double.
+<synopsis>
+int PGTYPESnumeric_to_double(numeric *nv, double *dp)
+</synopsis>
+ The function converts the numeric value from the variable that
+ <literal>nv</> points to into the double variable that <literal>dp</> points
+ to. It retuns 0 on success and -1 if an error occurs, including
+ overflow. On overflow, the global variable <literal>errno</> will be set
+ to <literal>PGTYPES_NUM_OVERFLOW</> additionally.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>PGTYPESnumeric_to_int</function></term>
+ <listitem>
+ <para>
+ Convert a variable of type numeric to int.
+<synopsis>
+int PGTYPESnumeric_to_int(numeric *nv, int *ip);
+</synopsis>
+ The function converts the numeric value from the variable that
+ <literal>nv</> points to into the integer variable that <literal>ip</>
+ points to. It retuns 0 on success and -1 if an error occurs, including
+ overflow. On overflow, the global variable <literal>errno</> will be set
+ to <literal>PGTYPES_NUM_OVERFLOW</> additionally.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>PGTYPESnumeric_to_long</function></term>
+ <listitem>
+ <para>
+ Convert a variable of type numeric to long.
+<synopsis>
+int PGTYPESnumeric_to_long(numeric *nv, long *lp);
+</synopsis>
+ The function converts the numeric value from the variable that
+ <literal>nv</> points to into the long integer variable that
+ <literal>lp</> points to. It retuns 0 on success and -1 if an error
+ occurs, including overflow. On overflow, the global variable
+ <literal>errno</> will be set to <literal>PGTYPES_NUM_OVERFLOW</>
+ additionally.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>PGTYPESnumeric_to_decimal</function></term>
+ <listitem>
+ <para>
+ Convert a variable of type numeric to decimal.
+<synopsis>
+int PGTYPESnumeric_to_decimal(numeric *src, decimal *dst);
+</synopsis>
+ The function converts the numeric value from the variable that
+ <literal>src</> points to into the decimal variable that
+ <literal>dst</> points to. It retuns 0 on success and -1 if an error
+ occurs, including overflow. On overflow, the global variable
+ <literal>errno</> will be set to <literal>PGTYPES_NUM_OVERFLOW</>
+ additionally.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>PGTYPESnumeric_from_decimal</function></term>
+ <listitem>
+ <para>
+ Convert a variable of type decimal to numeric.
+<synopsis>
+int PGTYPESnumeric_from_decimal(decimal *src, numeric *dst);
+</synopsis>
+ The function converts the decimal value from the variable that
+ <literal>src</> points to into the numeric variable that
+ <literal>dst</> points to. It retuns 0 on success and -1 if an error
+ occurs. Since the decimal type is implemented as a limited version of
+ the numeric type, overflow can not occur with this conversion.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>The date type</title>
+ <para>
+ The date type in C enables your programs to deal with data of the SQL type
+ date. See <xref linkend="datatype-datetime"> for the equivalent type in the
+ <productname>PostgreSQL</> server.
+ </para>
+ <para>
+ The following functions can be used to work with the date type:
+ <variablelist>
+ <varlistentry id="PGTYPESdatefromtimestamp">
+ <term><function>PGTYPESdate_from_timestamp</function></term>
+ <listitem>
+ <para>
+ Extract the date part from a timestamp.
+<synopsis>
+date PGTYPESdate_from_timestamp(timestamp dt);
+</synopsis>
+ The function receives a timestamp as its only argument and returns the
+ extracted date part from this timestamp.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPESdatefromasc">
+ <term><function>PGTYPESdate_from_asc</function></term>
+ <listitem>
+ <para>
+ Parse a date from its textual representation.
+<synopsis>
+date PGTYPESdate_from_asc(char *str, char **endptr);
+</synopsis>
+ The function receives a C char* string <literal>str</> and a pointer to
+ a C char* string <literal>endptr</>. At the moment ecpg always parses
+ the complete string and so it currently does not support to store the
+ address of the first invalid character in <literal>*endptr</literal>.
+ You can safely set <literal>endptr</literal> to NULL.
+ </para>
+ <para>
+ Note that the function always assumes MDY-formatted dates and there is
+ currently no variable to change that within ecpg.
+ </para>
+ <para>
+ The following input formats are allowed:
+ <table>
+ <title>Valid input formats for <function>PGTYPESdate_from_asc</function>.
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry>Input</entry>
+ <entry>Result</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>January 8, 1999</literal></entry>
+ <entry><literal>January 8, 1999</literal></entry>
+ </row>
+ <row>
+ <entry><literal>1999-01-08</literal></entry>
+ <entry><literal>January 8, 1999</literal></entry>
+ </row>
+ <row>
+ <entry><literal>1/8/1999</literal></entry>
+ <entry><literal>January 8, 1999</literal></entry>
+ </row>
+ <row>
+ <entry><literal>1/18/1999</literal></entry>
+ <entry><literal>January 18, 1999</literal></entry>
+ </row>
+ <row>
+ <entry><literal>01/02/03</literal></entry>
+ <entry><literal>February 1, 2003</literal></entry>
+ </row>
+ <row>
+ <entry><literal>1999-Jan-08</literal></entry>
+ <entry><literal>January 8, 1999</literal></entry>
+ </row>
+ <row>
+ <entry><literal>Jan-08-1999</literal></entry>
+ <entry><literal>January 8, 1999</literal></entry>
+ </row>
+ <row>
+ <entry><literal>08-Jan-1999</literal></entry>
+ <entry><literal>January 8, 1999</literal></entry>
+ </row>
+ <row>
+ <entry><literal>99-Jan-08</literal></entry>
+ <entry><literal>January 8, 1999</literal></entry>
+ </row>
+ <row>
+ <entry><literal>08-Jan-99</literal></entry>
+ <entry><literal>January 8, 1999</literal></entry>
+ </row>
+ <row>
+ <entry><literal>08-Jan-06</literal></entry>
+ <entry><literal>January 8, 2006</literal></entry>
+ </row>
+ <row>
+ <entry><literal>Jan-08-99</literal></entry>
+ <entry><literal>January 8, 1999</literal></entry>
+ </row>
+ <row>
+ <entry><literal>19990108</literal></entry>
+ <entry><literal>ISO 8601; January 8, 1999</literal></entry>
+ </row>
+ <row>
+ <entry><literal>990108</literal></entry>
+ <entry><literal>ISO 8601; January 8, 1999</literal></entry>
+ </row>
+ <row>
+ <entry><literal>1999.008</literal></entry>
+ <entry><literal>year and day of year</literal></entry>
+ </row>
+ <row>
+ <entry><literal>J2451187</literal></entry>
+ <entry><literal>Julian day</literal></entry>
+ </row>
+ <row>
+ <entry><literal>January 8, 99 BC</literal></entry>
+ <entry><literal>year 99 before the Common Era</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPESdatetoasc">
+ <term><function>PGTYPESdate_to_asc</function></term>
+ <listitem>
+ <para>
+ Return the textual representation of a date variable.
+<synopsis>
+char *PGTYPESdate_to_asc(date dDate);
+</synopsis>
+ The function receives the date <literal>dDate</> as its only parameter.
+ It will output the date in the form <literal>1999-01-18</>, i.e. in the
+ <literal>YYYY-MM-DD</> format.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPESdatejulmdy">
+ <term><function>PGTYPESdate_julmdy</function></term>
+ <listitem>
+ <para>
+ Extract the values for the day, the month and the year from a variable
+ of type date.
+<synopsis>
+void PGTYPESdate_julmdy(date d, int *mdy);
+</synopsis>
+ <!-- almost same description as for rjulmdy() -->
+ The function receives the date <literal>d</> and a pointer to an array
+ of 3 integer values <literal>mdy</>. The variable name indicates
+ the sequential order: <literal>mdy[0]</> will be set to contain the
+ number of the month, <literal>mdy[1]</> will be set to the value of the
+ day and <literal>mdy[2]</> will contain the year.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPESdatemdyjul">
+ <term><function>PGTYPESdate_mdyjul</function></term>
+ <listitem>
+ <para>
+ Create a date value from an array of 3 integers that specify the
+ day, the month and the year of the date.
+<synopsis>
+void PGTYPESdate_mdyjul(int *mdy, date *jdate);
+</synopsis>
+ The function receives the array of the 3 integers (<literal>mdy</>) as
+ its first argument and as its second argument a pointer to a variable
+ of type date that should hold the result of the operation.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPESdatedayofweek">
+ <term><function>PGTYPESdate_dayofweek</function></term>
+ <listitem>
+ <para>
+ Return a number representing the day of the week for a date value.
+<synopsis>
+int PGTYPESdate_dayofweek(date d);
+</synopsis>
+ The function receives the date variable <literal>d</> as its only
+ argument and returns an integer that indicates the day of the week for
+ this date.
+ <itemizedlist>
+ <listitem>
+ <para>
+ 0 - Sunday
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 1 - Monday
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 2 - Tuesday
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 3 - Wednesday
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 4 - Thursday
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 5 - Friday
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 6 - Saturday
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPESdatetoday">
+ <term><function>PGTYPESdate_today</function></term>
+ <listitem>
+ <para>
+ Get the current date.
+<synopsis>
+void PGTYPESdate_today(date *d);
+</synopsis>
+ The function receives a pointer to a date variable (<literal>d</>)
+ that it sets to the current date.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPESdatefmtasc">
+ <term><function>PGTYPESdate_fmt_asc</function></term>
+ <listitem>
+ <para>
+ Convert a variable of type date to its textual representation using a
+ format mask.
+<synopsis>
+int PGTYPESdate_fmt_asc(date dDate, char *fmtstring, char *outbuf);
+</synopsis>
+ The function receives the date to convert (<literal>dDate</>), the
+ format mask (<literal>fmtstring</>) and the string that will hold the
+ textual representation of the date (<literal>outbuf</>).
+ </para>
+ <para>
+ On success, 0 is returned and a negative value if an error occurred.
+ </para>
+ <para>
+ The following literals are the field specifiers you can use:
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>dd</literal> - The number of the day of the month.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>mm</literal> - The number of the month of the year.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>yy</literal> - The number of the year as a two digit number.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>yyyy</literal> - The number of the year as a four digit number.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ddd</literal> - The name of the day (abbreviated).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>mmm</literal> - The name of the month (abbreviated).
+ </para>
+ </listitem>
+ </itemizedlist>
+ All other characters are copied 1:1 to the output string.
+ </para>
+ <para>
+ The following table indicates a few possible formats. This will give
+ you an idea of how to use this function. All output lines are based on
+ the same date: November, 23rd, 1959.
+ <table>
+ <title>Valid input formats for <function>PGTYPESdate_fmt_asc</function>.
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry>fmt</entry>
+ <entry>result</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>mmddyy</literal></entry>
+ <entry><literal>112359</literal></entry>
+ </row>
+ <row>
+ <entry><literal>ddmmyy</literal></entry>
+ <entry><literal>231159</literal></entry>
+ </row>
+ <row>
+ <entry><literal>yymmdd</literal></entry>
+ <entry><literal>591123</literal></entry>
+ </row>
+ <row>
+ <entry><literal>yy/mm/dd</literal></entry>
+ <entry><literal>59/11/23</literal></entry>
+ </row>
+ <row>
+ <entry><literal>yy mm dd</literal></entry>
+ <entry><literal>59 11 23</literal></entry>
+ </row>
+ <row>
+ <entry><literal>yy.mm.dd</literal></entry>
+ <entry><literal>59.11.23</literal></entry>
+ </row>
+ <row>
+ <entry><literal>.mm.yyyy.dd.</literal></entry>
+ <entry><literal>.11.1959.23.</literal></entry>
+ </row>
+ <row>
+ <entry><literal>mmm. dd, yyyy</literal></entry>
+ <entry><literal>Nov. 23, 1959</literal></entry>
+ </row>
+ <row>
+ <entry><literal>mmm dd yyyy</literal></entry>
+ <entry><literal>Nov 23 1959</literal></entry>
+ </row>
+ <row>
+ <entry><literal>yyyy dd mm</literal></entry>
+ <entry><literal>1959 23 11</literal></entry>
+ </row>
+ <row>
+ <entry><literal>ddd, mmm. dd, yyyy</literal></entry>
+ <entry><literal>Mon, Nov. 23, 1959</literal></entry>
+ </row>
+ <row>
+ <entry><literal>(ddd) mmm. dd, yyyy</literal></entry>
+ <entry><literal>(Mon) Nov. 23, 1959</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPESdatedefmtasc">
+ <term><function>PGTYPESdate_defmt_asc</function></term>
+ <listitem>
+ <para>
+ Use a format mask to convert a C char* string to a value of type
+ date.
+<synopsis>
+int PGTYPESdate_defmt_asc(date *d, char *fmt, char *str);
+</synopsis>
+ <!-- same description as rdefmtdate -->
+ The function receives a pointer to the date value that should hold the
+ result of the operation (<literal>d</>), the format mask to use for
+ parsing the date (<literal>fmt</>) and the C char* string containing
+ the textual representation of the date (<literal>str</>). The textual
+ representation is expected to match the format mask. However you do not
+ need to have a 1:1 mapping of the string to the format mask. The
+ function only analyzes the sequential order and looks for the literals
+ <literal>yy</literal> or <literal>yyyy</literal> that indicate the
+ position of the year, <literal>mm</literal> to indicate the position of
+ the month and <literal>dd</literal> to indicate the position of the
+ day.
+ </para>
+ <para>
+ The following table indicates a few possible formats. This will give
+ you an idea of how to use this function.
+ <table>
+ <title>Valid input formats for <function>rdefmtdate</function>.
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry>fmt</entry>
+ <entry>str</entry>
+ <entry>result</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>ddmmyy</literal></entry>
+ <entry><literal>21-2-54</literal></entry>
+ <entry><literal>1954-02-21</literal></entry>
+ </row>
+ <row>
+ <entry><literal>ddmmyy</literal></entry>
+ <entry><literal>2-12-54</literal></entry>
+ <entry><literal>1954-12-02</literal></entry>
+ </row>
+ <row>
+ <entry><literal>ddmmyy</literal></entry>
+ <entry><literal>20111954</literal></entry>
+ <entry><literal>1954-11-20</literal></entry>
+ </row>
+ <row>
+ <entry><literal>ddmmyy</literal></entry>
+ <entry><literal>130464</literal></entry>
+ <entry><literal>1964-04-13</literal></entry>
+ </row>
+ <row>
+ <entry><literal>mmm.dd.yyyy</literal></entry>
+ <entry><literal>MAR-12-1967</literal></entry>
+ <entry><literal>1967-03-12</literal></entry>
+ </row>
+ <row>
+ <entry><literal>yy/mm/dd</literal></entry>
+ <entry><literal>1954, February 3rd</literal></entry>
+ <entry><literal>1954-02-03</literal></entry>
+ </row>
+ <row>
+ <entry><literal>mmm.dd.yyyy</literal></entry>
+ <entry><literal>041269</literal></entry>
+ <entry><literal>1969-04-12</literal></entry>
+ </row>
+ <row>
+ <entry><literal>yy/mm/dd</literal></entry>
+ <entry><literal>In the year 2525, in the month of July, mankind will be alive on the 28th day</literal></entry>
+ <entry><literal>2525-07-28</literal></entry>
+ </row>
+ <row>
+ <entry><literal>dd-mm-yy</literal></entry>
+ <entry><literal>I said on the 28th of July in the year 2525</literal></entry>
+ <entry><literal>2525-07-28</literal></entry>
+ </row>
+ <row>
+ <entry><literal>mmm.dd.yyyy</literal></entry>
+ <entry><literal>9/14/58</literal></entry>
+ <entry><literal>1958-09-14</literal></entry>
+ </row>
+ <row>
+ <entry><literal>yy/mm/dd</literal></entry>
+ <entry><literal>47/03/29</literal></entry>
+ <entry><literal>1947-03-29</literal></entry>
+ </row>
+ <row>
+ <entry><literal>mmm.dd.yyyy</literal></entry>
+ <entry><literal>oct 28 1975</literal></entry>
+ <entry><literal>1975-10-28</literal></entry>
+ </row>
+ <row>
+ <entry><literal>mmddyy</literal></entry>
+ <entry><literal>Nov 14th, 1985</literal></entry>
+ <entry><literal>1985-11-14</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>The timestamp type</title>
+ <para>
+ The timestamp type in C enables your programs to deal with data of the SQL
+ type timestamp. See <xref linkend="datatype-datetime"> for the equivalent
+ type in the <productname>PostgreSQL</> server.
+ </para>
+ <para>
+ The following functions can be used to work with the timestamp type:
+ <variablelist>
+ <varlistentry id="PGTYPEStimestampfromasc">
+ <term><function>PGTYPEStimestamp_from_asc</function></term>
+ <listitem>
+ <para>
+ Parse a timestamp from its textual representation into a timestamp
+ variable.
+<synopsis>
+timestamp PGTYPEStimestamp_from_asc(char *str, char **endptr);
+</synopsis>
+ The function receives the string to parse (<literal>str</>) and a
+ pointer to a C char* (<literal>endptr</>).
+ At the moment ecpg always parses
+ the complete string and so it currently does not support to store the
+ address of the first invalid character in <literal>*endptr</literal>.
+ You can safely set <literal>endptr</literal> to NULL.
+ </para>
+ <para>
+ The function returns the parsed timestamp on success. On error,
+ <literal>PGTYPESInvalidTimestamp</literal> is returned and errno is
+ set to <literal>PGTYPES_TS_BAD_TIMESTAMP</>. See <xref linkend="PGTYPESInvalidTimestamp"> for important notes on this value.
+
+ </para>
+ <para>
+ In general, the input string can contain any combination of an allowed
+ date specification, a whitespace character and an allowed time
+ specification. Note that timezones are not supported by ecpg. It can
+ parse them but does not apply any calculation as the
+ <productname>PostgreSQL</> server does for example. Timezone
+ specificiers are silently discarded.
+ </para>
+ <para>
+ The following table contains a few examples for input strings:
+ <table>
+ <title>Valid input formats for <function>PGTYPEStimestamp_from_asc</function>.
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry>Input</entry>
+ <entry>Result</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>1999-01-08 04:05:06</literal></entry>
+ <entry><literal>1999-01-08 04:05:06</literal></entry>
+ </row>
+ <row>
+ <entry><literal>January 8 04:05:06 1999 PST</literal></entry>
+ <entry><literal>1999-01-08 04:05:06</literal></entry>
+ </row>
+ <row>
+ <entry><literal>1999-Jan-08 04:05:06.789-8</literal></entry>
+ <entry><literal>1999-01-08 04:05:06.789 (time zone specifier ignored)</literal></entry>
+ </row>
+ <row>
+ <entry><literal>J2451187 04:05-08:00</literal></entry>
+ <entry><literal>1999-01-08 04:05:00 (time zone specifier ignored)</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPEStimestamptoasc">
+ <term><function>PGTYPEStimestamp_to_asc</function></term>
+ <listitem>
+ <para>
+ Converts a date to a C char* string.
+<synopsis>
+char *PGTYPEStimestamp_to_asc(timestamp tstamp);
+</synopsis>
+ The function receives the timestamp <literal>tstamp</> as
+ its only argument and returns an allocated string that contains the
+ textual representation of the timestamp.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPEStimestampcurrent">
+ <term><function>PGTYPEStimestamp_current</function></term>
+ <listitem>
+ <para>
+ Retrieve the current timestamp.
+<synopsis>
+void PGTYPEStimestamp_current(timestamp *ts);
+</synopsis>
+ The function retrieves the current timestamp and saves it into the
+ timestamp variable that <literal>ts</> points to.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPEStimestampfmtasc">
+ <term><function>PGTYPEStimestamp_fmt_asc</function></term>
+ <listitem>
+ <para>
+ Convert a timestamp variable to a C char* using a format mask.
+<synopsis>
+int PGTYPEStimestamp_fmt_asc(timestamp *ts, char *output, int str_len, char *fmtstr);
+</synopsis>
+ The function receives a pointer to the timestamp to convert as its
+ first argument (<literal>ts</>), a pointer to the output buffer
+ (<literal>output</>), the maximal length that has been allocated for
+ the output buffer (<literal>str_len</literal>) and the format mask to
+ use for the conversion (<literal>fmtstr</literal>).
+ </para>
+ <para>
+ Upon success, the function returns 0 and a negative value if an
+ error occurred.
+ </para>
+ <para>
+ You can use the following format specifiers for the format mask. The
+ format specifiers are the same ones that are used in the
+ <function>strftime</> function in <productname>libc</productname>. Any
+ non-format specifier will be copied into the output buffer.
+ <!-- This is from the FreeBSD man page:
+ http://www.freebsd.org/cgi/man.cgi?query=strftime&apropos=0&sektion=3&manpath=FreeBSD+7.0-current&format=html
+ -->
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>%A</literal> - is replaced by national representation of
+ the full weekday name.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%a</literal> - is replaced by national representation of
+ the abbreviated weekday name.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%B</literal> - is replaced by national representation of
+ the full month name.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%b</literal> - is replaced by national representation of
+ the abbreviated month name.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%C</literal> - is replaced by (year / 100) as decimal
+ number; single digits are preceded by a zero.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%c</literal> - is replaced by national representation of
+ time and date.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%D</literal> - is equivalent to
+ <literal>%m/%d/%y</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%d</literal> - is replaced by the day of the month as a
+ decimal number (01-31).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%E*</literal> <literal>%O*</literal> - POSIX locale
+ extensions. The sequences
+ <literal>%Ec</literal>
+ <literal>%EC</literal>
+ <literal>%Ex</literal>
+ <literal>%EX</literal>
+ <literal>%Ey</literal>
+ <literal>%EY</literal>
+ <literal>%Od</literal>
+ <literal>%Oe</literal>
+ <literal>%OH</literal>
+ <literal>%OI</literal>
+ <literal>%Om</literal>
+ <literal>%OM</literal>
+ <literal>%OS</literal>
+ <literal>%Ou</literal>
+ <literal>%OU</literal>
+ <literal>%OV</literal>
+ <literal>%Ow</literal>
+ <literal>%OW</literal>
+ <literal>%Oy</literal>
+ are supposed to provide alternate representations.
+ </para>
+ <para>
+ Additionally <literal>%OB</literal> implemented to represent
+ alternative months names (used standalone, without day mentioned).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%e</literal> - is replaced by the day of month as a decimal
+ number (1-31); single digits are preceded by a blank.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%F</literal> - is equivalent to <literal>%Y-%m-%d</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%G</literal> - is replaced by a year as a decimal number
+ with century. This year is the one that contains the greater part of
+ the week (Monday as the first day of the week).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%g</literal> - is replaced by the same year as in
+ <literal>%G</literal>, but as a decimal number without century
+ (00-99).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%H</literal> - is replaced by the hour (24-hour clock) as a
+ decimal number (00-23).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%h</literal> - the same as <literal>%b</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%I</literal> - is replaced by the hour (12-hour clock) as a
+ decimal number (01-12).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%j</literal> - is replaced by the day of the year as a
+ decimal number (001-366).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%k</literal> - is replaced by the hour (24-hour clock) as a
+ decimal number (0-23); single digits are preceded by a blank.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%l</literal> - is replaced by the hour (12-hour clock) as a
+ decimal number (1-12); single digits are preceded by a blank.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%M</literal> - is replaced by the minute as a decimal
+ number (00-59).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%m</literal> - is replaced by the month as a decimal number
+ (01-12).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%n</literal> - is replaced by a newline.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%O*</literal> - the same as <literal>%E*</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%p</literal> - is replaced by national representation of
+ either "ante meridiem" or "post meridiem" as appropriate.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%R</literal> - is equivalent to <literal>%H:%M</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%r</literal> - is equivalent to <literal>%I:%M:%S
+ %p</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%S</literal> - is replaced by the second as a decimal
+ number (00-60).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%s</literal> - is replaced by the number of seconds since
+ the Epoch, UTC.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%T</literal> - is equivalent to <literal>%H:%M:%S</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%t</literal> - is replaced by a tab.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%U</literal> - is replaced by the week number of the year
+ (Sunday as the first day of the week) as a decimal number (00-53).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%u</literal> - is replaced by the weekday (Monday as the
+ first day of the week) as a decimal number (1-7).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%V</literal> - is replaced by the week number of the year
+ (Monday as the first day of the week) as a decimal number (01-53).
+ If the week containing January 1 has four or more days in the new
+ year, then it is week 1; otherwise it is the last week of the
+ previous year, and the next week is week 1.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%v</literal> - is equivalent to
+ <literal>%e-%b-%Y</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%W</literal> - is replaced by the week number of the year
+ (Monday as the first day of the week) as a decimal number (00-53).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%w</literal> - is replaced by the weekday (Sunday as the
+ first day of the week) as a decimal number (0-6).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%X</literal> - is replaced by national representation of
+ the time.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%x</literal> - is replaced by national representation of
+ the date.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%Y</literal> - is replaced by the year with century as a
+ decimal number.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%y</literal> - is replaced by the year without century as a
+ decimal number (00-99).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%Z</literal> - is replaced by the time zone name.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%z</literal> - is replaced by the time zone offset from
+ UTC; a leading plus sign stands for east of UTC, a minus sign for
+ west of UTC, hours and minutes follow with two digits each and no
+ delimiter between them (common form for RFC 822 date headers).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%+</literal> - is replaced by national representation of
+ the date and time.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%-*</literal> - GNU libc extension. Do not do any padding
+ when performing numerical outputs.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ $_* - GNU libc extension. Explicitly specify space for padding.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%0*</literal> - GNU libc extension. Explicitly specify zero
+ for padding.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>%%</literal> - is replaced by <literal>%</literal>.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPEStimestampsub">
+ <term><function>PGTYPEStimestamp_sub</function></term>
+ <listitem>
+ <para>
+ Subtract one timestamp from another one and save the result in a
+ variable of type interval.
+<synopsis>
+int PGTYPEStimestamp_sub(timestamp *ts1, timestamp *ts2, interval *iv);
+</synopsis>
+ The function will subtract the timestamp variable that <literal>ts2</>
+ points to from the timestamp variable that <literal>ts1</> points to
+ and will store the result in the interval variable that <literal>iv</>
+ points to.
+ </para>
+ <para>
+ Upon success, the function returns 0 and a negative value if an
+ error occurred.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPEStimestampdefmtasc">
+ <term><function>PGTYPEStimestamp_defmt_asc</function></term>
+ <listitem>
+ <para>
+ Parse a timestamp value from its textual representation using a
+ formatting mask.
+<synopsis>
+int PGTYPEStimestamp_defmt_asc(char *str, char *fmt, timestamp *d);
+</synopsis>
+ The function receives the textual representation of a timestamp in the
+ variable <literal>str</> as well as the formatting mask to use in the
+ variable <literal>fmt</>. The result will be stored in the variable
+ that <literal>d</> points to.
+ </para>
+ <para>
+ If the formatting mask <literal>fmt</> is NULL, the function will fall
+ back to the default formatting mask which is <literal>%Y-%m-%d
+ %H:%M:%S</literal>.
+ </para>
+ <para>
+ This is the reverse function to <xref
+ linkend="PGTYPEStimestampfmtasc">. See the documentation there in
+ order to find out about the possible formatting mask entries.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPEStimestampaddinterval">
+ <term><function>PGTYPEStimestamp_add_interval</function></term>
+ <listitem>
+ <para>
+ Add an interval variable to a timestamp variable.
+<synopsis>
+int PGTYPEStimestamp_add_interval(timestamp *tin, interval *span, timestamp *tout);
+</synopsis>
+ The function receives a pointer to a timestamp variable <literal>tin</>
+ and a pointer to an interval variable <literal>span</>. It adds the
+ interval to the timestamp and saves the resulting timestamp in the
+ variable that <literal>tout</> points to.
+ </para>
+ <para>
+ Upon success, the function returns 0 and a negative value if an
+ error occurred.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPEStimestampsubinterval">
+ <term><function>PGTYPEStimestamp_sub_interval</function></term>
+ <listitem>
+ <para>
+ Subtract an interval variable from a timestamp variable.
+<synopsis>
+int PGTYPEStimestamp_sub_interval(timestamp *tin, interval *span, timestamp *tout);
+</synopsis>
+ The function subtracts the interval variable that <literal>span</>
+ points to from the timestamp variable that <literal>tin</> points to
+ and saves the result into the variable that <literal>tout</> points
+ to.
+ </para>
+ <para>
+ Upon success, the function returns 0 and a negative value if an
+ error occurred.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>The interval type</title>
+ <para>
+ The interval type in C enables your programs to deal with data of the SQL
+ type interval. See <xref linkend="datatype-datetime"> for the equivalent
+ type in the <productname>PostgreSQL</> server.
+ </para>
+ <para>
+ The following functions can be used to work with the interval type:
+ <variablelist>
+
+ <varlistentry id="PGTYPESintervalnew">
+ <term><function>PGTYPESinterval_new</function></term>
+ <listitem>
+ <para>
+ Return a pointer to a newly allocated interval variable.
+<synopsis>
+interval *PGTYPESinterval_new(void);
+</synopsis>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPESintervalfree">
+ <term><function>PGTYPESinterval_free</function></term>
+ <listitem>
+ <para>
+ Release the memory of a previously allocated interval variable.
+<synopsis>
+void PGTYPESinterval_new(interval *intvl);
+</synopsis>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPESintervalfromasc">
+ <term><function>PGTYPESinterval_from_asc</function></term>
+ <listitem>
+ <para>
+ Parse an interval from its textual representation.
+<synopsis>
+interval *PGTYPESinterval_from_asc(char *str, char **endptr);
+</synopsis>
+ The function parses the input string <literal>str</> and returns a
+ pointer to an allocated interval variable.
+ At the moment ecpg always parses
+ the complete string and so it currently does not support to store the
+ address of the first invalid character in <literal>*endptr</literal>.
+ You can safely set <literal>endptr</literal> to NULL.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPESintervaltoasc">
+ <term><function>PGTYPESinterval_to_asc</function></term>
+ <listitem>
+ <para>
+ Convert a variable of type interval to its textual representation.
+<synopsis>
+char *PGTYPESinterval_to_asc(interval *span);
+</synopsis>
+ The function converts the interval variable that <literal>span</>
+ points to into a C char*. The output looks like this example:
+ <literal>@ 1 day 12 hours 59 mins 10 secs</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="PGTYPESintervalcopy">
+ <term><function>PGTYPESinterval_copy</function></term>
+ <listitem>
+ <para>
+ Copy a variable of type interval.
+<synopsis>
+int PGTYPESinterval_copy(interval *intvlsrc, interval *intvldest);
+</synopsis>
+ The function copies the interval variable that <literal>intvlsrc</>
+ points to into the variable that <literal>intvldest</> points to. Note
+ that you need to allocate the memory for the destination variable
+ before.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>The decimal type</title>
+ <para>
+ The decimal type is similar to the numeric type. However it is limited to
+ a maximal precision of 30 significant digits. In contrast to the numeric
+ type which can be created on the heap only, the decimal type can be
+ created either on the stack or on the heap (by means of the functions
+ PGTYPESdecimal_new() and PGTYPESdecimal_free(). There are a lot of other
+ functions that deal with the decimal type in the Informix compatibility
+ mode described in <xref linkend="ecpg-informix-compat">.
+ </para>
+ <para>
+ The following functions can be used to work with the decimal type and are
+ not only contained in the <literal>libcompat</> library.
+ <variablelist>
+ <varlistentry>
+ <term><function>PGTYPESdecimal_new</function></term>
+ <listitem>
+ <para>
+ Request a pointer to a newly allocated decimal variable.
+<synopsis>
+decimal *PGTYPESdecimal_new(void);
+</synopsis>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>PGTYPESdecimal_free</function></term>
+ <listitem>
+ <para>
+ Free a decimal type, release all of its memory.
+<synopsis>
+void PGTYPESdecimal_free(decimal *var);
+</synopsis>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>errno values of pgtypeslib </title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>PGTYPES_NUM_BAD_NUMERIC</literal></term>
+ <listitem>
+ <para>
+ An argument should contain a numeric variable (or point to a numeric
+ variable) but in fact its in-memory representation was invalid.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>PGTYPES_NUM_OVERFLOW</literal></term>
+ <listitem>
+ <para>
+ An overflow occurred. Since the numeric type can deal with almost
+ arbitrary precision, converting a numeric variable into other types
+ might cause overflow.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>PGTYPES_NUM_OVERFLOW</literal></term>
+ <listitem>
+ <para>
+ An underflow occurred. Since the numeric type can deal with almost
+ arbitrary precision, converting a numeric variable into other types
+ might cause underflow.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>PGTYPES_NUM_DIVIDE_ZERO</literal></term>
+ <listitem>
+ <para>
+ A division by zero has been attempted.
+ </para>
+ </listitem>
+ </varlistentry>
+ <variablelist>
+
+ <varlistentry>
+ <term><literal>PGTYPES_DATE_BAD_DATE</literal></term>
+ <listitem>
+ <para>
+
+ </para>
+ </listitem>
+ </varlistentry>
+ <variablelist>
+
+ <varlistentry>
+ <term><literal>PGTYPES_DATE_ERR_EARGS</literal></term>
+ <listitem>
+ <para>
+
+ </para>
+ </listitem>
+ </varlistentry>
+ <variablelist>
+
+ <varlistentry>
+ <term><literal>PGTYPES_DATE_ERR_ENOSHORTDATE</literal></term>
+ <listitem>
+ <para>
+
+ </para>
+ </listitem>
+ </varlistentry>
+ <variablelist>
+
+ <varlistentry>
+ <term><literal>PGTYPES_INTVL_BAD_INTERVAL</literal></term>
+ <listitem>
+ <para>
+
+ </para>
+ </listitem>
+ </varlistentry>
+ <variablelist>
+
+ <varlistentry>
+ <term><literal>PGTYPES_DATE_ERR_ENOTDMY</literal></term>
+ <listitem>
+ <para>
+
+ </para>
+ </listitem>
+ </varlistentry>
+ <variablelist>
+
+ <varlistentry>
+ <term><literal>PGTYPES_DATE_BAD_DAY</literal></term>
+ <listitem>
+ <para>
+
+ </para>
+ </listitem>
+ </varlistentry>
+ <variablelist>
+
+ <varlistentry>
+ <term><literal>PGTYPES_DATE_BAD_MONTH</literal></term>
+ <listitem>
+ <para>
+
+ </para>
+ </listitem>
+ </varlistentry>
+ <variablelist>
+
+ <varlistentry>
+ <term><literal>PGTYPES_TS_BAD_TIMESTAMP</literal></term>
+ <listitem>
+ <para>
+
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>Special constants of pgtypeslib </title>
+ <para>
+ <variablelist>
+ <varlistentry id="PGTYPESInvalidTimestamp">
+ <term><literal>PGTYPESInvalidTimestamp</literal></term>
+ <listitem>
+ <para>
+ A value of type timestamp representing an invalid time stamp. This is
+ returned by the function <function>PGTYPEStimestamp_from_asc</> on
+ parse error.
+ Note that due to the internal representation of the timestamp datatype,
+ <literal>PGTYPESInvalidTimestamp</literal> is also a valid timestamp at
+ the same time. It is set to <literal>1899-12-31 23:59:59</>. In order
+ to detect errors, make sure that your application does not only test
+ for <literal>PGTYPESInvalidTimestamp</literal> but also for
+ <literal>errno != 0</> after each call to
+ <function>PGTYPEStimestamp_from_asc</>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1 id="ecpg-informix-compat">
+ <title>Informix compatibility mode</title>
+ <para>
+ ecpg can be run in a so-called <firstterm>Informix compatibility mode</>. If
+ this mode is active, it tries to behave as if it were the Informix
+ precompiler for Informix E/SQL. Generally spoken this will allow you to use
+ 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 Informix 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>
+ Informix 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 Informix compatibility
+ mode allow you to operate on those C host program types. Note however that
+ the extend of the compatibility is limited. It does not try to copy Informix
+ behaviour but 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 Informix 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>
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>Additional functions</title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><function>decadd</></term>
+ <listitem>
+ <para>
+ Add two decimal type values.
+<synopsis>
+int decadd(decimal *arg1, decimal *arg2, decimal *sum);
+</synopsis>
+ The function receives a pointer to the first operand of type decimal
+ (<literal>arg1</>), a pointer to the second operand of type decimal
+ (<literal>arg2</>) and a pointer to a value of type decimal that will
+ contain the sum (<literal>sum</>). On success, the function returns 0.
+ ECPG_INFORMIX_NUM_OVERFLOW is returned in case of overflow and
+ ECPG_INFORMIX_NUM_UNDERFLOW in case of underflow. -1 is returned for
+ other failures and errno is set to the respective errno number of the
+ pgtypeslib.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>deccmp</></term>
+ <listitem>
+ <para>
+ Compare two variables of type decimal.
+<synopsis>
+int deccmp(decimal *arg1, decimal *arg2);
+</synopsis>
+ The function receives a pointer to the first decimal value
+ (<literal>arg1</>), a pointer to the second decimal value
+ (<literal>arg2</>) and returns an integer value that indicates which is
+ the bigger value.
+ <itemizedlist>
+ <listitem>
+ <para>
+ 1, if the value that <literal>arg1</> points to is bigger than the
+ value that <literal>var2</> points to
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ -1, if the value that <literal>arg1</> points to is smaller than the
+ value that <literal>arg2</> points to </para>
+ </listitem>
+ <listitem>
+ <para>
+ 0, if the value that <literal>arg1</> points to and the value that
+ <literal>arg2</> points to are equal
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>deccopy</></term>
+ <listitem>
+ <para>
+ Copy a decimal value.
+<synopsis>
+void deccopy(decimal *src, decimal *target);
+</synopsis>
+ The function receives a pointer to the decimal value that should be
+ copied as the first argument (<literal>src</>) and a pointer to the
+ target structure of type decimal (<literal>target</>) as the second
+ argument.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>deccvasc</></term>
+ <listitem>
+ <para>
+ Convert a value from its ASCII representation into a decimal type.
+<synopsis>
+int deccvasc(char *cp, int len, decimal *np);
+</synopsis>
+ The function receives a pointer to string that contains the string
+ representation of the number to be converted (<literal>cp</>) as well
+ as its length <literal>len</>. <literal>np</> is a pointer to the
+ decimal value that saves the result of the operation.
+ </para>
+ <para>
+ Valid formats are for example:
+ <literal>-2</literal>,
+ <literal>.794</literal>,
+ <literal>+3.44</literal>,
+ <literal>592.49E07</literal> or
+ <literal>-32.84e-4</literal>.
+ </para>
+ <para>
+ The function returns 0 on success. If overflow or underflow occurred,
+ <literal>ECPG_INFORMIX_NUM_OVERFLOW</> or
+ <literal>ECPG_INFORMIX_NUM_UNDERFLOW</> is returned. If the ASCII
+ representation could not be parsed,
+ <literal>ECPG_INFORMIX_BAD_NUMERIC</> is returned or
+ <literal>ECPG_INFORMIX_BAD_EXPONENT</> if this problem ocurred while
+ parsing the exponent.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>deccvdbl</></term>
+ <listitem>
+ <para>
+ Convert a value of type double to a value of type decimal.
+<synopsis>
+int deccvdbl(double dbl, decimal *np);
+</synopsis>
+ The function receives the variable of type double that should be
+ converted as its first argument (<literal>dbl</>). As the second
+ argument (<literal>np</>), the function receives a pointer to the
+ decimal variable that should hold the result of the operation.
+ </para>
+ <para>
+ The function returns 0 on success and a negative value if the
+ conversion failed.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>deccvint</></term>
+ <listitem>
+ <para>
+ Convert a value of type int to a value of type decimal.
+<synopsis>
+int deccvint(int in, decimal *np);
+</synopsis>
+ The function receives the variable of type int that should be
+ converted as its first argument (<literal>in</>). As the second
+ argument (<literal>np</>), the function receives a pointer to the
+ decimal variable that should hold the result of the operation.
+ </para>
+ <para>
+ The function returns 0 on success and a negative value if the
+ conversion failed.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>deccvlong</></term>
+ <listitem>
+ <para>
+ Convert a value of type long to a value of type decimal.
+<synopsis>
+int deccvlong(long lng, decimal *np);
+</synopsis>
+ The function receives the variable of type long that should be
+ converted as its first argument (<literal>lng</>). As the second
+ argument (<literal>np</>), the function receives a pointer to the
+ decimal variable that should hold the result of the operation.
+ </para>
+ <para>
+ The function returns 0 on success and a negative value if the
+ conversion failed.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>decdiv</></term>
+ <listitem>
+ <para>
+ Divide two variables of type decimal.
+<synopsis>
+int decdiv(decimal *n1, decimal *n2, decimal *result);
+</synopsis>
+ The function receives pointers to the variables that are the first
+ (<literal>n1</>) and the second (<literal>n2</>) operands and
+ calculates <literal>n1</>/<literal>n2</>. <literal>result</> is a
+ pointer to the variable that should hold the result of the operation.
+ </para>
+ <para>
+ On success, 0 is returned and a negative value if the division fails.
+ If overflow or underflow occurred, the function returns
+ <literal>ECPG_INFORMIX_NUM_OVERFLOW</> or
+ <literal>ECPG_INFORMIX_NUM_UNDERFLOW</> respectively. If an attempt to
+ divide by zero is observed, the function returns
+ <literal>ECPG_INFORMIX_DIVIDE_ZERO</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>decmul</></term>
+ <listitem>
+ <para>
+ Multiply two decimal values.
+<synopsis>
+int decmul(decimal *n1, decimal *n2, decimal *result);
+</synopsis>
+ The function receives pointers to the variables that are the first
+ (<literal>n1</>) and the second (<literal>n2</>) operands and
+ calculates <literal>n1</>*<literal>n2</>. <literal>result</> is a
+ pointer to the variable that should hold the result of the operation.
+ </para>
+ <para>
+ On success, 0 is returned and a negative value if the multiplication
+ fails. If overflow or underflow occurred, the function returns
+ <literal>ECPG_INFORMIX_NUM_OVERFLOW</> or
+ <literal>ECPG_INFORMIX_NUM_UNDERFLOW</> respectively.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>decsub</></term>
+ <listitem>
+ <para>
+ Subtract one decimal value from another.
+<synopsis>
+int decsub(decimal *n1, decimal *n2, decimal *result);
+</synopsis>
+ The function receives pointers to the variables that are the first
+ (<literal>n1</>) and the second (<literal>n2</>) operands and
+ calculates <literal>n1</>-<literal>n2</>. <literal>result</> is a
+ pointer to the variable that should hold the result of the operation.
+ </para>
+ <para>
+ On success, 0 is returned and a negative value if the subtraction
+ fails. If overflow or underflow occurred, the function returns
+ <literal>ECPG_INFORMIX_NUM_OVERFLOW</> or
+ <literal>ECPG_INFORMIX_NUM_UNDERFLOW</> respectively.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>dectoasc</></term>
+ <listitem>
+ <para>
+ Convert a variable of type decimal to its ASCII representation in a C
+ char* string.
+<synopsis>
+int dectoasc(decimal *np, char *cp, int len, int right)
+</synopsis>
+ The function receives a pointer to a variable of type decimal
+ (<literal>np</>) that it converts to its textual representation.
+ <literal>cp</> is the buffer that should hold the result of the
+ operation. The parameter <literal>right</> specifies, how many digits
+ right of the decimal point should be included in the output. The result
+ will be rounded to this number of decimal digits. Setting
+ <literal>right</> to -1 indicates that all available decimal digits
+ should be included in the output. If the length of the output buffer,
+ which is indicated by <literal>len</> is not sufficient to hold the
+ textual representation including the trailing NUL character, only a
+ single <literal>*</> character is stored in the result and -1 is
+ returned.
+ </para>
+ <para>
+ The function returns either -1 if the buffer <literal>cp</> was too
+ small or <literal>ECPG_INFORMIX_OUT_OF_MEMORY</> if memory was
+ exhausted.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>dectodbl</></term>
+ <listitem>
+ <para>
+ Convert a variable of type decimal to a double.
+<synopsis>
+int dectodbl(decimal *np, double *dblp);
+</synopsis>
+ The function receives a pointer to the decimal value to convert
+ (<literal>np</>) and a pointer to the double variable that
+ should hold the result of the operation (<literal>dblp</>).
+ </para>
+ <para>
+ On success, 0 is returned and a negative value if the conversion
+ failed.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>dectoint</></term>
+ <listitem>
+ <para>
+ Convert a variable to type decimal to an integer.
+<synopsis>
+int dectoint(decimal *np, int *ip);
+</synopsis>
+ The function receives a pointer to the decimal value to convert
+ (<literal>np</>) and a pointer to the integer variable that
+ should hold the result of the operation (<literal>ip</>).
+ </para>
+ <para>
+ On success, 0 is returned and a negative value if the conversion
+ failed. If an overflow occurred, <literal>ECPG_INFORMIX_NUM_OVERFLOW</>
+ is returned.
+ </para>
+ <para>
+ Note that the ecpg implementation differs from the Informix
+ implementation. Informix limits an integer to the range from -32767 to
+ 32767, while the limits in the ecpg implementation depend on the
+ architecture (<literal>-INT_MAX .. INT_MAX</>).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>dectolong</></term>
+ <listitem>
+ <para>
+ Convert a variable to type decimal to a long integer.
+<synopsis>
+int dectolong(decimal *np, long *lngp);
+</synopsis>
+ The function receives a pointer to the decimal value to convert
+ (<literal>np</>) and a pointer to the long variable that
+ should hold the result of the operation (<literal>lngp</>).
+ </para>
+ <para>
+ On success, 0 is returned and a negative value if the conversion
+ failed. If an overflow occurred, <literal>ECPG_INFORMIX_NUM_OVERFLOW</>
+ is returned.
+ </para>
+ <para>
+ Note that the ecpg implementation differs from the Informix
+ implementation. Informix limits a long integer to the range from
+ -2,147,483,647 to 2,147,483,647, while the limits in the ecpg
+ implementation depend on the architecture (<literal>-LONG_MAX ..
+ LONG_MAX</>).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>rdatestr</></term>
+ <listitem>
+ <para>
+ Converts a date to a C char* string.
+<synopsis>
+int rdatestr(date d, char *str);
+</synopsis>
+ The function receives two arguments, the first one is the date to
+ convert (<literal>d</> and the second one is a pointer to the target
+ string. The output format is always <literal>yyyy-mm-dd</>, so you need
+ to allocate at least 11 bytes (including the NUL-terminator) for the
+ string.
+ </para>
+ <para>
+ The function returns 0 on success and a negative value in case of
+ error.
+ </para>
+ <para>
+ Note that ecpg's implementation differs from the Informix
+ implementation. In Informix the format can be influenced by setting
+ environment variables. In ecpg however, you cannot change the output
+ format.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>rstrdate</></term>
+ <listitem>
+ <para>
+ Parse the textual representation of a date.
+<synopsis>
+int rstrdate(char *str, date *d);
+</synopsis>
+ The function receives the textual representation of the date to convert
+ (<literal>str</>) and a pointer to a variable of type date
+ (<literal>d</>). This function does not allow you to specify a format
+ mask. It uses the default format mask of Informix which is
+ <literal>mm/dd/yyyy</>. Internally, this function is implemented by
+ means of <function>rdefmtdate</>. Therefore, <function>rstrdate</> is
+ not faster and if you have the choice you should opt for
+ <function>rdefmtdate</> which allows you to specify the format mask
+ explicitly.
+ </para>
+ <para>
+ The function returns the same values as <function>rdefmtdate</>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>rtoday</></term>
+ <listitem>
+ <para>
+ Get the current date.
+<synopsis>
+void rtoday(date *d);
+</synopsis>
+ The function receives a pointer to a date variable (<literal>d</>)
+ that it sets to the current date.
+ </para>
+ <para>
+ Internally this function uses the <xref linkend="PGTYPESdatetoday">
+ function.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>rjulmdy</></term>
+ <listitem>
+ <para>
+ Extract the values for the day, the month and the year from a variable
+ of type date.
+<synopsis>
+int rjulmdy(date d, short mdy[3]);
+</synopsis>
+ The function receives the date <literal>d</> and a pointer to an array
+ of 3 short integer values <literal>mdy</>. The variable name indicates
+ the sequential order: <literal>mdy[0]</> will be set to contain the
+ number of the month, <literal>mdy[1]</> will be set to the value of the
+ day and <literal>mdy[2]</> will contain the year.
+ </para>
+ <para>
+ The function always returns 0 at the moment.
+ </para>
+ <para>
+ Internally the function uses the <xref linkend="PGTYPESdatejulmdy">
+ function.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>rdefmtdate</></term>
+ <listitem>
+ <para>
+ Use a format mask to convert a character string to a value of type
+ date.
+<synopsis>
+int rdefmtdate(date *d, char *fmt, char *str);
+</synopsis>
+ The function receives a pointer to the date value that should hold the
+ result of the operation (<literal>d</>), the format mask to use for
+ parsing the date (<literal>fmt</>) and the C char* string containing
+ the textual representation of the date (<literal>str</>). The textual
+ representation is expected to match the format mask. However you do not
+ need to have a 1:1 mapping of the string to the format mask. The
+ function only analyzes the sequential order and looks for the literals
+ <literal>yy</literal> or <literal>yyyy</literal> that indicate the
+ position of the year, <literal>mm</literal> to indicate the position of
+ the month and <literal>dd</literal> to indicate the position of the
+ day.
+ </para>
+ <para>
+ The function returns the following values:
+ <itemizedlist>
+ <listitem>
+ <para>
+ 0 - The function terminated successfully.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ECPG_INFORMIX_ENOSHORTDATE</> - The date does not contain
+ delimiters between day, month and year. In this case the input
+ string must be exactly 6 or 8 bytes long but isn't.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ECPG_INFORMIX_ENOTDMY</> - The format string did not
+ correctly indicate the sequential order of year, month and day.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ECPG_INFORMIX_BAD_DAY</> - The input string does not
+ contain a valid day.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ECPG_INFORMIX_BAD_MONTH</> - The input string does not
+ contain a valid month.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ECPG_INFORMIX_BAD_YEAR</> - The input string does not
+ contain a valid year.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Internally this function is implemented to use the <xref
+ linkend="PGTYPESdatedefmtasc"> function. See the reference there for a
+ table of example input.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>rfmtdate</></term>
+ <listitem>
+ <para>
+ Convert a variable of type date to its textual representation using a
+ format mask.
+<synopsis>
+int rfmtdate(date d, char *fmt, char *str);
+</synopsis>
+ The function receives the date to convert (<literal>d</>), the format
+ mask (<literal>fmt</>) and the string that will hold the textual
+ representation of the date (<literal>str</>).
+ </para>
+ <para>
+ On success, 0 is returned and a negative value if an error occurred.
+ </para>
+ <para>
+ Internally this function uses the <xref linkend="PGTYPESdatefmtasc">
+ function, see the reference there for examples.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>rmdyjul</></term>
+ <listitem>
+ <para>
+ Create a date value from an array of 3 short integers that specify the
+ day, the month and the year of the date.
+<synopsis>
+int rmdyjul(short mdy[3], date *d);
+</synopsis>
+ The function receives the array of the 3 short integers
+ (<literal>mdy</>) and a pointer to a variable of type date that should
+ hold the result of the operation.
+ </para>
+ <para>
+ Currently the function returns always 0.
+ </para>
+ <para>
+ Internally the function is implemented to use the function <xref
+ linkend="PGTYPESdatemdyjul">.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>rdayofweek</></term>
+ <listitem>
+ <para>
+ Return a number representing the day of the week for a date value.
+<synopsis>
+int rdayofweek(date d);
+</synopsis>
+ The function receives the date variable <literal>d</> as its only
+ argument and returns an integer that indicates the day of the week for
+ this date.
+ <itemizedlist>
+ <listitem>
+ <para>
+ 0 - Sunday
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 1 - Monday
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 2 - Tuesday
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 3 - Wednesday
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 4 - Thursday
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 5 - Friday
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ 6 - Saturday
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Internally the function is implemented to use the function <xref
+ linkend="PGTYPESdatedayofweek">.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>dtcurrent</></term>
+ <listitem>
+ <para>
+ Retrieve the current timestamp.
+<synopsis>
+void dtcurrent(timestamp *ts);
+</synopsis>
+ The function retrieves the current timestamp and saves it into the
+ timestamp variable that <literal>ts</> points to.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>dtcvasc</></term>
+ <listitem>
+ <para>
+ Parses a timestamp from its textual representation in ANSI standard
+ into a timestamp variable.
+<synopsis>
+int dtcvasc(char *str, timestamp *ts);
+</synopsis>
+ The function receives the string to parse (<literal>str</>) and a
+ pointer to the timestamp variable that should hold the result of the
+ operation (<literal>ts</>).
+ </para>
+ <para>
+ The function returns 0 on success and a negative value in case of
+ error.
+ </para>
+ <para>
+ Internally this function uses the <xref
+ linkend="PGTYPEStimestampfromasc"> function. See the reference there
+ for a table with example inputs.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>dtcvfmtasc</></term>
+ <listitem>
+ <para>
+ Parses a timestamp from its textual representation in ANSI standard
+ using a format mask into a timestamp variable.
+<synopsis>
+dtcvfmtasc(char *inbuf, char *fmtstr, timestamp *dtvalue)
+</synopsis>
+ The function receives the string to parse (<literal>inbuf</>), the
+ format mask to use (<literal>fmtstr</>) and a pointer to the timestamp
+ variable that should hold the result of the operation (<literal>ts</>).
+ </para>
+ <para>
+ This functions is implemented by means of the <xref
+ linkend="PGTYPEStimestampdefmtasc">. See the documentation
+ there for a list of format specifiers that can be used.
+ </para>
+ <para>
+ The function returns 0 on success and a negative value in case of
+ error.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>dtsub</></term>
+ <listitem>
+ <para>
+ Subtract one timestamp from another and return a variable of type
+ interval.
+<synopsis>
+int dtsub(timestamp *ts1, timestamp *ts2, interval *iv);
+</synopsis>
+ The function will subtract the timestamp variable that <literal>ts2</>
+ points to from the timestamp variable that <literal>ts1</> points to
+ and will store the result in the interval variable that <literal>iv</>
+ points to.
+ </para>
+ <para>
+ Upon success, the function returns 0 and a negative value if an
+ error occurred.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>dttoasc</></term>
+ <listitem>
+ <para>
+ Convert a timestamp variable to a C char* string.
+<synopsis>
+int dttoasc(timestamp *ts, char *output);
+</synopsis>
+ The function receives a pointer to the timestamp variable to convert
+ (<literal>ts</>) and the string that should hold the result of the
+ operation <literal>output</>). It converts <literal>ts</> to its
+ textual representation in the ANSI SQL standard which is defined to
+ be <literal>YYYY-MM-DD HH:MM:SS</literal>.
+ </para>
+ <para>
+ Upon success, the function returns 0 and a negative value if an
+ error occurred.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>dttofmtasc</></term>
+ <listitem>
+ <para>
+ Convert a timestamp variable to a C char* using a format mask.
+<synopsis>
+int dttofmtasc(timestamp *ts, char *output, int str_len, char *fmtstr);
+</synopsis>
+ The function receives a pointer to the timestamp to convert as its
+ first argument (<literal>ts</>), a pointer to the output buffer
+ (<literal>output</>), the maximal length that has been allocated for
+ the output buffer (<literal>str_len</literal>) and the format mask to
+ use for the conversion (<literal>fmtstr</literal>).
+ </para>
+ <para>
+ Upon success, the function returns 0 and a negative value if an
+ error occurred.
+ </para>
+ <para>
+ Internally this function uses the <xref
+ linkend="PGTYPEStimestampfmtasc"> function. See the reference there for
+ informations on what format mask specifiers can be used.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>intoasc</></term>
+ <listitem>
+ <para>
+ Convert an interval variable to a C char* string.
+<synopsis>
+int intoasc(interval *i, char *str);
+</synopsis>
+ The function receives a pointer to the interval variable to convert
+ (<literal>i</>) and the string that should hold the result of the
+ operation <literal>str</>). It converts <literal>i</> to its
+ textual representation in the ANSI SQL standard which is defined to
+ be <literal>YYYY-MM-DD HH:MM:SS</literal>.
+ </para>
+ <para>
+ Upon success, the function returns 0 and a negative value if an
+ error occurred.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>rfmtlong</></term>
+ <listitem>
+ <para>
+ Convert a long integer value to its textual representation using a
+ format mask.
+<synopsis>
+int rfmtlong(long lng_val, char *fmt, char *outbuf);
+</synopsis>
+ The function receives the long value <literal>lng_val</>, the format
+ mask <literal>fmt</> and a pointer to the output buffer
+ <literal>outbuf</>. It converts the long value according to the format
+ mask to its textual representation.
+ </para>
+ <para>
+ The format mask can be composed of the following format specifying
+ characters:
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>*</literal> (asterisk) - if this position would be blank
+ otherwise, fill it with an asterisk.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>&</literal> (ampersand) - if this position would be
+ blank otherwise, fill it with a zero.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>#</literal> - turn leading zeroes into blanks.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal><</literal> - left-justify the number in the string.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>,</literal> (comma) - group numbers of four or more digits
+ into groups of three digits separated by a comma.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>.</literal> (period) - this character separates the
+ whole-number part of the number from the fractional part.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>-</literal> (minus) - the minus sign appears if the number
+ is a negative value.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>+</literal> (plus) - the plus sign appears if the number is
+ a positive value.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>(</literal> - this replaces the minus sign in front of the
+ negative number. The minus sign will not appear.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>)</literal> - this character replaces the minus and is
+ printed behind the negative value.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>$</literal> - the currency symbol.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>rupshift</></term>
+ <listitem>
+ <para>
+ Convert a string to upper case.
+<synopsis>
+void rupshift(char *str);
+</synopsis>
+ The function receives a pointer to the string and transforms every
+ lower case character to upper case.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>byleng</></term>
+ <listitem>
+ <para>
+ Return the number of characters in a string without counting trailing
+ blanks.
+<synopsis>
+int byleng(char *str, int len);
+</synopsis>
+ The function expects a fixed-length string as its first argument
+ (<literal>str</>) and its length as its second argument
+ (<literal>len</>). It returns the number of significant characters,
+ that is the length of the string without trailing blanks.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>ldchar</></term>
+ <listitem>
+ <para>
+ Copy a fixed-length string into a null-terminated string.
+<synopsis>
+void ldchar(char *src, int len, char *dest);
+</synopsis>
+ The function receives the fixed-length string to copy
+ (<literal>src</>), its length (<literal>len</>) and a pointer to the
+ destination memory (<literal>dest</>). Note that you need to reserve at
+ least <literal>len+1</> bytes for the string that <literal>dest</>
+ points to. The function copies at most <literal>len</> bytes to the new
+ location (less if the source string has trailing blanks) and adds the
+ null-terminator.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>rgetmsg</></term>
+ <listitem>
+ <para>
+<synopsis>
+int rgetmsg(int msgnum, char *s, int maxsize);
+</synopsis>
+ This function exists but is not implemented at the moment!
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>rtypalign</></term>
+ <listitem>
+ <para>
+<synopsis>
+int rtypalign(int offset, int type);
+</synopsis>
+ This function exists but is not implemented at the moment!
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>rtypmsize</></term>
+ <listitem>
+ <para>
+<synopsis>
+int rtypmsize(int type, int len);
+</synopsis>
+ This function exists but is not implemented at the moment!
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>rtypwidth</></term>
+ <listitem>
+ <para>
+<synopsis>
+int rtypwidth(int sqltype, int sqllen);
+</synopsis>
+ This function exists but is not implemented at the moment!
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="rsetnull">
+ <term><function>rsetnull</></term>
+ <listitem>
+ <para>
+ Set a variable to NULL.
+<synopsis>
+int rsetnull(int t, char *ptr);
+</synopsis>
+ The function receives an integer that indicates the type of the
+ variable and a pointer to the variable itself that is casted to a C
+ char* pointer.
+ </para>
+ <para>
+ The following types exist:
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>CCHARTYPE</literal> - For a variable of type char or char*
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>CSHORTTYPE</literal> - For a variable of type short int
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>CINTTYPE</literal> - For a variable of type int
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>CBOOLTYPE</literal> - For a variable of type boolean
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>CFLOATTYPE</literal> - For a variable of type float
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>CLONGTYPE</literal> - For a variable of type long
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>CDOUBLETYPE</literal> - For a variable of type double
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>CDECIMALTYPE</literal> - For a variable of type decimal
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>CDATETYPE</literal> - For a variable of type date
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>CDTIMETYPE</literal> - For a variable of type timestamp
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Here is an example of a call to this function:
+<programlisting>
+$char c[] = "abc ";
+$short s = 17;
+$int i = -74874;
+
+rsetnull(CCHARTYPE, (char *) c);
+rsetnull(CSHORTTYPE, (char *) &s);
+rsetnull(CINTTYPE, (char *) &i);
+</programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><function>risnull</></term>
+ <listitem>
+ <para>
+ Test if a variable is NULL.
+<synopsis>
+int risnull(int t, char *ptr);
+</synopsis>
+ The function receives the type of the variable to test (<literal>t</>)
+ as well a pointer to this variable (<literal>ptr</>). Note that the
+ latter needs to be casted to a char*. See the function <xref
+ linkend="rsetnull"> for a list of possible variable types.
+ </para>
+ <para>
+ Here is an example of how to use this function:
+<programlisting>
+$char c[] = "abc ";
+$short s = 17;
+$int i = -74874;
+
+risnull(CCHARTYPE, (char *) c);
+risnull(CSHORTTYPE, (char *) &s);
+risnull(CINTTYPE, (char *) &i);
+</programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>Additional constants</title>
<para>
- The examples above do not handle null values. In fact, the
- retrieval examples will raise an error if they fetch a null value
- from the database. To be able to pass null values to the database
- or retrieve null values from the database, you need to append a
- second host variable specification to each host variable that
- contains data. This second host variable is called the
- <firstterm>indicator</firstterm> and contains a flag that tells
- whether the datum is null, in which case the value of the real
- host variable is ignored. Here is an example that handles the
- retrieval of null values correctly:
-<programlisting>
-EXEC SQL BEGIN DECLARE SECTION;
-VARCHAR val;
-int val_ind;
-EXEC SQL END DECLARE SECTION:
+ Note that all constants here describe errors and all of them are defined
+ to represent negative values. In the descriptions of the different
+ constants you can also find the value that the constants represent in the
+ current implementation. However you should not rely on this number. You can
+ however rely on the fact all of them are defined to represent negative
+ values.
+ <variablelist>
+ <varlistentry>
+ <term><literal>ECPG_INFORMIX_NUM_OVERFLOW</></term>
+ <listitem>
+ <para>
+ Functions return this value if an overflow occurred in a
+ calculation. Internally it is defined to -1200 (the Informix
+ definition).
+ </para>
+ </listitem>
+ </varlistentry>
- ...
+ <varlistentry>
+ <term><literal>ECPG_INFORMIX_NUM_UNDERFLOW</></term>
+ <listitem>
+ <para>
+ Functions return this value if an underflow occurred in a calculation.
+ Internally it is defined to -1201 (the Informix definition).
+ </para>
+ </listitem>
+ </varlistentry>
-EXEC SQL SELECT b INTO :val :val_ind FROM test1;
-</programlisting>
- The indicator variable <varname>val_ind</varname> will be zero if
- the value was not null, and it will be negative if the value was
- null.
- </para>
+ <varlistentry>
+ <term><literal>ECPG_INFORMIX_DIVIDE_ZERO</></term>
+ <listitem>
+ <para>
+ Functions return this value if an attempt to divide by zero is
+ observed. Internally it is defined to -1202 (the Informix definition).
+ </para>
+ </listitem>
+ </varlistentry>
- <para>
- The indicator has another function: if the indicator value is
- positive, it means that the value is not null, but it was
- truncated when it was stored in the host variable.
- </para>
- </sect2>
- </sect1>
+ <varlistentry>
+ <term><literal>ECPG_INFORMIX_BAD_YEAR</></term>
+ <listitem>
+ <para>
+ Functions return this value if a bad value for a year was found while
+ parsing a date. Internally it is defined to -1204 (the Informix
+ definition).
+ </para>
+ </listitem>
+ </varlistentry>
- <sect1 id="ecpg-dynamic">
- <title>Dynamic SQL</title>
+ <varlistentry>
+ <term><literal>ECPG_INFORMIX_BAD_MONTH</></term>
+ <listitem>
+ <para>
+ Functions return this value if a bad value for a month was found while
+ parsing a date. Internally it is defined to -1205 (the Informix
+ definition).
+ </para>
+ </listitem>
+ </varlistentry>
- <para>
- In many cases, the particular SQL statements that an application
- has to execute are known at the time the application is written.
- In some cases, however, the SQL statements are composed at run time
- or provided by an external source. In these cases you cannot embed
- the SQL statements directly into the C source code, but there is a
- facility that allows you to call arbitrary SQL statements that you
- provide in a string variable.
- </para>
+ <varlistentry>
+ <term><literal>ECPG_INFORMIX_BAD_DAY</></term>
+ <listitem>
+ <para>
+ Functions return this value if a bad value for a day was found while
+ parsing a date. Internally it is defined to -1206 (the Informix
+ definition).
+ </para>
+ </listitem>
+ </varlistentry>
- <para>
- The simplest way to execute an arbitrary SQL statement is to use
- the command <command>EXECUTE IMMEDIATE</command>. For example:
-<programlisting>
-EXEC SQL BEGIN DECLARE SECTION;
-const char *stmt = "CREATE TABLE test1 (...);";
-EXEC SQL END DECLARE SECTION;
+ <varlistentry>
+ <term><literal>ECPG_INFORMIX_ENOSHORTDATE</></term>
+ <listitem>
+ <para>
+ Functions return this value if a parsing routine needs a short date
+ representation but did not get the date string in the right length.
+ Internally it is defined to -1209 (the Informix definition).
+ </para>
+ </listitem>
+ </varlistentry>
-EXEC SQL EXECUTE IMMEDIATE :stmt;
-</programlisting>
- You may not execute statements that retrieve data (e.g.,
- <command>SELECT</command>) this way.
- </para>
+ <varlistentry>
+ <term><literal>ECPG_INFORMIX_DATE_CONVERT</></term>
+ <listitem>
+ <para>
+ Functions return this value if Internally it is defined to -1210 (the
+ Informix definition).
+ </para>
+ </listitem>
+ </varlistentry>
- <para>
- A more powerful way to execute arbitrary SQL statements is to
- prepare them once and execute the prepared statement as often as
- you like. It is also possible to prepare a generalized version of
- a statement and then execute specific versions of it by
- substituting parameters. When preparing the statement, write
- question marks where you want to substitute parameters later. For
- example:
-<programlisting>
-EXEC SQL BEGIN DECLARE SECTION;
-const char *stmt = "INSERT INTO test1 VALUES(?, ?);";
-EXEC SQL END DECLARE SECTION;
+ <varlistentry>
+ <term><literal>ECPG_INFORMIX_OUT_OF_MEMORY</></term>
+ <listitem>
+ <para>
+ Functions return this value if Internally it is defined to -1211 (the
+ Informix definition).
+ </para>
+ </listitem>
+ </varlistentry>
-EXEC SQL PREPARE mystmt FROM :stmt;
- ...
-EXEC SQL EXECUTE mystmt USING 42, 'foobar';
-</programlisting>
- If the statement you are executing returns values, then add an
- <literal>INTO</literal> clause:
-<programlisting>
-EXEC SQL BEGIN DECLARE SECTION;
-const char *stmt = "SELECT a, b, c FROM test1 WHERE a > ?";
-int v1, v2;
-VARCHAR v3;
-EXEC SQL END DECLARE SECTION;
+ <varlistentry>
+ <term><literal>ECPG_INFORMIX_ENOTDMY</></term>
+ <listitem>
+ <para>
+ Functions return this value if a parsing routine was supposed to get a
+ format mask (like <literal>mmddyy</>) but not all fields were listed
+ correctly. Internally it is defined to -1212 (the Informix definition).
+ </para>
+ </listitem>
+ </varlistentry>
-EXEC SQL PREPARE mystmt FROM :stmt;
- ...
-EXEC SQL EXECUTE mystmt INTO v1, v2, v3 USING 37;
-</programlisting>
- An <command>EXECUTE</command> command may have an
- <literal>INTO</literal> clause, a <literal>USING</literal> clause,
- both, or neither.
- </para>
+ <varlistentry>
+ <term><literal>ECPG_INFORMIX_BAD_NUMERIC</></term>
+ <listitem>
+ <para>
+ Functions return this value either if a parsing routine cannot parse
+ the textual representation for a numeric value because it contains
+ errors or if a routine cannot complete a calculation involving numeric
+ variables because at least one of the numeric variables is invalid.
+ Internally it is defined to -1213 (the Informix definition).
+ </para>
+ </listitem>
+ </varlistentry>
- <para>
- When you don't need the prepared statement anymore, you should
- deallocate it:
-<programlisting>
-EXEC SQL DEALLOCATE PREPARE <replaceable>name</replaceable>;
-</programlisting>
- </para>
+ <varlistentry>
+ <term><literal>ECPG_INFORMIX_BAD_EXPONENT</></term>
+ <listitem>
+ <para>
+ Functions return this value if Internally it is defined to -1216 (the
+ Informix definition).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>ECPG_INFORMIX_BAD_DATE</></term>
+ <listitem>
+ <para>
+ Functions return this value if Internally it is defined to -1218 (the
+ Informix definition).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>ECPG_INFORMIX_EXTRA_CHARS</></term>
+ <listitem>
+ <para>
+ Functions return this value if Internally it is defined to -1264 (the
+ Informix definition).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </sect2>
</sect1>
<sect1 id="ecpg-descriptors">
</varlistentry>
<varlistentry>
- <term><literal>BREAK</literal></term>
+ <term><literal>DO BREAK</literal></term>
<listitem>
<para>
Execute the C statement <literal>break</literal>. This should
</sect2>
</sect1>
- <sect1 id="ecpg-include">
- <title>Including Files</title>
+ <sect1 id="ecpg-preproc">
+ <title>Preprocessor directives</title>
- <para>
- To include an external file into your embedded SQL program, use:
+ <sect2>
+ <title>Including files</title>
+
+ <para>
+ To include an external file into your embedded SQL program, use:
<programlisting>
EXEC SQL INCLUDE <replaceable>filename</replaceable>;
</programlisting>
- The embedded SQL preprocessor will look for a file named
- <literal><replaceable>filename</replaceable>.h</literal>,
- preprocess it, and include it in the resulting C output. Thus,
- embedded SQL statements in the included file are handled correctly.
- </para>
+ The embedded SQL preprocessor will look for a file named
+ <literal><replaceable>filename</replaceable>.h</literal>,
+ preprocess it, and include it in the resulting C output. Thus,
+ embedded SQL statements in the included file are handled correctly.
+ </para>
- <para>
- Note that this is <emphasis>not</emphasis> the same as
+ <para>
+ Note that this is <emphasis>not</emphasis> the same as
<programlisting>
#include <<replaceable>filename</replaceable>.h>
</programlisting>
- because this file would not be subject to SQL command preprocessing.
- Naturally, you can continue to use the C
- <literal>#include</literal> directive to include other header
- files.
- </para>
+ because this file would not be subject to SQL command preprocessing.
+ Naturally, you can continue to use the C
+ <literal>#include</literal> directive to include other header
+ files.
+ </para>
+
+ <note>
+ <para>
+ The include file name is case-sensitive, even though the rest of
+ the <literal>EXEC SQL INCLUDE</literal> command follows the normal
+ SQL case-sensitivity rules.
+ </para>
+ </note>
+ </sect2>
+
+ <sect2>
+ <title>The #define and #undef directives</title>
+ <para>
+ Similar to the directive <literal>#define</literal> that is known from C,
+ embedded SQL has a similar concept:
+<programlisting>
+EXEC SQL DEFINE <replaceable>name</>;
+EXEC SQL DEFINE <replaceable>name</> <replaceable>value</>;
+</programlisting>
+ So you can define a name:
+<programlisting>
+EXEC SQL DEFINE HAVE_FEATURE;
+</programlisting>
+ And you can also define constants:
+<programlisting>
+EXEC SQL DEFINE MYNUMBER 12;
+EXEC SQL DEFINE MYSTRING 'abc';
+</programlisting>
+ Use <literal>undef</> to remove a previous definition:
+<programlisting>
+EXEC SQL UNDEF MYNUMBER;
+</programlisting>
+ </para>
- <note>
<para>
- The include file name is case-sensitive, even though the rest of
- the <literal>EXEC SQL INCLUDE</literal> command follows the normal
- SQL case-sensitivity rules.
+ Of course you can continue to use the C versions <literal>#define</literal>
+ and <literal>#undef</literal> in your embedded SQL program. The difference
+ is where your defined values get evaluated. If you use <literal>EXEC SQL
+ DEFINE</> then the ecpg preprocessor evaluates the defines and substitutes
+ the values. For example if you write:
+<programlisting>
+EXEC SQL DEFINE MYNUMBER 12;
+...
+EXEC SQL UPDATE Tbl SET col = MYNUMBER;
+</programlisting>
+ then ecpg will already do the substitution and your C compiler will never
+ see any name or identifier <literal>MYNUMBER</>. Note that you can not use
+ <literal>#define</literal> for a constant that you are going to use in an
+ embedded SQL query because in this case the embedded SQL precompiler is not
+ able to see this declaration.
</para>
- </note>
- </sect1>
+ </sect2>
+
+ <sect2>
+ <title>ifdef, ifndef, else, elif and endif directives</title>
+ <para>
+ You can use the following directives to compile code sections conditionally:
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>EXEC SQL ifdef <replaceable>name</>;</literal></term>
+ <listitem>
+ <para>
+ Checks a <replaceable>name</> and processes subsequent lines if
+ <replaceable>name</> has been created with <literal>EXEC SQL define
+ <replaceable>name</></literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>EXEC SQL ifndef <replaceable>name</>;</literal></term>
+ <listitem>
+ <para>
+ Checks a <replaceable>name</> and processes subsequent lines if
+ <replaceable>name</> has <emphasis>not</emphasis> been created with
+ <literal>EXEC SQL define <replaceable>name</></literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>EXEC SQL else;</literal></term>
+ <listitem>
+ <para>
+ Starts processing an alternative section to a section introduced by
+ either <literal>EXEC SQL ifdef <replaceable>name</></literal> or
+ <literal>EXEC SQL ifndef <replaceable>name</></literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>EXEC SQL elif <replaceable>name</>;</literal></term>
+ <listitem>
+ <para>
+ Checks <replaceable>name</> and starts an alternative section if
+ <replaceable>name</> has been created with <literal>EXEC SQL define
+ <replaceable>name</></literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>EXEC SQL endif;</literal></term>
+ <listitem>
+ <para>
+ Ends an alternative section.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
- <sect1 id="ecpg-process">
+ <para>
+ Example:
+<programlisting>
+ exec sql ifndef TZVAR;
+ exec sql SET TIMEZONE TO 'GMT';
+ exec sql elif TZNAME;
+ exec sql SET TIMEZONE TO TZNAME;
+ exec sql else;
+ exec sql SET TIMEZONE TO TZVAR;
+ exec sql endif;
+</programlisting>
+ </para>
+
+ </sect2>
+ </sect1>
+
+ <sect1 id="ecpg-process">
<title>Processing Embedded SQL Programs</title>
<para>