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-24 10:15:00.538924601 +0100
*************** EXEC SQL COMMIT;
*** 454,459 ****
--- 454,479 ----
details.
+
+ ECPG may use cursor readahead to improve performance of programs
+ that use single-row FETCH statements. Option -R number
+ option for ECPG modifies the default for all cursors from NO READAHEAD
+ to READAHEAD number. Explicit READAHEAD number or
+ NO READAHEAD turns cursor readahead on (with number
+ as the size of the readahead window) or off for the specified cursor,
+ respectively. For cursors using a non-0 readahead window size is 256 rows,
+ the window size may be modified by setting the ECPGFETCHSZ
+ environment variable to a different value.
+
+
+
+ UPDATE or DELETE with the
+ WHERE CURRENT OF clause, cursor readahead may or may not
+ actually improve performance, as MOVE statement has to be
+ sent to the backend before the DML statement to ensure correct cursor position
+ in the backend.
+
+
The ECPG DECLARE command does not actually
*************** while (1)
*** 5289,5294 ****
--- 5309,5324 ----
+ -231 (ECPG_INVALID_CURSOR)
+
+
+ The cursor you are trying to use with readahead has not been opened yet.
+ (SQLSTATE 34000)
+
+
+
+
+
-239 (ECPG_INFORMIX_DUPLICATE_KEY)
*************** EXEC SQL DEALLOCATE DESCRIPTOR mydesc;
*** 6583,6590 ****
! DECLARE cursor_name [ BINARY ] [ INSENSITIVE ] [ [ NO ] SCROLL ] CURSOR [ { WITH | WITHOUT } HOLD ] FOR prepared_name
! DECLARE cursor_name [ BINARY ] [ INSENSITIVE ] [ [ NO ] SCROLL ] CURSOR [ { WITH | WITHOUT } HOLD ] FOR query
--- 6613,6620 ----
! DECLARE cursor_name [ BINARY ] [ INSENSITIVE ] [ [ NO ] SCROLL ] [ NO READAHEAD | READAHEAD number ] [ OPEN RETURNS LAST ROW POSITION | OPEN RETURNS 0 FOR LAST ROW POSITION ] CURSOR [ { WITH | WITHOUT } HOLD ] FOR prepared_name
! DECLARE cursor_name [ BINARY ] [ INSENSITIVE ] [ [ NO ] SCROLL ] [ NO READAHEAD | READAHEAD number ] [ OPEN RETURNS LAST ROW POSITION | OPEN RETURNS 0 FOR LAST ROW POSITION ] CURSOR [ { WITH | WITHOUT } HOLD ] FOR query
*************** DECLARE c
*** 6639,6649 ****
! For the meaning of the cursor options,
! see .
--- 6669,6728 ----
+
+
+
+ Cursor options
! For the meaning of other cursor options, see .
+
+
+
+ READAHEAD number
+ NO READAHEAD
+
+
+ READAHEAD number makes the ECPG preprocessor and
+ runtime library use a client-side cursor accounting and data readahead
+ during FETCH. This improves performance for programs
+ that use single-row FETCH statements.
+
+
+
+ NO READAHEAD disables data readahead in case
+ -R number is used for compiling the file.
+
+
+
+
+
+ OPEN RETURNS LAST ROW POSITION
+ OPEN RETURNS 0 FOR LAST ROW POSITION
+
+
+ When the cursor is opened, it's possible to discover the size of the result set
+ using MOVE ALL which traverses the result set and move
+ the cursor back to the beginning using MOVE ABSOLUTE 0.
+ The size of the result set is returned in sqlca.sqlerrd[2].
+
+
+
+ This slows down opening the cursor from the application point of view
+ but may also have side effects. If the cursor query contains volatile function
+ calls with side effects, they will be evaluated twice because of traversing
+ the result set this way during OPEN.
+
+
+
+ The default is not to discover.
+
+
+
+
+
+
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-24 10:13:08.679284063 +0100
*************** PostgreSQL documentation
*** 171,176 ****
--- 171,196 ----
+
+
+
+ Turn on cursor readahead by default using number
+ as readahead window size.
+
+
+
+
+
+
+
+
+ Detect the cursor result set size during OPEN and
+ return it in sqlca.sqlerrd[2].
+
+
+
+
+
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-24 09:41:25.613366390 +0100
*************** 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-24 09:41:25.615366400 +0100
***************
*** 0 ****
--- 1,1190 ----
+ /*
+ * FETCH readahead support routines
+ */
+
+ #define POSTGRES_ECPG_INTERNAL
+ #include "postgres_fe.h"
+
+ #include
+ #include
+
+ #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. */
+ static bool default_return_rssz = false;
+ /* return the size of the resultset
+ in ECPGopen */
+
+ /*
+ * 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;
+ desc->cachable = (ra_size > 0);
+ /*
+ * If this cursor is allowed to be cached, the readahead
+ * windows is also allowed to be overridden (possibly
+ * even disabled) by default_fetch_size if it's set.
+ */
+ if (desc->cachable)
+ desc->ra_size = (default_fetch_size > 0 ?
+ default_fetch_size :
+ ra_size);
+ else
+ desc->ra_size = 1;
+
+ desc->backward = false;
+ desc->cache_start_pos = 0;
+ desc->atstart = true;
+ desc->atend = false;
+ desc->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 transactions, no matter if COMMIT or ROLL BACK
+ */
+ 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;
+ }
+
+ tmp = getenv("ECPGOPENRETURNSRESULTSETSIZE");
+ default_return_rssz = (tmp != NULL);
+
+ 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 &&
+ (default_return_rssz || 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 tmp[64];
+ 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 will result
+ * in a record set having tuples 1 ... ra_size. Similarly,
+ * MOVE ALL and FETCH BACKWARD 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\n",
+ stmt->lineno, start_pos);
+
+ sprintf(tmp, "%lld", (long long)start_pos);
+ query = ecpg_alloc(strlen(tmp) + strlen(cur->name) + 32, stmt->lineno);
+ /* The cursor is walked via positive absolute positions. */
+ if (cur->pos >= 0)
+ sprintf(query, "move absolute %s in %s", tmp, 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 %s in %s", tmp, 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(tmp, "%lld", (long long)cur->ra_size);
+ sprintf(query, "fetch %s %s from %s", (cur->pos < 0 ? "backward" : "forward"),
+ tmp, 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);
+ }
+
+ 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);
+
+ recheck_cursor_position(stmt, cur, forward, &overflow);
+
+ ecpg_free(query);
+
+ 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(""));
+ 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(""));
+ 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)
+ {
+ 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);
+ }
+
+ 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(""));
+ 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-24 10:35:07.663760867 +0100
*************** 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-24 09:41:25.616366406 +0100
*************** 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-24 09:41:25.616366406 +0100
*************** 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-24 09:41:25.617366412 +0100
*************** 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 *) ¤t_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 *) ¤t_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(""));
- 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(""));
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-24 09:41:25.618366418 +0100
*************** 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-24 09:41:25.619366424 +0100
*************** 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,124 ----
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;
+ /*
+ * False if ra_size = 0 was passed to ECPGopen().
+ * ECPGFETCHSZ will not override it.
+ */
+ bool cachable;
+ /* 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 */
+ };
+
/* structure to store connections */
struct connection
{
*************** struct connection
*** 79,84 ****
--- 127,134 ----
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);
--- 185,191 ----
/* 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);
--- 211,228 ----
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 ****
--- 238,245 ----
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-24 09:41:25.619366424 +0100
*************** 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-24 09:41:25.620366430 +0100
*************** 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-24 09:41:25.621366435 +0100
*************** 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-24 09:41:25.622366440 +0100
***************
*** 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-24 09:41:25.622366440 +0100
*************** 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-24 09:41:25.623366446 +0100
*************** 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-24 09:41:25.623366446 +0100
*************** 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 opt_open_return_rssz 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-24 09:41:25.625366459 +0100
*************** 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_readaheadopt_open_return_rsszCURSORopt_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,550 ----
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->open_returns_resultset_size = atoi($5);
! this->with_hold = (strncmp($7, "with ", 5) == 0);
! this->command = cat_str(7, mm_strdup("declare"), cursor_marker, $3, mm_strdup("cursor"), $7, mm_strdup("for"), $9);
this->argsinsert = argsinsert;
this->argsinsert_oos = NULL;
this->argsresult = argsresult;
*************** ECPG: DeclareCursorStmtDECLAREcursor_nam
*** 343,348 ****
--- 571,579 ----
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 ****
--- 649,720 ----
{
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-24 09:41:25.625366459 +0100
***************
*** 6,11 ****
--- 6,12 ----
#include "postgres_fe.h"
#include
+ #include
#include
#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. 1 is special
! */
! 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[])
*** 229,240 ****
--- 246,276 ----
auto_prepare = true;
else if (strcmp(optarg, "questionmarks") == 0)
questionmarks = true;
+ else if (strcmp(optarg, "fetch_readahead") == 0)
+ fetch_readahead = true;
else
{
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), argv[0]);
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-24 09:41:25.627366471 +0100
***************
*** 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-24 09:41:25.627366471 +0100
*************** 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-24 09:41:25.628366476 +0100
***************
*** 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-24 09:41:25.629366482 +0100
*************** 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 opt_open_return_rssz 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,334 ----
/* 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->open_returns_resultset_size = atoi($5);
! this->with_hold = (strncmp($7, "with ", 5) == 0);
! this->command = cat_str(6, mm_strdup("declare"), cursor_marker, $3, mm_strdup("cursor"), $7, 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($9));
! sprintf(thisquery->name, "ECPGprepared_statement(%s, %s, __LINE__)", con, $9);
this->argsinsert = NULL;
this->argsinsert_oos = NULL;
*************** ECPGCursorStmt: DECLARE cursor_name cur
*** 348,353 ****
--- 353,379 ----
}
;
+ opt_readahead: SQL_READAHEAD Iconst { $$ = $2; }
+ | NO SQL_READAHEAD { $$ = mm_strdup("0"); }
+ | /* EMPTY */
+ {
+ char val[16];
+ sprintf(val, "%ld", fetch_readahead);
+ $$ = mm_strdup(val);
+ }
+ ;
+
+ opt_open_return_rssz:
+ SQL_OPEN RETURNS LAST_P ROW POSITION { $$ = mm_strdup("1"); }
+ | SQL_OPEN RETURNS '0' FOR LAST_P ROW POSITION { $$ = mm_strdup("0"); }
+ | /* EMPTY */
+ {
+ char val[16];
+ sprintf(val, "%d", cursor_rssz);
+ $$ = mm_strdup(val);
+ }
+ ;
+
ECPGExecuteImmediateStmt: EXECUTE IMMEDIATE execstring
{
/* execute immediate means prepare the statement and
*************** ECPGFree: SQL_FREE cursor_name { $$ = $2
*** 986,991 ****
--- 1012,1018 ----
*/
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 ****
--- 1684,1695 ----
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-24 09:41:25.629366482 +0100
***************
*** 81,90 ****
--- 81,92 ----
%type opt_ecpg_fetch_into
%type opt_ecpg_using
%type opt_initializer
+ %type opt_open_return_rssz
%type opt_options
%type opt_output
%type opt_pointer
%type opt_port
+ %type opt_readahead
%type opt_reference
%type opt_scale
%type 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-24 09:41:25.630366487 +0100
*************** 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-24 09:41:25.630366487 +0100
*************** 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,
+ ptr->open_returns_resultset_size,
+ 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-24 09:41:25.631366492 +0100
*************** 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 opt_open_return_rssz 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-24 09:41:25.632366498 +0100
*************** struct _include_path
*** 125,134 ****
--- 125,139 ----
struct cursor
{
char *name;
+ enum ECPGttype vartype;
char *function;
char *command;
char *connection;
bool opened;
+ bool scrollable;
+ long fetch_readahead;
+ bool open_returns_resultset_size;
+ 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-24 09:41:25.632366498 +0100
*************** 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-24 09:41:25.632366498 +0100
*************** 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-24 09:41:25.632366498 +0100
*************** 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-24 09:41:25.633366505 +0100
*************** 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-24 09:41:25.634366511 +0100
*************** 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-24 09:41:25.634366511 +0100
*************** 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-24 09:41:25.635366517 +0100
*************** 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-24 09:41:25.636366523 +0100
*************** 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-24 09:41:25.636366523 +0100
*************** 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-24 09:41:25.637366528 +0100
*************** 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-24 09:41:25.637366528 +0100
*************** 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-24 09:41:25.638366534 +0100
***************
*** 0 ****
--- 1,775 ----
+ /* Processed by ecpg (regression mode) */
+ /* These include files are added by the preprocessor */
+ #include
+ #include
+ #include
+ /* End of automatic include section */
+ #define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+ #line 1 "cursor-readahead.pgc"
+ #include
+ #include
+
+ /* 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-24 09:41:25.638366534 +0100
***************
*** 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-24 09:41:25.639366539 +0100
***************
*** 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-24 09:41:25.639366539 +0100
*************** 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-24 09:41:25.640366544 +0100
*************** 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-24 09:41:25.641366550 +0100
*************** 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-24 09:41:25.641366550 +0100
*************** 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-24 09:41:25.642366557 +0100
*************** 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-24 09:41:25.643366563 +0100
*************** 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-24 09:41:25.643366563 +0100
*************** 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-24 09:41:25.644366569 +0100
*************** 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-24 09:41:25.644366569 +0100
*************** 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-24 09:41:25.645366575 +0100
*************** 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-24 09:41:25.646366580 +0100
*************** 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-24 09:41:25.646366580 +0100
*************** 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-24 09:41:25.647366586 +0100
*************** 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-24 09:41:25.648366591 +0100
*************** 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-24 09:41:25.648366591 +0100
*************** 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-24 09:41:25.649366596 +0100
***************
*** 0 ****
--- 1,292 ----
+ #include
+ #include
+
+ /* 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 0
+ 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-24 09:41:25.650366602 +0100
*************** 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 \