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 \