diff -dcrpN postgresql.orig/doc/src/sgml/ecpg.sgml postgresql/doc/src/sgml/ecpg.sgml
*** postgresql.orig/doc/src/sgml/ecpg.sgml	2012-03-12 09:24:31.699560098 +0100
--- postgresql/doc/src/sgml/ecpg.sgml	2012-03-30 00:06:59.342967143 +0200
*************** EXEC SQL COMMIT;
*** 454,459 ****
--- 454,486 ----
     details.
    </para>
  
+   <para>
+    ECPG may use cursor readahead to improve performance of programs
+    that use single-row FETCH statements. Option <literal>-R number</literal>
+    for ECPG modifies the default for all cursors from <literal>NO READAHEAD</literal>
+    to <literal>READAHEAD number</literal>. Explicit <literal>READAHEAD number</literal> or
+    <literal>NO READAHEAD</literal> turns cursor readahead on (with <literal>number</literal>
+    as the size of the readahead window) or off for the specified cursor,
+    respectively. The window size may be modified by setting the <literal>ECPGFETCHSZ</literal>
+    environment variable to a different value except where NO READAHEAD was explicitly specified.
+   </para>
+ 
+   <para>
+    To execute an UPDATE or DELETE statement bearing the WHERE CURRENT OF
+    clause, ECPG may first execute an implicit MOVE to synchronize the server
+    cursor position with the local cursor position.  This can reduce or
+    eliminate the performance benefit of readahead for affected cursors.
+   </para>
+ 
+   <para>
+    There is also a possibility to return the number of tuples returned by the cursor
+    in sqlca.sqlerrd[2] at <command>OPEN</command>. To turn this on, use the
+    <option>--detect-cursor-resultset-size</option> ECPG command line parameter.
+    This may cause side effects if the cursor query contains calls to volatile
+    functions. See <xref linkend="xfunc-volatility">. Using this feature slows
+    down opening the cursor.
+   </para>
+ 
     <note>
      <para>
       The ECPG <command>DECLARE</command> command does not actually
*************** struct
*** 4874,4879 ****
--- 4901,4911 ----
      processed row, if applicable, and
      <literal>sqlca.sqlerrd[2]</literal> contains the number of
      processed or returned rows, if applicable to the command.
+     The <command>OPEN</command> statement may return the
+     result set size in <literal>sqlca.sqlerrd[2]</literal> if
+     option <literal>--detect-cursor-resultset-size</literal> 
+     is specified on the ECPG command line. This may cause side effects
+     because of traversing the result set. See <xref linkend="xfunc-volatility">.
     </para>
  
     <para>
*************** while (1)
*** 5289,5294 ****
--- 5321,5336 ----
      </varlistentry>
  
      <varlistentry>
+      <term>-231 (<symbol>ECPG_INVALID_CURSOR</symbol>)</term>
+      <listitem>
+       <para>
+        The cursor you are trying to use with readahead has not been opened yet.
+        (SQLSTATE 34000)
+       </para>
+      </listitem>
+     </varlistentry>
+ 
+     <varlistentry>
       <term>-239 (<symbol>ECPG_INFORMIX_DUPLICATE_KEY</symbol>)</term>
       <listitem>
        <para>
*************** EXEC SQL DEALLOCATE DESCRIPTOR mydesc;
*** 6583,6590 ****
  
     <refsynopsisdiv>
  <synopsis>
! DECLARE <replaceable class="PARAMETER">cursor_name</replaceable> [ BINARY ] [ INSENSITIVE ] [ [ NO ] SCROLL ] CURSOR [ { WITH | WITHOUT } HOLD ] FOR <replaceable class="PARAMETER">prepared_name</replaceable>
! DECLARE <replaceable class="PARAMETER">cursor_name</replaceable> [ BINARY ] [ INSENSITIVE ] [ [ NO ] SCROLL ] CURSOR [ { WITH | WITHOUT } HOLD ] FOR <replaceable class="PARAMETER">query</replaceable>
  </synopsis>
     </refsynopsisdiv>
  
--- 6625,6632 ----
  
     <refsynopsisdiv>
  <synopsis>
! DECLARE <replaceable class="PARAMETER">cursor_name</replaceable> [ BINARY ] [ INSENSITIVE ] [ [ NO ] SCROLL ] [ NO READAHEAD | READAHEAD number ] CURSOR [ { WITH | WITHOUT } HOLD ] FOR <replaceable class="PARAMETER">prepared_name</replaceable>
! DECLARE <replaceable class="PARAMETER">cursor_name</replaceable> [ BINARY ] [ INSENSITIVE ] [ [ NO ] SCROLL ] [ NO READAHEAD | READAHEAD number ] CURSOR [ { WITH | WITHOUT } HOLD ] FOR <replaceable class="PARAMETER">query</replaceable>
  </synopsis>
     </refsynopsisdiv>
  
*************** DECLARE <replaceable class="PARAMETER">c
*** 6639,6649 ****
        </listitem>
       </varlistentry>
      </variablelist>
  
      <para>
!      For the meaning of the cursor options,
!      see <xref linkend="sql-declare">.
      </para>
     </refsect1>
  
     <refsect1>
--- 6681,6715 ----
        </listitem>
       </varlistentry>
      </variablelist>
+    </refsect1>
+ 
+    <refsect1>
+     <title>Cursor options</title>
  
      <para>
!      For the meaning of other cursor options, see <xref linkend="sql-declare">.
      </para>
+ 
+     <variablelist>
+      <varlistentry>
+       <term><literal>READAHEAD number</literal></term>
+       <term><literal>NO READAHEAD</literal></term>
+        <listitem>
+         <para>
+          <literal>READAHEAD number</literal> makes the ECPG preprocessor and
+          runtime library use a client-side cursor accounting and data readahead
+          during <command>FETCH</command>. This improves performance for programs
+          that use single-row <command>FETCH</command> statements.
+         </para>
+ 
+         <para>
+          <literal>NO READAHEAD</literal> disables data readahead in case
+          <parameter>-R number</parameter> is used for compiling the file.
+         </para>
+        </listitem>
+      </varlistentry>
+     </variablelist>
+ 
     </refsect1>
  
     <refsect1>
diff -dcrpN postgresql.orig/doc/src/sgml/ref/ecpg-ref.sgml postgresql/doc/src/sgml/ref/ecpg-ref.sgml
*** postgresql.orig/doc/src/sgml/ref/ecpg-ref.sgml	2011-08-07 11:29:16.003256959 +0200
--- postgresql/doc/src/sgml/ref/ecpg-ref.sgml	2012-03-29 11:24:53.961185155 +0200
*************** PostgreSQL documentation
*** 171,176 ****
--- 171,196 ----
      </varlistentry>
  
      <varlistentry>
+      <term><option>-R <replaceable>number</replaceable></option></term>
+      <listitem>
+       <para>
+        Turn on cursor readahead by default using <replaceable>number</replaceable>
+        as readahead window size.
+       </para>
+      </listitem>
+     </varlistentry>
+ 
+     <varlistentry>
+      <term><option>--detect-cursor-resultset-size</option></term>
+      <listitem>
+       <para>
+        Detect the cursor result set size during <command>OPEN</command> and
+        return it in sqlca.sqlerrd[2].
+       </para>
+      </listitem>
+     </varlistentry>
+ 
+     <varlistentry>
       <term><option>-t</option></term>
       <listitem>
        <para>
diff -dcrpN postgresql.orig/src/interfaces/ecpg/ecpglib/connect.c postgresql/src/interfaces/ecpg/ecpglib/connect.c
*** postgresql.orig/src/interfaces/ecpg/ecpglib/connect.c	2012-03-09 09:26:27.593365975 +0100
--- postgresql/src/interfaces/ecpg/ecpglib/connect.c	2012-03-29 11:24:53.962185160 +0200
*************** ECPGconnect(int lineno, int c, const cha
*** 474,479 ****
--- 474,481 ----
  
  	this->cache_head = NULL;
  	this->prep_stmts = NULL;
+ 	this->subxact_desc = NULL;
+ 	this->cursor_desc = NULL;
  
  	if (all_connections == NULL)
  		this->next = NULL;
diff -dcrpN postgresql.orig/src/interfaces/ecpg/ecpglib/cursor.c postgresql/src/interfaces/ecpg/ecpglib/cursor.c
*** postgresql.orig/src/interfaces/ecpg/ecpglib/cursor.c	1970-01-01 01:00:00.000000000 +0100
--- postgresql/src/interfaces/ecpg/ecpglib/cursor.c	2012-03-29 23:20:17.326721907 +0200
***************
*** 0 ****
--- 1,1205 ----
+ /*
+  * FETCH readahead support routines
+  */
+ 
+ #define POSTGRES_ECPG_INTERNAL
+ #include "postgres_fe.h"
+ 
+ #include <stdlib.h>
+ #include <limits.h>
+ 
+ #include "ecpgtype.h"
+ #include "ecpglib.h"
+ #include "ecpgerrno.h"
+ #include "extern.h"
+ 
+ static bool	envvars_read = false;	/* the variables below are already
+ 					   initialized */
+ static int	default_fetch_size = -1;/* use this value instead of the
+ 					   passed-in per-cursor window size.
+ 					   -1 means unset. */
+ 
+ /*
+  * Compare two cursor names.
+  * If both the stored (in a descriptor) and the new cursor name are quoted,
+  * use case-sensitive comparation. Otherwise case-insensitive.
+  * Both pointers must be valid.
+  */
+ static int
+ cursor_strcmp(const char *stored, const char *searched)
+ {
+ 	if (stored[0] == '"' && searched[0] == '"')
+ 		return strcmp(stored, searched);
+ 	else
+ 		return pg_strcasecmp(stored, searched);
+ }
+ 
+ /*
+  * Find the cursor with the given name.
+  * Optionally, return the previous one in the list.
+  */
+ static struct cursor_descriptor *
+ find_cursor(struct connection *con, const char *name,
+ 				struct cursor_descriptor **out_prev)
+ {
+ 	struct cursor_descriptor *desc = con->cursor_desc,
+ 					*prev = NULL;
+ 	bool	found = false;
+ 
+ 	if (!name)
+ 		return NULL;
+ 
+ 	while (desc)
+ 	{
+ 		int ret = cursor_strcmp(desc->name, name);
+ 
+ 		if (ret == 0)
+ 		{
+ 			found = true;
+ 			break;
+ 		}
+ 		/*
+ 		 * The cursor list is ordered alphabetically,
+ 		 * don't search the whole list.
+ 		 */
+ 		if (ret > 0)
+ 			break;
+ 		prev = desc;
+ 		desc = desc->next;
+ 	}
+ 
+ 	if (out_prev)
+ 		*out_prev = prev;
+ 	return (found ? desc : NULL);
+ }
+ 
+ /*
+  * Add a new cursor descriptor, maintain "mostly" alphabetic order.
+  * - case sensitive alphabetic order for quoted cursor names
+  * - case insensitive alphabetic order for non-quoted cursor names
+  */
+ static struct cursor_descriptor *
+ add_cursor(int lineno, struct connection *con,
+ 					const char *name,
+ 					int subxact_level,
+ 					bool with_hold,
+ 					int ra_size)
+ {
+ 	struct cursor_descriptor *desc, *prev;
+ 
+ 	if (!name || name[0] == '\0')
+ 		return NULL;
+ 
+ 	desc = find_cursor(con, name, &prev);
+ 	if (desc)
+ 		return desc;
+ 
+ 	desc = (struct cursor_descriptor *)
+ 			ecpg_alloc(sizeof(struct cursor_descriptor),
+ 								lineno);
+ 	if (!desc)
+ 		return NULL;
+ 
+ 	/* Copy the name */
+ 	desc->name = ecpg_strdup(name, lineno);
+ 	if (!desc->name)
+ 	{
+ 		ecpg_free(desc);
+ 		return NULL;
+ 	}
+ 
+ 	desc->subxact_level = subxact_level;
+ 	desc->with_hold = with_hold;
+ 	desc->res = NULL;
+ 	/*
+ 	 * The readahead windows is allowed to be overridden
+ 	 * (possibly even disabled) by default_fetch_size if it's set.
+ 	 */
+ 	desc->ra_size = (default_fetch_size > 0 ?
+ 						default_fetch_size :
+ 						ra_size);
+ 
+ 	desc->backward = false;
+ 	desc->cache_start_pos = 0;
+ 	desc->atstart = true;
+ 	desc->atend = false;
+ 	desc->pos = 0;
+ 	desc->backend_pos = 0;
+ 
+ 	/* Finally add it to the chain */
+ 	if (prev)
+ 	{
+ 		desc->next = prev->next;
+ 		prev->next = desc;
+ 	}
+ 	else
+ 	{
+ 		desc->next = con->cursor_desc;
+ 		con->cursor_desc = desc;
+ 	}
+ 
+ 	return desc;
+ }
+ 
+ /*
+  * Delete the cursor from the list of descriptors.
+  */
+ static void
+ del_cursor(struct connection *con, const char *name)
+ {
+ 	struct cursor_descriptor *desc, *prev;
+ 
+ 	desc = find_cursor(con, name, &prev);
+ 	if (desc)
+ 	{
+ 		if (prev)
+ 			prev->next = desc->next;
+ 		else
+ 			con->cursor_desc = desc->next;
+ 
+ 		ecpg_free((void *)desc->name);
+ 		PQclear(desc->res);
+ 		ecpg_free(desc);
+ 	}
+ }
+ 
+ /*
+  * Commit or roll back cursors:
+  * - all transactional (non-WITH HOLD) cursors are forgotten at
+  *   the end of the transaction, no matter if COMMIT or ROLLBACK
+  * - at RELEASE SAVEPOINT, the cursors are propagated one
+  *   subtransaction level up.
+  * - at ROLLBACK TO SAVEPOINT, all cursors are forgotten that were
+  *   created in this subtransaction or below that level
+  * - WITH HOLD cursors are kept after the transaction in case of
+  *   toplevel COMMIT. The caller checks for the transaction in error
+  *   and sets the rollback flag accordingly.
+  */
+ void
+ ecpg_commit_cursors(int lineno, struct connection * conn,
+ 						bool rollback, int level)
+ {
+ 	struct cursor_descriptor *desc, *tmp,
+ 					*prev = NULL;
+ 
+ 	desc = conn->cursor_desc;
+ 	while (desc)
+ 	{
+ 		/* Keep already COMMITted WITH HOLD cursors */
+ 		if (desc->with_hold && desc->subxact_level == 0)
+ 			;
+ 		else if (rollback)
+ 		{
+ 			/*
+ 			 * On ROLLBACK [ TO SAVEPOINT ... ] forget about
+ 			 * every cursor DECLAREd under this level.
+ 			 */
+ 			if (desc->subxact_level >= level)
+ 			{
+ 				tmp = desc->next;
+ 				PQclear(desc->res);
+ 				ecpg_free(desc->name);
+ 				ecpg_free(desc);
+ 				desc = tmp;
+ 				if (prev)
+ 					prev->next = tmp;
+ 				else
+ 					conn->cursor_desc = tmp;
+ 				continue;
+ 			}
+ 		}
+ 		else
+ 		{
+ 			/*
+ 			 * If this is a WITH HOLD cursor or we're in a
+ 			 * subtransaction, COMMIT the cursor one level up.
+ 			 */
+ 			if (desc->with_hold || level > 1)
+ 				desc->subxact_level = level - 1;
+ 			/*
+ 			 * Otherwise (not WITH HOLD cursor AND it's the
+ 			 * toplevel transaction) free the cursor.
+ 			 */
+ 			else
+ 			{
+ 				tmp = desc->next;
+ 				PQclear(desc->res);
+ 				ecpg_free(desc->name);
+ 				ecpg_free(desc);
+ 				desc = tmp;
+ 				if (prev)
+ 					prev->next = tmp;
+ 				else
+ 					conn->cursor_desc = tmp;
+ 				continue;
+ 			}
+ 		}
+ 
+ 		prev = desc;
+ 		desc = desc->next;
+ 	}
+ }
+ 
+ /*
+  * Declare the cursor in the backend and create a
+  * minimalistic descriptor to make caching the resultset possible.
+  * This function is called when the ECPG code OPENs the cursor.
+  */
+ bool
+ ECPGopen(const int lineno, const int compat, const int force_indicator,
+ 		const char *connection_name, const bool questionmarks,
+ 		const long ra_size, const bool return_rssz,
+ 		const bool scrollable, const bool with_hold,
+ 		const char *curname, const int st, const char *query, ...)
+ {
+ 	struct connection *con = ecpg_get_connection(connection_name);
+ 	struct sqlca_t *sqlca = ECPGget_sqlca();
+ 	bool		ret;
+ 	int64		n_tuples = -1;
+ 	int		subxact_level;
+ 	va_list		args;
+ 
+ 	/* Process the environment variables only once */
+ 	if (!envvars_read)
+ 	{
+ 		char	   *tmp, *endptr;
+ 		long		fetch_size_env;
+ 
+ 		/*
+ 		 * If ECPGFETCHSZ is set, interpret it.
+ 		 * - return error for invalid numbers
+ 		 * - if ECPGFETCHSZ <= 0, caching is disabled (readahead = 1) 
+ 		 * - otherwise use the actual number
+ 		 * If it's unset, leave its -1 value.
+ 		 */
+ 		tmp = getenv("ECPGFETCHSZ");
+ 		if (tmp)
+ 		{
+ 			fetch_size_env = strtol(tmp, &endptr, 10);
+ 			if (*endptr)
+ 			{
+ 				ecpg_raise(lineno, ECPG_INT_FORMAT, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, tmp);
+ 				return false;
+ 			}
+ 
+ 			/* Readahead disabled */
+ 			if (fetch_size_env <= 0)
+ 				fetch_size_env = 1;
+ 
+ 			default_fetch_size = fetch_size_env;
+ 		}
+ 
+ 		envvars_read = true;
+ 	}
+ 
+ 	if (!query)
+ 	{
+ 		ecpg_raise(lineno, ECPG_EMPTY, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, NULL);
+ 		return false;
+ 	}
+ 
+ 	/*
+ 	 * Execute the DECLARE query in the backend.
+ 	 */
+ 	va_start(args, query);
+ 	ret = ecpg_do(lineno, compat, force_indicator, connection_name, questionmarks,
+ 									st,
+ 									query,
+ 									args);
+ 	va_end(args);
+ 
+ 	if (!ret)
+ 		return false;
+ 
+ 	/*
+ 	 * The cursor is opened successfully.
+ 	 * Now discover the number of tuples in the result set only if:
+ 	 * - the cursor is known scrollable, and
+ 	 * - the user requested to return the number of tuples in
+ 	 *   the result set.
+ 	 * Although this slows down OPEN, for some loads caching
+ 	 * still overweights it.
+ 	 *
+ 	 * One downside is the multiple evaluation of volatile functions
+ 	 * and their possible side effects.
+ 	 */
+ 	if (scrollable && return_rssz)
+ 	{
+ 		PGresult   *res;
+ 		char	   *move_query;
+ 		char	   *endptr = NULL;
+ 
+ 		move_query = ecpg_alloc(20 + strlen(curname), lineno);
+ 		if (move_query == NULL)
+ 			return false;
+ 
+ 		/*
+ 		 * We are at the start of the result set,
+ 		 * MOVE ALL returns the number of tuples in it.
+ 		 */
+ 		sprintf(move_query, "move all in %s", curname);
+ 		res = PQexec(con->connection, move_query);
+ 		if (!ecpg_check_PQresult(res, lineno, con->connection, compat))
+ 		{
+ 			ecpg_free(move_query);
+ 			return false;
+ 		}
+ 		n_tuples = strtoull(PQcmdTuples(res), &endptr, 10);
+ 		PQclear(res);
+ 
+ 		/* Go back to the beginning of the resultset. */
+ 		sprintf(move_query, "move absolute 0 in %s", curname);
+ 		res = PQexec(con->connection, move_query);
+ 		if (!ecpg_check_PQresult(res, lineno, con->connection, compat))
+ 		{
+ 			ecpg_free(move_query);
+ 			return false;
+ 		}
+ 		PQclear(res);
+ 		ecpg_free(move_query);
+ 
+ 		sqlca->sqlerrd[2] = (n_tuples < LONG_MAX ?
+ 							n_tuples : LONG_MAX);
+ 	}
+ 
+ 	/* Finally add the cursor to the connection. */
+ 	if (con->subxact_desc)
+ 		subxact_level = con->subxact_desc->level;
+ 	else
+ 		subxact_level =
+ 			(PQtransactionStatus(con->connection) != PQTRANS_IDLE ?
+ 				1 : 0);
+ 	add_cursor(lineno, con, curname, subxact_level, with_hold, ra_size);
+ 
+ 	return true;
+ }
+ 
+ /*
+  * Compute and canonicalize the amount of cursor movement.
+  */
+ static int64
+ ecpg_canonical_cursor_movement(struct statement *stmt,
+ 				enum ECPG_cursor_direction *direction,
+ 				const char *amount, bool *fetchall)
+ {
+ 	const char *amount1;
+ 	bool	negate = false;
+ 	int64	n_amount;
+ 
+ 	/*
+ 	 * If the amount is passed in a used variable, ecpg_build_params()
+ 	 * converted it to a string for us.
+ 	 */
+ 	if (amount[0] == '$')
+ 		amount1 = stmt->dollarzero[0];
+ 	/*
+ 	 * Otherwise we got a constant string from the grammar.
+ 	 * Handle negative and explicitely positive constants in
+ 	 * FETCH/MOVE ABSOLUTE/RELATIVE const. E.g. '-2' arrives as
+ 	 * '- 2', '+2' arrives as '+ 2' from the grammar.
+ 	 * strtoll() under Linux stops processing at the space.
+ 	 */
+ 	else if (amount[0] == '-' || amount[0] == '+')
+ 	{
+ 		if (amount[0] == '-')
+ 			negate = true;
+ 		amount1 = amount + 1;
+ 		while (*amount1 == ' ')
+ 			amount1++;
+ 	}
+ 	else
+ 		amount1 = amount;
+ 
+ 	/* FETCH/MOVE [ FORWARD | BACKWARD ] ALL */
+ 	if (strcmp(amount1, "all") == 0)
+ 	{
+ 		*fetchall = true;
+ 		n_amount = 0;
+ 	}
+ 	else
+ 	{
+ 		char	   *endptr;
+ 
+ 		n_amount = strtoll(amount1, &endptr, 10);
+ 		if (negate)
+ 			n_amount = -n_amount;
+ 		*fetchall = false;
+ 	}
+ 
+ 	/*
+ 	 * Canonicalize ECPGc_backward but don't lose
+ 	 * FETCH BACKWARD ALL semantics.
+ 	 */
+ 	if ((*fetchall == false) && (*direction == ECPGc_backward))
+ 	{
+ 		n_amount = -n_amount;
+ 		*direction = ECPGc_forward;
+ 	}
+ 
+ 	return n_amount;
+ }
+ 
+ /*
+  * Save network turnaround of MOVE statements as much as possible.
+  * Compute the cursor position here for the application instead
+  * and send a MOVE ABSOLUTE to the server before the first FETCH
+  * in ecpg_cursor_execute(). The position may not be correct in
+  * all cases as we don't know the size of the result set.
+  */
+ static bool
+ ecpg_cursor_move(int lineno, struct cursor_descriptor *cur,
+ 					enum ECPG_cursor_direction direction,
+ 					int64 n_amount, bool fetchall)
+ {
+ 	struct sqlca_t		   *sqlca = ECPGget_sqlca();
+ 	int64_t	old_pos;
+ 	long	return_pos;
+ 	bool	ret = true;
+ 
+ 	switch (direction)
+ 	{
+ 	case ECPGc_absolute:
+ 		/*
+ 		 * Store the position as-is, even negative positions.
+ 		 * The caching can be fooled and may perform worse if
+ 		 * the application constantly switches between positive
+ 		 * and negative FETCH/MOVE ABSOLUTE N.
+ 		 */
+ 		cur->pos = n_amount;
+ 
+ 		/*
+ 		 * Cheat slightly: we only know that we are at the beginning of the
+ 		 * cursor. At this point, we may not know that we are at the end of
+ 		 * the cursor, so return 1 in sqlerrd[2] if we got a MOVE statement.
+ 		 * cur->atend and the sqlerrd[2] = 0 will be set by FETCH at the end
+ 		 * of the cursor.
+ 		 */
+ 		cur->atstart = (n_amount == 0);
+ 		cur->atend = false;
+ 		return_pos = (n_amount == 0 ? 0 : 1);
+ 
+ 		break;
+ 
+ 	/*
+ 	 * MOVE FORWARD and MOVE RELATIVE are almost synonyms.
+ 	 * The difference is in returning the number of rows.
+ 	 */
+ 	case ECPGc_forward:
+ 	case ECPGc_relative:
+ 		old_pos = cur->pos;
+ 		cur->pos += n_amount;
+ 		return_pos = (direction == ECPGc_relative ?  1 : n_amount);
+ 
+ 		if (fetchall)
+ 		{
+ 			/* FETCH/MOVE FORWARD ALL case */
+ 			cur->pos = 0;
+ 			cur->atstart = false;
+ 			cur->atend = true;
+ 			return_pos = (old_pos < 0 ? -old_pos - 1 : 0);
+ 		}
+ 		else if (old_pos < 0 && cur->pos >= 0)
+ 		{
+ 			/*
+ 			 * The application used negative absolute positions
+ 			 * and we reached the end.
+ 			 */
+ 			cur->pos = 0;
+ 			cur->atstart = false;
+ 			cur->atend = true;
+ 			return_pos = (direction == ECPGc_relative ?  1 : -old_pos - 1);
+ 		}
+ 		else if (old_pos >= 0 && cur->pos <= 0)
+ 		{
+ 			/*
+ 			 * The application used positive absolute positions
+ 			 * and we reached the start.
+ 			 */
+ 			cur->pos = 0;
+ 			cur->atstart = true;
+ 			cur->atend = false;
+ 			return_pos = (direction == ECPGc_relative ?  1 : old_pos - 1);
+ 		}
+ 		else
+ 		{
+ 			/*
+ 			 * We can't possibly know the current position at this point,
+ 			 * just guesstimate.
+ 			 */
+ 			return_pos = (direction == ECPGc_relative ?  1 : n_amount);
+ 			cur->atstart = cur->atend = false;
+ 		}
+ 		break;
+ 
+ 	/*
+ 	 * After canonicalization, ECPGc_backward shows up only
+ 	 * when FETCH/MOVE BACKWARD ALL
+ 	 */
+ 	case ECPGc_backward:
+ 		cur->atstart = true;
+ 		cur->atend = false;
+ 		/*
+ 		 * We can only know the correct amount if the application
+ 		 * is using positive positions.
+ 		 */
+ 		return_pos = (cur->pos < 0 ? 0 : cur->pos);
+ 		cur->pos = 0;
+ 		break;
+ 
+ 	default:
+ 		ecpg_raise(lineno, ECPG_INVALID_CURSOR,
+ 					ECPG_SQLSTATE_ECPG_INTERNAL_ERROR,
+ 					NULL);
+ 		return_pos = 0;
+ 		ret = false;
+ 	}
+ 
+ 	sqlca->sqlerrd[2] = (ret ? return_pos : 0);
+ 
+ 	ecpg_log("ecpg_cursor_move on line %d backward %d atstart %d atend %d pos %ld\n", lineno, cur->backward, cur->atstart, cur->atend, cur->pos);
+ 
+ 	return ret;
+ }
+ 
+ /*
+  * recheck_cursor_position
+  *	Check whether the application-side cursor position is in
+  *	the cache and return this fact. Adjust atstart/atend markers.
+  */
+ static bool
+ recheck_cursor_position(struct statement * stmt,
+ 					struct cursor_descriptor *cur,
+ 					bool forward, bool *overflow)
+ {
+ 	int	cache_tuples;
+ 
+ 	ecpg_log("recheck_cursor_position on line %d: "
+ 			"backward %d atstart %d atend %d pos %ld\n",
+ 						stmt->lineno, cur->backward,
+ 						cur->atstart, cur->atend,
+ 						cur->pos);
+ 
+ 	/* There is no cache yet. */
+ 	if (cur->res == NULL)
+ 	{
+ 		*overflow = false;
+ 		return false;
+ 	}
+ 
+ 	cache_tuples = PQntuples(cur->res);
+ 
+ 	/* The application is using negative cursor positions */
+ 	if (cur->backward)
+ 	{
+ 		/* We're in the cache, keep it. */
+ 		if ((cur->pos <= cur->cache_start_pos) &&
+ 			(cur->pos > cur->cache_start_pos - cache_tuples))
+ 		{
+ 			ecpg_log("recheck_cursor_position on line %d: "
+ 					"clearing atstart and atend (no FETCH)\n",
+ 								stmt->lineno);
+ 			cur->atstart = false;
+ 			cur->atend = false;
+ 			*overflow = false;
+ 			stmt->results = cur->res;
+ 			return true;
+ 		}
+ 
+ 		/*
+ 		 * We just reached end of cursor while going forward.
+ 		 * Keep the cache.
+ 		 */
+ 		if (forward && cur->pos >= 0)
+ 		{
+ 			ecpg_log("recheck_cursor_position on line %d: "
+ 					"setting atend (no FETCH)\n",
+ 								stmt->lineno);
+ 			cur->atstart = false;
+ 			cur->atend = true;
+ 			*overflow = true;
+ 			/* Set the cursor position for safety. */
+ 			cur->pos = 0;
+ 			stmt->results = cur->res;
+ 			return false;
+ 		}
+ 		/*
+ 		 * The cache has less tuples than readahead size and the
+ 		 * position is before that: we reached start of cursor.
+ 		 * Keep the cache.
+ 		 */
+ 		if ((cache_tuples < cur->ra_size) &&
+ 			(cur->pos <= cur->cache_start_pos - cache_tuples))
+ 		{
+ 			ecpg_log("recheck_cursor_position on line %d: "
+ 					"setting atstart to true (no FETCH)\n",
+ 								stmt->lineno);
+ 			cur->atstart = true;
+ 			*overflow = true;
+ 			/* Set the cursor position in negative terms. */
+ 			cur->pos = cur->cache_start_pos - cache_tuples;
+ 			stmt->results = cur->res;
+ 			return false;
+ 		}
+ 	}
+ 	/* The application is using positive cursor positions. */
+ 	else
+ 	{
+ 		/* We're in the cache, keep it. */
+ 		if ((cur->pos >= cur->cache_start_pos) &&
+ 			(cur->pos < cur->cache_start_pos + cache_tuples))
+ 		{
+ 			ecpg_log("recheck_cursor_position on line %d: "
+ 					"clearing atstart and atend (no FETCH)\n",
+ 								stmt->lineno);
+ 			cur->atstart = false;
+ 			cur->atend = false;
+ 			*overflow = false;
+ 			stmt->results = cur->res;
+ 			return true;
+ 		}
+ 
+ 		/*
+ 		 * We just reached start of cursor while going backward.
+ 		 * Keep the cache.
+ 		 */
+ 		if (!forward && cur->pos <= 0)
+ 		{
+ 			ecpg_log("recheck_cursor_position on line %d: "
+ 					"setting atstart (no FETCH)\n",
+ 								stmt->lineno);
+ 			cur->atstart = true;
+ 			*overflow = true;
+ 			/* Set the cursor position for safety. */
+ 			cur->pos = 0;
+ 			stmt->results = cur->res;
+ 			return false;
+ 		}
+ 
+ 		/*
+ 		 * The cache has less tuples than readahead size and the
+ 		 * position is after that: we reached end of cursor.
+ 		 * Keep the cache.
+ 		 */
+ 		if ((cache_tuples < cur->ra_size) &&
+ 			(cur->pos >= cur->cache_start_pos + cache_tuples))
+ 		{
+ 			ecpg_log("recheck_cursor_position on line %d: "
+ 					"setting atend to true (no FETCH)\n",
+ 								stmt->lineno);
+ 			cur->atend = true;
+ 			*overflow = true;
+ 			/* Set the cursor position in positive terms. */
+ 			cur->pos = cur->cache_start_pos - cache_tuples;
+ 			stmt->results = cur->res;
+ 			return false;
+ 		}
+ 	}
+ 
+ 	/*
+ 	 * Surely not inside the cache and we don't know
+ 	 * where we are correctly. ecpg_cursor_execute() will recheck
+ 	 * after the FETCH.
+ 	 */
+ 	*overflow = false;
+ 	return false;
+ }
+ 
+ /*
+  * ecpg_cursor_execute
+  * 	Execute the next FETCH statement if needed.
+  */
+ static bool
+ ecpg_cursor_execute(struct statement * stmt, struct cursor_descriptor *cur, bool forward)
+ {
+ 	char	   *query;
+ 	int64		start_pos;
+ 	bool		inside_cache, overflow;
+ 
+ 	inside_cache = recheck_cursor_position(stmt, cur, forward, &overflow);
+ 	if (inside_cache || overflow)
+ 		return true;
+ 
+ 	/*
+ 	 * Compute the tuple position before the resultset. E.g.:
+ 	 * MOVE ABSOLUTE 0 + FETCH NEXT <ra_size> will result
+ 	 * in a record set having tuples 1 ... ra_size. Similarly,
+ 	 * MOVE ALL and FETCH BACKWARD <ra_size> will result in
+ 	 * a record set with -1 ... -ra_size, in backward order.
+ 	 */
+ 	if (cur->pos > 0)
+ 		start_pos = (cur->pos - 1) / cur->ra_size;
+ 	else if (cur->pos < 0)
+ 		start_pos = (cur->pos + 1) / cur->ra_size;
+ 	else
+ 		start_pos = 0;
+ 	start_pos *= cur->ra_size;
+ 
+ 	ecpg_log("ecpg_cursor_execute on line %d: start_pos %ld cur->backend_pos %ld\n",
+ 						stmt->lineno, start_pos,
+ 						cur->backend_pos);
+ 
+ 	query = ecpg_alloc(strlen(cur->name) + 64, stmt->lineno);
+ 
+ 	/* Don't MOVE the cursor if no need to. */
+ 	if ((cur->backward != (cur->pos < 0)) ||
+ 		(start_pos != cur->backend_pos))
+ 	{
+ 		/* The cursor is walked via positive absolute positions. */
+ 		if (cur->pos >= 0)
+ 			sprintf(query, "move absolute %lld in %s",
+ 					(long long)start_pos, cur->name);
+ 		else
+ 		{
+ 			if (start_pos == 0)
+ 				sprintf(query, "move all in %s", cur->name);
+ 			else /* start_pos can only be negative */
+ 				sprintf(query, "move absolute %lld in %s",
+ 					(long long)start_pos, cur->name);
+ 		}
+ 
+ 		ecpg_log("ecpg_cursor_execute on line %d: "
+ 					"query: %s; on connection %s\n",
+ 						stmt->lineno, query,
+ 						stmt->connection->name);
+ 
+ 		stmt->results = PQexec(stmt->connection->connection, query);
+ 
+ 		if (!ecpg_check_PQresult(stmt->results, stmt->lineno,
+ 				stmt->connection->connection, stmt->compat))
+ 		{
+ 			ecpg_free(query);
+ 			return false;
+ 		}
+ 
+ 		PQclear(stmt->results);
+ 	}
+ 
+ 	sprintf(query, "fetch %s %lld from %s",
+ 					(cur->pos < 0 ? "backward" :
+ 								"forward"),
+ 					(long long)cur->ra_size, cur->name);
+ 
+ 	if (cur->res)
+ 		PQclear(cur->res);
+ 
+ 	ecpg_log("ecpg_cursor_execute on line %d: query: %s;"
+ 			" with %d parameter(s) on connection %s\n",
+ 						stmt->lineno, query,
+ 						stmt->nparams,
+ 						stmt->connection->name);
+ 
+ 	if (stmt->nparams == 0)
+ 	{
+ 		cur->res = PQexec(stmt->connection->connection, query);
+ 		ecpg_log("ecpg_cursor_execute on line %d: using PQexec\n", stmt->lineno);
+ 	}
+ 	else
+ 	{
+ 		/* shouldn't happen */
+ 		cur->res = PQexecParams(stmt->connection->connection,
+ 								query,
+ 								stmt->nparams,
+ 								NULL,
+ 								(const char * const*)stmt->param_values,
+ 								NULL, NULL, 0);
+ 		ecpg_log("ecpg_cursor_execute on line %d: using PQexecParams\n", stmt->lineno);
+ 	}
+ 
+ 	ecpg_free(query);
+ 
+ 	if (!ecpg_check_PQresult(cur->res, stmt->lineno, stmt->connection->connection, stmt->compat))
+ 	{
+ 		stmt->results = cur->res = NULL;
+ 		return false;
+ 	}
+ 
+ 	cur->backward = (cur->pos < 0);
+ 
+ 	/* The tuple position in the cursor is 1 based. */
+ 	cur->cache_start_pos = start_pos + (cur->backward ? -1 :  1);
+ 
+ 	inside_cache = recheck_cursor_position(stmt, cur, forward, &overflow);
+ 	if (inside_cache)
+ 	{
+ 		if (cur->backward)
+ 			cur->backend_pos = start_pos - PQntuples(cur->res);
+ 		else
+ 			cur->backend_pos = start_pos + PQntuples(cur->res);
+ 	}
+ 
+ 	return true;
+ }
+ 
+ /*
+  * ECPGfetch
+  *	Execute a FETCH or MOVE statement for the application.
+  *
+  *	This function maintains the internal cursor descriptor and
+  *	possibly returns data from the previously fetched result set
+  *	which is used as local cache. This function also tries to
+  *	save on network round trip further by reducing the amount of
+  *	MOVE statements to a single one before a FETCH.
+  *
+  *	This function also modifies the cursor behaviour in a way that
+  *	non-scrollable cursors can still "fetch backward" from the cache
+  *	contents. The application will get an error from the backend
+  *	as soon the the request spills out of the cache.
+  *
+  *	Also, "FETCH ALL" is broken into chunks of readahead size.
+  *	This prevents duplication of memory needed for big result sets.
+  */
+ bool
+ ECPGfetch(const int lineno, const int compat, const int force_indicator,
+ 		const char *connection_name, const bool questionmarks,
+ 		const char *curname, enum ECPG_cursor_direction direction,
+ 		const char *amount, const int st, const char *query, ...)
+ {
+ 	struct cursor_descriptor *cur;
+ 	struct statement *stmt;
+ 	va_list			args;
+ 	bool			move, fetchall = false, ret;
+ 	int			step;
+ 	int64			n_amount, count, start_idx;
+ 	struct sqlca_t		   *sqlca = ECPGget_sqlca();
+ 
+ 	if (!query)
+ 	{
+ 		ecpg_raise(lineno, ECPG_EMPTY,
+ 				ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, NULL);
+ 		return false;
+ 	}
+ 
+ 	cur = find_cursor(ecpg_get_connection(connection_name),
+ 							curname, NULL);
+ 	if (!cur)
+ 	{
+ 		ecpg_raise(lineno, ECPG_INVALID_CURSOR,
+ 					ECPG_SQLSTATE_INVALID_CURSOR_NAME,
+ 					curname ?
+ 						curname :
+ 						ecpg_gettext("<empty>"));
+ 		return false;
+ 	}
+ 
+ 	move = (pg_strncasecmp(query, "move ", 5) == 0);
+ 
+ 	va_start(args, query);
+ 
+ 	if (!ecpg_do_prologue(lineno, compat, force_indicator,
+ 						connection_name,
+ 						questionmarks,
+ 						(enum ECPG_statement_type) st,
+ 						query, args, &stmt))
+ 	{
+ 		va_end(args);
+ 		return false;
+ 	}
+ 
+ 	if (!ecpg_build_params(stmt))
+ 	{
+ 		ecpg_do_epilogue(stmt);
+ 		va_end(args);
+ 		return false;
+ 	}
+ 
+ 	if (!ecpg_autostart_transaction(stmt))
+ 	{
+ 		ecpg_do_epilogue(stmt);
+ 		va_end(args);
+ 		return false;
+ 	}
+ 
+ 	ecpg_log("ECPGfetch on line %d: before ecpg_canonical_cursor_movement "
+ 			"amount %s direction %d query: %s\n",
+ 			lineno, amount, direction, query);
+ 
+ 	n_amount = ecpg_canonical_cursor_movement(stmt, &direction,
+ 							amount, &fetchall);
+ 	ecpg_log("ECPGfetch on line %d: ecpg_canonical_cursor_movement "
+ 			"n_amount %lld direction %d fetchall %d query: %s\n",
+ 			lineno, (long long)n_amount, direction, fetchall, query);
+ 
+ 	if (move)
+ 	{
+ 		ret = ecpg_cursor_move(lineno, cur, direction, n_amount, fetchall);
+ 
+ 		ecpg_free_params(stmt, true);
+ 		ecpg_do_epilogue(stmt);
+ 		va_end(args);
+ 		return ret;
+ 	}
+ 
+ 	switch (direction)
+ 	{
+ 	case ECPGc_absolute:
+ 	case ECPGc_relative:
+ relative:
+ 		ecpg_log("ECPGfetch on line %d: ECPGc_absolute/ECPGc_relative before ecpg_cursor_move\n", lineno);
+ 		if (!ecpg_cursor_move(lineno, cur, direction, n_amount, fetchall))
+ 		{
+ 			ecpg_free_params(stmt, true);
+ 			ecpg_do_epilogue(stmt);
+ 			va_end(args);
+ 			return false;
+ 		}
+ 
+ 		if (!ecpg_cursor_execute(stmt, cur, (n_amount >= 0)))
+ 		{
+ 			ecpg_free_params(stmt, true);
+ 			ecpg_do_epilogue(stmt);
+ 			va_end(args);
+ 			return false;
+ 		}
+ 
+ 		if (cur->atstart || cur->atend)
+ 		{
+ 			ecpg_free_params(stmt, true);
+ 			ecpg_do_epilogue(stmt);
+ 			va_end(args);
+ 			ecpg_raise(lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL);
+ 			return false;
+ 		}
+ 
+ 		if (cur->backward)
+ 			start_idx = cur->cache_start_pos - cur->pos;
+ 		else
+ 			start_idx = cur->pos - cur->cache_start_pos;
+ 
+ 		if (!ecpg_process_output(stmt, start_idx, start_idx + 1, 0, true, false))
+ 		{
+ 			ecpg_free_params(stmt, true);
+ 			ecpg_do_epilogue(stmt);
+ 			va_end(args);
+ 			return false;
+ 		}
+ 		sqlca->sqlerrd[2] = (cur->atstart || cur->atend ? 0 : 1);
+ 		break;
+ 
+ 	case ECPGc_backward:
+ 		/*
+ 		 * After canonicalization, this only occurs for
+ 		 * FETCH BACKWARD ALL. Fall through.
+ 		 */
+ 
+ 	case ECPGc_forward:
+ 		/* FETCH FORWARD/BACKWARD 0 is equivalent with FORWARD RELATIVE 0 */
+ 		if (!fetchall && n_amount == 0)
+ 			goto relative;
+ 
+ 		step = (((n_amount < 0) || (direction == ECPGc_backward)) ? -1 : 1);
+ 		ecpg_log("ECPGfetch on line %d: ECPGc_forward/ECPGc_backward, step %d\n", lineno, step);
+ 		if (n_amount < 0)
+ 			n_amount = -n_amount;
+ 
+ 		for (count = 0; (!fetchall && count < n_amount) || fetchall; count++)
+ 		{
+ 			cur->pos += step;
+ 
+ 			if (!ecpg_cursor_execute(stmt, cur, (step > 0)))
+ 			{
+ 				ecpg_free_params(stmt, true);
+ 				ecpg_do_epilogue(stmt);
+ 				va_end(args);
+ 				return false;
+ 			}
+ 
+ 			if (cur->atstart || cur->atend)
+ 				break;
+ 
+ 			if (cur->backward)
+ 				start_idx = cur->cache_start_pos - cur->pos;
+ 			else
+ 				start_idx = cur->pos - cur->cache_start_pos;
+ 
+ 			if (!ecpg_process_output(stmt, start_idx,
+ 							start_idx + 1,
+ 							count, true,
+ 							(count > 0)))
+ 			{
+ 				ecpg_free_params(stmt, true);
+ 				ecpg_do_epilogue(stmt);
+ 				va_end(args);
+ 				return false;
+ 			}
+ 		}
+ 
+ 		sqlca->sqlerrd[2] = count;
+ 
+ 		if (count == 0)
+ 		{
+ 			ecpg_free_params(stmt, true);
+ 			ecpg_do_epilogue(stmt);
+ 			va_end(args);
+ 			ecpg_raise(lineno, ECPG_NOT_FOUND,
+ 						ECPG_SQLSTATE_NO_DATA, NULL);
+ 			return false;
+ 		}
+ 
+ 		break;
+ 
+ 	default:
+ 		ecpg_raise(lineno, ECPG_INVALID_CURSOR,
+ 					ECPG_SQLSTATE_ECPG_INTERNAL_ERROR,
+ 					NULL);
+ 		break;
+ 	}
+ 
+ 	ecpg_free_params(stmt, true);
+ 	ecpg_do_epilogue(stmt);
+ 	va_end(args);
+ 
+ 	return true;
+ }
+ 
+ /*
+  * ECPGcursor_dml
+  *	Called for DELETE / UPDATE ... WHERE CURRENT OF cursorname
+  */
+ bool
+ ECPGcursor_dml(const int lineno, const int compat, const int force_indicator,
+ 		const char *connection_name, const bool questionmarks,
+ 		const char *curname, const int st, const char *query, ...)
+ {
+ 	struct statement *stmt;
+ 	struct connection  *con;
+ 	struct cursor_descriptor *cur;
+ 	va_list		args;
+ 	PGresult	*res;
+ 	char	   *move_query;
+ 
+ 	if (!query)
+ 	{
+ 		ecpg_raise(lineno, ECPG_EMPTY,
+ 					ECPG_SQLSTATE_ECPG_INTERNAL_ERROR,
+ 					NULL);
+ 		return false;
+ 	}
+ 
+ 	con = ecpg_get_connection(connection_name);
+ 
+ 	cur = find_cursor(con, curname, NULL);
+ 	if (!cur)
+ 	{
+ 		ecpg_raise(lineno, ECPG_INVALID_CURSOR,
+ 					ECPG_SQLSTATE_INVALID_CURSOR_NAME,
+ 					(connection_name) ?
+ 						connection_name :
+ 						ecpg_gettext("<empty>"));
+ 		return false;
+ 	}
+ 
+ 	va_start(args, query);
+ 
+ 	if (!ecpg_do_prologue(lineno, compat, force_indicator,
+ 					connection_name, questionmarks,
+ 					(enum ECPG_statement_type) st,
+ 					query, args, &stmt))
+ 	{
+ 		va_end(args);
+ 		return false;
+ 	}
+ 
+ 	if (!ecpg_build_params(stmt))
+ 	{
+ 		ecpg_do_epilogue(stmt);
+ 		va_end(args);
+ 		return false;
+ 	}
+ 
+ 	if (!ecpg_autostart_transaction(stmt))
+ 	{
+ 		ecpg_do_epilogue(stmt);
+ 		va_end(args);
+ 		return false;
+ 	}
+ 
+ 	/*
+ 	 * Move the cursor in the backend if we are doing
+ 	 * client-side caching.
+ 	 */
+ 	if (cur->ra_size > 1 && cur->pos != cur->backend_pos)
+ 	{
+ 		move_query = ecpg_alloc(strlen(curname) + 64, lineno);
+ 		if (move_query == NULL)
+ 		{
+ 			ecpg_do_epilogue(stmt);
+ 			va_end(args);
+ 			return false;
+ 		}
+ 
+ 		if (cur->atstart)
+ 			sprintf(move_query, "move absolute 0 in %s", curname);
+ 		else if (cur->atend)
+ 			sprintf(move_query, "move all in %s", curname);
+ 		else
+ 			sprintf(move_query, "move absolute %lld in %s", (long long)cur->pos, curname);
+ 
+ 		res = PQexec(con->connection, move_query);
+ 		if (!ecpg_check_PQresult(res, lineno, con->connection, compat))
+ 		{
+ 			ecpg_free(move_query);
+ 			ecpg_do_epilogue(stmt);
+ 			va_end(args);
+ 			return false;
+ 		}
+ 		PQclear(res);
+ 		ecpg_free(move_query);
+ 
+ 		cur->backend_pos = cur->pos;
+ 	}
+ 
+ 	if (!ecpg_execute(stmt))
+ 	{
+ 		ecpg_do_epilogue(stmt);
+ 		va_end(args);
+ 		return false;
+ 	}
+ 
+ 	if (!ecpg_process_output(stmt, 0, PQntuples(stmt->results),
+ 					0, false, false))
+ 	{
+ 		ecpg_do_epilogue(stmt);
+ 		va_end(args);
+ 		return false;
+ 	}
+ 
+ 	ecpg_do_epilogue(stmt);
+ 	va_end(args);
+ 	return true;
+ }
+ 
+ /*
+  * ECPGclose
+  *	Close and free a cursor.
+  */
+ bool
+ ECPGclose(const int lineno, const int compat, const int force_indicator,
+ 		const char *connection_name, const bool questionmarks,
+ 		const char *curname, const int st, const char *query, ...)
+ {
+ 	struct connection  *con;
+ 	va_list			args;
+ 	bool			ret;
+ 
+ 	con = ecpg_get_connection(connection_name);
+ 
+ 	if (!find_cursor(con, curname, NULL))
+ 	{
+ 		ecpg_raise(lineno, ECPG_INVALID_CURSOR,
+ 					ECPG_SQLSTATE_INVALID_CURSOR_NAME,
+ 					(connection_name) ?
+ 						connection_name :
+ 						ecpg_gettext("<empty>"));
+ 		return false;
+ 	}
+ 
+ 	va_start(args, query);
+ 	ret = ecpg_do(lineno, compat, force_indicator, connection_name,
+ 							questionmarks,
+ 							st, query, args);
+ 	va_end(args);
+ 
+ 	del_cursor(con, curname);
+ 
+ 	return ret;
+ }
diff -dcrpN postgresql.orig/src/interfaces/ecpg/ecpglib/data.c postgresql/src/interfaces/ecpg/ecpglib/data.c
*** postgresql.orig/src/interfaces/ecpg/ecpglib/data.c	2011-12-28 13:34:48.504381691 +0100
--- postgresql/src/interfaces/ecpg/ecpglib/data.c	2012-03-29 11:24:53.966185182 +0200
*************** check_special_value(char *ptr, double *r
*** 119,126 ****
  	return false;
  }
  
  bool
! ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
  			  enum ECPGttype type, enum ECPGttype ind_type,
  			  char *var, char *ind, long varcharsize, long offset,
  			  long ind_offset, enum ARRAY_TYPE isarray, enum COMPAT_MODE compat, bool force_indicator)
--- 119,151 ----
  	return false;
  }
  
+ /*
+  * ecpg_get_data
+  *	Store one field data from PQgetvalue(results, act_tuple, act_field)
+  *	into a target variable. If the field is NULL, store the indication or
+  *	emit an error about the fact that there is no NULL indicator given.
+  * Parameters:
+  *	results:	result set
+  *	var_index:	optional array index in the target variable
+  *	lineno:		line number in the ECPG source file for debugging
+  *	type:		type of target variable
+  *	ind_type:	type of NULL indicator variable
+  *	var:		target variable
+  *	ind:		NULL indicator variable
+  *	varcharsize:	size of the variable if it's varchar
+  *	offset:		size of the target variable
+  *			(used for indexing in an array)
+  *	ind_offset:	size of the NULL indicator variable
+  *			(used for indexing in an array)
+  *	isarray:	array type
+  *	compat:		native PostgreSQL or Informix compatibility mode
+  *	force_indicator:
+  *			if Informix compatibility mode is set and no NULL indicator
+  *			is given, provide a way to indicate NULL value in the
+  *			target variable itself
+  */
  bool
! ecpg_get_data(const PGresult *results, int var_index, int act_tuple, int act_field, int lineno,
  			  enum ECPGttype type, enum ECPGttype ind_type,
  			  char *var, char *ind, long varcharsize, long offset,
  			  long ind_offset, enum ARRAY_TYPE isarray, enum COMPAT_MODE compat, bool force_indicator)
*************** ecpg_get_data(const PGresult *results, i
*** 167,186 ****
  	{
  		case ECPGt_short:
  		case ECPGt_unsigned_short:
! 			*((short *) (ind + ind_offset * act_tuple)) = value_for_indicator;
  			break;
  		case ECPGt_int:
  		case ECPGt_unsigned_int:
! 			*((int *) (ind + ind_offset * act_tuple)) = value_for_indicator;
  			break;
  		case ECPGt_long:
  		case ECPGt_unsigned_long:
! 			*((long *) (ind + ind_offset * act_tuple)) = value_for_indicator;
  			break;
  #ifdef HAVE_LONG_LONG_INT
  		case ECPGt_long_long:
  		case ECPGt_unsigned_long_long:
! 			*((long long int *) (ind + ind_offset * act_tuple)) = value_for_indicator;
  			break;
  #endif   /* HAVE_LONG_LONG_INT */
  		case ECPGt_NO_INDICATOR:
--- 192,211 ----
  	{
  		case ECPGt_short:
  		case ECPGt_unsigned_short:
! 			*((short *) (ind + ind_offset * var_index)) = value_for_indicator;
  			break;
  		case ECPGt_int:
  		case ECPGt_unsigned_int:
! 			*((int *) (ind + ind_offset * var_index)) = value_for_indicator;
  			break;
  		case ECPGt_long:
  		case ECPGt_unsigned_long:
! 			*((long *) (ind + ind_offset * var_index)) = value_for_indicator;
  			break;
  #ifdef HAVE_LONG_LONG_INT
  		case ECPGt_long_long:
  		case ECPGt_unsigned_long_long:
! 			*((long long int *) (ind + ind_offset * var_index)) = value_for_indicator;
  			break;
  #endif   /* HAVE_LONG_LONG_INT */
  		case ECPGt_NO_INDICATOR:
*************** ecpg_get_data(const PGresult *results, i
*** 192,198 ****
  					 * Informix has an additional way to specify NULLs note
  					 * that this uses special values to denote NULL
  					 */
! 					ECPGset_noind_null(type, var + offset * act_tuple);
  				}
  				else
  				{
--- 217,223 ----
  					 * Informix has an additional way to specify NULLs note
  					 * that this uses special values to denote NULL
  					 */
! 					ECPGset_noind_null(type, var + offset * var_index);
  				}
  				else
  				{
*************** ecpg_get_data(const PGresult *results, i
*** 243,252 ****
  		if (binary)
  		{
  			if (varcharsize == 0 || varcharsize * offset >= size)
! 				memcpy(var + offset * act_tuple, pval, size);
  			else
  			{
! 				memcpy(var + offset * act_tuple, pval, varcharsize * offset);
  
  				if (varcharsize * offset < size)
  				{
--- 268,277 ----
  		if (binary)
  		{
  			if (varcharsize == 0 || varcharsize * offset >= size)
! 				memcpy(var + offset * var_index, pval, size);
  			else
  			{
! 				memcpy(var + offset * var_index, pval, varcharsize * offset);
  
  				if (varcharsize * offset < size)
  				{
*************** ecpg_get_data(const PGresult *results, i
*** 255,274 ****
  					{
  						case ECPGt_short:
  						case ECPGt_unsigned_short:
! 							*((short *) (ind + ind_offset * act_tuple)) = size;
  							break;
  						case ECPGt_int:
  						case ECPGt_unsigned_int:
! 							*((int *) (ind + ind_offset * act_tuple)) = size;
  							break;
  						case ECPGt_long:
  						case ECPGt_unsigned_long:
! 							*((long *) (ind + ind_offset * act_tuple)) = size;
  							break;
  #ifdef HAVE_LONG_LONG_INT
  						case ECPGt_long_long:
  						case ECPGt_unsigned_long_long:
! 							*((long long int *) (ind + ind_offset * act_tuple)) = size;
  							break;
  #endif   /* HAVE_LONG_LONG_INT */
  						default:
--- 280,299 ----
  					{
  						case ECPGt_short:
  						case ECPGt_unsigned_short:
! 							*((short *) (ind + ind_offset * var_index)) = size;
  							break;
  						case ECPGt_int:
  						case ECPGt_unsigned_int:
! 							*((int *) (ind + ind_offset * var_index)) = size;
  							break;
  						case ECPGt_long:
  						case ECPGt_unsigned_long:
! 							*((long *) (ind + ind_offset * var_index)) = size;
  							break;
  #ifdef HAVE_LONG_LONG_INT
  						case ECPGt_long_long:
  						case ECPGt_unsigned_long_long:
! 							*((long long int *) (ind + ind_offset * var_index)) = size;
  							break;
  #endif   /* HAVE_LONG_LONG_INT */
  						default:
*************** ecpg_get_data(const PGresult *results, i
*** 307,319 ****
  					switch (type)
  					{
  						case ECPGt_short:
! 							*((short *) (var + offset * act_tuple)) = (short) res;
  							break;
  						case ECPGt_int:
! 							*((int *) (var + offset * act_tuple)) = (int) res;
  							break;
  						case ECPGt_long:
! 							*((long *) (var + offset * act_tuple)) = (long) res;
  							break;
  						default:
  							/* Cannot happen */
--- 332,344 ----
  					switch (type)
  					{
  						case ECPGt_short:
! 							*((short *) (var + offset * var_index)) = (short) res;
  							break;
  						case ECPGt_int:
! 							*((int *) (var + offset * var_index)) = (int) res;
  							break;
  						case ECPGt_long:
! 							*((long *) (var + offset * var_index)) = (long) res;
  							break;
  						default:
  							/* Cannot happen */
*************** ecpg_get_data(const PGresult *results, i
*** 336,348 ****
  					switch (type)
  					{
  						case ECPGt_unsigned_short:
! 							*((unsigned short *) (var + offset * act_tuple)) = (unsigned short) ures;
  							break;
  						case ECPGt_unsigned_int:
! 							*((unsigned int *) (var + offset * act_tuple)) = (unsigned int) ures;
  							break;
  						case ECPGt_unsigned_long:
! 							*((unsigned long *) (var + offset * act_tuple)) = (unsigned long) ures;
  							break;
  						default:
  							/* Cannot happen */
--- 361,373 ----
  					switch (type)
  					{
  						case ECPGt_unsigned_short:
! 							*((unsigned short *) (var + offset * var_index)) = (unsigned short) ures;
  							break;
  						case ECPGt_unsigned_int:
! 							*((unsigned int *) (var + offset * var_index)) = (unsigned int) ures;
  							break;
  						case ECPGt_unsigned_long:
! 							*((unsigned long *) (var + offset * var_index)) = (unsigned long) ures;
  							break;
  						default:
  							/* Cannot happen */
*************** ecpg_get_data(const PGresult *results, i
*** 353,359 ****
  #ifdef HAVE_LONG_LONG_INT
  #ifdef HAVE_STRTOLL
  				case ECPGt_long_long:
! 					*((long long int *) (var + offset * act_tuple)) = strtoll(pval, &scan_length, 10);
  					if (garbage_left(isarray, scan_length, compat))
  					{
  						ecpg_raise(lineno, ECPG_INT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
--- 378,384 ----
  #ifdef HAVE_LONG_LONG_INT
  #ifdef HAVE_STRTOLL
  				case ECPGt_long_long:
! 					*((long long int *) (var + offset * var_index)) = strtoll(pval, &scan_length, 10);
  					if (garbage_left(isarray, scan_length, compat))
  					{
  						ecpg_raise(lineno, ECPG_INT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
*************** ecpg_get_data(const PGresult *results, i
*** 365,371 ****
  #endif   /* HAVE_STRTOLL */
  #ifdef HAVE_STRTOULL
  				case ECPGt_unsigned_long_long:
! 					*((unsigned long long int *) (var + offset * act_tuple)) = strtoull(pval, &scan_length, 10);
  					if ((isarray && *scan_length != ',' && *scan_length != '}')
  						|| (!isarray && !(INFORMIX_MODE(compat) && *scan_length == '.') && *scan_length != '\0' && *scan_length != ' '))		/* Garbage left */
  					{
--- 390,396 ----
  #endif   /* HAVE_STRTOLL */
  #ifdef HAVE_STRTOULL
  				case ECPGt_unsigned_long_long:
! 					*((unsigned long long int *) (var + offset * var_index)) = strtoull(pval, &scan_length, 10);
  					if ((isarray && *scan_length != ',' && *scan_length != '}')
  						|| (!isarray && !(INFORMIX_MODE(compat) && *scan_length == '.') && *scan_length != '\0' && *scan_length != ' '))		/* Garbage left */
  					{
*************** ecpg_get_data(const PGresult *results, i
*** 400,409 ****
  					switch (type)
  					{
  						case ECPGt_float:
! 							*((float *) (var + offset * act_tuple)) = dres;
  							break;
  						case ECPGt_double:
! 							*((double *) (var + offset * act_tuple)) = dres;
  							break;
  						default:
  							/* Cannot happen */
--- 425,434 ----
  					switch (type)
  					{
  						case ECPGt_float:
! 							*((float *) (var + offset * var_index)) = dres;
  							break;
  						case ECPGt_double:
! 							*((double *) (var + offset * var_index)) = dres;
  							break;
  						default:
  							/* Cannot happen */
*************** ecpg_get_data(const PGresult *results, i
*** 415,423 ****
  					if (pval[0] == 'f' && pval[1] == '\0')
  					{
  						if (offset == sizeof(char))
! 							*((char *) (var + offset * act_tuple)) = false;
  						else if (offset == sizeof(int))
! 							*((int *) (var + offset * act_tuple)) = false;
  						else
  							ecpg_raise(lineno, ECPG_CONVERT_BOOL,
  									   ECPG_SQLSTATE_DATATYPE_MISMATCH,
--- 440,448 ----
  					if (pval[0] == 'f' && pval[1] == '\0')
  					{
  						if (offset == sizeof(char))
! 							*((char *) (var + offset * var_index)) = false;
  						else if (offset == sizeof(int))
! 							*((int *) (var + offset * var_index)) = false;
  						else
  							ecpg_raise(lineno, ECPG_CONVERT_BOOL,
  									   ECPG_SQLSTATE_DATATYPE_MISMATCH,
*************** ecpg_get_data(const PGresult *results, i
*** 427,442 ****
  					else if (pval[0] == 't' && pval[1] == '\0')
  					{
  						if (offset == sizeof(char))
! 							*((char *) (var + offset * act_tuple)) = true;
  						else if (offset == sizeof(int))
! 							*((int *) (var + offset * act_tuple)) = true;
  						else
  							ecpg_raise(lineno, ECPG_CONVERT_BOOL,
  									   ECPG_SQLSTATE_DATATYPE_MISMATCH,
  									   NULL);
  						break;
  					}
! 					else if (pval[0] == '\0' && PQgetisnull(results, act_tuple, act_field))
  					{
  						/* NULL is valid */
  						break;
--- 452,467 ----
  					else if (pval[0] == 't' && pval[1] == '\0')
  					{
  						if (offset == sizeof(char))
! 							*((char *) (var + offset * var_index)) = true;
  						else if (offset == sizeof(int))
! 							*((int *) (var + offset * var_index)) = true;
  						else
  							ecpg_raise(lineno, ECPG_CONVERT_BOOL,
  									   ECPG_SQLSTATE_DATATYPE_MISMATCH,
  									   NULL);
  						break;
  					}
! 					else if (pval[0] == '\0' && PQgetisnull(results, var_index, act_field))
  					{
  						/* NULL is valid */
  						break;
*************** ecpg_get_data(const PGresult *results, i
*** 451,457 ****
  				case ECPGt_unsigned_char:
  				case ECPGt_string:
  					{
! 						char	   *str = (char *) (var + offset * act_tuple);
  
  						if (varcharsize == 0 || varcharsize > size)
  						{
--- 476,482 ----
  				case ECPGt_unsigned_char:
  				case ECPGt_string:
  					{
! 						char	   *str = (char *) (var + offset * var_index);
  
  						if (varcharsize == 0 || varcharsize > size)
  						{
*************** ecpg_get_data(const PGresult *results, i
*** 479,498 ****
  								{
  									case ECPGt_short:
  									case ECPGt_unsigned_short:
! 										*((short *) (ind + ind_offset * act_tuple)) = size;
  										break;
  									case ECPGt_int:
  									case ECPGt_unsigned_int:
! 										*((int *) (ind + ind_offset * act_tuple)) = size;
  										break;
  									case ECPGt_long:
  									case ECPGt_unsigned_long:
! 										*((long *) (ind + ind_offset * act_tuple)) = size;
  										break;
  #ifdef HAVE_LONG_LONG_INT
  									case ECPGt_long_long:
  									case ECPGt_unsigned_long_long:
! 										*((long long int *) (ind + ind_offset * act_tuple)) = size;
  										break;
  #endif   /* HAVE_LONG_LONG_INT */
  									default:
--- 504,523 ----
  								{
  									case ECPGt_short:
  									case ECPGt_unsigned_short:
! 										*((short *) (ind + ind_offset * var_index)) = size;
  										break;
  									case ECPGt_int:
  									case ECPGt_unsigned_int:
! 										*((int *) (ind + ind_offset * var_index)) = size;
  										break;
  									case ECPGt_long:
  									case ECPGt_unsigned_long:
! 										*((long *) (ind + ind_offset * var_index)) = size;
  										break;
  #ifdef HAVE_LONG_LONG_INT
  									case ECPGt_long_long:
  									case ECPGt_unsigned_long_long:
! 										*((long long int *) (ind + ind_offset * var_index)) = size;
  										break;
  #endif   /* HAVE_LONG_LONG_INT */
  									default:
*************** ecpg_get_data(const PGresult *results, i
*** 508,514 ****
  				case ECPGt_varchar:
  					{
  						struct ECPGgeneric_varchar *variable =
! 						(struct ECPGgeneric_varchar *) (var + offset * act_tuple);
  
  						variable->len = size;
  						if (varcharsize == 0)
--- 533,539 ----
  				case ECPGt_varchar:
  					{
  						struct ECPGgeneric_varchar *variable =
! 						(struct ECPGgeneric_varchar *) (var + offset * var_index);
  
  						variable->len = size;
  						if (varcharsize == 0)
*************** ecpg_get_data(const PGresult *results, i
*** 524,543 ****
  								{
  									case ECPGt_short:
  									case ECPGt_unsigned_short:
! 										*((short *) (ind + offset * act_tuple)) = variable->len;
  										break;
  									case ECPGt_int:
  									case ECPGt_unsigned_int:
! 										*((int *) (ind + offset * act_tuple)) = variable->len;
  										break;
  									case ECPGt_long:
  									case ECPGt_unsigned_long:
! 										*((long *) (ind + offset * act_tuple)) = variable->len;
  										break;
  #ifdef HAVE_LONG_LONG_INT
  									case ECPGt_long_long:
  									case ECPGt_unsigned_long_long:
! 										*((long long int *) (ind + ind_offset * act_tuple)) = variable->len;
  										break;
  #endif   /* HAVE_LONG_LONG_INT */
  									default:
--- 549,568 ----
  								{
  									case ECPGt_short:
  									case ECPGt_unsigned_short:
! 										*((short *) (ind + offset * var_index)) = variable->len;
  										break;
  									case ECPGt_int:
  									case ECPGt_unsigned_int:
! 										*((int *) (ind + offset * var_index)) = variable->len;
  										break;
  									case ECPGt_long:
  									case ECPGt_unsigned_long:
! 										*((long *) (ind + offset * var_index)) = variable->len;
  										break;
  #ifdef HAVE_LONG_LONG_INT
  									case ECPGt_long_long:
  									case ECPGt_unsigned_long_long:
! 										*((long long int *) (ind + ind_offset * var_index)) = variable->len;
  										break;
  #endif   /* HAVE_LONG_LONG_INT */
  									default:
*************** ecpg_get_data(const PGresult *results, i
*** 604,612 ****
  					pval = scan_length;
  
  					if (type == ECPGt_numeric)
! 						PGTYPESnumeric_copy(nres, (numeric *) (var + offset * act_tuple));
  					else
! 						PGTYPESnumeric_to_decimal(nres, (decimal *) (var + offset * act_tuple));
  
  					PGTYPESnumeric_free(nres);
  					break;
--- 629,637 ----
  					pval = scan_length;
  
  					if (type == ECPGt_numeric)
! 						PGTYPESnumeric_copy(nres, (numeric *) (var + offset * var_index));
  					else
! 						PGTYPESnumeric_to_decimal(nres, (decimal *) (var + offset * var_index));
  
  					PGTYPESnumeric_free(nres);
  					break;
*************** ecpg_get_data(const PGresult *results, i
*** 657,663 ****
  					}
  					pval = scan_length;
  
! 					PGTYPESinterval_copy(ires, (interval *) (var + offset * act_tuple));
  					free(ires);
  					break;
  
--- 682,688 ----
  					}
  					pval = scan_length;
  
! 					PGTYPESinterval_copy(ires, (interval *) (var + offset * var_index));
  					free(ires);
  					break;
  
*************** ecpg_get_data(const PGresult *results, i
*** 701,707 ****
  						}
  					}
  
! 					*((date *) (var + offset * act_tuple)) = ddres;
  					pval = scan_length;
  					break;
  
--- 726,732 ----
  						}
  					}
  
! 					*((date *) (var + offset * var_index)) = ddres;
  					pval = scan_length;
  					break;
  
*************** ecpg_get_data(const PGresult *results, i
*** 745,751 ****
  						}
  					}
  
! 					*((timestamp *) (var + offset * act_tuple)) = tres;
  					pval = scan_length;
  					break;
  
--- 770,776 ----
  						}
  					}
  
! 					*((timestamp *) (var + offset * var_index)) = tres;
  					pval = scan_length;
  					break;
  
*************** ecpg_get_data(const PGresult *results, i
*** 762,767 ****
--- 787,793 ----
  
  				/* set array to next entry */
  				++act_tuple;
+ 				++var_index;
  
  				/* set pval to the next entry */
  
diff -dcrpN postgresql.orig/src/interfaces/ecpg/ecpglib/descriptor.c postgresql/src/interfaces/ecpg/ecpglib/descriptor.c
*** postgresql.orig/src/interfaces/ecpg/ecpglib/descriptor.c	2012-03-15 20:33:58.069702814 +0100
--- postgresql/src/interfaces/ecpg/ecpglib/descriptor.c	2012-03-29 11:24:53.967185188 +0200
*************** ECPGget_desc(int lineno, const char *des
*** 481,487 ****
  
  		/* desparate try to guess something sensible */
  		stmt.connection = ecpg_get_connection(NULL);
! 		ecpg_store_result(ECPGresult, index, &stmt, &data_var);
  
  		setlocale(LC_NUMERIC, oldlocale);
  		ecpg_free(oldlocale);
--- 481,487 ----
  
  		/* desparate try to guess something sensible */
  		stmt.connection = ecpg_get_connection(NULL);
! 		ecpg_store_result(ECPGresult, 0, PQntuples(ECPGresult), index, &stmt, &data_var, 0);
  
  		setlocale(LC_NUMERIC, oldlocale);
  		ecpg_free(oldlocale);
diff -dcrpN postgresql.orig/src/interfaces/ecpg/ecpglib/error.c postgresql/src/interfaces/ecpg/ecpglib/error.c
*** postgresql.orig/src/interfaces/ecpg/ecpglib/error.c	2011-09-12 09:54:31.197312383 +0200
--- postgresql/src/interfaces/ecpg/ecpglib/error.c	2012-03-29 11:24:53.968185194 +0200
*************** ecpg_raise(int line, int code, const cha
*** 268,273 ****
--- 268,296 ----
  					 ecpg_gettext("could not connect to database \"%s\" on line %d"), str, line);
  			break;
  
+ 		case ECPG_INVALID_CURSOR:
+ 			if (strcmp(sqlstate, ECPG_SQLSTATE_INVALID_CURSOR_NAME) == 0)
+ 			{
+ 				snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
+ 
+ 			/*
+ 			 * translator: this string will be truncated at 149 characters
+ 			 * expanded.
+ 			 */
+ 					 ecpg_gettext("invalid cursorname \"%s\" on line %d"), str, line);
+ 			}
+ 			else
+ 			{
+ 				snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
+ 
+ 			/*
+ 			 * translator: this string will be truncated at 149 characters
+ 			 * expanded.
+ 			 */
+ 					 ecpg_gettext("invalid cursor error %d on line %d"), code, line);
+ 			}
+ 			break;
+ 
  		default:
  			snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
  
diff -dcrpN postgresql.orig/src/interfaces/ecpg/ecpglib/execute.c postgresql/src/interfaces/ecpg/ecpglib/execute.c
*** postgresql.orig/src/interfaces/ecpg/ecpglib/execute.c	2012-03-09 09:26:27.593365975 +0100
--- postgresql/src/interfaces/ecpg/ecpglib/execute.c	2012-03-29 11:24:53.971185209 +0200
*************** free_variable(struct variable * var)
*** 87,102 ****
  {
  	struct variable *var_next;
  
! 	if (var == NULL)
! 		return;
! 	var_next = var->next;
! 	ecpg_free(var);
! 
! 	while (var_next)
  	{
- 		var = var_next;
  		var_next = var->next;
  		ecpg_free(var);
  	}
  }
  
--- 87,97 ----
  {
  	struct variable *var_next;
  
! 	while (var)
  	{
  		var_next = var->next;
  		ecpg_free(var);
+ 		var = var_next;
  	}
  }
  
*************** free_statement(struct statement * stmt)
*** 109,114 ****
--- 104,110 ----
  	free_variable(stmt->outlist);
  	ecpg_free(stmt->command);
  	ecpg_free(stmt->name);
+ 	ecpg_free(stmt->oldlocale);
  	ecpg_free(stmt);
  }
  
*************** ecpg_is_type_an_array(int type, const st
*** 310,322 ****
  }
  
  
  bool
! ecpg_store_result(const PGresult *results, int act_field,
! 				  const struct statement * stmt, struct variable * var)
  {
  	enum ARRAY_TYPE isarray;
  	int			act_tuple,
! 				ntuples = PQntuples(results);
  	bool		status = true;
  
  	if ((isarray = ecpg_is_type_an_array(PQftype(results, act_field), stmt, var)) == ECPG_ARRAY_ERROR)
--- 306,331 ----
  }
  
  
+ /*
+  * ecpg_store_result
+  *	Store the query result in user variables, possibly
+  *	multiple rows if the user variable is an array.
+  * Paremeters:
+  *	results:	PGresult with tuples
+  *	start,
+  *	end:		[start, end) interval in "results"
+  *	act_field:	actual field in the tuple
+  *	stmt:		the statement structure
+  *	var:		the user variable
+  *	var_index:	starting index in var
+  */
  bool
! ecpg_store_result(const PGresult *results, int start, int end, int act_field,
! 				  const struct statement * stmt, struct variable * var, int var_index)
  {
  	enum ARRAY_TYPE isarray;
  	int			act_tuple,
! 				ntuples = end - start;
  	bool		status = true;
  
  	if ((isarray = ecpg_is_type_an_array(PQftype(results, act_field), stmt, var)) == ECPG_ARRAY_ERROR)
*************** ecpg_store_result(const PGresult *result
*** 367,373 ****
  					if (!var->varcharsize && !var->arrsize)
  					{
  						/* special mode for handling char**foo=0 */
! 						for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
  							len += strlen(PQgetvalue(results, act_tuple, act_field)) + 1;
  						len *= var->offset;		/* should be 1, but YMNK */
  						len += (ntuples + 1) * sizeof(char *);
--- 376,382 ----
  					if (!var->varcharsize && !var->arrsize)
  					{
  						/* special mode for handling char**foo=0 */
! 						for (act_tuple = start; act_tuple < end; act_tuple++)
  							len += strlen(PQgetvalue(results, act_tuple, act_field)) + 1;
  						len *= var->offset;		/* should be 1, but YMNK */
  						len += (ntuples + 1) * sizeof(char *);
*************** ecpg_store_result(const PGresult *result
*** 376,382 ****
  					{
  						var->varcharsize = 0;
  						/* check strlen for each tuple */
! 						for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
  						{
  							int			len = strlen(PQgetvalue(results, act_tuple, act_field)) + 1;
  
--- 385,391 ----
  					{
  						var->varcharsize = 0;
  						/* check strlen for each tuple */
! 						for (act_tuple = start; act_tuple < end; act_tuple++)
  						{
  							int			len = strlen(PQgetvalue(results, act_tuple, act_field)) + 1;
  
*************** ecpg_store_result(const PGresult *result
*** 397,403 ****
  		}
  		else
  		{
! 			for (act_tuple = 0; act_tuple < ntuples; act_tuple++)
  				len += PQgetlength(results, act_tuple, act_field);
  		}
  
--- 406,412 ----
  		}
  		else
  		{
! 			for (act_tuple = start; act_tuple < end; act_tuple++)
  				len += PQgetlength(results, act_tuple, act_field);
  		}
  
*************** ecpg_store_result(const PGresult *result
*** 433,443 ****
  		/* storing the data (after the last array element) */
  		char	   *current_data_location = (char *) &current_string[ntuples + 1];
  
! 		for (act_tuple = 0; act_tuple < ntuples && status; act_tuple++)
  		{
  			int			len = strlen(PQgetvalue(results, act_tuple, act_field)) + 1;
  
! 			if (!ecpg_get_data(results, act_tuple, act_field, stmt->lineno,
  							 var->type, var->ind_type, current_data_location,
  							   var->ind_value, len, 0, var->ind_offset, isarray, stmt->compat, stmt->force_indicator))
  				status = false;
--- 442,452 ----
  		/* storing the data (after the last array element) */
  		char	   *current_data_location = (char *) &current_string[ntuples + 1];
  
! 		for (act_tuple = start; act_tuple < end && status; act_tuple++, var_index++)
  		{
  			int			len = strlen(PQgetvalue(results, act_tuple, act_field)) + 1;
  
! 			if (!ecpg_get_data(results, var_index, act_tuple, act_field, stmt->lineno,
  							 var->type, var->ind_type, current_data_location,
  							   var->ind_value, len, 0, var->ind_offset, isarray, stmt->compat, stmt->force_indicator))
  				status = false;
*************** ecpg_store_result(const PGresult *result
*** 454,462 ****
  	}
  	else
  	{
! 		for (act_tuple = 0; act_tuple < ntuples && status; act_tuple++)
  		{
! 			if (!ecpg_get_data(results, act_tuple, act_field, stmt->lineno,
  							   var->type, var->ind_type, var->value,
  							   var->ind_value, var->varcharsize, var->offset, var->ind_offset, isarray, stmt->compat, stmt->force_indicator))
  				status = false;
--- 463,471 ----
  	}
  	else
  	{
! 		for (act_tuple = start; act_tuple < end && status; act_tuple++, var_index++)
  		{
! 			if (!ecpg_get_data(results, var_index, act_tuple, act_field, stmt->lineno,
  							   var->type, var->ind_type, var->value,
  							   var->ind_value, var->varcharsize, var->offset, var->ind_offset, isarray, stmt->compat, stmt->force_indicator))
  				status = false;
*************** ecpg_store_input(const int lineno, const
*** 1082,1099 ****
  	return true;
  }
  
! static void
! free_params(char **paramValues, int nParams, bool print, int lineno)
  {
  	int			n;
  
! 	for (n = 0; n < nParams; n++)
  	{
  		if (print)
! 			ecpg_log("free_params on line %d: parameter %d = %s\n", lineno, n + 1, paramValues[n] ? paramValues[n] : "null");
! 		ecpg_free(paramValues[n]);
  	}
! 	ecpg_free(paramValues);
  }
  
  
--- 1091,1123 ----
  	return true;
  }
  
! /*
!  * ecpg_free_params
!  *	Free statement parameters.
!  */
! void
! ecpg_free_params(struct statement *stmt, bool print)
  {
  	int			n;
  
! 	for (n = 0; n < stmt->nparams; n++)
  	{
  		if (print)
! 			ecpg_log("free_params on line %d: parameter %d = %s\n",
! 					stmt->lineno, n + 1,
! 					(stmt->param_values[n] ?
! 						stmt->param_values[n] : "null"));
! 		ecpg_free(stmt->param_values[n]);
  	}
! 	ecpg_free(stmt->param_values);
! 	stmt->nparams = 0;
! 	stmt->param_values = NULL;
! 
! 	for (n = 0; n < stmt->ndollarzero; n++)
! 		ecpg_free((void *) (stmt->dollarzero[n]));
! 	ecpg_free(stmt->dollarzero);
! 	stmt->ndollarzero = 0;
! 	stmt->dollarzero = NULL;
  }
  
  
*************** insert_tobeinserted(int position, int ph
*** 1129,1148 ****
  	return true;
  }
  
! static bool
! ecpg_execute(struct statement * stmt)
  {
- 	bool		status = false;
- 	char	   *cmdstat;
- 	PGresult   *results;
- 	PGnotify   *notify;
  	struct variable *var;
  	int			desc_counter = 0;
- 	char	  **paramValues = NULL;
- 	int			nParams = 0;
  	int			position = 0;
- 	struct sqlca_t *sqlca = ECPGget_sqlca();
- 	bool		clear_result = true;
  
  	/*
  	 * If the type is one of the fill in types then we take the argument and
--- 1153,1170 ----
  	return true;
  }
  
! /*
!  * ecpg_build_params
!  *	Build statement parameters from user variables into
!  *	an array of strings for PQexecParams(). Keep the $0
!  *	elements for cursor purposes.
!  */
! bool
! ecpg_build_params(struct statement * stmt)
  {
  	struct variable *var;
  	int			desc_counter = 0;
  	int			position = 0;
  
  	/*
  	 * If the type is one of the fill in types then we take the argument and
*************** ecpg_execute(struct statement * stmt)
*** 1342,1348 ****
  			ecpg_raise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS,
  					   ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS,
  					   NULL);
! 			free_params(paramValues, nParams, false, stmt->lineno);
  			return false;
  		}
  
--- 1364,1370 ----
  			ecpg_raise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS,
  					   ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS,
  					   NULL);
! 			ecpg_free_params(stmt, false);
  			return false;
  		}
  
*************** ecpg_execute(struct statement * stmt)
*** 1357,1363 ****
  
  			if (!insert_tobeinserted(position, ph_len, stmt, tobeinserted))
  			{
! 				free_params(paramValues, nParams, false, stmt->lineno);
  				return false;
  			}
  			tobeinserted = NULL;
--- 1379,1385 ----
  
  			if (!insert_tobeinserted(position, ph_len, stmt, tobeinserted))
  			{
! 				ecpg_free_params(stmt, false);
  				return false;
  			}
  			tobeinserted = NULL;
*************** ecpg_execute(struct statement * stmt)
*** 1370,1392 ****
  		 */
  		else if (stmt->command[position] == '0')
  		{
  			if (!insert_tobeinserted(position, 2, stmt, tobeinserted))
  			{
! 				free_params(paramValues, nParams, false, stmt->lineno);
  				return false;
  			}
  			tobeinserted = NULL;
  		}
  		else
  		{
! 			nParams++;
! 			if (!(paramValues = (char **) ecpg_realloc(paramValues, sizeof(char *) * nParams, stmt->lineno)))
  			{
! 				ecpg_free(paramValues);
  				return false;
  			}
  
! 			paramValues[nParams - 1] = tobeinserted;
  
  			/* let's see if this was an old style placeholder */
  			if (stmt->command[position] == '?')
--- 1392,1435 ----
  		 */
  		else if (stmt->command[position] == '0')
  		{
+ 			char **dollarzero;
+ 
+ 			dollarzero = (char **) ecpg_realloc(stmt->dollarzero,
+ 								sizeof(char *) * (stmt->ndollarzero + 1),
+ 								stmt->lineno);
+ 
+ 			if (!dollarzero)
+ 			{
+ 				ecpg_free_params(stmt, false);
+ 				return false;
+ 			}
+ 			stmt->ndollarzero++;
+ 			stmt->dollarzero = dollarzero;
+ 			stmt->dollarzero[stmt->ndollarzero - 1] = strdup(tobeinserted);
+ 
  			if (!insert_tobeinserted(position, 2, stmt, tobeinserted))
  			{
! 				ecpg_free_params(stmt, false);
  				return false;
  			}
  			tobeinserted = NULL;
  		}
  		else
  		{
! 			char **paramValues;
! 
! 			paramValues = (char **) ecpg_realloc(stmt->param_values, sizeof(char *) * (stmt->nparams + 1), stmt->lineno);
! 
! 			if (!paramValues)
  			{
! 				ecpg_free_params(stmt, false);
  				return false;
  			}
  
! 			stmt->nparams++;
! 			stmt->param_values = paramValues;
! 
! 			stmt->param_values[stmt->nparams - 1] = tobeinserted;
  
  			/* let's see if this was an old style placeholder */
  			if (stmt->command[position] == '?')
*************** ecpg_execute(struct statement * stmt)
*** 1397,1403 ****
  
  				if (!(tobeinserted = (char *) ecpg_alloc(buffersize, stmt->lineno)))
  				{
! 					free_params(paramValues, nParams, false, stmt->lineno);
  					return false;
  				}
  
--- 1440,1446 ----
  
  				if (!(tobeinserted = (char *) ecpg_alloc(buffersize, stmt->lineno)))
  				{
! 					ecpg_free_params(stmt, false);
  					return false;
  				}
  
*************** ecpg_execute(struct statement * stmt)
*** 1405,1411 ****
  
  				if (!insert_tobeinserted(position, 2, stmt, tobeinserted))
  				{
! 					free_params(paramValues, nParams, false, stmt->lineno);
  					return false;
  				}
  				tobeinserted = NULL;
--- 1448,1454 ----
  
  				if (!insert_tobeinserted(position, 2, stmt, tobeinserted))
  				{
! 					ecpg_free_params(stmt, false);
  					return false;
  				}
  				tobeinserted = NULL;
*************** ecpg_execute(struct statement * stmt)
*** 1421,1479 ****
  	{
  		ecpg_raise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS,
  				 ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, NULL);
! 		free_params(paramValues, nParams, false, stmt->lineno);
  		return false;
  	}
  
! 	/* The request has been build. */
  
  	if (PQtransactionStatus(stmt->connection->connection) == PQTRANS_IDLE && !stmt->connection->autocommit)
  	{
! 		results = PQexec(stmt->connection->connection, "begin transaction");
! 		if (!ecpg_check_PQresult(results, stmt->lineno, stmt->connection->connection, stmt->compat))
  		{
! 			free_params(paramValues, nParams, false, stmt->lineno);
  			return false;
  		}
! 		PQclear(results);
  	}
  
! 	ecpg_log("ecpg_execute on line %d: query: %s; with %d parameter(s) on connection %s\n", stmt->lineno, stmt->command, nParams, stmt->connection->name);
  	if (stmt->statement_type == ECPGst_execute)
  	{
! 		results = PQexecPrepared(stmt->connection->connection, stmt->name, nParams, (const char *const*) paramValues, NULL, NULL, 0);
  		ecpg_log("ecpg_execute on line %d: using PQexecPrepared for \"%s\"\n", stmt->lineno, stmt->command);
  	}
  	else
  	{
! 		if (nParams == 0)
  		{
! 			results = PQexec(stmt->connection->connection, stmt->command);
  			ecpg_log("ecpg_execute on line %d: using PQexec\n", stmt->lineno);
  		}
  		else
  		{
! 			results = PQexecParams(stmt->connection->connection, stmt->command, nParams, NULL, (const char *const*) paramValues, NULL, NULL, 0);
  			ecpg_log("ecpg_execute on line %d: using PQexecParams\n", stmt->lineno);
  		}
  	}
  
! 	free_params(paramValues, nParams, true, stmt->lineno);
  
! 	if (!ecpg_check_PQresult(results, stmt->lineno, stmt->connection->connection, stmt->compat))
  		return (false);
  
  	var = stmt->outlist;
! 	switch (PQresultStatus(results))
  	{
  			int			nfields,
  						ntuples,
  						act_field;
  
  		case PGRES_TUPLES_OK:
! 			nfields = PQnfields(results);
! 			sqlca->sqlerrd[2] = ntuples = PQntuples(results);
! 			ecpg_log("ecpg_execute on line %d: correctly got %d tuples with %d fields\n", stmt->lineno, ntuples, nfields);
  			status = true;
  
  			if (ntuples < 1)
--- 1464,1591 ----
  	{
  		ecpg_raise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS,
  				 ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, NULL);
! 		ecpg_free_params(stmt, false);
  		return false;
  	}
  
! 	return true;
! }
  
+ /*
+  * ecpg_autostart_transaction
+  *	If we are in non-autocommit mode, automatically start
+  *	a transaction.
+  */
+ bool
+ ecpg_autostart_transaction(struct statement * stmt)
+ {
  	if (PQtransactionStatus(stmt->connection->connection) == PQTRANS_IDLE && !stmt->connection->autocommit)
  	{
! 		stmt->results = PQexec(stmt->connection->connection, "begin transaction");
! 		if (!ecpg_check_PQresult(stmt->results, stmt->lineno, stmt->connection->connection, stmt->compat))
  		{
! 			ecpg_free_params(stmt, false);
  			return false;
  		}
! 		PQclear(stmt->results);
! 		stmt->results = NULL;
  	}
+ 	return true;
+ }
  
! /*
!  * ecpg_execute
!  *	Execute the SQL statement.
!  */
! bool
! ecpg_execute(struct statement * stmt)
! {
! 	ecpg_log("ecpg_execute on line %d: query: %s; with %d parameter(s) on connection %s\n", stmt->lineno, stmt->command, stmt->nparams, stmt->connection->name);
  	if (stmt->statement_type == ECPGst_execute)
  	{
! 		stmt->results = PQexecPrepared(stmt->connection->connection,
! 								stmt->name,
! 								stmt->nparams,
! 								(const char * const *)stmt->param_values,
! 								NULL, NULL, 0);
  		ecpg_log("ecpg_execute on line %d: using PQexecPrepared for \"%s\"\n", stmt->lineno, stmt->command);
  	}
  	else
  	{
! 		if (stmt->nparams == 0)
  		{
! 			stmt->results = PQexec(stmt->connection->connection,
! 								stmt->command);
  			ecpg_log("ecpg_execute on line %d: using PQexec\n", stmt->lineno);
  		}
  		else
  		{
! 			stmt->results = PQexecParams(stmt->connection->connection,
! 								stmt->command,
! 								stmt->nparams,
! 								NULL,
! 								(const char * const *)stmt->param_values,
! 								NULL, NULL, 0);
  			ecpg_log("ecpg_execute on line %d: using PQexecParams\n", stmt->lineno);
  		}
  	}
  
! 	ecpg_free_params(stmt, true);
  
! 	if (!ecpg_check_PQresult(stmt->results, stmt->lineno, stmt->connection->connection, stmt->compat))
  		return (false);
  
+ 	return (true);
+ }
+ 
+ /*
+  * ecpg_process_output
+  *	Process the statement result and store it into application variables.
+  *	This function can be called repeatedly during the same statement
+  *	in case cursor readahed is used and the application does FETCH N which
+  *	overflows the readahead window.
+  *
+  * Parameters
+  *	stmt	statement structure holding the PGresult and
+  *		the list of output variables
+  *	start, end
+  *		row indexes (start ... end-1) in PGresult to process
+  *	var_index
+  *		variable index to store the row data into is an array and
+  *		it already contains data from previous calls
+  *	keep_result
+  *		don't PQclear() the result upon returning from this function
+  *	append_result
+  *		the result variable is a descriptor and it already contains
+  *		data from previous calls
+  *
+  * Returns success as boolean. Also an SQL error is raised in case of failure.
+  */
+ bool
+ ecpg_process_output(struct statement * stmt,
+ 					int start, int end, int var_index,
+ 					bool keep_result, bool append_result)
+ {
+ 	char		*cmdstat;
+ 	PGnotify	*notify; 
+ 	bool		status = false;
+ 	struct variable *var;
+ 	struct sqlca_t *sqlca = ECPGget_sqlca();
+ 
  	var = stmt->outlist;
! 	switch (PQresultStatus(stmt->results))
  	{
  			int			nfields,
  						ntuples,
  						act_field;
  
  		case PGRES_TUPLES_OK:
! 			nfields = PQnfields(stmt->results);
! 			sqlca->sqlerrd[2] = ntuples = (end - start);
! 			ecpg_log("ecpg_execute on line %d: correctly got %d tuples with %d fields\n",
! 									 stmt->lineno,
! 									 ntuples,
! 									 nfields);
  			status = true;
  
  			if (ntuples < 1)
*************** ecpg_execute(struct statement * stmt)
*** 1494,1505 ****
  					status = false;
  				else
  				{
! 					if (desc->result)
! 						PQclear(desc->result);
! 					desc->result = results;
! 					clear_result = false;
  					ecpg_log("ecpg_execute on line %d: putting result (%d tuples) into descriptor %s\n",
! 							 stmt->lineno, PQntuples(results), (const char *) var->pointer);
  				}
  				var = var->next;
  			}
--- 1606,1639 ----
  					status = false;
  				else
  				{
! 					int	row, srcrow, col;
! 
! 					if (append_result)
! 						row = PQntuples(desc->result);
! 					else
! 					{
! 						if (desc->result)
! 							PQclear(desc->result);
! 						desc->result = PQcopyResult(stmt->results, PG_COPYRES_ATTRS | PG_COPYRES_EVENTS | PG_COPYRES_NOTICEHOOKS);
! 						row = 0;
! 					}
! 
! 					for (srcrow = start; srcrow < end; srcrow++, row++)
! 						for (col = 0; col < nfields; col++)
! 						{
! 							bool	isnull = PQgetisnull(stmt->results, srcrow, col);
! 							if (!PQsetvalue(desc->result, row, col,
! 										isnull ? NULL : PQgetvalue(stmt->results, srcrow, col),
! 										isnull ? -1 : PQgetlength(stmt->results, srcrow, col)))
! 							{
! 								ecpg_raise(stmt->lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
! 								status = false;
! 								break;
! 							}
! 						}
! 
  					ecpg_log("ecpg_execute on line %d: putting result (%d tuples) into descriptor %s\n",
! 							 stmt->lineno, PQntuples(stmt->results), (const char *) var->pointer);
  				}
  				var = var->next;
  			}
*************** ecpg_execute(struct statement * stmt)
*** 1509,1544 ****
  				{
  					struct sqlda_compat **_sqlda = (struct sqlda_compat **) var->pointer;
  					struct sqlda_compat *sqlda = *_sqlda;
! 					struct sqlda_compat *sqlda_new;
  					int			i;
  
! 					/*
! 					 * If we are passed in a previously existing sqlda (chain)
! 					 * then free it.
! 					 */
! 					while (sqlda)
  					{
! 						sqlda_new = sqlda->desc_next;
! 						free(sqlda);
! 						sqlda = sqlda_new;
  					}
! 					*_sqlda = sqlda = sqlda_new = NULL;
! 					for (i = ntuples - 1; i >= 0; i--)
  					{
  						/*
! 						 * Build a new sqlda structure. Note that only
! 						 * fetching 1 record is supported
  						 */
! 						sqlda_new = ecpg_build_compat_sqlda(stmt->lineno, results, i, stmt->compat);
  
! 						if (!sqlda_new)
  						{
  							/* cleanup all SQLDAs we created up */
  							while (sqlda)
  							{
! 								sqlda_new = sqlda->desc_next;
  								free(sqlda);
! 								sqlda = sqlda_new;
  							}
  							*_sqlda = NULL;
  
--- 1643,1694 ----
  				{
  					struct sqlda_compat **_sqlda = (struct sqlda_compat **) var->pointer;
  					struct sqlda_compat *sqlda = *_sqlda;
! 					struct sqlda_compat *sqlda_last, *sqlda_new = NULL;
  					int			i;
  
! 					if (append_result)
  					{
! 						sqlda_last = sqlda;
! 						while (sqlda_last && sqlda_last->desc_next)
! 							sqlda_last = sqlda_last->desc_next;
  					}
! 					else
  					{
  						/*
! 						 * If we are passed in a previously existing sqlda (chain)
! 						 * then free it.
  						 */
! 						while (sqlda)
! 						{
! 							sqlda_last = sqlda->desc_next;
! 							free(sqlda);
! 							sqlda = sqlda_last;
! 						}
! 						*_sqlda = sqlda = sqlda_last = NULL;
! 					}
! 					for (i = end - 1; i >= start; i--)
! 					{
! 						struct sqlda_compat *tmp;
  
! 						/*
! 						 * Build a new sqlda structure. 
! 						 */
! 						tmp = ecpg_build_compat_sqlda(stmt->lineno, stmt->results, i, stmt->compat);
! 
! 						if (!tmp)
  						{
  							/* cleanup all SQLDAs we created up */
+ 							while (sqlda_new)
+ 							{
+ 								tmp = sqlda_new->desc_next;
+ 								free(sqlda_new);
+ 								sqlda_new = tmp;
+ 							}
  							while (sqlda)
  							{
! 								tmp = sqlda->desc_next;
  								free(sqlda);
! 								sqlda = tmp;
  							}
  							*_sqlda = NULL;
  
*************** ecpg_execute(struct statement * stmt)
*** 1550,1600 ****
  						{
  							ecpg_log("ecpg_execute on line %d: new sqlda was built\n", stmt->lineno);
  
! 							*_sqlda = sqlda_new;
  
! 							ecpg_set_compat_sqlda(stmt->lineno, _sqlda, results, i, stmt->compat);
  							ecpg_log("ecpg_execute on line %d: putting result (1 tuple %d fields) into sqlda descriptor\n",
! 									 stmt->lineno, PQnfields(results));
! 
! 							sqlda_new->desc_next = sqlda;
! 							sqlda = sqlda_new;
  						}
  					}
  				}
  				else
  				{
  					struct sqlda_struct **_sqlda = (struct sqlda_struct **) var->pointer;
  					struct sqlda_struct *sqlda = *_sqlda;
! 					struct sqlda_struct *sqlda_new;
  					int			i;
  
! 					/*
! 					 * If we are passed in a previously existing sqlda (chain)
! 					 * then free it.
! 					 */
! 					while (sqlda)
  					{
! 						sqlda_new = sqlda->desc_next;
! 						free(sqlda);
! 						sqlda = sqlda_new;
  					}
! 					*_sqlda = sqlda = sqlda_new = NULL;
! 					for (i = ntuples - 1; i >= 0; i--)
  					{
  						/*
! 						 * Build a new sqlda structure. Note that only
! 						 * fetching 1 record is supported
  						 */
! 						sqlda_new = ecpg_build_native_sqlda(stmt->lineno, results, i, stmt->compat);
  
! 						if (!sqlda_new)
  						{
  							/* cleanup all SQLDAs we created up */
  							while (sqlda)
  							{
! 								sqlda_new = sqlda->desc_next;
  								free(sqlda);
! 								sqlda = sqlda_new;
  							}
  							*_sqlda = NULL;
  
--- 1700,1773 ----
  						{
  							ecpg_log("ecpg_execute on line %d: new sqlda was built\n", stmt->lineno);
  
! 							if (sqlda_new == NULL)
! 								sqlda_new = tmp;
! 							else
! 							{
! 								tmp->desc_next = sqlda_new;
! 								sqlda_new = tmp;
! 							}
  
! 							ecpg_set_compat_sqlda(stmt->lineno, &tmp, stmt->results, i, stmt->compat);
  							ecpg_log("ecpg_execute on line %d: putting result (1 tuple %d fields) into sqlda descriptor\n",
! 									 stmt->lineno, PQnfields(stmt->results));
  						}
  					}
+ 					if (sqlda_last)
+ 						sqlda_last->desc_next = sqlda_new;
+ 					else
+ 						*_sqlda = sqlda_new;
  				}
  				else
  				{
  					struct sqlda_struct **_sqlda = (struct sqlda_struct **) var->pointer;
  					struct sqlda_struct *sqlda = *_sqlda;
! 					struct sqlda_struct *sqlda_last, *sqlda_new = NULL;
  					int			i;
  
! 					if (append_result)
  					{
! 						sqlda_last = sqlda;
! 						while (sqlda_last && sqlda_last->desc_next)
! 							sqlda_last = sqlda_last->desc_next;
  					}
! 					else
  					{
  						/*
! 						 * If we are passed in a previously existing sqlda (chain)
! 						 * then free it.
  						 */
! 						while (sqlda)
! 						{
! 							sqlda_last = sqlda->desc_next;
! 							free(sqlda);
! 							sqlda = sqlda_last;
! 						}
! 						*_sqlda = sqlda = sqlda_last = NULL;
! 					}
! 					for (i = end - 1; i >= start; i--)
! 					{
! 						struct sqlda_struct *tmp;
  
! 						/*
! 						 * Build a new sqlda structure. 
! 						 */
! 						tmp = ecpg_build_native_sqlda(stmt->lineno, stmt->results, i, stmt->compat);
! 
! 						if (!tmp)
  						{
  							/* cleanup all SQLDAs we created up */
+ 							while (sqlda_new)
+ 							{
+ 								tmp = sqlda_new->desc_next;
+ 								free(sqlda_new);
+ 								sqlda_new = tmp;
+ 							}
  							while (sqlda)
  							{
! 								tmp = sqlda->desc_next;
  								free(sqlda);
! 								sqlda = tmp;
  							}
  							*_sqlda = NULL;
  
*************** ecpg_execute(struct statement * stmt)
*** 1606,1621 ****
  						{
  							ecpg_log("ecpg_execute on line %d: new sqlda was built\n", stmt->lineno);
  
! 							*_sqlda = sqlda_new;
  
! 							ecpg_set_native_sqlda(stmt->lineno, _sqlda, results, i, stmt->compat);
  							ecpg_log("ecpg_execute on line %d: putting result (1 tuple %d fields) into sqlda descriptor\n",
! 									 stmt->lineno, PQnfields(results));
! 
! 							sqlda_new->desc_next = sqlda;
! 							sqlda = sqlda_new;
  						}
  					}
  				}
  
  				var = var->next;
--- 1779,1801 ----
  						{
  							ecpg_log("ecpg_execute on line %d: new sqlda was built\n", stmt->lineno);
  
! 							if (sqlda_new == NULL)
! 								sqlda_new = tmp;
! 							else
! 							{
! 								tmp->desc_next = sqlda_new;
! 								sqlda_new = tmp;
! 							}
  
! 							ecpg_set_native_sqlda(stmt->lineno, &tmp, stmt->results, i, stmt->compat);
  							ecpg_log("ecpg_execute on line %d: putting result (1 tuple %d fields) into sqlda descriptor\n",
! 									 stmt->lineno, PQnfields(stmt->results));
  						}
  					}
+ 					if (sqlda_last)
+ 						sqlda_last->desc_next = sqlda_new;
+ 					else
+ 						*_sqlda = sqlda_new;
  				}
  
  				var = var->next;
*************** ecpg_execute(struct statement * stmt)
*** 1625,1631 ****
  				{
  					if (var != NULL)
  					{
! 						status = ecpg_store_result(results, act_field, stmt, var);
  						var = var->next;
  					}
  					else if (!INFORMIX_MODE(stmt->compat))
--- 1805,1811 ----
  				{
  					if (var != NULL)
  					{
! 						status = ecpg_store_result(stmt->results, start, end, act_field, stmt, var, var_index);
  						var = var->next;
  					}
  					else if (!INFORMIX_MODE(stmt->compat))
*************** ecpg_execute(struct statement * stmt)
*** 1644,1652 ****
  			break;
  		case PGRES_COMMAND_OK:
  			status = true;
! 			cmdstat = PQcmdStatus(results);
! 			sqlca->sqlerrd[1] = PQoidValue(results);
! 			sqlca->sqlerrd[2] = atol(PQcmdTuples(results));
  			ecpg_log("ecpg_execute on line %d: OK: %s\n", stmt->lineno, cmdstat);
  			if (stmt->compat != ECPG_COMPAT_INFORMIX_SE &&
  				!sqlca->sqlerrd[2] &&
--- 1824,1832 ----
  			break;
  		case PGRES_COMMAND_OK:
  			status = true;
! 			cmdstat = PQcmdStatus(stmt->results);
! 			sqlca->sqlerrd[1] = PQoidValue(stmt->results);
! 			sqlca->sqlerrd[2] = atol(PQcmdTuples(stmt->results));
  			ecpg_log("ecpg_execute on line %d: OK: %s\n", stmt->lineno, cmdstat);
  			if (stmt->compat != ECPG_COMPAT_INFORMIX_SE &&
  				!sqlca->sqlerrd[2] &&
*************** ecpg_execute(struct statement * stmt)
*** 1670,1681 ****
  				if (res == -1)
  				{
  					/* COPY done */
! 					PQclear(results);
! 					results = PQgetResult(stmt->connection->connection);
! 					if (PQresultStatus(results) == PGRES_COMMAND_OK)
  						ecpg_log("ecpg_execute on line %d: got PGRES_COMMAND_OK after PGRES_COPY_OUT\n", stmt->lineno);
  					else
! 						ecpg_log("ecpg_execute on line %d: got error after PGRES_COPY_OUT: %s", stmt->lineno, PQresultErrorMessage(results));
  				}
  				break;
  			}
--- 1850,1861 ----
  				if (res == -1)
  				{
  					/* COPY done */
! 					PQclear(stmt->results);
! 					stmt->results = PQgetResult(stmt->connection->connection);
! 					if (PQresultStatus(stmt->results) == PGRES_COMMAND_OK)
  						ecpg_log("ecpg_execute on line %d: got PGRES_COMMAND_OK after PGRES_COPY_OUT\n", stmt->lineno);
  					else
! 						ecpg_log("ecpg_execute on line %d: got error after PGRES_COPY_OUT: %s", stmt->lineno, PQresultErrorMessage(stmt->results));
  				}
  				break;
  			}
*************** ecpg_execute(struct statement * stmt)
*** 1687,1698 ****
  			 */
  			ecpg_log("ecpg_execute on line %d: unknown execution status type\n",
  					 stmt->lineno);
! 			ecpg_raise_backend(stmt->lineno, results, stmt->connection->connection, stmt->compat);
  			status = false;
  			break;
  	}
! 	if (clear_result)
! 		PQclear(results);
  
  	/* check for asynchronous returns */
  	notify = PQnotifies(stmt->connection->connection);
--- 1867,1878 ----
  			 */
  			ecpg_log("ecpg_execute on line %d: unknown execution status type\n",
  					 stmt->lineno);
! 			ecpg_raise_backend(stmt->lineno, stmt->results, stmt->connection->connection, stmt->compat);
  			status = false;
  			break;
  	}
! 	if (!keep_result)
! 		PQclear(stmt->results);
  
  	/* check for asynchronous returns */
  	notify = PQnotifies(stmt->connection->connection);
*************** ecpg_execute(struct statement * stmt)
*** 1706,1752 ****
  	return status;
  }
  
  bool
! ECPGdo(const int lineno, const int compat, const int force_indicator, const char *connection_name, const bool questionmarks, const int st, const char *query,...)
  {
- 	va_list		args;
  	struct statement *stmt;
  	struct connection *con;
- 	bool		status;
- 	char	   *oldlocale;
  	enum ECPGttype type;
  	struct variable **list;
! 	enum ECPG_statement_type statement_type = (enum ECPG_statement_type) st;
! 	char	   *prepname;
! 
! 	if (!query)
! 	{
! 		ecpg_raise(lineno, ECPG_EMPTY, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, NULL);
! 		return (false);
! 	}
! 
! 	/* Make sure we do NOT honor the locale for numeric input/output */
! 	/* since the database wants the standard decimal point */
! 	oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL), lineno);
! 	setlocale(LC_NUMERIC, "C");
! 
! #ifdef ENABLE_THREAD_SAFETY
! 	ecpg_pthreads_init();
! #endif
! 
! 	con = ecpg_get_connection(connection_name);
! 
! 	if (!ecpg_init(con, connection_name, lineno))
! 	{
! 		setlocale(LC_NUMERIC, oldlocale);
! 		ecpg_free(oldlocale);
! 		return (false);
! 	}
  
! 	/* construct statement in our own structure */
! 	va_start(args, query);
  
! 	/*
  	 * create a list of variables The variables are listed with input
  	 * variables preceding outputvariables The end of each group is marked by
  	 * an end marker. per variable we list: type - as defined in ecpgtype.h
--- 1886,1914 ----
  	return status;
  }
  
+ /*
+  * ecpg_do_prologue
+  *	Initialize various infrastructure elements for executing the statement:
+  *	- create the statement structure
+  *	- set the C locale for communicating with the backend
+  *	- preprocess the variable list of input/output parameters into
+  *	  linked lists
+  */
  bool
! ecpg_do_prologue(int lineno, const int compat, const int force_indicator,
! 		const char *connection_name, const bool questionmarks,
! 		enum ECPG_statement_type statement_type, const char *query,
! 		va_list args, struct statement **stmt_out)
  {
  	struct statement *stmt;
  	struct connection *con;
  	enum ECPGttype type;
  	struct variable **list;
! 	char	*prepname;
  
! 	*stmt_out = NULL;
  
!     	/*
  	 * create a list of variables The variables are listed with input
  	 * variables preceding outputvariables The end of each group is marked by
  	 * an end marker. per variable we list: type - as defined in ecpgtype.h
*************** ECPGdo(const int lineno, const int compa
*** 1759,1770 ****
  	 * arraysize of indicator array ind_offset - indicator offset
  	 */
  	if (!(stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno)))
- 	{
- 		setlocale(LC_NUMERIC, oldlocale);
- 		ecpg_free(oldlocale);
- 		va_end(args);
  		return false;
! 	}
  
  	/*
  	 * If statement type is ECPGst_prepnormal we are supposed to prepare the
--- 1921,1943 ----
  	 * arraysize of indicator array ind_offset - indicator offset
  	 */
  	if (!(stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno)))
  		return false;
! 
! 	memset(stmt, 0, sizeof(struct statement));
! 
! 	/* Make sure we do NOT honor the locale for numeric input/output */
! 	/* since the database wants the standard decimal point */
! 	stmt->oldlocale = ecpg_strdup(setlocale(LC_NUMERIC, NULL), lineno);
! 	setlocale(LC_NUMERIC, "C");
! 
! #ifdef ENABLE_THREAD_SAFETY
! 	ecpg_pthreads_init();
! #endif
! 
! 	con = ecpg_get_connection(connection_name);
! 
! 	if (!ecpg_init(con, connection_name, lineno))
! 		return (false);
  
  	/*
  	 * If statement type is ECPGst_prepnormal we are supposed to prepare the
*************** ECPGdo(const int lineno, const int compa
*** 1773,1785 ****
  	if (statement_type == ECPGst_prepnormal)
  	{
  		if (!ecpg_auto_prepare(lineno, connection_name, compat, &prepname, query))
- 		{
- 			setlocale(LC_NUMERIC, oldlocale);
- 			ecpg_free(oldlocale);
- 			free_statement(stmt);
- 			va_end(args);
  			return (false);
- 		}
  
  		/*
  		 * statement is now prepared, so instead of the query we have to
--- 1946,1952 ----
*************** ECPGdo(const int lineno, const int compa
*** 1806,1815 ****
  		else
  		{
  			ecpg_raise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, stmt->command);
- 			setlocale(LC_NUMERIC, oldlocale);
- 			ecpg_free(oldlocale);
- 			free_statement(stmt);
- 			va_end(args);
  			return (false);
  		}
  	}
--- 1973,1978 ----
*************** ECPGdo(const int lineno, const int compa
*** 1835,1847 ****
  					   *ptr;
  
  			if (!(var = (struct variable *) ecpg_alloc(sizeof(struct variable), lineno)))
- 			{
- 				setlocale(LC_NUMERIC, oldlocale);
- 				ecpg_free(oldlocale);
- 				free_statement(stmt);
- 				va_end(args);
  				return false;
- 			}
  
  			var->type = type;
  			var->pointer = va_arg(args, char *);
--- 1998,2004 ----
*************** ECPGdo(const int lineno, const int compa
*** 1894,1903 ****
  			{
  				ecpg_raise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, NULL);
  				ecpg_free(var);
- 				setlocale(LC_NUMERIC, oldlocale);
- 				ecpg_free(oldlocale);
- 				free_statement(stmt);
- 				va_end(args);
  				return false;
  			}
  
--- 2051,2056 ----
*************** ECPGdo(const int lineno, const int compa
*** 1912,1940 ****
  		type = va_arg(args, enum ECPGttype);
  	}
  
- 	va_end(args);
- 
  	/* are we connected? */
  	if (con == NULL || con->connection == NULL)
  	{
- 		free_statement(stmt);
  		ecpg_raise(lineno, ECPG_NOT_CONN, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, (con) ? con->name : ecpg_gettext("<empty>"));
- 		setlocale(LC_NUMERIC, oldlocale);
- 		ecpg_free(oldlocale);
  		return false;
  	}
  
  	/* initialize auto_mem struct */
  	ecpg_clear_auto_mem();
  
! 	status = ecpg_execute(stmt);
  	free_statement(stmt);
  
! 	/* and reset locale value so our application is not affected */
! 	setlocale(LC_NUMERIC, oldlocale);
! 	ecpg_free(oldlocale);
  
! 	return (status);
  }
  
  /* old descriptor interface */
--- 2065,2178 ----
  		type = va_arg(args, enum ECPGttype);
  	}
  
  	/* are we connected? */
  	if (con == NULL || con->connection == NULL)
  	{
  		ecpg_raise(lineno, ECPG_NOT_CONN, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, (con) ? con->name : ecpg_gettext("<empty>"));
  		return false;
  	}
  
  	/* initialize auto_mem struct */
  	ecpg_clear_auto_mem();
  
! 	*stmt_out = stmt;
! 
! 	return (true);
! }
! 
! /*
!  * ecpg_do_epilogue
!  *	Restore the application locale and free the statement structure.
!  */
! void
! ecpg_do_epilogue(struct statement *stmt)
! {
! 	if (stmt == NULL)
! 		return;
! 
! 	/* reset locale value so our application is not affected */
! 	setlocale(LC_NUMERIC, stmt->oldlocale);
  	free_statement(stmt);
+ }
  
! /*
!  * Execute SQL statements in the backend.
!  *	The input/output parameters (variable argument list) are passed
!  *	in a va_list, so e.g. cursor functions can use this interface.
!  */
! bool
! ecpg_do(const int lineno, const int compat, const int force_indicator,
! 	const char *connection_name, const bool questionmarks,
! 	const int st, const char *query, va_list args)
! {
! 	struct statement *stmt;
  
! 	if (!query)
! 	{
! 		ecpg_raise(lineno, ECPG_EMPTY,
! 					ECPG_SQLSTATE_ECPG_INTERNAL_ERROR,
! 					NULL);
! 		return false;
! 	}
! 
! 	if (!ecpg_do_prologue(lineno, compat, force_indicator,
! 			connection_name, questionmarks,
! 			(enum ECPG_statement_type) st,
! 			query, args, &stmt))
! 	{
! 		ecpg_do_epilogue(stmt);
! 		return false;
! 	}
! 
! 	if (!ecpg_build_params(stmt))
! 	{
! 		ecpg_do_epilogue(stmt);
! 		return false;
! 	}
! 
! 	if (!ecpg_autostart_transaction(stmt))
! 	{
! 		ecpg_do_epilogue(stmt);
! 		return false;
! 	}
! 
! 	if (!ecpg_execute(stmt))
! 	{
! 		ecpg_do_epilogue(stmt);
! 		return false;
! 	}
! 
! 	if (!ecpg_process_output(stmt, 0, PQntuples(stmt->results),
! 							0, false, false))
! 	{
! 		ecpg_do_epilogue(stmt);
! 		return false;  
! 	}
! 
! 	ecpg_do_epilogue(stmt);
! 
! 	return true;
! }
! 
! /*
!  * Execute SQL statements in the backend.
!  * The input/output parameters are passed as variable-length argument list.
!  */
! bool
! ECPGdo(const int lineno, const int compat, const int force_indicator,
! 	const char *connection_name, const bool questionmarks,
! 	const int st, const char *query, ...)
! {
! 	va_list		args;
! 	bool		ret;
! 
! 	va_start(args, query);
! 	ret = ecpg_do(lineno, compat, force_indicator, connection_name,
! 							questionmarks,
! 							st, query, args);
! 	va_end(args);
! 
! 	return ret;
  }
  
  /* old descriptor interface */
diff -dcrpN postgresql.orig/src/interfaces/ecpg/ecpglib/exports.txt postgresql/src/interfaces/ecpg/ecpglib/exports.txt
*** postgresql.orig/src/interfaces/ecpg/ecpglib/exports.txt	2010-09-21 13:49:59.000000000 +0200
--- postgresql/src/interfaces/ecpg/ecpglib/exports.txt	2012-03-29 11:24:53.972185214 +0200
*************** ECPGget_PGconn			 26
*** 29,31 ****
--- 29,35 ----
  ECPGtransactionStatus		 27
  ECPGset_var			 28
  ECPGget_var			 29
+ ECPGopen			 30
+ ECPGfetch			 31
+ ECPGcursor_dml			 32
+ ECPGclose			 33
diff -dcrpN postgresql.orig/src/interfaces/ecpg/ecpglib/extern.h postgresql/src/interfaces/ecpg/ecpglib/extern.h
*** postgresql.orig/src/interfaces/ecpg/ecpglib/extern.h	2012-01-05 15:04:42.521294844 +0100
--- postgresql/src/interfaces/ecpg/ecpglib/extern.h	2012-03-29 23:18:01.949905202 +0200
*************** struct statement
*** 58,65 ****
  	bool		force_indicator;
  	enum ECPG_statement_type statement_type;
  	bool		questionmarks;
! 	struct variable *inlist;
! 	struct variable *outlist;
  };
  
  /* structure to store prepared statements for a connection */
--- 58,71 ----
  	bool		force_indicator;
  	enum ECPG_statement_type statement_type;
  	bool		questionmarks;
! 	struct variable *inlist;			/* transformed list of input vars */
! 	struct variable *outlist;			/* transformed list of output vars */
! 	char		*oldlocale;
! 	char		**dollarzero;			/* values for $0 placeholder vars */
! 	int		ndollarzero;			/* number of $0 placeholder vars */
! 	char		**param_values;			/* values for $N vars */
! 	int		nparams;			/* number of $N vars */
! 	PGresult	*results;			/* result for statement */
  };
  
  /* structure to store prepared statements for a connection */
*************** struct prepared_statement
*** 71,76 ****
--- 77,120 ----
  	struct prepared_statement *next;
  };
  
+ struct subxact_descriptor
+ {
+ 	char	    *name;
+ 	struct subxact_descriptor *next;
+ 	int		level;
+ };
+ 
+ struct cursor_descriptor {
+ 	struct cursor_descriptor *next;
+ 
+ 	char *name;
+ 
+ 	/*
+ 	 * The cursor was created in this level of * (sub-)transaction.
+ 	 * 0: WITH HOLD, committed successfully in a previous transaction
+ 	 * 1: cursor declared in the toplevel transaction
+ 	 * >=2: cursor declared in a named SAVEPOINT at the specified level
+ 	 */
+ 	int		subxact_level;
+ 	bool		with_hold;
+ 
+ 	PGresult   *res;		/* the cache */
+ 	/*
+ 	 * Readahead window size attempted to read at once. Actual number
+ 	 * of tuples in the cache is PQntuples(->res)
+ 	 */
+ 	long		ra_size;
+ 	/* the current cache content came from FETCH BACKWARD */
+ 	bool		backward;
+ 	/* Position of the first tuple in the cache, 1-based */
+ 	int64		cache_start_pos;
+ 	/* positions known by the application */
+ 	bool		atstart;	/* cursor is before the first tuple */
+ 	bool		atend;		/* cursor is after the last tuple */
+ 	int64		pos;		/* cursor position in the application */
+ 	int64		backend_pos;	/* cursor position in the backend */
+ };
+ 
  /* structure to store connections */
  struct connection
  {
*************** struct connection
*** 79,84 ****
--- 123,130 ----
  	bool		autocommit;
  	struct ECPGtype_information_cache *cache_head;
  	struct prepared_statement *prep_stmts;
+ 	struct subxact_descriptor *subxact_desc;
+ 	struct cursor_descriptor *cursor_desc;
  	struct connection *next;
  };
  
*************** extern struct var_list *ivlist;
*** 135,141 ****
  /* Returns a pointer to a string containing a simple type name. */
  void		ecpg_add_mem(void *ptr, int lineno);
  
! bool ecpg_get_data(const PGresult *, int, int, int, enum ECPGttype type,
  			  enum ECPGttype, char *, char *, long, long, long,
  			  enum ARRAY_TYPE, enum COMPAT_MODE, bool);
  
--- 181,187 ----
  /* Returns a pointer to a string containing a simple type name. */
  void		ecpg_add_mem(void *ptr, int lineno);
  
! bool ecpg_get_data(const PGresult *, int, int, int, int, enum ECPGttype type,
  			  enum ECPGttype, char *, char *, long, long, long,
  			  enum ARRAY_TYPE, enum COMPAT_MODE, bool);
  
*************** struct descriptor *ecpg_find_desc(int li
*** 161,169 ****
  struct prepared_statement *ecpg_find_prepared_statement(const char *,
  						  struct connection *, struct prepared_statement **);
  
! bool ecpg_store_result(const PGresult *results, int act_field,
! 				  const struct statement * stmt, struct variable * var);
  bool		ecpg_store_input(const int, const bool, const struct variable *, char **, bool);
  
  bool		ecpg_check_PQresult(PGresult *, int, PGconn *, enum COMPAT_MODE);
  void		ecpg_raise(int line, int code, const char *sqlstate, const char *str);
--- 207,224 ----
  struct prepared_statement *ecpg_find_prepared_statement(const char *,
  						  struct connection *, struct prepared_statement **);
  
! bool ecpg_store_result(const PGresult *results, int start, int end, int act_field,
! 				  const struct statement * stmt, struct variable * var, int var_index);
  bool		ecpg_store_input(const int, const bool, const struct variable *, char **, bool);
+ bool		ecpg_do_prologue(int, const int, const int, const char *, const bool,
+ 				  enum ECPG_statement_type, const char *, va_list, struct statement **);
+ bool		ecpg_build_params(struct statement *);
+ bool		ecpg_autostart_transaction(struct statement * stmt);
+ bool		ecpg_execute(struct statement * stmt);
+ bool		ecpg_process_output(struct statement *, int, int, int, bool, bool);
+ void		ecpg_free_params(struct statement *, bool);
+ void		ecpg_do_epilogue(struct statement *);
+ bool		ecpg_do(const int, const int, const int, const char *, const bool, const int, const char *, va_list);
  
  bool		ecpg_check_PQresult(PGresult *, int, PGconn *, enum COMPAT_MODE);
  void		ecpg_raise(int line, int code, const char *sqlstate, const char *str);
*************** void		ecpg_set_compat_sqlda(int, struct
*** 179,184 ****
--- 234,241 ----
  struct sqlda_struct *ecpg_build_native_sqlda(int, PGresult *, int, enum COMPAT_MODE);
  void		ecpg_set_native_sqlda(int, struct sqlda_struct **, const PGresult *, int, enum COMPAT_MODE);
  
+ void		ecpg_commit_cursors(int lineno, struct connection * conn, bool rollback, int level);
+ 
  /* SQLSTATE values generated or processed by ecpglib (intentionally
   * not exported -- users should refer to the codes directly) */
  
diff -dcrpN postgresql.orig/src/interfaces/ecpg/ecpglib/Makefile postgresql/src/interfaces/ecpg/ecpglib/Makefile
*** postgresql.orig/src/interfaces/ecpg/ecpglib/Makefile	2012-01-02 12:35:11.648178348 +0100
--- postgresql/src/interfaces/ecpg/ecpglib/Makefile	2012-03-29 11:24:53.973185220 +0200
*************** override CFLAGS += $(PTHREAD_CFLAGS)
*** 25,31 ****
  LIBS := $(filter-out -lpgport, $(LIBS))
  
  OBJS= execute.o typename.o descriptor.o sqlda.o data.o error.o prepare.o memory.o \
! 	connect.o misc.o path.o pgstrcasecmp.o \
  	$(filter snprintf.o strlcpy.o win32setlocale.o, $(LIBOBJS))
  
  # thread.c is needed only for non-WIN32 implementation of path.c
--- 25,31 ----
  LIBS := $(filter-out -lpgport, $(LIBS))
  
  OBJS= execute.o typename.o descriptor.o sqlda.o data.o error.o prepare.o memory.o \
! 	connect.o misc.o path.o pgstrcasecmp.o cursor.o \
  	$(filter snprintf.o strlcpy.o win32setlocale.o, $(LIBOBJS))
  
  # thread.c is needed only for non-WIN32 implementation of path.c
diff -dcrpN postgresql.orig/src/interfaces/ecpg/ecpglib/misc.c postgresql/src/interfaces/ecpg/ecpglib/misc.c
*** postgresql.orig/src/interfaces/ecpg/ecpglib/misc.c	2012-03-09 09:26:27.593365975 +0100
--- postgresql/src/interfaces/ecpg/ecpglib/misc.c	2012-03-29 11:24:53.976185236 +0200
*************** ECPGtransactionStatus(const char *connec
*** 187,212 ****
  }
  
  bool
! ECPGtrans(int lineno, const char *connection_name, const char *transaction)
  {
  	PGresult   *res;
  	struct connection *con = ecpg_get_connection(connection_name);
  
  	if (!ecpg_init(con, connection_name, lineno))
  		return (false);
  
! 	ecpg_log("ECPGtrans on line %d: action \"%s\"; connection \"%s\"\n", lineno, transaction, con ? con->name : "null");
  
  	/* if we have no connection we just simulate the command */
  	if (con && con->connection)
  	{
  		/*
  		 * If we got a transaction command but have no open transaction, we
  		 * have to start one, unless we are in autocommit, where the
! 		 * developers have to take care themselves. However, if the command is
  		 * a begin statement, we just execute it once.
  		 */
! 		if (PQtransactionStatus(con->connection) == PQTRANS_IDLE && !con->autocommit && strncmp(transaction, "begin", 5) != 0 && strncmp(transaction, "start", 5) != 0)
  		{
  			res = PQexec(con->connection, "begin transaction");
  			if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
--- 187,228 ----
  }
  
  bool
! ECPGtrans(int lineno, const char *connection_name, const char *transaction,
! 					const bool prepared,
! 					const bool begin,
! 					const bool rollback,
! 					const char *savepoint_name)
  {
  	PGresult   *res;
  	struct connection *con = ecpg_get_connection(connection_name);
+ 	int		level;
  
  	if (!ecpg_init(con, connection_name, lineno))
  		return (false);
  
! 	ecpg_log("ECPGtrans on line %d: action \"%s\"; connection \"%s\"\n",
! 						lineno, transaction,
! 						con ? con->name : "null");
  
  	/* if we have no connection we just simulate the command */
  	if (con && con->connection)
  	{
+ 		struct subxact_descriptor *desc, *oldptr;
+ 
  		/*
  		 * If we got a transaction command but have no open transaction, we
  		 * have to start one, unless we are in autocommit, where the
! 		 * developers have to take care themselves. Or the transaction
! 		 * statement is COMMIT/ROLLBACK PREPARED, these must be executed
! 		 * outside of a transaction. However, if the command is
  		 * a begin statement, we just execute it once.
  		 */
! 		if (PQtransactionStatus(con->connection) == PQTRANS_IDLE &&
! 			!con->autocommit &&
! 			/* exclude BEGIN */
! 			!(!prepared && begin && savepoint_name == NULL) &&
! 			/* exclude COMMIT/ROLLBACK PREPARED */
! 			!(prepared && !begin))
  		{
  			res = PQexec(con->connection, "begin transaction");
  			if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
*************** ECPGtrans(int lineno, const char *connec
*** 218,223 ****
--- 234,306 ----
  		if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
  			return FALSE;
  		PQclear(res);
+ 
+ 		/*
+ 		 * We keep track of subtransactions to be able to correctly
+ 		 * account for transactional cursors as well.
+ 		 */
+ 		if (!prepared && savepoint_name)
+ 		{
+ 			if (begin)
+ 			{
+ 				/* SAVEPOINT nnn */
+ 				oldptr = con->subxact_desc;
+ 				desc = (struct subxact_descriptor *)
+ 					ecpg_alloc(sizeof(struct subxact_descriptor),
+ 										lineno);
+ 				desc->level = (oldptr ? oldptr->level + 1 : 2);
+ 				desc->name = ecpg_strdup(savepoint_name, lineno);
+ 				desc->next = oldptr;
+ 				con->subxact_desc = desc;
+ 			}
+ 			else
+ 			{
+ 				/* ROLLBACK TO / RELEASE SAVEPOINT nnn */
+ 				struct subxact_descriptor *desc, *next;
+ 
+ 				desc = con->subxact_desc;
+ 				while (desc)
+ 				{
+ 					if (strcmp(desc->name, savepoint_name) == 0)
+ 						break;
+ 					next = desc->next;
+ 					ecpg_free(desc->name);
+ 					ecpg_free(desc);
+ 					desc = next;
+ 				}
+ 				/*
+ 				 * The above PQexec() already succeeded for
+ 				 * th named subtransaction, so the name
+ 				 * exists and "desc" cannot be NULL.
+ 				 */
+ 				next = desc->next;
+ 				level = desc->level;
+ 				ecpg_free(desc->name);
+ 				ecpg_free(desc);
+ 				con->subxact_desc = next;
+ 
+ 				ecpg_commit_cursors(lineno, con, rollback, level);
+ 			}
+ 		}
+ 		/* Toplevel COMMIT / ROLLBACK */
+ 		else if (!prepared && savepoint_name == NULL && !begin)
+ 		{
+ 			struct subxact_descriptor *desc, *next;
+ 			desc = con->subxact_desc;
+ 			while (desc)
+ 			{
+ 				next = desc->next;
+ 				ecpg_free(desc->name);
+ 				ecpg_free(desc);
+ 				desc = next;
+ 			}
+ 
+ 			/* COMMIT during PQTRANS_INERROR also counts as ROLLBACK */
+ 			ecpg_commit_cursors(lineno, con,
+ 				rollback ||
+ 					(PQtransactionStatus(con->connection) == PQTRANS_INERROR),
+ 				1);
+ 		}
  	}
  
  	return true;
diff -dcrpN postgresql.orig/src/interfaces/ecpg/ecpglib/sqlda.c postgresql/src/interfaces/ecpg/ecpglib/sqlda.c
*** postgresql.orig/src/interfaces/ecpg/ecpglib/sqlda.c	2011-12-04 18:54:54.362894118 +0100
--- postgresql/src/interfaces/ecpg/ecpglib/sqlda.c	2012-03-29 11:24:53.977185241 +0200
*************** ecpg_set_compat_sqlda(int lineno, struct
*** 393,399 ****
  		if (!isnull)
  		{
  			if (set_data)
! 				ecpg_get_data(res, row, i, lineno,
  							  sqlda->sqlvar[i].sqltype, ECPGt_NO_INDICATOR,
  							  sqlda->sqlvar[i].sqldata, NULL, 0, 0, 0,
  							  ECPG_ARRAY_NONE, compat, false);
--- 393,399 ----
  		if (!isnull)
  		{
  			if (set_data)
! 				ecpg_get_data(res, 0, row, i, lineno,
  							  sqlda->sqlvar[i].sqltype, ECPGt_NO_INDICATOR,
  							  sqlda->sqlvar[i].sqldata, NULL, 0, 0, 0,
  							  ECPG_ARRAY_NONE, compat, false);
*************** ecpg_set_native_sqlda(int lineno, struct
*** 578,584 ****
  		if (!isnull)
  		{
  			if (set_data)
! 				ecpg_get_data(res, row, i, lineno,
  							  sqlda->sqlvar[i].sqltype, ECPGt_NO_INDICATOR,
  							  sqlda->sqlvar[i].sqldata, NULL, 0, 0, 0,
  							  ECPG_ARRAY_NONE, compat, false);
--- 578,584 ----
  		if (!isnull)
  		{
  			if (set_data)
! 				ecpg_get_data(res, 0, row, i, lineno,
  							  sqlda->sqlvar[i].sqltype, ECPGt_NO_INDICATOR,
  							  sqlda->sqlvar[i].sqldata, NULL, 0, 0, 0,
  							  ECPG_ARRAY_NONE, compat, false);
diff -dcrpN postgresql.orig/src/interfaces/ecpg/include/ecpgerrno.h postgresql/src/interfaces/ecpg/include/ecpgerrno.h
*** postgresql.orig/src/interfaces/ecpg/include/ecpgerrno.h	2010-09-21 13:49:59.000000000 +0200
--- postgresql/src/interfaces/ecpg/include/ecpgerrno.h	2012-03-29 11:24:53.977185241 +0200
***************
*** 37,42 ****
--- 37,43 ----
  #define ECPG_NOT_CONN			-221
  
  #define ECPG_INVALID_STMT		-230
+ #define ECPG_INVALID_CURSOR		-231
  
  /* dynamic SQL related */
  #define ECPG_UNKNOWN_DESCRIPTOR		-240
diff -dcrpN postgresql.orig/src/interfaces/ecpg/include/ecpglib.h postgresql/src/interfaces/ecpg/include/ecpglib.h
*** postgresql.orig/src/interfaces/ecpg/include/ecpglib.h	2011-03-29 12:28:41.821555437 +0200
--- postgresql/src/interfaces/ecpg/include/ecpglib.h	2012-03-29 11:24:53.978185246 +0200
*************** bool		ECPGsetcommit(int, const char *, c
*** 52,58 ****
  bool		ECPGsetconn(int, const char *);
  bool		ECPGconnect(int, int, const char *, const char *, const char *, const char *, int);
  bool		ECPGdo(const int, const int, const int, const char *, const bool, const int, const char *,...);
! bool		ECPGtrans(int, const char *, const char *);
  bool		ECPGdisconnect(int, const char *);
  bool		ECPGprepare(int, const char *, const bool, const char *, const char *);
  bool		ECPGdeallocate(int, int, const char *, const char *);
--- 52,58 ----
  bool		ECPGsetconn(int, const char *);
  bool		ECPGconnect(int, int, const char *, const char *, const char *, const char *, int);
  bool		ECPGdo(const int, const int, const int, const char *, const bool, const int, const char *,...);
! bool		ECPGtrans(int, const char *, const char *, const bool, const bool, const bool, const char *);
  bool		ECPGdisconnect(int, const char *);
  bool		ECPGprepare(int, const char *, const bool, const char *, const char *);
  bool		ECPGdeallocate(int, int, const char *, const char *);
*************** PGTransactionStatusType ECPGtransactionS
*** 63,68 ****
--- 63,80 ----
  
  char	   *ECPGerrmsg(void);
  
+ /* Cursor functions */
+ bool		ECPGopen(const int, const int, const int, const char *, const bool,
+ 				const long, const bool, const bool, const bool,
+ 				const char *, const int, const char *, ...);
+ bool		ECPGfetch(const int, const int, const int, const char *, const bool,
+ 				const char *, enum ECPG_cursor_direction,
+ 				const char *, const int, const char *, ...);
+ bool		ECPGcursor_dml(const int, const int, const int, const char *, const bool,
+ 				const char *, const int, const char *, ...);
+ bool		ECPGclose(const int, const int, const int, const char *, const bool,
+ 				const char *, const int, const char *, ...);
+ 
   /* print an error message */
  void		sqlprint(void);
  
diff -dcrpN postgresql.orig/src/interfaces/ecpg/include/ecpgtype.h postgresql/src/interfaces/ecpg/include/ecpgtype.h
*** postgresql.orig/src/interfaces/ecpg/include/ecpgtype.h	2010-09-21 13:49:59.000000000 +0200
--- postgresql/src/interfaces/ecpg/include/ecpgtype.h	2012-03-29 11:24:53.978185246 +0200
*************** enum ECPG_statement_type
*** 99,104 ****
--- 99,112 ----
  	ECPGst_prepnormal
  };
  
+ enum ECPG_cursor_direction
+ {
+ 	ECPGc_absolute,
+ 	ECPGc_relative,
+ 	ECPGc_forward, 
+ 	ECPGc_backward 
+ };
+ 
  #ifdef __cplusplus
  }
  #endif
diff -dcrpN postgresql.orig/src/interfaces/ecpg/preproc/check_rules.pl postgresql/src/interfaces/ecpg/preproc/check_rules.pl
*** postgresql.orig/src/interfaces/ecpg/preproc/check_rules.pl	2012-01-02 12:35:11.648178348 +0100
--- postgresql/src/interfaces/ecpg/preproc/check_rules.pl	2012-03-29 19:43:50.151260714 +0200
*************** my %replace_line = (
*** 43,49 ****
  		'CREATE OptTemp TABLE create_as_target AS EXECUTE prepared_name execute_param_clause',
  
  	'PrepareStmtPREPAREnameprep_type_clauseASPreparableStmt' =>
! 		'PREPARE prepared_name prep_type_clause AS PreparableStmt'
  );
  
  my $block        = '';
--- 43,52 ----
  		'CREATE OptTemp TABLE create_as_target AS EXECUTE prepared_name execute_param_clause',
  
  	'PrepareStmtPREPAREnameprep_type_clauseASPreparableStmt' =>
! 		'PREPARE prepared_name prep_type_clause AS PreparableStmt',
! 
! 	'DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectStmt' =>
! 		'DECLARE cursor_name cursor_options opt_readahead CURSOR opt_hold FOR SelectStmt'
  );
  
  my $block        = '';
diff -dcrpN postgresql.orig/src/interfaces/ecpg/preproc/ecpg.addons postgresql/src/interfaces/ecpg/preproc/ecpg.addons
*** postgresql.orig/src/interfaces/ecpg/preproc/ecpg.addons	2011-12-28 13:34:48.507381487 +0100
--- postgresql/src/interfaces/ecpg/preproc/ecpg.addons	2012-03-29 19:46:44.592167662 +0200
*************** ECPG: stmtClosePortalStmt block
*** 15,21 ****
  			}
  		}
  
! 		output_statement($1, 0, ECPGst_normal);
  	}
  ECPG: stmtDeallocateStmt block
  	{
--- 15,24 ----
  			}
  		}
  
! 		if (current_cursor_readahead)
! 			output_close_statement($1, 0, ECPGst_normal);
! 		else
! 			output_statement($1, 0, ECPGst_normal);
  	}
  ECPG: stmtDeallocateStmt block
  	{
*************** ECPG: stmtDeallocateStmt block
*** 24,36 ****
  ECPG: stmtDeclareCursorStmt block
  	{ output_simple_statement($1); }
  ECPG: stmtDiscardStmt block
- ECPG: stmtFetchStmt block
  	{ output_statement($1, 1, ECPGst_normal); }
! ECPG: stmtDeleteStmt block
  ECPG: stmtInsertStmt block
  ECPG: stmtSelectStmt block
- ECPG: stmtUpdateStmt block
  	{ output_statement($1, 1, ECPGst_prepnormal); }
  ECPG: stmtExecuteStmt block
  	{ output_statement($1, 1, ECPGst_execute); }
  ECPG: stmtPrepareStmt block
--- 27,51 ----
  ECPG: stmtDeclareCursorStmt block
  	{ output_simple_statement($1); }
  ECPG: stmtDiscardStmt block
  	{ output_statement($1, 1, ECPGst_normal); }
! ECPG: stmtFetchStmt block
! 	{
! 		if (current_cursor_readahead)
! 			output_fetch_statement($1, 1, ECPGst_normal);
! 		else
! 			output_statement($1, 1, ECPGst_normal);
! 	}
  ECPG: stmtInsertStmt block
  ECPG: stmtSelectStmt block
  	{ output_statement($1, 1, ECPGst_prepnormal); }
+ ECPG: stmtDeleteStmt block
+ ECPG: stmtUpdateStmt block
+ 	{
+ 		if (current_cursor)
+ 			output_cursor_dml_statement($1, 1, ECPGst_prepnormal);
+ 		else
+ 			output_statement($1, 1, ECPGst_prepnormal);
+ 	}
  ECPG: stmtExecuteStmt block
  	{ output_statement($1, 1, ECPGst_execute); }
  ECPG: stmtPrepareStmt block
*************** ECPG: stmtPrepareStmt block
*** 42,51 ****
  	}
  ECPG: stmtTransactionStmt block
  	{
! 		fprintf(yyout, "{ ECPGtrans(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1);
  		whenever_action(2);
  		free($1);
  	}
  ECPG: stmtViewStmt rule
  	| ECPGAllocateDescr
  	{
--- 57,149 ----
  	}
  ECPG: stmtTransactionStmt block
  	{
! 		char *tr_name;
! 
! 		if (transact_name)
! 		{
! 			tr_name = mm_alloc(4 + strlen(transact_name));
! 			sprintf(tr_name, "\"%s\"", transact_name);
! 		}
! 		else
! 			tr_name = mm_strdup("NULL");
! 
! 		fprintf(yyout, "{ ECPGtrans(__LINE__, %s, \"%s\", %d, %d, %d, %s);",
! 					connection ? connection : "NULL",
! 					$1,
! 					transact_prepared ? 1 : 0,
! 					transact_start ? 1 : 0,
! 					transact_rollback ? 1 : 0,
! 					tr_name);
! 		free(tr_name);
! 		free(transact_name);
! 		transact_name = NULL;
  		whenever_action(2);
  		free($1);
  	}
+ ECPG: TransactionStmtABORT_Popt_transaction addon
+ ECPG: TransactionStmtROLLBACKopt_transaction addon
+ 		transact_prepared = false;
+ 		transact_start = false;
+ 		transact_rollback = true;
+ 		transact_name = NULL;
+ ECPG: TransactionStmtBEGIN_Popt_transactiontransaction_mode_list_or_empty addon
+ ECPG: TransactionStmtSTARTTRANSACTIONtransaction_mode_list_or_empty addon
+ 		transact_prepared = false;
+ 		transact_start = true;
+ 		transact_rollback = false;
+ 		transact_name = NULL;
+ ECPG: TransactionStmtCOMMITopt_transaction addon
+ ECPG: TransactionStmtEND_Popt_transaction addon
+ 		transact_prepared = false;
+ 		transact_start = false;
+ 		transact_rollback = false;
+ 		transact_name = NULL;
+ ECPG: TransactionStmtSAVEPOINTColId addon
+ 		transact_prepared = false;
+ 		transact_start = true;
+ 		transact_rollback = false;
+ 		transact_name = mm_strdup($2);
+ ECPG: TransactionStmtRELEASESAVEPOINTColId addon
+ 		transact_prepared = false;
+ 		transact_start = false;
+ 		transact_rollback = false;
+ 		transact_name = mm_strdup($3);
+ ECPG: TransactionStmtRELEASEColId addon
+ 		transact_prepared = false;
+ 		transact_start = false;
+ 		transact_rollback = false;
+ 		transact_name = mm_strdup($2);
+ ECPG: TransactionStmtROLLBACKopt_transactionTOSAVEPOINTColId addon
+ 		transact_prepared = false;
+ 		transact_start = false;
+ 		transact_rollback = true;
+ 		transact_name = mm_strdup($5);
+ ECPG: TransactionStmtROLLBACKopt_transactionTOColId addon
+ 		transact_prepared = false;
+ 		transact_start = false;
+ 		transact_rollback = true;
+ 		transact_name = mm_strdup($4);
+ ECPG: TransactionStmtPREPARETRANSACTIONSconst addon
+ 		transact_prepared = true;
+ 		transact_start = true;
+ 		transact_rollback = false;
+ 		transact_name = NULL;
+ ECPG: TransactionStmtCOMMITPREPAREDSconst addon
+ 		transact_prepared = true;
+ 		transact_start = false;
+ 		transact_rollback = false;
+ 		transact_name = NULL;
+ ECPG: TransactionStmtROLLBACKPREPAREDSconst addon
+ 		transact_prepared = true;
+ 		transact_start = false;
+ 		transact_rollback = true;
+ 		transact_name = NULL;
+ ECPG: cursor_options addon
+ 	current_cursor_scroll = false;
+ ECPG: cursor_optionscursor_optionsNOSCROLL addon
+ 	current_cursor_scroll = false;
+ ECPG: cursor_optionscursor_optionsSCROLL addon
+ 	current_cursor_scroll = true;
  ECPG: stmtViewStmt rule
  	| ECPGAllocateDescr
  	{
*************** ECPG: stmtViewStmt rule
*** 132,138 ****
  		if ((ptr = add_additional_variables($1, true)) != NULL)
  		{
  			connection = ptr->connection ? mm_strdup(ptr->connection) : NULL;
! 			output_statement(mm_strdup(ptr->command), 0, ECPGst_normal);
  			ptr->opened = true;
  		}
  	}
--- 230,241 ----
  		if ((ptr = add_additional_variables($1, true)) != NULL)
  		{
  			connection = ptr->connection ? mm_strdup(ptr->connection) : NULL;
! 			if (current_cursor_readahead)
! 				output_open_statement(mm_strdup(ptr->command),
! 							ptr->fetch_readahead,
! 							0, ECPGst_normal);
! 			else
! 				output_statement(mm_strdup(ptr->command), 0, ECPGst_normal);
  			ptr->opened = true;
  		}
  	}
*************** ECPG: stmtViewStmt rule
*** 190,195 ****
--- 293,308 ----
  ECPG: where_or_current_clauseWHERECURRENT_POFcursor_name block
  	{
  		char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4;
+ 		struct cursor *ptr;
+ 
+ 		for (ptr = cur; ptr != NULL; ptr = ptr->next)
+ 		{
+ 			if (strcmp(ptr->name, $4) == 0)
+ 				break;
+ 		}
+ 		if (!ptr)
+ 			mmerror(PARSE_ERROR, ET_FATAL, "cursor \"%s\" does not exist", $4);
+ 
  		$$ = cat_str(2,mm_strdup("where current of"), cursor_marker);
  	}
  ECPG: CopyStmtCOPYopt_binaryqualified_nameopt_column_listopt_oidscopy_fromcopy_file_namecopy_delimiteropt_withcopy_options addon
*************** ECPG: var_valueNumericOnly addon
*** 210,240 ****
--- 323,399 ----
  		}
  ECPG: fetch_argscursor_name addon
  		add_additional_variables($1, false);
+ 		set_cursor_readahead($1);
  		if ($1[0] == ':')
  		{
  			free($1);
  			$1 = mm_strdup("$0");
  		}
+ 		current_cursor_direction = ECPGc_forward;
+ 		current_cursor_amount = mm_strdup("1");
  ECPG: fetch_argsfrom_incursor_name addon
  		add_additional_variables($2, false);
+ 		set_cursor_readahead($2);
  		if ($2[0] == ':')
  		{
  			free($2);
  			$2 = mm_strdup("$0");
  		}
+ 		current_cursor_direction = ECPGc_forward;
+ 		current_cursor_amount = mm_strdup("1");
  ECPG: fetch_argsNEXTopt_from_incursor_name addon
+ 		add_additional_variables($3, false);
+ 		set_cursor_readahead($3);
+ 		if ($3[0] == ':')
+ 		{
+ 			free($3);
+ 			$3 = mm_strdup("$0");
+ 		}
+ 		current_cursor_direction = ECPGc_forward;
+ 		current_cursor_amount = mm_strdup("1");
  ECPG: fetch_argsPRIORopt_from_incursor_name addon
+ 		add_additional_variables($3, false);
+ 		set_cursor_readahead($3);
+ 		if ($3[0] == ':')
+ 		{
+ 			free($3);
+ 			$3 = mm_strdup("$0");
+ 		}
+ 		current_cursor_direction = ECPGc_backward;
+ 		current_cursor_amount = mm_strdup("1"); 
  ECPG: fetch_argsFIRST_Popt_from_incursor_name addon
+ 		add_additional_variables($3, false);
+ 		set_cursor_readahead($3);
+ 		if ($3[0] == ':')
+ 		{
+ 			free($3);
+ 			$3 = mm_strdup("$0");
+ 		}
+ 		current_cursor_direction = ECPGc_absolute;
+ 		current_cursor_amount = mm_strdup("1");
  ECPG: fetch_argsLAST_Popt_from_incursor_name addon
+ 		add_additional_variables($3, false);
+ 		set_cursor_readahead($3);
+ 		if ($3[0] == ':')
+ 		{
+ 			free($3);
+ 			$3 = mm_strdup("$0");
+ 		}
+ 		current_cursor_direction = ECPGc_absolute;
+ 		current_cursor_amount = mm_strdup("-1");
  ECPG: fetch_argsALLopt_from_incursor_name addon
  		add_additional_variables($3, false);
+ 		set_cursor_readahead($3);
  		if ($3[0] == ':')
  		{
  			free($3);
  			$3 = mm_strdup("$0");
  		}
+ 		current_cursor_direction = ECPGc_forward;
+ 		current_cursor_amount = mm_strdup("all");
  ECPG: fetch_argsSignedIconstopt_from_incursor_name addon
  		add_additional_variables($3, false);
+ 		set_cursor_readahead($3);
  		if ($3[0] == ':')
  		{
  			free($3);
*************** ECPG: fetch_argsSignedIconstopt_from_inc
*** 245,263 ****
--- 404,479 ----
  			free($1);
  			$1 = mm_strdup("$0");
  		}
+ 		current_cursor_direction = ECPGc_forward;
+ 		current_cursor_amount = mm_strdup($1);
  ECPG: fetch_argsFORWARDALLopt_from_incursor_name addon
+ 		add_additional_variables($4, false);
+ 		set_cursor_readahead($4);
+ 		if ($4[0] == ':')
+ 		{
+ 			free($4);
+ 			$4 = mm_strdup("$0");
+ 		}
+ 		current_cursor_direction = ECPGc_forward;
+ 		current_cursor_amount = mm_strdup("all");
  ECPG: fetch_argsBACKWARDALLopt_from_incursor_name addon
  		add_additional_variables($4, false);
+ 		set_cursor_readahead($4);
  		if ($4[0] == ':')
  		{
  			free($4);
  			$4 = mm_strdup("$0");
  		}
+ 		current_cursor_direction = ECPGc_backward;
+ 		current_cursor_amount = mm_strdup("all");
  ECPG: fetch_argsABSOLUTE_PSignedIconstopt_from_incursor_name addon
+ 		add_additional_variables($4, false);
+ 		set_cursor_readahead($4);
+ 		if ($4[0] == ':')
+ 		{
+ 			free($4);
+ 			$4 = mm_strdup("$0");
+ 		}
+ 		if ($2[0] == '$')
+ 		{
+ 			free($2);
+ 			$2 = mm_strdup("$0");
+ 		}
+ 		current_cursor_direction = ECPGc_absolute;
+ 		current_cursor_amount = mm_strdup($2);
  ECPG: fetch_argsRELATIVE_PSignedIconstopt_from_incursor_name addon
+ 		add_additional_variables($4, false);
+ 		set_cursor_readahead($4);
+ 		if ($4[0] == ':')
+ 		{
+ 			free($4);
+ 			$4 = mm_strdup("$0");
+ 		}
+ 		if ($2[0] == '$')
+ 		{
+ 			free($2);
+ 			$2 = mm_strdup("$0");
+ 		}
+ 		current_cursor_direction = ECPGc_relative;
+ 		current_cursor_amount = mm_strdup($2);
  ECPG: fetch_argsFORWARDSignedIconstopt_from_incursor_name addon
+ 		add_additional_variables($4, false);
+ 		set_cursor_readahead($4);
+ 		if ($4[0] == ':')
+ 		{
+ 			free($4);
+ 			$4 = mm_strdup("$0");
+ 		}
+ 		if ($2[0] == '$')
+ 		{
+ 			free($2);
+ 			$2 = mm_strdup("$0");
+ 		}
+ 		current_cursor_direction = ECPGc_forward;
+ 		current_cursor_amount = mm_strdup($2);
  ECPG: fetch_argsBACKWARDSignedIconstopt_from_incursor_name addon
  		add_additional_variables($4, false);
+ 		set_cursor_readahead($4);
  		if ($4[0] == ':')
  		{
  			free($4);
*************** ECPG: fetch_argsBACKWARDSignedIconstopt_
*** 268,280 ****
  			free($2);
  			$2 = mm_strdup("$0");
  		}
! ECPG: cursor_namename rule
  	| char_civar
  		{
  			char *curname = mm_alloc(strlen($1) + 2);
  			sprintf(curname, ":%s", $1);
  			free($1);
  			$1 = curname;
  			$$ = $1;
  		}
  ECPG: PrepareStmtPREPAREprepared_nameprep_type_clauseASPreparableStmt block
--- 484,504 ----
  			free($2);
  			$2 = mm_strdup("$0");
  		}
! 		current_cursor_direction = ECPGc_backward;
! 		current_cursor_amount = mm_strdup($2);
! ECPG: cursor_namename block
! 		{
! 			current_cursor = mm_strdup($1);
! 			current_cursor_vartype = ECPGt_const;
! 			$$ = $1;
! 		}
  	| char_civar
  		{
  			char *curname = mm_alloc(strlen($1) + 2);
  			sprintf(curname, ":%s", $1);
  			free($1);
  			$1 = curname;
+ 			current_cursor = mm_strdup(curname);
  			$$ = $1;
  		}
  ECPG: PrepareStmtPREPAREprepared_nameprep_type_clauseASPreparableStmt block
*************** ECPG: PrepareStmtPREPAREprepared_namepre
*** 291,306 ****
  	}
  ECPG: ExecuteStmtEXECUTEprepared_nameexecute_param_clauseexecute_rest block
  	{ $$ = $2; }
! ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectStmt block
  	{
  		struct cursor *ptr, *this;
  		char *cursor_marker = $2[0] == ':' ? mm_strdup("$0") : mm_strdup($2);
  		char *comment, *c1, *c2;
- 		int (* strcmp_fn)(const char *, const char *) = ($2[0] == ':' ? strcmp : pg_strcasecmp);
  
  		for (ptr = cur; ptr != NULL; ptr = ptr->next)
  		{
! 			if (strcmp_fn($2, ptr->name) == 0)
  			{
  				if ($2[0] == ':')
  					mmerror(PARSE_ERROR, ET_ERROR, "using variable \"%s\" in different declare statements is not supported", $2+1);
--- 515,529 ----
  	}
  ECPG: ExecuteStmtEXECUTEprepared_nameexecute_param_clauseexecute_rest block
  	{ $$ = $2; }
! ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsopt_readaheadCURSORopt_holdFORSelectStmt block
  	{
  		struct cursor *ptr, *this;
  		char *cursor_marker = $2[0] == ':' ? mm_strdup("$0") : mm_strdup($2);
  		char *comment, *c1, *c2;
  
  		for (ptr = cur; ptr != NULL; ptr = ptr->next)
  		{
! 			if (cursor_strcmp(ptr->name, $2) == 0)
  			{
  				if ($2[0] == ':')
  					mmerror(PARSE_ERROR, ET_ERROR, "using variable \"%s\" in different declare statements is not supported", $2+1);
*************** ECPG: DeclareCursorStmtDECLAREcursor_nam
*** 313,322 ****
  
  		this->next = cur;
  		this->name = $2;
  		this->function = (current_function ? mm_strdup(current_function) : NULL);
  		this->connection = connection;
  		this->opened = false;
! 		this->command =  cat_str(7, mm_strdup("declare"), cursor_marker, $3, mm_strdup("cursor"), $5, mm_strdup("for"), $7);
  		this->argsinsert = argsinsert;
  		this->argsinsert_oos = NULL;
  		this->argsresult = argsresult;
--- 536,549 ----
  
  		this->next = cur;
  		this->name = $2;
+ 		this->vartype = current_cursor_vartype;
  		this->function = (current_function ? mm_strdup(current_function) : NULL);
  		this->connection = connection;
  		this->opened = false;
! 		this->fetch_readahead = atoi($4);
! 		this->scrollable = current_cursor_scroll;
! 		this->with_hold = (strncmp($6, "with ", 5) == 0);
! 		this->command =  cat_str(7, mm_strdup("declare"), cursor_marker, $3, mm_strdup("cursor"), $6, mm_strdup("for"), $8);
  		this->argsinsert = argsinsert;
  		this->argsinsert_oos = NULL;
  		this->argsresult = argsresult;
*************** ECPG: DeclareCursorStmtDECLAREcursor_nam
*** 343,348 ****
--- 570,578 ----
  ECPG: ClosePortalStmtCLOSEcursor_name block
  	{
  		char *cursor_marker = $2[0] == ':' ? mm_strdup("$0") : $2;
+ 		if (!(INFORMIX_MODE &&
+ 				pg_strcasecmp($2, "database") == 0))
+ 			set_cursor_readahead($2);
  		$$ = cat2_str(mm_strdup("close"), cursor_marker);
  	}
  ECPG: opt_hold block
*************** ECPG: FetchStmtMOVEfetch_args rule
*** 418,465 ****
--- 648,719 ----
  	{
  		char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3;
  		add_additional_variables($3, false);
+ 		set_cursor_readahead($3);
+ 		current_cursor_direction = ECPGc_forward;
+ 		current_cursor_amount = mm_strdup("1");
  		$$ = cat_str(2, mm_strdup("fetch forward"), cursor_marker);
  	}
  	| FETCH FORWARD from_in cursor_name opt_ecpg_fetch_into
  	{
  		char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4;
  		add_additional_variables($4, false);
+ 		set_cursor_readahead($4);
+ 		current_cursor_direction = ECPGc_forward;
+ 		current_cursor_amount = mm_strdup("1");
  		$$ = cat_str(2, mm_strdup("fetch forward from"), cursor_marker);
  	}
  	| FETCH BACKWARD cursor_name opt_ecpg_fetch_into
  	{
  		char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3;
  		add_additional_variables($3, false);
+ 		set_cursor_readahead($3);
+ 		current_cursor_direction = ECPGc_backward;
+ 		current_cursor_amount = mm_strdup("1");
  		$$ = cat_str(2, mm_strdup("fetch backward"), cursor_marker);
  	}
  	| FETCH BACKWARD from_in cursor_name opt_ecpg_fetch_into
  	{
  		char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4;
  		add_additional_variables($4, false);
+ 		set_cursor_readahead($4);
+ 		current_cursor_direction = ECPGc_backward;
+ 		current_cursor_amount = mm_strdup("1");
  		$$ = cat_str(2, mm_strdup("fetch backward from"), cursor_marker);
  	}
  	| MOVE FORWARD cursor_name
  	{
  		char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3;
  		add_additional_variables($3, false);
+ 		set_cursor_readahead($3);
+ 		current_cursor_direction = ECPGc_forward;
+ 		current_cursor_amount = mm_strdup("1");
  		$$ = cat_str(2, mm_strdup("move forward"), cursor_marker);
  	}
  	| MOVE FORWARD from_in cursor_name
  	{
  		char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4;
  		add_additional_variables($4, false);
+ 		set_cursor_readahead($4);
+ 		current_cursor_direction = ECPGc_forward;
+ 		current_cursor_amount = mm_strdup("1");
  		$$ = cat_str(2, mm_strdup("move forward from"), cursor_marker);
  	}
  	| MOVE BACKWARD cursor_name
  	{
  		char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3;
  		add_additional_variables($3, false);
+ 		set_cursor_readahead($3);
+ 		current_cursor_direction = ECPGc_backward;
+ 		current_cursor_amount = mm_strdup("1");
  		$$ = cat_str(2, mm_strdup("move backward"), cursor_marker);
  	}
  	| MOVE BACKWARD from_in cursor_name
  	{
  		char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4;
  		add_additional_variables($4, false);
+ 		set_cursor_readahead($4);
+ 		current_cursor_direction = ECPGc_backward;
+ 		current_cursor_amount = mm_strdup("1");
  		$$ = cat_str(2, mm_strdup("move backward from"), cursor_marker);
  	}
  ECPG: limit_clauseLIMITselect_limit_value','select_offset_value block
diff -dcrpN postgresql.orig/src/interfaces/ecpg/preproc/ecpg.c postgresql/src/interfaces/ecpg/preproc/ecpg.c
*** postgresql.orig/src/interfaces/ecpg/preproc/ecpg.c	2012-01-02 12:35:11.648178348 +0100
--- postgresql/src/interfaces/ecpg/preproc/ecpg.c	2012-03-29 23:22:33.871544093 +0200
***************
*** 6,11 ****
--- 6,12 ----
  #include "postgres_fe.h"
  
  #include <unistd.h>
+ #include <stdlib.h>
  #include <string.h>
  #include "getopt_long.h"
  
*************** bool		autocommit = false,
*** 18,24 ****
  			force_indicator = true,
  			questionmarks = false,
  			regression_mode = false,
! 			auto_prepare = false;
  
  char	   *output_filename;
  
--- 19,33 ----
  			force_indicator = true,
  			questionmarks = false,
  			regression_mode = false,
! 			auto_prepare = false,
! 			cursor_rssz = false;
! /*
!  * Values for fetch_readahead:
!  * 0:   Cursors are uncachable, cursor stmts go through ECPGdo.
!  * 1+:  Cursor stmts go through ECPGopen/ECPGfetch/ECPGclose
!  *      with the specified readahead window.
!  */
! long		fetch_readahead = 0; /* Disabled by default */
  
  char	   *output_filename;
  
*************** help(const char *progname)
*** 52,57 ****
--- 61,71 ----
  	printf(_("  -o OUTFILE     write result to OUTFILE\n"));
  	printf(_("  -r OPTION      specify run-time behavior; OPTION can be:\n"
  	 "                 \"no_indicator\", \"prepare\", \"questionmarks\"\n"));
+ 	printf(_("  -R NUMBER      cursor readahead window size for FETCH statements\n"
+ 	 "                 default 0 (disabled)\n"));
+ 	printf(_("  --detect-cursor-resultset-size\n"
+ 	 "                 opening a cursor detects and returns the number of rows\n"
+ 	 "                 in sqlca.sqlerrd[2]. Read the documentation before enabling it.\n"));
  	printf(_("  --regression   run in regression testing mode\n"));
  	printf(_("  -t             turn on autocommit of transactions\n"));
  	printf(_("  --help         show this help, then exit\n"));
*************** add_preprocessor_define(char *define)
*** 114,119 ****
--- 128,134 ----
  #define ECPG_GETOPT_LONG_HELP			1
  #define ECPG_GETOPT_LONG_VERSION		2
  #define ECPG_GETOPT_LONG_REGRESSION		3
+ #define	ECPG_GETOPT_LONG_CURSOR_RESULTSET_SIZE	4
  int
  main(int argc, char *const argv[])
  {
*************** main(int argc, char *const argv[])
*** 121,126 ****
--- 136,142 ----
  		{"help", no_argument, NULL, ECPG_GETOPT_LONG_HELP},
  		{"version", no_argument, NULL, ECPG_GETOPT_LONG_VERSION},
  		{"regression", no_argument, NULL, ECPG_GETOPT_LONG_REGRESSION},
+ 		{"detect-cursor-resultset-size", no_argument, NULL, ECPG_GETOPT_LONG_CURSOR_RESULTSET_SIZE},
  		{NULL, 0, NULL, 0}
  	};
  
*************** main(int argc, char *const argv[])
*** 131,136 ****
--- 147,153 ----
  				header_mode = false;
  	struct _include_path *ip;
  	const char *progname;
+ 	char	   *endptr;
  	char		my_exec_path[MAXPGPATH];
  	char		include_path[MAXPGPATH];
  
*************** main(int argc, char *const argv[])
*** 141,147 ****
  	find_my_exec(argv[0], my_exec_path);
  
  	output_filename = NULL;
! 	while ((c = getopt_long(argc, argv, "vcio:I:tD:dC:r:h?", ecpg_options, NULL)) != -1)
  	{
  		switch (c)
  		{
--- 158,164 ----
  	find_my_exec(argv[0], my_exec_path);
  
  	output_filename = NULL;
! 	while ((c = getopt_long(argc, argv, "vcio:I:tD:dC:r:R:h?", ecpg_options, NULL)) != -1)
  	{
  		switch (c)
  		{
*************** main(int argc, char *const argv[])
*** 235,240 ****
--- 252,274 ----
  					return ILLEGAL_OPTION;
  				}
  				break;
+ 			case 'R':
+ 				fetch_readahead = strtoul(optarg, &endptr, 10);
+ 				if (*endptr)
+ 				{
+ 					fprintf(stderr, _("%s is not an integer number\n"), optarg);
+ 					fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
+ 					return ILLEGAL_OPTION;
+ 				}
+ 				if (fetch_readahead < 0)
+ 				{
+ 					fprintf(stderr, _("-R argument cannot be negative\n"));
+ 					return ILLEGAL_OPTION;
+ 				}
+ 				break;
+ 			case ECPG_GETOPT_LONG_CURSOR_RESULTSET_SIZE:
+ 				cursor_rssz = true;
+ 				break;
  			case 'D':
  				add_preprocessor_define(optarg);
  				break;
diff -dcrpN postgresql.orig/src/interfaces/ecpg/preproc/ecpg.header postgresql/src/interfaces/ecpg/preproc/ecpg.header
*** postgresql.orig/src/interfaces/ecpg/preproc/ecpg.header	2012-01-04 17:43:33.230905075 +0100
--- postgresql/src/interfaces/ecpg/preproc/ecpg.header	2012-03-29 11:24:53.982185269 +0200
***************
*** 35,40 ****
--- 35,50 ----
  int struct_level = 0;
  int braces_open; /* brace level counter */
  char *current_function;
+ char *current_cursor = NULL;
+ long current_cursor_readahead = 0;
+ enum ECPGttype current_cursor_vartype;
+ enum ECPG_cursor_direction current_cursor_direction;
+ bool current_cursor_scroll;
+ char *current_cursor_amount = NULL;
+ bool transact_prepared;
+ bool transact_start;
+ bool transact_rollback;
+ char *transact_name = NULL;
  int ecpg_internal_var = 0;
  char	*connection = NULL;
  char	*input_filename = NULL;
*************** mmerror(int error_code, enum errortype t
*** 111,116 ****
--- 121,172 ----
  }
  
  /*
+  * Compare two cursor names.
+  * If both the stored (in a descriptor) and the new cursor name are quoted,
+  * or the new cursor is a dynamic one (:variable) use case-sensitive comparison.
+  * Otherwise case-insensitive. Both pointers must be valid.
+  */
+ static int
+ cursor_strcmp(const char *stored, const char *searched)
+ {
+ 	if (stored[0] == '"' && searched[0] == '"')
+ 		return strcmp(stored, searched);
+ 	else if (searched[0] == ':')
+ 		return strcmp(stored, searched);
+ 	else
+ 		return pg_strcasecmp(stored, searched);
+ }
+ 
+ /*
+  * Find a cursor
+  */
+ struct cursor *
+ get_cursor(const char *curname)
+ {
+ 	struct cursor *ptr;
+ 
+ 	for (ptr = cur; ptr != NULL; ptr = ptr->next)
+ 	{
+ 		if (cursor_strcmp(ptr->name, curname) == 0)
+ 			break;
+ 	}
+ 	if (!ptr)
+ 		mmerror(PARSE_ERROR, ET_FATAL, "cursor \"%s\" does not exist (get_cursor)", curname);
+ 	return ptr;
+ }
+ 
+ /*
+  * Set current_cursor_readahead based on the current cursor.
+  * Doesn't return if the cursor is not declared.
+  */
+ static void
+ set_cursor_readahead(const char *curname)
+ {
+ 	struct cursor *ptr = get_cursor(curname);
+ 	current_cursor_readahead = ptr->fetch_readahead;
+ }
+ 
+ /*
   * string concatenation
   */
  
*************** add_additional_variables(char *name, boo
*** 477,487 ****
  {
  	struct cursor *ptr;
  	struct arguments *p;
- 	int (* strcmp_fn)(const char *, const char *) = (name[0] == ':' ? strcmp : pg_strcasecmp);
  
  	for (ptr = cur; ptr != NULL; ptr=ptr->next)
  	{
! 		if (strcmp_fn(ptr->name, name) == 0)
  			break;
  	}
  
--- 533,542 ----
  {
  	struct cursor *ptr;
  	struct arguments *p;
  
  	for (ptr = cur; ptr != NULL; ptr=ptr->next)
  	{
! 		if (cursor_strcmp(ptr->name, name) == 0)
  			break;
  	}
  
diff -dcrpN postgresql.orig/src/interfaces/ecpg/preproc/ecpg_keywords.c postgresql/src/interfaces/ecpg/preproc/ecpg_keywords.c
*** postgresql.orig/src/interfaces/ecpg/preproc/ecpg_keywords.c	2010-09-21 13:49:59.000000000 +0200
--- postgresql/src/interfaces/ecpg/preproc/ecpg_keywords.c	2012-03-29 11:24:53.983185274 +0200
*************** static const ScanKeyword ScanECPGKeyword
*** 56,61 ****
--- 56,62 ----
  	{"octet_length", SQL_OCTET_LENGTH, 0},
  	{"open", SQL_OPEN, 0},
  	{"output", SQL_OUTPUT, 0},
+ 	{"readahead", SQL_READAHEAD, 0},
  	{"reference", SQL_REFERENCE, 0},
  	{"returned_length", SQL_RETURNED_LENGTH, 0},
  	{"returned_octet_length", SQL_RETURNED_OCTET_LENGTH, 0},
diff -dcrpN postgresql.orig/src/interfaces/ecpg/preproc/ecpg.tokens postgresql/src/interfaces/ecpg/preproc/ecpg.tokens
*** postgresql.orig/src/interfaces/ecpg/preproc/ecpg.tokens	2010-11-24 20:16:22.770628769 +0100
--- postgresql/src/interfaces/ecpg/preproc/ecpg.tokens	2012-03-29 11:24:53.983185274 +0200
***************
*** 10,16 ****
                  SQL_FREE SQL_GET SQL_GO SQL_GOTO SQL_IDENTIFIED
                  SQL_INDICATOR SQL_KEY_MEMBER SQL_LENGTH
                  SQL_LONG SQL_NULLABLE SQL_OCTET_LENGTH
!                 SQL_OPEN SQL_OUTPUT SQL_REFERENCE
                  SQL_RETURNED_LENGTH SQL_RETURNED_OCTET_LENGTH SQL_SCALE
                  SQL_SECTION SQL_SHORT SQL_SIGNED SQL_SQL SQL_SQLERROR
                  SQL_SQLPRINT SQL_SQLWARNING SQL_START SQL_STOP
--- 10,16 ----
                  SQL_FREE SQL_GET SQL_GO SQL_GOTO SQL_IDENTIFIED
                  SQL_INDICATOR SQL_KEY_MEMBER SQL_LENGTH
                  SQL_LONG SQL_NULLABLE SQL_OCTET_LENGTH
!                 SQL_OPEN SQL_OUTPUT SQL_READAHEAD SQL_REFERENCE
                  SQL_RETURNED_LENGTH SQL_RETURNED_OCTET_LENGTH SQL_SCALE
                  SQL_SECTION SQL_SHORT SQL_SIGNED SQL_SQL SQL_SQLERROR
                  SQL_SQLPRINT SQL_SQLWARNING SQL_START SQL_STOP
diff -dcrpN postgresql.orig/src/interfaces/ecpg/preproc/ecpg.trailer postgresql/src/interfaces/ecpg/preproc/ecpg.trailer
*** postgresql.orig/src/interfaces/ecpg/preproc/ecpg.trailer	2012-02-14 18:01:58.920669718 +0100
--- postgresql/src/interfaces/ecpg/preproc/ecpg.trailer	2012-03-29 21:04:28.610954890 +0200
*************** prepared_name: name
*** 287,304 ****
   * Declare a prepared cursor. The syntax is different from the standard
   * declare statement, so we create a new rule.
   */
! ECPGCursorStmt:  DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_name
  		{
  			struct cursor *ptr, *this;
  			char *cursor_marker = $2[0] == ':' ? mm_strdup("$0") : mm_strdup($2);
- 			int (* strcmp_fn)(const char *, const char *) = ($2[0] == ':' ? strcmp : pg_strcasecmp);
  			struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
  			const char *con = connection ? connection : "NULL";
  			char *comment;
  
  			for (ptr = cur; ptr != NULL; ptr = ptr->next)
  			{
! 				if (strcmp_fn($2, ptr->name) == 0)
  				{
  					/* re-definition is a bug */
  					if ($2[0] == ':')
--- 287,303 ----
   * Declare a prepared cursor. The syntax is different from the standard
   * declare statement, so we create a new rule.
   */
! ECPGCursorStmt:  DECLARE cursor_name cursor_options opt_readahead CURSOR opt_hold FOR prepared_name
  		{
  			struct cursor *ptr, *this;
  			char *cursor_marker = $2[0] == ':' ? mm_strdup("$0") : mm_strdup($2);
  			struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
  			const char *con = connection ? connection : "NULL";
  			char *comment;
  
  			for (ptr = cur; ptr != NULL; ptr = ptr->next)
  			{
! 				if (cursor_strcmp(ptr->name, $2) == 0)
  				{
  					/* re-definition is a bug */
  					if ($2[0] == ':')
*************** ECPGCursorStmt:  DECLARE cursor_name cur
*** 313,329 ****
  			/* initial definition */
  			this->next = cur;
  			this->name = $2;
  			this->function = (current_function ? mm_strdup(current_function) : NULL);
  			this->connection = connection;
! 			this->command =  cat_str(6, mm_strdup("declare"), cursor_marker, $3, mm_strdup("cursor"), $5, mm_strdup("for $1"));
  			this->argsresult = NULL;
  			this->argsresult_oos = NULL;
  
  			thisquery->type = &ecpg_query;
  			thisquery->brace_level = 0;
  			thisquery->next = NULL;
! 			thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(, , __LINE__)") + strlen(con) + strlen($7));
! 			sprintf(thisquery->name, "ECPGprepared_statement(%s, %s, __LINE__)", con, $7);
  
  			this->argsinsert = NULL;
  			this->argsinsert_oos = NULL;
--- 312,333 ----
  			/* initial definition */
  			this->next = cur;
  			this->name = $2;
+ 			this->vartype = current_cursor_vartype;
  			this->function = (current_function ? mm_strdup(current_function) : NULL);
  			this->connection = connection;
! 			this->opened = false;
! 			this->fetch_readahead = atoi($4);
! 			this->scrollable = current_cursor_scroll;
! 			this->with_hold = (strncmp($6, "with ", 5) == 0);
! 			this->command =  cat_str(6, mm_strdup("declare"), cursor_marker, $3, mm_strdup("cursor"), $6, mm_strdup("for $1"));
  			this->argsresult = NULL;
  			this->argsresult_oos = NULL;
  
  			thisquery->type = &ecpg_query;
  			thisquery->brace_level = 0;
  			thisquery->next = NULL;
! 			thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(, , __LINE__)") + strlen(con) + strlen($8));
! 			sprintf(thisquery->name, "ECPGprepared_statement(%s, %s, __LINE__)", con, $8);
  
  			this->argsinsert = NULL;
  			this->argsinsert_oos = NULL;
*************** ECPGCursorStmt:  DECLARE cursor_name cur
*** 348,353 ****
--- 352,367 ----
  		}
  		;
  
+ opt_readahead:	SQL_READAHEAD Iconst				{ $$ = $2; }
+ 		| NO SQL_READAHEAD				{ $$ = mm_strdup("0"); }
+ 		| /* EMPTY */
+ 		{
+ 			char	val[16];
+ 			sprintf(val, "%ld", fetch_readahead);
+ 			$$ = mm_strdup(val);
+ 		}
+ 		;
+ 
  ECPGExecuteImmediateStmt: EXECUTE IMMEDIATE execstring
  			{
  			  /* execute immediate means prepare the statement and
*************** ECPGFree:	SQL_FREE cursor_name	{ $$ = $2
*** 986,991 ****
--- 1000,1006 ----
   */
  ECPGOpen: SQL_OPEN cursor_name opt_ecpg_using
  		{
+ 			set_cursor_readahead($2);
  			if ($2[0] == ':')
  				remove_variable_from_list(&argsinsert, find_variable($2 + 1));
  			$$ = $2;
*************** char_civar: char_variable
*** 1657,1663 ****
--- 1672,1683 ----
  			char *ptr = strstr($1, ".arr");
  
  			if (ptr) /* varchar, we need the struct name here, not the struct element */
+ 			{
+ 				current_cursor_vartype = ECPGt_varchar;
  				*ptr = '\0';
+ 			}
+ 			else
+ 				current_cursor_vartype = ECPGt_char;
  			add_variable_to_head(&argsinsert, find_variable($1), &no_indicator);
  			$$ = $1;
  		}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/preproc/ecpg.type postgresql/src/interfaces/ecpg/preproc/ecpg.type
*** postgresql.orig/src/interfaces/ecpg/preproc/ecpg.type	2010-11-24 20:16:22.771628701 +0100
--- postgresql/src/interfaces/ecpg/preproc/ecpg.type	2012-03-29 19:44:03.035330117 +0200
***************
*** 85,90 ****
--- 85,91 ----
  %type <str> opt_output
  %type <str> opt_pointer
  %type <str> opt_port
+ %type <str> opt_readahead
  %type <str> opt_reference
  %type <str> opt_scale
  %type <str> opt_server
diff -dcrpN postgresql.orig/src/interfaces/ecpg/preproc/extern.h postgresql/src/interfaces/ecpg/preproc/extern.h
*** postgresql.orig/src/interfaces/ecpg/preproc/extern.h	2011-04-29 10:11:35.883844760 +0200
--- postgresql/src/interfaces/ecpg/preproc/extern.h	2012-03-29 11:24:53.986185290 +0200
*************** extern bool autocommit,
*** 24,35 ****
  			force_indicator,
  			questionmarks,
  			regression_mode,
! 			auto_prepare;
  extern int	braces_open,
  			ret_value,
  			struct_level,
  			ecpg_internal_var;
  extern char *current_function;
  extern char *descriptor_index;
  extern char *descriptor_name;
  extern char *connection;
--- 24,42 ----
  			force_indicator,
  			questionmarks,
  			regression_mode,
! 			auto_prepare,
! 			cursor_rssz;
! extern long	fetch_readahead;
  extern int	braces_open,
  			ret_value,
  			struct_level,
  			ecpg_internal_var;
  extern char *current_function;
+ extern char *current_cursor;  
+ extern enum ECPGttype current_cursor_vartype;
+ extern long current_cursor_readahead;
+ extern enum ECPG_cursor_direction current_cursor_direction;
+ extern char *current_cursor_amount;
  extern char *descriptor_index;
  extern char *descriptor_name;
  extern char *connection;
*************** extern void output_statement(char *, int
*** 67,72 ****
--- 74,83 ----
  extern void output_prepare_statement(char *, char *);
  extern void output_deallocate_prepare_statement(char *);
  extern void output_simple_statement(char *);
+ extern void output_open_statement(char *, int, int, enum ECPG_statement_type);
+ extern void output_fetch_statement(char *, int, enum ECPG_statement_type);
+ extern void output_cursor_dml_statement(char *, int, enum ECPG_statement_type);
+ extern void output_close_statement(char *, int, enum ECPG_statement_type);
  extern char *hashline_number(void);
  extern int	base_yyparse(void);
  extern int	base_yylex(void);
*************** extern void scanner_init(const char *);
*** 106,111 ****
--- 117,123 ----
  extern void parser_init(void);
  extern void scanner_finish(void);
  extern int	filtered_base_yylex(void);
+ extern struct cursor *get_cursor(const char *);
  
  /* return codes */
  
diff -dcrpN postgresql.orig/src/interfaces/ecpg/preproc/output.c postgresql/src/interfaces/ecpg/preproc/output.c
*** postgresql.orig/src/interfaces/ecpg/preproc/output.c	2011-12-28 13:34:48.508381419 +0100
--- postgresql/src/interfaces/ecpg/preproc/output.c	2012-03-29 19:48:36.064744861 +0200
*************** static char *ecpg_statement_type_name[]
*** 112,121 ****
  	"ECPGst_prepnormal"
  };
  
! void
! output_statement(char *stmt, int whenever_mode, enum ECPG_statement_type st)
  {
- 	fprintf(yyout, "{ ECPGdo(__LINE__, %d, %d, %s, %d, ", compat, force_indicator, connection ? connection : "NULL", questionmarks);
  	if (st == ECPGst_execute || st == ECPGst_exec_immediate)
  	{
  		fprintf(yyout, "%s, %s, ", ecpg_statement_type_name[st], stmt);
--- 112,146 ----
  	"ECPGst_prepnormal"
  };
  
! static char *ecpg_cursor_direction_name[] = {
! 	"ECPGc_absolute",
! 	"ECPGc_relative",
! 	"ECPGc_forward", 
! 	"ECPGc_backward" 
! };
! 
! static void output_cursor_name(struct cursor *ptr)
! {
! 	if (current_cursor[0] == ':')
! 	{
! 		char *curname = current_cursor + 1;
! 
! 		fputs(curname, yyout);
! 		if (ptr->vartype == ECPGt_varchar)
! 			fputs(".arr", yyout);
! 		fputs(", ", yyout);
! 	}
! 	else
! 	{
! 		fputs("\"", yyout);
! 		output_escaped_str(current_cursor, false);
! 		fputs("\", ", yyout);
! 	}
! }
! 
! static void
! output_statement_epilogue(char *stmt, int whenever_mode, enum ECPG_statement_type st)
  {
  	if (st == ECPGst_execute || st == ECPGst_exec_immediate)
  	{
  		fprintf(yyout, "%s, %s, ", ecpg_statement_type_name[st], stmt);
*************** output_statement(char *stmt, int wheneve
*** 140,150 ****
--- 165,187 ----
  
  	whenever_action(whenever_mode | 2);
  	free(stmt);
+ 	if (current_cursor)
+ 	{
+ 		free(current_cursor);
+ 		current_cursor = NULL;
+ 	}
  	if (connection != NULL)
  		free(connection);
  }
  
  void
+ output_statement(char *stmt, int whenever_mode, enum ECPG_statement_type st)
+ {
+ 	fprintf(yyout, "{ ECPGdo(__LINE__, %d, %d, %s, %d, ", compat, force_indicator, connection ? connection : "NULL", questionmarks);
+ 	output_statement_epilogue(stmt, whenever_mode, st);
+ }
+ 
+ void
  output_prepare_statement(char *name, char *stmt)
  {
  	fprintf(yyout, "{ ECPGprepare(__LINE__, %s, %d, ", connection ? connection : "NULL", questionmarks);
*************** output_deallocate_prepare_statement(char
*** 178,183 ****
--- 215,284 ----
  		free(connection);
  }
  
+ void
+ output_open_statement(char *stmt, int fetch_readahead, int whenever_mode, enum ECPG_statement_type st)
+ {
+ 	struct cursor *ptr = get_cursor(current_cursor);
+ 
+ 	fprintf(yyout, "{ ECPGopen(__LINE__, %d, %d, %s, %d, %ld, %d, %d, %d, ",
+ 			compat,
+ 			force_indicator,
+ 			connection ? connection : "NULL",
+ 			questionmarks,
+ 			ptr->fetch_readahead,
+ 			cursor_rssz,
+ 			ptr->scrollable,
+ 			ptr->with_hold);
+ 	output_cursor_name(ptr);
+ 	output_statement_epilogue(stmt, whenever_mode, st);
+ }
+ 
+ void
+ output_fetch_statement(char *stmt, int whenever_mode, enum ECPG_statement_type st)
+ {
+ 	char	*amount = mm_alloc(strlen(current_cursor_amount) + 3);
+ 
+ 	if (!amount)
+ 		return;
+ 
+ 	sprintf(amount, "\"%s\"", current_cursor_amount);
+ 	fprintf(yyout, "{ ECPGfetch(__LINE__, %d, %d, %s, %d, ", 
+ 			compat,
+ 			force_indicator,
+ 			connection ? connection : "NULL",
+ 			questionmarks);
+ 	output_cursor_name(get_cursor(current_cursor));
+ 	fprintf(yyout, "%s, %s, ",
+ 			ecpg_cursor_direction_name[current_cursor_direction],
+ 			amount);
+ 	output_statement_epilogue(stmt, whenever_mode, st);
+ 	free(amount);
+ }
+ 
+ void
+ output_cursor_dml_statement(char *stmt, int whenever_mode, enum ECPG_statement_type st)
+ {
+ 	fprintf(yyout, "{ ECPGcursor_dml(__LINE__, %d, %d, %s, %d, ",
+ 			compat,
+ 			force_indicator,
+ 			connection ? connection : "NULL",
+ 			questionmarks);
+ 	output_cursor_name(get_cursor(current_cursor));
+ 	output_statement_epilogue(stmt, whenever_mode, st);
+ }
+ 
+ void
+ output_close_statement(char *stmt, int whenever_mode, enum ECPG_statement_type st)
+ {
+ 	fprintf(yyout, "{ ECPGclose(__LINE__, %d, %d, %s, %d, ",
+ 			compat,
+ 			force_indicator,
+ 			connection ? connection : "NULL",
+ 			questionmarks);
+ 	output_cursor_name(get_cursor(current_cursor));
+ 	output_statement_epilogue(stmt, whenever_mode, st);
+ }
+ 
  static void
  output_escaped_str(char *str, bool quoted)
  {
diff -dcrpN postgresql.orig/src/interfaces/ecpg/preproc/parse.pl postgresql/src/interfaces/ecpg/preproc/parse.pl
*** postgresql.orig/src/interfaces/ecpg/preproc/parse.pl	2012-01-02 12:35:11.649178290 +0100
--- postgresql/src/interfaces/ecpg/preproc/parse.pl	2012-03-29 19:43:37.391191991 +0200
*************** my %replace_line = (
*** 90,95 ****
--- 90,97 ----
  	'fetch_argsFORWARDopt_from_incursor_name'      => 'ignore',
  	'fetch_argsBACKWARDopt_from_incursor_name'     => 'ignore',
  	"opt_array_boundsopt_array_bounds'['Iconst']'" => 'ignore',
+ 	'DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectStmt' =>
+ 			'DECLARE cursor_name cursor_options opt_readahead CURSOR opt_hold FOR SelectStmt',
  	'VariableShowStmtSHOWvar_name'                 => 'SHOW var_name ecpg_into',
  	'VariableShowStmtSHOWTIMEZONE' => 'SHOW TIME ZONE ecpg_into',
  	'VariableShowStmtSHOWTRANSACTIONISOLATIONLEVEL' => 'SHOW TRANSACTION ISOLATION LEVEL ecpg_into',
diff -dcrpN postgresql.orig/src/interfaces/ecpg/preproc/type.h postgresql/src/interfaces/ecpg/preproc/type.h
*** postgresql.orig/src/interfaces/ecpg/preproc/type.h	2012-02-14 18:01:58.921669649 +0100
--- postgresql/src/interfaces/ecpg/preproc/type.h	2012-03-29 19:44:55.738605170 +0200
*************** struct _include_path
*** 125,134 ****
--- 125,138 ----
  struct cursor
  {
  	char	   *name;
+ 	enum ECPGttype vartype;
  	char	   *function;
  	char	   *command;
  	char	   *connection;
  	bool		opened;
+ 	bool		scrollable;
+ 	long		fetch_readahead;
+ 	bool		with_hold;
  	struct arguments *argsinsert;
  	struct arguments *argsinsert_oos;
  	struct arguments *argsresult;
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/ecpg_schedule postgresql/src/interfaces/ecpg/test/ecpg_schedule
*** postgresql.orig/src/interfaces/ecpg/test/ecpg_schedule	2010-09-21 13:50:00.000000000 +0200
--- postgresql/src/interfaces/ecpg/test/ecpg_schedule	2012-03-29 11:24:53.989185307 +0200
*************** test: preproc/array_of_struct
*** 20,25 ****
--- 20,26 ----
  test: preproc/autoprep
  test: preproc/comment
  test: preproc/cursor
+ test: preproc/cursor-readahead
  test: preproc/define
  test: preproc/init
  test: preproc/strings
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/ecpg_schedule_tcp postgresql/src/interfaces/ecpg/test/ecpg_schedule_tcp
*** postgresql.orig/src/interfaces/ecpg/test/ecpg_schedule_tcp	2010-09-21 13:50:00.000000000 +0200
--- postgresql/src/interfaces/ecpg/test/ecpg_schedule_tcp	2012-03-29 11:24:53.989185307 +0200
*************** test: preproc/array_of_struct
*** 20,25 ****
--- 20,26 ----
  test: preproc/autoprep
  test: preproc/comment
  test: preproc/cursor
+ test: preproc/cursor-readahead
  test: preproc/define
  test: preproc/init
  test: preproc/strings
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/compat_informix-describe.c postgresql/src/interfaces/ecpg/test/expected/compat_informix-describe.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/compat_informix-describe.c	2010-11-24 20:16:22.773628567 +0100
--- postgresql/src/interfaces/ecpg/test/expected/compat_informix-describe.c	2012-03-29 11:24:53.990185312 +0200
*************** if (sqlca.sqlcode < 0) exit (1);}
*** 135,141 ****
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 42 "describe.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
--- 135,141 ----
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 42 "describe.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
*************** if (sqlca.sqlcode < 0) exit (1);}
*** 448,454 ****
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 193 "describe.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
--- 448,454 ----
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 193 "describe.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/compat_informix-rnull.c postgresql/src/interfaces/ecpg/test/expected/compat_informix-rnull.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/compat_informix-rnull.c	2010-09-21 13:50:00.000000000 +0200
--- postgresql/src/interfaces/ecpg/test/expected/compat_informix-rnull.c	2012-03-29 11:24:53.994185333 +0200
*************** if (sqlca.sqlcode < 0) sqlprint ( );}
*** 111,117 ****
  if (sqlca.sqlcode < 0) sqlprint ( );}
  #line 33 "rnull.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 34 "rnull.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
--- 111,117 ----
  if (sqlca.sqlcode < 0) sqlprint ( );}
  #line 33 "rnull.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 34 "rnull.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
*************** if (sqlca.sqlcode < 0) sqlprint ( );}
*** 138,144 ****
  if (sqlca.sqlcode < 0) sqlprint ( );}
  #line 38 "rnull.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 39 "rnull.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
--- 138,144 ----
  if (sqlca.sqlcode < 0) sqlprint ( );}
  #line 38 "rnull.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 39 "rnull.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
*************** if (sqlca.sqlcode < 0) sqlprint ( );}
*** 182,188 ****
  if (sqlca.sqlcode < 0) sqlprint ( );}
  #line 54 "rnull.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 55 "rnull.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
--- 182,188 ----
  if (sqlca.sqlcode < 0) sqlprint ( );}
  #line 54 "rnull.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 55 "rnull.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
*************** if (sqlca.sqlcode < 0) sqlprint ( );}
*** 275,281 ****
  if (sqlca.sqlcode < 0) sqlprint ( );}
  #line 91 "rnull.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 92 "rnull.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
--- 275,281 ----
  if (sqlca.sqlcode < 0) sqlprint ( );}
  #line 91 "rnull.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 92 "rnull.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c postgresql/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c	2010-11-24 20:16:22.773628567 +0100
--- postgresql/src/interfaces/ecpg/test/expected/compat_informix-sqlda.c	2012-03-29 11:24:53.994185333 +0200
*************** if (sqlca.sqlcode < 0) exit (1);}
*** 216,222 ****
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 88 "sqlda.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
--- 216,222 ----
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 88 "sqlda.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
*************** if (sqlca.sqlcode < 0) exit (1);}
*** 473,479 ****
  	dump_sqlda(outp_sqlda);
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, "con2", "commit");
  #line 226 "sqlda.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
--- 473,479 ----
  	dump_sqlda(outp_sqlda);
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, "con2", "commit", 0, 0, 0, NULL);
  #line 226 "sqlda.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
*************** if (sqlca.sqlcode < 0) exit (1);}
*** 511,517 ****
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 244 "sqlda.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
--- 511,517 ----
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 244 "sqlda.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/compat_informix-test_informix2.c postgresql/src/interfaces/ecpg/test/expected/compat_informix-test_informix2.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/compat_informix-test_informix2.c	2010-11-24 20:16:22.773628567 +0100
--- postgresql/src/interfaces/ecpg/test/expected/compat_informix-test_informix2.c	2012-03-29 11:24:53.995185339 +0200
*************** static void sql_check(char *fn, char *ca
*** 114,120 ****
        printf("%s\n", errorstring);
  
        /* attempt a ROLLBACK */
!       { ECPGtrans(__LINE__, NULL, "rollback");}
  #line 27 "test_informix2.pgc"
  
  
--- 114,120 ----
        printf("%s\n", errorstring);
  
        /* attempt a ROLLBACK */
!       { ECPGtrans(__LINE__, NULL, "rollback", 0, 0, 1, NULL);}
  #line 27 "test_informix2.pgc"
  
  
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 245,251 ****
  
  	sql_check("main", "update", 0);
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 100 "test_informix2.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
--- 245,251 ----
  
  	sql_check("main", "update", 0);
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 100 "test_informix2.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 260,266 ****
  
  	sql_check("main", "drop", 0);
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 105 "test_informix2.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
--- 260,266 ----
  
  	sql_check("main", "drop", 0);
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 105 "test_informix2.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/compat_informix-test_informix.c postgresql/src/interfaces/ecpg/test/expected/compat_informix-test_informix.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/compat_informix-test_informix.c	2010-11-24 20:16:22.773628567 +0100
--- postgresql/src/interfaces/ecpg/test/expected/compat_informix-test_informix.c	2012-03-29 11:24:53.996185345 +0200
*************** if (sqlca.sqlcode < 0) dosqlprint ( );}
*** 80,86 ****
  if (sqlca.sqlcode < 0) dosqlprint ( );}
  #line 28 "test_informix.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 29 "test_informix.pgc"
  
  if (sqlca.sqlcode < 0) dosqlprint ( );}
--- 80,86 ----
  if (sqlca.sqlcode < 0) dosqlprint ( );}
  #line 28 "test_informix.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 29 "test_informix.pgc"
  
  if (sqlca.sqlcode < 0) dosqlprint ( );}
*************** if (sqlca.sqlcode < 0) dosqlprint ( );}
*** 95,101 ****
  #line 32 "test_informix.pgc"
  
  	printf("INSERT: %ld=%s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
! 	if (sqlca.sqlcode != 0) { ECPGtrans(__LINE__, NULL, "rollback");
  #line 34 "test_informix.pgc"
  
  if (sqlca.sqlcode < 0) dosqlprint ( );}
--- 95,101 ----
  #line 32 "test_informix.pgc"
  
  	printf("INSERT: %ld=%s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
! 	if (sqlca.sqlcode != 0) { ECPGtrans(__LINE__, NULL, "rollback", 0, 0, 1, NULL);
  #line 34 "test_informix.pgc"
  
  if (sqlca.sqlcode < 0) dosqlprint ( );}
*************** if (sqlca.sqlcode < 0) dosqlprint ( );}
*** 110,116 ****
  if (sqlca.sqlcode < 0) dosqlprint ( );}
  #line 36 "test_informix.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 37 "test_informix.pgc"
  
  if (sqlca.sqlcode < 0) dosqlprint ( );}
--- 110,116 ----
  if (sqlca.sqlcode < 0) dosqlprint ( );}
  #line 36 "test_informix.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 37 "test_informix.pgc"
  
  if (sqlca.sqlcode < 0) dosqlprint ( );}
*************** if (sqlca.sqlcode < 0) dosqlprint ( );}
*** 124,130 ****
  if (sqlca.sqlcode < 0) dosqlprint ( );}
  #line 40 "test_informix.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback");
  #line 41 "test_informix.pgc"
  
  if (sqlca.sqlcode < 0) dosqlprint ( );}
--- 124,130 ----
  if (sqlca.sqlcode < 0) dosqlprint ( );}
  #line 40 "test_informix.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback", 0, 0, 1, NULL);
  #line 41 "test_informix.pgc"
  
  if (sqlca.sqlcode < 0) dosqlprint ( );}
*************** if (sqlca.sqlcode < 0) dosqlprint ( );}
*** 139,145 ****
  #line 44 "test_informix.pgc"
  
  	printf("SELECT: %ld=%s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
! 	if (sqlca.sqlcode != 0) { ECPGtrans(__LINE__, NULL, "rollback");
  #line 46 "test_informix.pgc"
  
  if (sqlca.sqlcode < 0) dosqlprint ( );}
--- 139,145 ----
  #line 44 "test_informix.pgc"
  
  	printf("SELECT: %ld=%s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
! 	if (sqlca.sqlcode != 0) { ECPGtrans(__LINE__, NULL, "rollback", 0, 0, 1, NULL);
  #line 46 "test_informix.pgc"
  
  if (sqlca.sqlcode < 0) dosqlprint ( );}
*************** if (sqlca.sqlcode < 0) dosqlprint ( );}
*** 213,219 ****
  
  	printf("Does not exist: %ld\n", sqlca.sqlcode);
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 84 "test_informix.pgc"
  
  if (sqlca.sqlcode < 0) dosqlprint ( );}
--- 213,219 ----
  
  	printf("Does not exist: %ld\n", sqlca.sqlcode);
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 84 "test_informix.pgc"
  
  if (sqlca.sqlcode < 0) dosqlprint ( );}
*************** if (sqlca.sqlcode < 0) dosqlprint ( );}
*** 225,231 ****
  if (sqlca.sqlcode < 0) dosqlprint ( );}
  #line 85 "test_informix.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 86 "test_informix.pgc"
  
  if (sqlca.sqlcode < 0) dosqlprint ( );}
--- 225,231 ----
  if (sqlca.sqlcode < 0) dosqlprint ( );}
  #line 85 "test_informix.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 86 "test_informix.pgc"
  
  if (sqlca.sqlcode < 0) dosqlprint ( );}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c postgresql/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c	2010-11-24 20:16:22.774628500 +0100
--- postgresql/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test.c	2012-03-29 11:24:53.997185351 +0200
*************** if (sqlca.sqlcode < 0) sqlprint ( );}
*** 430,436 ****
  	printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
  	free(text);
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback");
  #line 359 "dt_test.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
--- 430,436 ----
  	printf("timestamp_defmt_asc(%s, %s) = %s, error: %d\n", in, fmt, text, i);
  	free(text);
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback", 0, 0, 1, NULL);
  #line 359 "dt_test.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-nan_test.c postgresql/src/interfaces/ecpg/test/expected/pgtypeslib-nan_test.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-nan_test.c	2010-09-21 13:50:00.000000000 +0200
--- postgresql/src/interfaces/ecpg/test/expected/pgtypeslib-nan_test.c	2012-03-29 11:24:53.997185351 +0200
*************** if (sqlca.sqlcode < 0) sqlprint ( );}
*** 254,260 ****
  
  	PGTYPESnumeric_free(num);
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback");
  #line 88 "nan_test.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
--- 254,260 ----
  
  	PGTYPESnumeric_free(num);
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback", 0, 0, 1, NULL);
  #line 88 "nan_test.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-num_test.c postgresql/src/interfaces/ecpg/test/expected/pgtypeslib-num_test.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/pgtypeslib-num_test.c	2010-09-21 13:50:00.000000000 +0200
--- postgresql/src/interfaces/ecpg/test/expected/pgtypeslib-num_test.c	2012-03-29 11:24:53.998185356 +0200
*************** if (sqlca.sqlcode < 0) sqlprint ( );}
*** 144,150 ****
  	PGTYPESnumeric_free(value2);
  	PGTYPESnumeric_free(res);
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback");
  #line 93 "num_test.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
--- 144,150 ----
  	PGTYPESnumeric_free(value2);
  	PGTYPESnumeric_free(res);
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback", 0, 0, 1, NULL);
  #line 93 "num_test.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/preproc-cursor.c postgresql/src/interfaces/ecpg/test/expected/preproc-cursor.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/preproc-cursor.c	2012-02-14 18:01:58.922669580 +0100
--- postgresql/src/interfaces/ecpg/test/expected/preproc-cursor.c	2012-03-29 11:24:53.999185361 +0200
*************** if (sqlca.sqlcode < 0) exit (1);}
*** 165,177 ****
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, "test1", "commit");
  #line 57 "cursor.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
  #line 57 "cursor.pgc"
  
! 	{ ECPGtrans(__LINE__, "test2", "commit");
  #line 58 "cursor.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
--- 165,177 ----
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, "test1", "commit", 0, 0, 0, NULL);
  #line 57 "cursor.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
  #line 57 "cursor.pgc"
  
! 	{ ECPGtrans(__LINE__, "test2", "commit", 0, 0, 0, NULL);
  #line 58 "cursor.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
*************** if (sqlca.sqlcode < 0) exit (1);}
*** 815,821 ****
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, "test1", "commit");
  #line 250 "cursor.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
--- 815,821 ----
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, "test1", "commit", 0, 0, 0, NULL);
  #line 250 "cursor.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/preproc-cursor-readahead.c postgresql/src/interfaces/ecpg/test/expected/preproc-cursor-readahead.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/preproc-cursor-readahead.c	1970-01-01 01:00:00.000000000 +0100
--- postgresql/src/interfaces/ecpg/test/expected/preproc-cursor-readahead.c	2012-03-29 11:24:54.002185376 +0200
***************
*** 0 ****
--- 1,775 ----
+ /* Processed by ecpg (regression mode) */
+ /* These include files are added by the preprocessor */
+ #include <ecpglib.h>
+ #include <ecpgerrno.h>
+ #include <sqlca.h>
+ /* End of automatic include section */
+ #define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+ 
+ #line 1 "cursor-readahead.pgc"
+ #include <stdio.h>
+ #include <stdlib.h>
+ 
+ /* test automatic prepare for all statements */
+ 
+ #line 1 "regression.h"
+ 
+ 
+ 
+ 
+ 
+ 
+ #line 5 "cursor-readahead.pgc"
+ 
+ 
+ 
+ #line 1 "sqlda.h"
+ #ifndef ECPG_SQLDA_H
+ #define ECPG_SQLDA_H
+ 
+ #ifdef _ECPG_INFORMIX_H
+ 
+ #include "sqlda-compat.h"
+ typedef struct sqlvar_compat	sqlvar_t;
+ typedef struct sqlda_compat	sqlda_t;
+ 
+ #else
+ 
+ #include "sqlda-native.h"
+ typedef struct sqlvar_struct	sqlvar_t;
+ typedef struct sqlda_struct	sqlda_t;
+ 
+ #endif
+ 
+ #endif /* ECPG_SQLDA_H */
+ 
+ #line 7 "cursor-readahead.pgc"
+ 
+ 
+ /* exec sql whenever sqlerror  sqlprint ; */
+ #line 9 "cursor-readahead.pgc"
+ 
+ /* exec sql whenever sql_warning  sqlprint ; */
+ #line 10 "cursor-readahead.pgc"
+ 
+ 
+ #define MAXID	(513)
+ 
+ int main(void)
+ {
+ 	int	counts[2] = { 1, 5 };
+ 	/* exec sql begin declare section */
+ 		
+ 		
+ 		     
+ 		  
+ 		
+ 		
+ 	
+ #line 18 "cursor-readahead.pgc"
+  char * curname ;
+  
+ #line 19 "cursor-readahead.pgc"
+  int maxid ;
+  
+ #line 20 "cursor-readahead.pgc"
+  int i , j , count , rows , rows0 , sqlcode ;
+  
+ #line 21 "cursor-readahead.pgc"
+  int id , id1 [ 5 ] , id2 [ 5 ] ;
+  
+ #line 22 "cursor-readahead.pgc"
+  char t0 [ 5 ] [ 64 ] ;
+  
+ #line 23 "cursor-readahead.pgc"
+  char t [ 64 ] ;
+ /* exec sql end declare section */
+ #line 24 "cursor-readahead.pgc"
+ 
+ 	sqlda_t	*sqlda;
+ 
+ 	/*
+ 	 * Intentionally don't create a 2MB stderr file for this test.
+ 	 * Enable it manually if you're interested in it.
+ 	 */
+ #if 0
+ 	ECPGdebug(1, stderr);
+ #else
+ 	fprintf(stderr, "Dummy non-empty error output\n");
+ #endif
+ 
+ 	{ ECPGconnect(__LINE__, 0, "regress1" , NULL, NULL , NULL, 0); 
+ #line 37 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 37 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 37 "cursor-readahead.pgc"
+ 
+ 
+ 	{ ECPGtrans(__LINE__, NULL, "begin", 0, 1, 0, NULL);
+ #line 39 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 39 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 39 "cursor-readahead.pgc"
+ 
+ 
+ 	maxid = MAXID;
+ 
+ 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table ra_test ( id integer primary key , t text )", ECPGt_EOIT, ECPGt_EORT);
+ #line 43 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 43 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 43 "cursor-readahead.pgc"
+ 
+ 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into ra_test select i . i , 'a' from generate_series ( 1 , $1  ) as i", 
+ 	ECPGt_int,&(maxid),(long)1,(long)1,sizeof(int), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+ #line 44 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 44 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 44 "cursor-readahead.pgc"
+ 
+ 
+ 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
+ #line 46 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 46 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 46 "cursor-readahead.pgc"
+ 
+ 
+ 	{ ECPGtrans(__LINE__, NULL, "begin", 0, 1, 0, NULL);
+ #line 48 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 48 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 48 "cursor-readahead.pgc"
+ 
+ 
+ 	curname = "xx";
+ 	ECPGset_var( 0, &( curname ), __LINE__);\
+  /* declare $0 scroll cursor for select * from ra_test order by id */
+ #line 51 "cursor-readahead.pgc"
+ 
+ 	/* declare xcur scroll cursor for select * from ra_test order by id */
+ #line 52 "cursor-readahead.pgc"
+ 
+ 
+ 	for (i = 0; i < 2; i++)
+ 	{
+ 		count = counts[i];
+ 
+ 		{ ECPGopen(__LINE__, 0, 1, NULL, 0, 256, 0, 1, 0, "xcur", ECPGst_normal, "declare xcur scroll cursor for select * from ra_test order by id", ECPGt_EOIT, ECPGt_EORT);
+ #line 58 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 58 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 58 "cursor-readahead.pgc"
+ 
+ 		{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "declare $0 scroll cursor for select * from ra_test order by id", 
+ 	ECPGt_char,&(curname),(long)0,(long)1,(1)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+ #line 59 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 59 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 59 "cursor-readahead.pgc"
+ 
+ 
+ 		id = 0;
+ 		while (1)
+ 		{
+ 			for (j = 0; j < count; j++)
+ 			{
+ 				id1[j] = -1;
+ 				id2[j] = -1;
+ 			}
+ 
+ 			{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch $0 from $0", 
+ 	ECPGt_int,&(count),(long)1,(long)1,sizeof(int), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+ 	ECPGt_char,&(curname),(long)0,(long)1,(1)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
+ 	ECPGt_int,(id1),(long)1,(long)5,sizeof(int), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+ 	ECPGt_char,(t0),(long)64,(long)5,(64)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 70 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 70 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 70 "cursor-readahead.pgc"
+ 
+ 			if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ 			if (sqlca.sqlcode < 0) sqlprint();
+ 			sqlcode = sqlca.sqlcode;
+ 			rows0 = sqlca.sqlerrd[2];
+ 
+ 			{ ECPGfetch(__LINE__, 0, 1, NULL, 0, "xcur", ECPGc_forward, "$0", ECPGst_normal, "fetch $0 from xcur", 
+ 	ECPGt_int,&(count),(long)1,(long)1,sizeof(int), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
+ 	ECPGt_int,(id2),(long)1,(long)5,sizeof(int), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+ 	ECPGt_char,(t0),(long)64,(long)5,(64)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 76 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 76 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 76 "cursor-readahead.pgc"
+ 
+ 			if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ 			if (sqlca.sqlcode < 0) sqlprint();
+ 
+ 			if (sqlca.sqlcode != 0 || sqlcode != 0)
+ 				break;
+ 
+ 			rows = sqlca.sqlerrd[2];
+ 
+ 			if (rows0 != rows)
+ 			{
+ 				printf("the two cursors don't return the same amount of rows (%d vs %d)\n", rows0, rows);
+ 				break;
+ 			}
+ 
+ 			for (j = 0; j < rows; j++)
+ 			{
+ 				id++;
+ 
+ 				if (id != id1[j] || id != id2[j] || id1[j] != id2[j])
+ 				{
+ 					printf("Reading two cursors forward: ERROR. id = %d id1 = %d id2 = %d\n", id, id1[j], id2[j]);
+ 					break;
+ 				}
+ 			}
+ 			if (j != rows)
+ 				break;
+ 		}
+ 
+ 		if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ 		if (sqlca.sqlcode < 0) sqlprint();
+ 
+ 		if (id == maxid)
+ 			printf("Reading readahead and non-readahead cursors simultaneously forward by %d record: SUCCESS\n", count);
+ 		else
+ 			printf("Reading readahead and non-readahead cursors simultaneously forward by %d record: FAILED at %d, id1 %d id2 %d\n", count, id, id1[j], id2[j]);
+ 
+ 		{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "close $0", 
+ 	ECPGt_char,&(curname),(long)0,(long)1,(1)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+ #line 113 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 113 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 113 "cursor-readahead.pgc"
+ 
+ 		{ ECPGclose(__LINE__, 0, 1, NULL, 0, "xcur", ECPGst_normal, "close xcur", ECPGt_EOIT, ECPGt_EORT);
+ #line 114 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 114 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 114 "cursor-readahead.pgc"
+ 
+ 
+ 		/* exec sql whenever not found  continue ; */
+ #line 116 "cursor-readahead.pgc"
+ 
+ 
+ 		{ ECPGopen(__LINE__, 0, 1, NULL, 0, 256, 0, 1, 0, "xcur", ECPGst_normal, "declare xcur scroll cursor for select * from ra_test order by id", ECPGt_EOIT, ECPGt_EORT);
+ #line 118 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 118 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 118 "cursor-readahead.pgc"
+ 
+ 		{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "declare $0 scroll cursor for select * from ra_test order by id", 
+ 	ECPGt_char,&(curname),(long)0,(long)1,(1)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+ #line 119 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 119 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 119 "cursor-readahead.pgc"
+ 
+ 
+ 		{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch last from $0", 
+ 	ECPGt_char,&(curname),(long)0,(long)1,(1)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
+ 	ECPGt_int,(id1),(long)1,(long)5,sizeof(int), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+ 	ECPGt_char,(t0),(long)64,(long)5,(64)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 121 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 121 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 121 "cursor-readahead.pgc"
+ 
+ 		{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch from $0", 
+ 	ECPGt_char,&(curname),(long)0,(long)1,(1)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
+ 	ECPGt_int,(id1),(long)1,(long)5,sizeof(int), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+ 	ECPGt_char,(t0),(long)64,(long)5,(64)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 122 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 122 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 122 "cursor-readahead.pgc"
+ 
+ 		if (sqlca.sqlcode == ECPG_NOT_FOUND)
+ 			printf("After last record in cursor '%s' (value %d), fetching backwards.\n", curname, id1[0]);
+ 		else
+ 			goto err;
+ 
+ 		{ ECPGfetch(__LINE__, 0, 1, NULL, 0, "xcur", ECPGc_absolute, "-1", ECPGst_normal, "fetch last from xcur", ECPGt_EOIT, 
+ 	ECPGt_int,(id2),(long)1,(long)5,sizeof(int), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+ 	ECPGt_char,(t0),(long)64,(long)5,(64)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 128 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 128 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 128 "cursor-readahead.pgc"
+ 
+ 		{ ECPGfetch(__LINE__, 0, 1, NULL, 0, "xcur", ECPGc_forward, "1", ECPGst_normal, "fetch from xcur", ECPGt_EOIT, 
+ 	ECPGt_int,(id2),(long)1,(long)5,sizeof(int), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+ 	ECPGt_char,(t0),(long)64,(long)5,(64)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 129 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 129 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 129 "cursor-readahead.pgc"
+ 
+ 		if (sqlca.sqlcode == ECPG_NOT_FOUND)
+ 			printf("After last record in cursor 'xcur' (value %d), fetching backwards.\n", id2[0]);
+ 		else
+ 			goto err;
+ 
+ 		id = maxid;
+ 		while (1)
+ 		{
+ 			for (j = 0; j < count; j++)
+ 			{
+ 				id1[j] = -1;
+ 				id2[j] = -1;
+ 			}
+ 
+ 			{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch backward $0 from $0", 
+ 	ECPGt_int,&(count),(long)1,(long)1,sizeof(int), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+ 	ECPGt_char,&(curname),(long)0,(long)1,(1)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
+ 	ECPGt_int,(id1),(long)1,(long)5,sizeof(int), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+ 	ECPGt_char,(t0),(long)64,(long)5,(64)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 144 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 144 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 144 "cursor-readahead.pgc"
+ 
+ 			if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ 			if (sqlca.sqlcode < 0) sqlprint();
+ 			sqlcode = sqlca.sqlcode;
+ 			rows0 = sqlca.sqlerrd[2];
+ 
+ 			{ ECPGfetch(__LINE__, 0, 1, NULL, 0, "xcur", ECPGc_backward, "$0", ECPGst_normal, "fetch backward $0 from xcur", 
+ 	ECPGt_int,&(count),(long)1,(long)1,sizeof(int), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
+ 	ECPGt_int,(id2),(long)1,(long)5,sizeof(int), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+ 	ECPGt_char,(t0),(long)64,(long)5,(64)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 150 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 150 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 150 "cursor-readahead.pgc"
+ 
+ 			if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ 			if (sqlca.sqlcode < 0) sqlprint();
+ 
+ 			if (sqlca.sqlcode != 0 || sqlcode != 0)
+ 				break;
+ 
+ 			rows = sqlca.sqlerrd[2];
+ 
+ 			if (rows0 != rows)
+ 			{
+ 				printf("the two cursors don't return the same amount of rows (%d vs %d)\n", rows0, rows);
+ 				break;
+ 			}
+ 
+ 			for (j = 0; j < rows; j++)
+ 			{
+ 				if (id != id1[j] || id != id2[j] || id1[j] != id2[j])
+ 				{
+ 					printf("Reading two cursors backward: ERROR. id = %d id1 = %d id2 = %d\n", id, id1[j], id2[j]);
+ 					break;
+ 				}
+ 				id--;
+ 			}
+ 			if (j != rows)
+ 				break;
+ 		}
+ 
+ 		if (id == 0)
+ 			printf("Reading readahead and non-readahead cursors simultaneously backwards by %d record(s): SUCCESS\n", count);
+ 		else
+ 			printf("Reading readahead and non-readahead cursors simultaneously backwards by %d record(s): FAILED at %d, id1 %d id2 %d\n", count, id, id1[j], id2[j]);
+ 
+ 		{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "close $0", 
+ 	ECPGt_char,&(curname),(long)0,(long)1,(1)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);
+ #line 183 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 183 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 183 "cursor-readahead.pgc"
+ 
+ 		{ ECPGclose(__LINE__, 0, 1, NULL, 0, "xcur", ECPGst_normal, "close xcur", ECPGt_EOIT, ECPGt_EORT);
+ #line 184 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 184 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 184 "cursor-readahead.pgc"
+ 
+ 
+ 		/* exec sql whenever not found  continue ; */
+ #line 186 "cursor-readahead.pgc"
+ 
+ 	}
+ 
+ 	sqlda = NULL;
+ 	{ ECPGopen(__LINE__, 0, 1, NULL, 0, 256, 0, 1, 0, "xcur", ECPGst_normal, "declare xcur scroll cursor for select * from ra_test order by id", ECPGt_EOIT, ECPGt_EORT);
+ #line 190 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 190 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 190 "cursor-readahead.pgc"
+ 
+ 	{ ECPGfetch(__LINE__, 0, 1, NULL, 0, "xcur", ECPGc_forward, "all", ECPGst_normal, "fetch all xcur", ECPGt_EOIT, 
+ 	ECPGt_sqlda, &sqlda, 0L, 0L, 0L, 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 191 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 191 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 191 "cursor-readahead.pgc"
+ 
+ 
+ 	/* exec sql whenever not found  break ; */
+ #line 193 "cursor-readahead.pgc"
+ 
+ 
+ 	id = 0;
+ 	id1[0] = -1;
+ 	while (sqlda)
+ 	{
+ 		sqlda_t *tmp;
+ 
+ 		id++;
+ 		id1[0] = *(int *)sqlda->sqlvar[0].sqldata;
+ 
+ 		if (id != id1[0])
+ 		{
+ 			printf("Reading readahead cursors forward into sqlda chain: ERROR. id = %d id1 = %d\n", id, id1[0]);
+ 			break;
+ 		}
+ 		tmp = sqlda->desc_next;
+ 		free(sqlda);
+ 		sqlda = tmp;
+ 	}
+ 
+ 	if (id == maxid)
+ 		printf("Reading all records from a readahead cursor forward into sqlda chain: SUCCESS\n");
+ 	else
+ 		printf("Reading all records from a readahead cursor forward into sqlda chain: FAILED. id %d, id1 %d\n", id, id1[0]);
+ 
+ 	{ ECPGclose(__LINE__, 0, 1, NULL, 0, "xcur", ECPGst_normal, "close xcur", ECPGt_EOIT, ECPGt_EORT);
+ #line 219 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 219 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 219 "cursor-readahead.pgc"
+ 
+ 
+ 	/* exec sql whenever not found  continue ; */
+ #line 221 "cursor-readahead.pgc"
+ 
+ 
+ 	sqlda = NULL;
+ 	{ ECPGopen(__LINE__, 0, 1, NULL, 0, 256, 0, 1, 0, "xcur", ECPGst_normal, "declare xcur scroll cursor for select * from ra_test order by id", ECPGt_EOIT, ECPGt_EORT);
+ #line 224 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 224 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 224 "cursor-readahead.pgc"
+ 
+ 	{ ECPGfetch(__LINE__, 0, 1, NULL, 0, "xcur", ECPGc_absolute, "-1", ECPGst_normal, "fetch last from xcur", ECPGt_EOIT, 
+ 	ECPGt_int,(id1),(long)1,(long)5,sizeof(int), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+ 	ECPGt_char,(t0),(long)64,(long)5,(64)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 225 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 225 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 225 "cursor-readahead.pgc"
+ 
+ 	{ ECPGfetch(__LINE__, 0, 1, NULL, 0, "xcur", ECPGc_forward, "1", ECPGst_normal, "fetch from xcur", ECPGt_EOIT, 
+ 	ECPGt_int,(id1),(long)1,(long)5,sizeof(int), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+ 	ECPGt_char,(t0),(long)64,(long)5,(64)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 226 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 226 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 226 "cursor-readahead.pgc"
+ 
+ 	if (sqlca.sqlcode == ECPG_NOT_FOUND)
+ 		printf("After last record in cursor 'xcur' (value %d), fetching backwards.\n", id1[0]);
+ 	else
+ 		goto err;
+ 
+ 	{ ECPGfetch(__LINE__, 0, 1, NULL, 0, "xcur", ECPGc_backward, "all", ECPGst_normal, "fetch backward all xcur", ECPGt_EOIT, 
+ 	ECPGt_sqlda, &sqlda, 0L, 0L, 0L, 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 232 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 232 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 232 "cursor-readahead.pgc"
+ 
+ 
+ 	/* exec sql whenever not found  break ; */
+ #line 234 "cursor-readahead.pgc"
+ 
+ 
+ 	id = maxid;
+ 	id1[0] = -1;
+ 	while (sqlda)
+ 	{
+ 		sqlda_t	*tmp;
+ 
+ 		id1[0] = *(int *)sqlda->sqlvar[0].sqldata;
+ 
+ 		if (id != id1[0])
+ 		{
+ 			printf("Reading readahead cursors backward into sqlda chain: ERROR. id = %d id1 = %d\n", id, id1[0]);
+ 			break;
+ 		}
+ 
+ 		tmp = sqlda->desc_next;
+ 		free(sqlda);
+ 		sqlda = tmp;
+ 
+ 		id--;
+ 	}
+ 
+ 	if (id == 0)
+ 		printf("Reading all records from readahead cursor backwards into sqlda chain: SUCCESS\n");
+ 	else
+ 		printf("Reading all records from readahead cursors backwards into sqlda chain: FAILED, id %d, id1 %d\n", id, id1[0]);
+ 
+ 	/* exec sql whenever not found  continue ; */
+ #line 262 "cursor-readahead.pgc"
+ 
+ 
+ 	{ ECPGfetch(__LINE__, 0, 1, NULL, 0, "xcur", ECPGc_absolute, "127", ECPGst_normal, "move absolute 127 in xcur", ECPGt_EOIT, ECPGt_EORT);
+ #line 264 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 264 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 264 "cursor-readahead.pgc"
+ 
+ 	{ ECPGcursor_dml(__LINE__, 0, 1, NULL, 0, "xcur", ECPGst_normal, "update ra_test set t = 'b' where current of xcur", ECPGt_EOIT, ECPGt_EORT);
+ #line 265 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 265 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 265 "cursor-readahead.pgc"
+ 
+ 
+ 	/* id = MAXID */
+ 	{ ECPGfetch(__LINE__, 0, 1, NULL, 0, "xcur", ECPGc_absolute, "- 1", ECPGst_normal, "move absolute - 1 in xcur", ECPGt_EOIT, ECPGt_EORT);
+ #line 268 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 268 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 268 "cursor-readahead.pgc"
+ 
+ 	{ ECPGcursor_dml(__LINE__, 0, 1, NULL, 0, "xcur", ECPGst_normal, "update ra_test set t = 'b' where current of xcur", ECPGt_EOIT, ECPGt_EORT);
+ #line 269 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 269 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 269 "cursor-readahead.pgc"
+ 
+ 
+ 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select t from ra_test where id = 127", ECPGt_EOIT, 
+ 	ECPGt_char,(t),(long)64,(long)1,(64)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 271 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 271 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 271 "cursor-readahead.pgc"
+ 
+ 	printf("id = 127, t = '%s'\n", t);
+ 
+ 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "select t from ra_test where id = 513", ECPGt_EOIT, 
+ 	ECPGt_char,(t),(long)64,(long)1,(64)*sizeof(char), 
+ 	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+ #line 274 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 274 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 274 "cursor-readahead.pgc"
+ 
+ 	printf("id = 513, t = '%s'\n", t);
+ 
+ 	{ ECPGclose(__LINE__, 0, 1, NULL, 0, "xcur", ECPGst_normal, "close xcur", ECPGt_EOIT, ECPGt_EORT);
+ #line 277 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 277 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 277 "cursor-readahead.pgc"
+ 
+ 
+ err:
+ 
+ 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
+ #line 281 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 281 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 281 "cursor-readahead.pgc"
+ 
+ 
+ 	{ ECPGtrans(__LINE__, NULL, "begin", 0, 1, 0, NULL);
+ #line 283 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 283 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 283 "cursor-readahead.pgc"
+ 
+ 
+ 	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table ra_test", ECPGt_EOIT, ECPGt_EORT);
+ #line 285 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 285 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 285 "cursor-readahead.pgc"
+ 
+ 
+ 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
+ #line 287 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 287 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 287 "cursor-readahead.pgc"
+ 
+ 
+ 	{ ECPGdisconnect(__LINE__, "ALL");
+ #line 289 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ #line 289 "cursor-readahead.pgc"
+ 
+ if (sqlca.sqlcode < 0) sqlprint();}
+ #line 289 "cursor-readahead.pgc"
+ 
+ 
+ 	return 0;
+ }
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/preproc-cursor-readahead.stderr postgresql/src/interfaces/ecpg/test/expected/preproc-cursor-readahead.stderr
*** postgresql.orig/src/interfaces/ecpg/test/expected/preproc-cursor-readahead.stderr	1970-01-01 01:00:00.000000000 +0100
--- postgresql/src/interfaces/ecpg/test/expected/preproc-cursor-readahead.stderr	2012-03-29 11:24:54.003185382 +0200
***************
*** 0 ****
--- 1 ----
+ Dummy non-empty error output
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/preproc-cursor-readahead.stdout postgresql/src/interfaces/ecpg/test/expected/preproc-cursor-readahead.stdout
*** postgresql.orig/src/interfaces/ecpg/test/expected/preproc-cursor-readahead.stdout	1970-01-01 01:00:00.000000000 +0100
--- postgresql/src/interfaces/ecpg/test/expected/preproc-cursor-readahead.stdout	2012-03-29 11:24:54.003185382 +0200
***************
*** 0 ****
--- 1,13 ----
+ Reading readahead and non-readahead cursors simultaneously forward by 1 record: SUCCESS
+ After last record in cursor 'xx' (value 513), fetching backwards.
+ After last record in cursor 'xcur' (value 513), fetching backwards.
+ Reading readahead and non-readahead cursors simultaneously backwards by 1 record(s): SUCCESS
+ Reading readahead and non-readahead cursors simultaneously forward by 5 record: SUCCESS
+ After last record in cursor 'xx' (value 513), fetching backwards.
+ After last record in cursor 'xcur' (value 513), fetching backwards.
+ Reading readahead and non-readahead cursors simultaneously backwards by 5 record(s): SUCCESS
+ Reading all records from a readahead cursor forward into sqlda chain: SUCCESS
+ After last record in cursor 'xcur' (value 513), fetching backwards.
+ Reading all records from readahead cursor backwards into sqlda chain: SUCCESS
+ id = 127, t = 'b'
+ id = 513, t = 'b'
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/preproc-define.c postgresql/src/interfaces/ecpg/test/expected/preproc-define.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/preproc-define.c	2010-09-21 13:50:00.000000000 +0200
--- postgresql/src/interfaces/ecpg/test/expected/preproc-define.c	2012-03-29 11:24:54.004185388 +0200
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 83,89 ****
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 36 "define.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 37 "define.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
--- 83,89 ----
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 36 "define.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 37 "define.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 102,108 ****
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 40 "define.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 41 "define.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
--- 102,108 ----
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 40 "define.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 41 "define.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 147,153 ****
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 56 "define.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 57 "define.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
--- 147,153 ----
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 56 "define.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 57 "define.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/preproc-outofscope.c postgresql/src/interfaces/ecpg/test/expected/preproc-outofscope.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/preproc-outofscope.c	2012-01-04 17:43:33.231905007 +0100
--- postgresql/src/interfaces/ecpg/test/expected/preproc-outofscope.c	2012-03-29 11:24:54.005185394 +0200
*************** if (sqlca.sqlcode < 0) exit (1);}
*** 315,321 ****
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 89 "outofscope.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
--- 315,321 ----
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 89 "outofscope.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
*************** if (sqlca.sqlcode < 0) exit (1);}
*** 356,362 ****
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 118 "outofscope.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
--- 356,362 ----
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 118 "outofscope.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/preproc-variable.c postgresql/src/interfaces/ecpg/test/expected/preproc-variable.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/preproc-variable.c	2012-02-14 18:01:58.923669512 +0100
--- postgresql/src/interfaces/ecpg/test/expected/preproc-variable.c	2012-03-29 11:24:54.005185394 +0200
*************** if (sqlca.sqlcode < 0) exit (1);}
*** 182,188 ****
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 60 "variable.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
--- 182,188 ----
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 60 "variable.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
*************** if (sqlca.sqlcode < 0) exit (1);}
*** 257,263 ****
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 95 "variable.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
--- 257,263 ----
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 95 "variable.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/preproc-whenever.c postgresql/src/interfaces/ecpg/test/expected/preproc-whenever.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/preproc-whenever.c	2010-11-24 20:16:22.775628433 +0100
--- postgresql/src/interfaces/ecpg/test/expected/preproc-whenever.c	2012-03-29 11:24:54.006185400 +0200
*************** if (sqlca.sqlwarn[0] == 'W') warn ( );
*** 93,99 ****
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 36 "whenever.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback");
  #line 37 "whenever.pgc"
  
  if (sqlca.sqlwarn[0] == 'W') warn ( );
--- 93,99 ----
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 36 "whenever.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback", 0, 0, 1, NULL);
  #line 37 "whenever.pgc"
  
  if (sqlca.sqlwarn[0] == 'W') warn ( );
*************** if (sqlca.sqlwarn[0] == 'W') warn ( );
*** 114,120 ****
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 39 "whenever.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback");
  #line 40 "whenever.pgc"
  
  if (sqlca.sqlwarn[0] == 'W') warn ( );
--- 114,120 ----
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 39 "whenever.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback", 0, 0, 1, NULL);
  #line 40 "whenever.pgc"
  
  if (sqlca.sqlwarn[0] == 'W') warn ( );
*************** if (sqlca.sqlwarn[0] == 'W') warn ( );
*** 138,144 ****
  if (sqlca.sqlcode < 0) print ( "select" );}
  #line 43 "whenever.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback");
  #line 44 "whenever.pgc"
  
  if (sqlca.sqlwarn[0] == 'W') warn ( );
--- 138,144 ----
  if (sqlca.sqlcode < 0) print ( "select" );}
  #line 43 "whenever.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback", 0, 0, 1, NULL);
  #line 44 "whenever.pgc"
  
  if (sqlca.sqlwarn[0] == 'W') warn ( );
*************** if (sqlca.sqlwarn[0] == 'W') warn ( );
*** 162,168 ****
  if (sqlca.sqlcode < 0) print2 ( );}
  #line 47 "whenever.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback");
  #line 48 "whenever.pgc"
  
  if (sqlca.sqlwarn[0] == 'W') warn ( );
--- 162,168 ----
  if (sqlca.sqlcode < 0) print2 ( );}
  #line 47 "whenever.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback", 0, 0, 1, NULL);
  #line 48 "whenever.pgc"
  
  if (sqlca.sqlwarn[0] == 'W') warn ( );
*************** if (sqlca.sqlcode < 0) print2 ( );}
*** 183,189 ****
  if (sqlca.sqlwarn[0] == 'W') warn ( );}
  #line 51 "whenever.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback");
  #line 52 "whenever.pgc"
  
  if (sqlca.sqlwarn[0] == 'W') warn ( );}
--- 183,189 ----
  if (sqlca.sqlwarn[0] == 'W') warn ( );}
  #line 51 "whenever.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback", 0, 0, 1, NULL);
  #line 52 "whenever.pgc"
  
  if (sqlca.sqlwarn[0] == 'W') warn ( );}
*************** if (sqlca.sqlcode < 0) goto error;}
*** 207,213 ****
  	printf("Should not be reachable\n");
  
  	error:
! 	{ ECPGtrans(__LINE__, NULL, "rollback");
  #line 59 "whenever.pgc"
  
  if (sqlca.sqlwarn[0] == 'W') warn ( );
--- 207,213 ----
  	printf("Should not be reachable\n");
  
  	error:
! 	{ ECPGtrans(__LINE__, NULL, "rollback", 0, 0, 1, NULL);
  #line 59 "whenever.pgc"
  
  if (sqlca.sqlwarn[0] == 'W') warn ( );
*************** if (sqlca.sqlwarn[0] == 'W') warn ( );
*** 233,239 ****
  if (sqlca.sqlcode < 0) exit (1);}
  #line 64 "whenever.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback");
  #line 65 "whenever.pgc"
  
  if (sqlca.sqlwarn[0] == 'W') warn ( );
--- 233,239 ----
  if (sqlca.sqlcode < 0) exit (1);}
  #line 64 "whenever.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "rollback", 0, 0, 1, NULL);
  #line 65 "whenever.pgc"
  
  if (sqlca.sqlwarn[0] == 'W') warn ( );
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/sql-array.c postgresql/src/interfaces/ecpg/test/expected/sql-array.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/sql-array.c	2010-11-24 20:16:22.775628433 +0100
--- postgresql/src/interfaces/ecpg/test/expected/sql-array.c	2012-03-29 11:24:54.007185406 +0200
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 148,154 ****
  #line 29 "array.pgc"
  
  
! 	{ ECPGtrans(__LINE__, NULL, "begin work");
  #line 31 "array.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
--- 148,154 ----
  #line 29 "array.pgc"
  
  
! 	{ ECPGtrans(__LINE__, NULL, "begin work", 0, 1, 0, NULL);
  #line 31 "array.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 193,206 ****
  #line 39 "array.pgc"
  
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 41 "array.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 41 "array.pgc"
  
  
! 	{ ECPGtrans(__LINE__, NULL, "begin work");
  #line 43 "array.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
--- 193,206 ----
  #line 39 "array.pgc"
  
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 41 "array.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 41 "array.pgc"
  
  
! 	{ ECPGtrans(__LINE__, NULL, "begin work", 0, 1, 0, NULL);
  #line 43 "array.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 259,265 ****
  #line 70 "array.pgc"
  
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 72 "array.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
--- 259,265 ----
  #line 70 "array.pgc"
  
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 72 "array.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/sql-code100.c postgresql/src/interfaces/ecpg/test/expected/sql-code100.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/sql-code100.c	2010-11-24 20:16:22.775628433 +0100
--- postgresql/src/interfaces/ecpg/test/expected/sql-code100.c	2012-03-29 11:24:54.008185411 +0200
*************** int main()
*** 114,120 ****
  #line 20 "code100.pgc"
  
     if (sqlca.sqlcode) printf("%ld:%s\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
!    { ECPGtrans(__LINE__, NULL, "commit work");}
  #line 22 "code100.pgc"
  
     if (sqlca.sqlcode) printf("%ld:%s\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
--- 114,120 ----
  #line 20 "code100.pgc"
  
     if (sqlca.sqlcode) printf("%ld:%s\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
!    { ECPGtrans(__LINE__, NULL, "commit work", 0, 0, 0, NULL);}
  #line 22 "code100.pgc"
  
     if (sqlca.sqlcode) printf("%ld:%s\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
*************** int main()
*** 127,133 ****
  
        if (sqlca.sqlcode) printf("%ld:%s\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
     }
!    { ECPGtrans(__LINE__, NULL, "commit work");}
  #line 31 "code100.pgc"
  
     if (sqlca.sqlcode) printf("%ld:%s\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
--- 127,133 ----
  
        if (sqlca.sqlcode) printf("%ld:%s\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
     }
!    { ECPGtrans(__LINE__, NULL, "commit work", 0, 0, 0, NULL);}
  #line 31 "code100.pgc"
  
     if (sqlca.sqlcode) printf("%ld:%s\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
*************** int main()
*** 151,157 ****
  #line 44 "code100.pgc"
  
     if (sqlca.sqlcode) printf("%ld:%s\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
!    { ECPGtrans(__LINE__, NULL, "commit work");}
  #line 46 "code100.pgc"
  
     if (sqlca.sqlcode) printf("%ld:%s\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
--- 151,157 ----
  #line 44 "code100.pgc"
  
     if (sqlca.sqlcode) printf("%ld:%s\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
!    { ECPGtrans(__LINE__, NULL, "commit work", 0, 0, 0, NULL);}
  #line 46 "code100.pgc"
  
     if (sqlca.sqlcode) printf("%ld:%s\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/sql-describe.c postgresql/src/interfaces/ecpg/test/expected/sql-describe.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/sql-describe.c	2010-11-24 20:16:22.775628433 +0100
--- postgresql/src/interfaces/ecpg/test/expected/sql-describe.c	2012-03-29 11:24:54.012185432 +0200
*************** if (sqlca.sqlcode < 0) exit (1);}
*** 133,139 ****
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 42 "describe.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
--- 133,139 ----
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 42 "describe.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
*************** if (sqlca.sqlcode < 0) exit (1);}
*** 446,452 ****
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 193 "describe.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
--- 446,452 ----
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 193 "describe.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/sql-dynalloc2.c postgresql/src/interfaces/ecpg/test/expected/sql-dynalloc2.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/sql-dynalloc2.c	2010-11-24 20:16:22.776628366 +0100
--- postgresql/src/interfaces/ecpg/test/expected/sql-dynalloc2.c	2012-03-29 11:24:54.013185437 +0200
*************** if (sqlca.sqlcode < 0) sqlprint ( );}
*** 240,246 ****
  if (sqlca.sqlcode < 0) sqlprint ( );
  #line 51 "dynalloc2.pgc"
  
!    { ECPGtrans(__LINE__, NULL, "rollback");
  #line 52 "dynalloc2.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
--- 240,246 ----
  if (sqlca.sqlcode < 0) sqlprint ( );
  #line 51 "dynalloc2.pgc"
  
!    { ECPGtrans(__LINE__, NULL, "rollback", 0, 0, 1, NULL);
  #line 52 "dynalloc2.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint ( );}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/sql-execute.c postgresql/src/interfaces/ecpg/test/expected/sql-execute.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/sql-execute.c	2010-09-21 13:50:00.000000000 +0200
--- postgresql/src/interfaces/ecpg/test/expected/sql-execute.c	2012-03-29 11:24:54.013185437 +0200
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 70,76 ****
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 25 "execute.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 26 "execute.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
--- 70,76 ----
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 25 "execute.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 26 "execute.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 121,127 ****
  
  	printf("Inserted %ld tuples via prepared execute\n", sqlca.sqlerrd[2]);
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 45 "execute.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
--- 121,127 ----
  
  	printf("Inserted %ld tuples via prepared execute\n", sqlca.sqlerrd[2]);
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 45 "execute.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 314,320 ****
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 108 "execute.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 109 "execute.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
--- 314,320 ----
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 108 "execute.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 109 "execute.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/sql-indicators.c postgresql/src/interfaces/ecpg/test/expected/sql-indicators.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/sql-indicators.c	2010-09-21 13:50:00.000000000 +0200
--- postgresql/src/interfaces/ecpg/test/expected/sql-indicators.c	2012-03-29 11:24:54.014185442 +0200
*************** int main()
*** 118,124 ****
  	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table indicator_test ( \"id\" int primary key , \"str\" text not null , val int null )", ECPGt_EOIT, ECPGt_EORT);}
  #line 21 "indicators.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit work");}
  #line 22 "indicators.pgc"
  
  
--- 118,124 ----
  	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table indicator_test ( \"id\" int primary key , \"str\" text not null , val int null )", ECPGt_EOIT, ECPGt_EORT);}
  #line 21 "indicators.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit work", 0, 0, 0, NULL);}
  #line 22 "indicators.pgc"
  
  
*************** int main()
*** 138,144 ****
  	ECPGt_int,&(nullind),(long)1,(long)1,sizeof(int), ECPGt_EOIT, ECPGt_EORT);}
  #line 29 "indicators.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit work");}
  #line 30 "indicators.pgc"
  
  
--- 138,144 ----
  	ECPGt_int,&(nullind),(long)1,(long)1,sizeof(int), ECPGt_EOIT, ECPGt_EORT);}
  #line 29 "indicators.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit work", 0, 0, 0, NULL);}
  #line 30 "indicators.pgc"
  
  
*************** int main()
*** 178,184 ****
  	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table indicator_test", ECPGt_EOIT, ECPGt_EORT);}
  #line 45 "indicators.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit work");}
  #line 46 "indicators.pgc"
  
  
--- 178,184 ----
  	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table indicator_test", ECPGt_EOIT, ECPGt_EORT);}
  #line 45 "indicators.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit work", 0, 0, 0, NULL);}
  #line 46 "indicators.pgc"
  
  
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/sql-oldexec.c postgresql/src/interfaces/ecpg/test/expected/sql-oldexec.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/sql-oldexec.c	2010-09-21 13:50:00.000000000 +0200
--- postgresql/src/interfaces/ecpg/test/expected/sql-oldexec.c	2012-03-29 11:24:54.015185447 +0200
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 70,76 ****
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 25 "oldexec.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 26 "oldexec.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
--- 70,76 ----
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 25 "oldexec.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 26 "oldexec.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 121,127 ****
  
  	printf("Inserted %ld tuples via prepared execute\n", sqlca.sqlerrd[2]);
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 45 "oldexec.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
--- 121,127 ----
  
  	printf("Inserted %ld tuples via prepared execute\n", sqlca.sqlerrd[2]);
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 45 "oldexec.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 253,259 ****
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 88 "oldexec.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 89 "oldexec.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
--- 253,259 ----
  if (sqlca.sqlcode < 0) sqlprint();}
  #line 88 "oldexec.pgc"
  
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 89 "oldexec.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/sql-quote.c postgresql/src/interfaces/ecpg/test/expected/sql-quote.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/sql-quote.c	2010-09-21 13:50:00.000000000 +0200
--- postgresql/src/interfaces/ecpg/test/expected/sql-quote.c	2012-03-29 11:24:54.015185447 +0200
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 149,155 ****
  #line 40 "quote.pgc"
  
  
!   { ECPGtrans(__LINE__, NULL, "begin");
  #line 42 "quote.pgc"
  
  if (sqlca.sqlwarn[0] == 'W') sqlprint();
--- 149,155 ----
  #line 40 "quote.pgc"
  
  
!   { ECPGtrans(__LINE__, NULL, "begin", 0, 1, 0, NULL);
  #line 42 "quote.pgc"
  
  if (sqlca.sqlwarn[0] == 'W') sqlprint();
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 197,203 ****
  	printf("value: %d %s\n", i, var);
    }
  
!   { ECPGtrans(__LINE__, NULL, "rollback");
  #line 55 "quote.pgc"
  
  if (sqlca.sqlwarn[0] == 'W') sqlprint();
--- 197,203 ----
  	printf("value: %d %s\n", i, var);
    }
  
!   { ECPGtrans(__LINE__, NULL, "rollback", 0, 0, 1, NULL);
  #line 55 "quote.pgc"
  
  if (sqlca.sqlwarn[0] == 'W') sqlprint();
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/sql-sqlda.c postgresql/src/interfaces/ecpg/test/expected/sql-sqlda.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/sql-sqlda.c	2010-11-24 20:16:22.776628366 +0100
--- postgresql/src/interfaces/ecpg/test/expected/sql-sqlda.c	2012-03-29 11:24:54.016185452 +0200
*************** if (sqlca.sqlcode < 0) exit (1);}
*** 226,232 ****
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 90 "sqlda.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
--- 226,232 ----
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 90 "sqlda.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
*************** if (sqlca.sqlcode < 0) exit (1);}
*** 475,481 ****
  	dump_sqlda(outp_sqlda);
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, "con2", "commit");
  #line 227 "sqlda.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
--- 475,481 ----
  	dump_sqlda(outp_sqlda);
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, "con2", "commit", 0, 0, 0, NULL);
  #line 227 "sqlda.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
*************** if (sqlca.sqlcode < 0) exit (1);}
*** 512,518 ****
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit");
  #line 244 "sqlda.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
--- 512,518 ----
  
  
  	strcpy(msg, "commit");
! 	{ ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 244 "sqlda.pgc"
  
  if (sqlca.sqlcode < 0) exit (1);}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/thread-thread.c postgresql/src/interfaces/ecpg/test/expected/thread-thread.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/thread-thread.c	2010-09-21 13:50:00.000000000 +0200
--- postgresql/src/interfaces/ecpg/test/expected/thread-thread.c	2012-03-29 11:24:54.017185458 +0200
*************** int main()
*** 72,84 ****
    { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table test_thread", ECPGt_EOIT, ECPGt_EORT);}
  #line 47 "thread.pgc"
   /* DROP might fail */
!   { ECPGtrans(__LINE__, NULL, "commit");}
  #line 48 "thread.pgc"
  
    { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test_thread ( tstamp timestamp not null default cast ( timeofday ( ) as timestamp ) , thread text not null , iteration integer not null , primary key ( thread , iteration ) )", ECPGt_EOIT, ECPGt_EORT);}
  #line 53 "thread.pgc"
  
!   { ECPGtrans(__LINE__, NULL, "commit");}
  #line 54 "thread.pgc"
  
    { ECPGdisconnect(__LINE__, "CURRENT");}
--- 72,84 ----
    { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table test_thread", ECPGt_EOIT, ECPGt_EORT);}
  #line 47 "thread.pgc"
   /* DROP might fail */
!   { ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);}
  #line 48 "thread.pgc"
  
    { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test_thread ( tstamp timestamp not null default cast ( timeofday ( ) as timestamp ) , thread text not null , iteration integer not null , primary key ( thread , iteration ) )", ECPGt_EOIT, ECPGt_EORT);}
  #line 53 "thread.pgc"
  
!   { ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);}
  #line 54 "thread.pgc"
  
    { ECPGdisconnect(__LINE__, "CURRENT");}
*************** int main()
*** 121,127 ****
  	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
  #line 86 "thread.pgc"
  
!   { ECPGtrans(__LINE__, NULL, "commit");}
  #line 87 "thread.pgc"
  
    { ECPGdisconnect(__LINE__, "CURRENT");}
--- 121,127 ----
  	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
  #line 86 "thread.pgc"
  
!   { ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);}
  #line 87 "thread.pgc"
  
    { ECPGdisconnect(__LINE__, "CURRENT");}
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 171,177 ****
        printf("%s: ERROR: cannot connect to database!\n", l_connection);
        return( NULL );
      }
!   { ECPGtrans(__LINE__, l_connection, "begin");
  #line 118 "thread.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
--- 171,177 ----
        printf("%s: ERROR: cannot connect to database!\n", l_connection);
        return( NULL );
      }
!   { ECPGtrans(__LINE__, l_connection, "begin", 0, 1, 0, NULL);
  #line 118 "thread.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 196,202 ****
      }
  
    /* all done */
!   { ECPGtrans(__LINE__, l_connection, "commit");
  #line 129 "thread.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
--- 196,202 ----
      }
  
    /* all done */
!   { ECPGtrans(__LINE__, l_connection, "commit", 0, 0, 0, NULL);
  #line 129 "thread.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/expected/thread-thread_implicit.c postgresql/src/interfaces/ecpg/test/expected/thread-thread_implicit.c
*** postgresql.orig/src/interfaces/ecpg/test/expected/thread-thread_implicit.c	2010-09-21 13:50:00.000000000 +0200
--- postgresql/src/interfaces/ecpg/test/expected/thread-thread_implicit.c	2012-03-29 11:24:54.018185464 +0200
*************** int main()
*** 73,85 ****
    { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table test_thread", ECPGt_EOIT, ECPGt_EORT);}
  #line 48 "thread_implicit.pgc"
   /* DROP might fail */
!   { ECPGtrans(__LINE__, NULL, "commit");}
  #line 49 "thread_implicit.pgc"
  
    { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test_thread ( tstamp timestamp not null default cast ( timeofday ( ) as timestamp ) , thread text not null , iteration integer not null , primary key ( thread , iteration ) )", ECPGt_EOIT, ECPGt_EORT);}
  #line 54 "thread_implicit.pgc"
  
!   { ECPGtrans(__LINE__, NULL, "commit");}
  #line 55 "thread_implicit.pgc"
  
    { ECPGdisconnect(__LINE__, "CURRENT");}
--- 73,85 ----
    { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table test_thread", ECPGt_EOIT, ECPGt_EORT);}
  #line 48 "thread_implicit.pgc"
   /* DROP might fail */
!   { ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);}
  #line 49 "thread_implicit.pgc"
  
    { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test_thread ( tstamp timestamp not null default cast ( timeofday ( ) as timestamp ) , thread text not null , iteration integer not null , primary key ( thread , iteration ) )", ECPGt_EOIT, ECPGt_EORT);}
  #line 54 "thread_implicit.pgc"
  
!   { ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);}
  #line 55 "thread_implicit.pgc"
  
    { ECPGdisconnect(__LINE__, "CURRENT");}
*************** int main()
*** 122,128 ****
  	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
  #line 87 "thread_implicit.pgc"
  
!   { ECPGtrans(__LINE__, NULL, "commit");}
  #line 88 "thread_implicit.pgc"
  
    { ECPGdisconnect(__LINE__, "CURRENT");}
--- 122,128 ----
  	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
  #line 87 "thread_implicit.pgc"
  
!   { ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);}
  #line 88 "thread_implicit.pgc"
  
    { ECPGdisconnect(__LINE__, "CURRENT");}
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 172,178 ****
        printf("%s: ERROR: cannot connect to database!\n", l_connection);
        return( NULL );
      }
!   { ECPGtrans(__LINE__, NULL, "begin");
  #line 119 "thread_implicit.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
--- 172,178 ----
        printf("%s: ERROR: cannot connect to database!\n", l_connection);
        return( NULL );
      }
!   { ECPGtrans(__LINE__, NULL, "begin", 0, 1, 0, NULL);
  #line 119 "thread_implicit.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
*************** if (sqlca.sqlcode < 0) sqlprint();}
*** 197,203 ****
      }
  
    /* all done */
!   { ECPGtrans(__LINE__, NULL, "commit");
  #line 130 "thread_implicit.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
--- 197,203 ----
      }
  
    /* all done */
!   { ECPGtrans(__LINE__, NULL, "commit", 0, 0, 0, NULL);
  #line 130 "thread_implicit.pgc"
  
  if (sqlca.sqlcode < 0) sqlprint();}
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/preproc/cursor-readahead.pgc postgresql/src/interfaces/ecpg/test/preproc/cursor-readahead.pgc
*** postgresql.orig/src/interfaces/ecpg/test/preproc/cursor-readahead.pgc	1970-01-01 01:00:00.000000000 +0100
--- postgresql/src/interfaces/ecpg/test/preproc/cursor-readahead.pgc	2012-03-29 22:55:03.381183556 +0200
***************
*** 0 ****
--- 1,292 ----
+ #include <stdio.h>
+ #include <stdlib.h>
+ 
+ /* test automatic prepare for all statements */
+ EXEC SQL INCLUDE ../regression;
+ 
+ EXEC SQL INCLUDE sqlda.h;
+ 
+ EXEC SQL WHENEVER SQLERROR SQLPRINT;
+ EXEC SQL WHENEVER SQLWARNING SQLPRINT;
+ 
+ #define MAXID	(513)
+ 
+ int main(void)
+ {
+ 	int	counts[2] = { 1, 5 };
+ 	EXEC SQL BEGIN DECLARE SECTION;
+ 	char	*curname;
+ 	int	maxid;
+ 	int	i, j, count, rows, rows0, sqlcode;
+ 	int	id, id1[5], id2[5];
+ 	char	t0[5][64];
+ 	char	t[64];
+ 	EXEC SQL END DECLARE SECTION;
+ 	sqlda_t	*sqlda;
+ 
+ 	/*
+ 	 * Intentionally don't create a 2MB stderr file for this test.
+ 	 * Enable it manually if you're interested in it.
+ 	 */
+ #if 1
+ 	ECPGdebug(1, stderr);
+ #else
+ 	fprintf(stderr, "Dummy non-empty error output\n");
+ #endif
+ 
+ 	EXEC SQL CONNECT TO REGRESSDB1;
+ 
+ 	EXEC SQL BEGIN;
+ 
+ 	maxid = MAXID;
+ 
+ 	EXEC SQL CREATE TABLE ra_test (id INTEGER PRIMARY KEY, t text);
+ 	EXEC SQL INSERT INTO ra_test SELECT i.i, 'a' FROM generate_series(1, :maxid) as i;
+ 
+ 	EXEC SQL COMMIT;
+ 
+ 	EXEC SQL BEGIN;
+ 
+ 	curname = "xx";
+ 	EXEC SQL DECLARE :curname SCROLL CURSOR FOR SELECT * FROM ra_test ORDER BY id;
+ 	EXEC SQL DECLARE xcur SCROLL READAHEAD 256 CURSOR FOR SELECT * FROM ra_test ORDER BY id;
+ 
+ 	for (i = 0; i < 2; i++)
+ 	{
+ 		count = counts[i];
+ 
+ 		EXEC SQL OPEN xcur;
+ 		EXEC SQL OPEN :curname;
+ 
+ 		id = 0;
+ 		while (1)
+ 		{
+ 			for (j = 0; j < count; j++)
+ 			{
+ 				id1[j] = -1;
+ 				id2[j] = -1;
+ 			}
+ 
+ 			EXEC SQL FETCH :count FROM :curname INTO :id1, :t0;
+ 			if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ 			if (sqlca.sqlcode < 0) sqlprint();
+ 			sqlcode = sqlca.sqlcode;
+ 			rows0 = sqlca.sqlerrd[2];
+ 
+ 			EXEC SQL FETCH :count FROM xcur INTO :id2, :t0;
+ 			if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ 			if (sqlca.sqlcode < 0) sqlprint();
+ 
+ 			if (sqlca.sqlcode != 0 || sqlcode != 0)
+ 				break;
+ 
+ 			rows = sqlca.sqlerrd[2];
+ 
+ 			if (rows0 != rows)
+ 			{
+ 				printf("the two cursors don't return the same amount of rows (%d vs %d)\n", rows0, rows);
+ 				break;
+ 			}
+ 
+ 			for (j = 0; j < rows; j++)
+ 			{
+ 				id++;
+ 
+ 				if (id != id1[j] || id != id2[j] || id1[j] != id2[j])
+ 				{
+ 					printf("Reading two cursors forward: ERROR. id = %d id1 = %d id2 = %d\n", id, id1[j], id2[j]);
+ 					break;
+ 				}
+ 			}
+ 			if (j != rows)
+ 				break;
+ 		}
+ 
+ 		if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ 		if (sqlca.sqlcode < 0) sqlprint();
+ 
+ 		if (id == maxid)
+ 			printf("Reading readahead and non-readahead cursors simultaneously forward by %d record: SUCCESS\n", count);
+ 		else
+ 			printf("Reading readahead and non-readahead cursors simultaneously forward by %d record: FAILED at %d, id1 %d id2 %d\n", count, id, id1[j], id2[j]);
+ 
+ 		EXEC SQL CLOSE :curname;
+ 		EXEC SQL CLOSE xcur;
+ 
+ 		EXEC SQL WHENEVER NOT FOUND CONTINUE;
+ 
+ 		EXEC SQL OPEN xcur;
+ 		EXEC SQL OPEN :curname;
+ 
+ 		EXEC SQL FETCH LAST FROM :curname INTO :id1, :t0;
+ 		EXEC SQL FETCH FROM :curname INTO :id1, :t0;
+ 		if (sqlca.sqlcode == ECPG_NOT_FOUND)
+ 			printf("After last record in cursor '%s' (value %d), fetching backwards.\n", curname, id1[0]);
+ 		else
+ 			goto err;
+ 
+ 		EXEC SQL FETCH LAST FROM xcur INTO :id2, :t0;
+ 		EXEC SQL FETCH FROM xcur INTO :id2, :t0;
+ 		if (sqlca.sqlcode == ECPG_NOT_FOUND)
+ 			printf("After last record in cursor 'xcur' (value %d), fetching backwards.\n", id2[0]);
+ 		else
+ 			goto err;
+ 
+ 		id = maxid;
+ 		while (1)
+ 		{
+ 			for (j = 0; j < count; j++)
+ 			{
+ 				id1[j] = -1;
+ 				id2[j] = -1;
+ 			}
+ 
+ 			EXEC SQL FETCH BACKWARD :count FROM :curname INTO :id1, :t0;
+ 			if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ 			if (sqlca.sqlcode < 0) sqlprint();
+ 			sqlcode = sqlca.sqlcode;
+ 			rows0 = sqlca.sqlerrd[2];
+ 
+ 			EXEC SQL FETCH BACKWARD :count FROM xcur INTO :id2, :t0;
+ 			if (sqlca.sqlwarn[0] == 'W') sqlprint();
+ 			if (sqlca.sqlcode < 0) sqlprint();
+ 
+ 			if (sqlca.sqlcode != 0 || sqlcode != 0)
+ 				break;
+ 
+ 			rows = sqlca.sqlerrd[2];
+ 
+ 			if (rows0 != rows)
+ 			{
+ 				printf("the two cursors don't return the same amount of rows (%d vs %d)\n", rows0, rows);
+ 				break;
+ 			}
+ 
+ 			for (j = 0; j < rows; j++)
+ 			{
+ 				if (id != id1[j] || id != id2[j] || id1[j] != id2[j])
+ 				{
+ 					printf("Reading two cursors backward: ERROR. id = %d id1 = %d id2 = %d\n", id, id1[j], id2[j]);
+ 					break;
+ 				}
+ 				id--;
+ 			}
+ 			if (j != rows)
+ 				break;
+ 		}
+ 
+ 		if (id == 0)
+ 			printf("Reading readahead and non-readahead cursors simultaneously backwards by %d record(s): SUCCESS\n", count);
+ 		else
+ 			printf("Reading readahead and non-readahead cursors simultaneously backwards by %d record(s): FAILED at %d, id1 %d id2 %d\n", count, id, id1[j], id2[j]);
+ 
+ 		EXEC SQL CLOSE :curname;
+ 		EXEC SQL CLOSE xcur;
+ 
+ 		EXEC SQL WHENEVER NOT FOUND CONTINUE;
+ 	}
+ 
+ 	sqlda = NULL;
+ 	EXEC SQL OPEN xcur;
+ 	EXEC SQL FETCH ALL xcur INTO DESCRIPTOR sqlda;
+ 
+ 	EXEC SQL WHENEVER NOT FOUND DO BREAK;
+ 
+ 	id = 0;
+ 	id1[0] = -1;
+ 	while (sqlda)
+ 	{
+ 		sqlda_t *tmp;
+ 
+ 		id++;
+ 		id1[0] = *(int *)sqlda->sqlvar[0].sqldata;
+ 
+ 		if (id != id1[0])
+ 		{
+ 			printf("Reading readahead cursors forward into sqlda chain: ERROR. id = %d id1 = %d\n", id, id1[0]);
+ 			break;
+ 		}
+ 		tmp = sqlda->desc_next;
+ 		free(sqlda);
+ 		sqlda = tmp;
+ 	}
+ 
+ 	if (id == maxid)
+ 		printf("Reading all records from a readahead cursor forward into sqlda chain: SUCCESS\n");
+ 	else
+ 		printf("Reading all records from a readahead cursor forward into sqlda chain: FAILED. id %d, id1 %d\n", id, id1[0]);
+ 
+ 	EXEC SQL CLOSE xcur;
+ 
+ 	EXEC SQL WHENEVER NOT FOUND CONTINUE;
+ 
+ 	sqlda = NULL;
+ 	EXEC SQL OPEN xcur;
+ 	EXEC SQL FETCH LAST FROM xcur INTO :id1, :t0;
+ 	EXEC SQL FETCH FROM xcur INTO :id1, :t0;
+ 	if (sqlca.sqlcode == ECPG_NOT_FOUND)
+ 		printf("After last record in cursor 'xcur' (value %d), fetching backwards.\n", id1[0]);
+ 	else
+ 		goto err;
+ 
+ 	EXEC SQL FETCH BACKWARD ALL xcur INTO DESCRIPTOR sqlda;
+ 
+ 	EXEC SQL WHENEVER NOT FOUND DO BREAK;
+ 
+ 	id = maxid;
+ 	id1[0] = -1;
+ 	while (sqlda)
+ 	{
+ 		sqlda_t	*tmp;
+ 
+ 		id1[0] = *(int *)sqlda->sqlvar[0].sqldata;
+ 
+ 		if (id != id1[0])
+ 		{
+ 			printf("Reading readahead cursors backward into sqlda chain: ERROR. id = %d id1 = %d\n", id, id1[0]);
+ 			break;
+ 		}
+ 
+ 		tmp = sqlda->desc_next;
+ 		free(sqlda);
+ 		sqlda = tmp;
+ 
+ 		id--;
+ 	}
+ 
+ 	if (id == 0)
+ 		printf("Reading all records from readahead cursor backwards into sqlda chain: SUCCESS\n");
+ 	else
+ 		printf("Reading all records from readahead cursors backwards into sqlda chain: FAILED, id %d, id1 %d\n", id, id1[0]);
+ 
+ 	EXEC SQL WHENEVER NOT FOUND CONTINUE;
+ 
+ 	EXEC SQL MOVE ABSOLUTE 127 IN xcur;
+ 	EXEC SQL UPDATE ra_test SET t = 'b' WHERE CURRENT OF xcur;
+ 
+ 	/* id = MAXID */
+ 	EXEC SQL MOVE ABSOLUTE -1 IN xcur;
+ 	EXEC SQL UPDATE ra_test SET t = 'b' WHERE CURRENT OF xcur;
+ 
+ 	EXEC SQL SELECT t INTO :t FROM ra_test WHERE id = 127;
+ 	printf("id = 127, t = '%s'\n", t);
+ 
+ 	EXEC SQL SELECT t INTO :t FROM ra_test WHERE id = 513;
+ 	printf("id = 513, t = '%s'\n", t);
+ 
+ 	EXEC SQL CLOSE xcur;
+ 
+ err:
+ 
+ 	EXEC SQL COMMIT;
+ 
+ 	EXEC SQL BEGIN;
+ 
+ 	EXEC SQL DROP TABLE ra_test;
+ 
+ 	EXEC SQL COMMIT;
+ 
+ 	EXEC SQL DISCONNECT ALL;
+ 
+ 	return 0;
+ }
diff -dcrpN postgresql.orig/src/interfaces/ecpg/test/preproc/Makefile postgresql/src/interfaces/ecpg/test/preproc/Makefile
*** postgresql.orig/src/interfaces/ecpg/test/preproc/Makefile	2010-09-21 13:50:00.000000000 +0200
--- postgresql/src/interfaces/ecpg/test/preproc/Makefile	2012-03-29 11:24:54.019185470 +0200
*************** TESTS = array_of_struct array_of_struct.
*** 8,13 ****
--- 8,14 ----
  	autoprep autoprep.c \
  	comment comment.c \
  	cursor cursor.c \
+ 	cursor-readahead cursor-readahead.c \
  	define define.c \
  	init init.c \
  	strings strings.c \
