aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/auto_explain/auto_explain.c4
-rw-r--r--contrib/pg_stat_statements/pg_stat_statements.c12
-rw-r--r--contrib/spi/refint.c2
-rw-r--r--contrib/tablefunc/tablefunc.c28
-rw-r--r--contrib/xml2/xpath.c6
-rw-r--r--doc/src/sgml/spi.sgml17
-rw-r--r--src/backend/commands/createas.c2
-rw-r--r--src/backend/commands/portalcmds.c14
-rw-r--r--src/backend/executor/execMain.c12
-rw-r--r--src/backend/executor/functions.c4
-rw-r--r--src/backend/executor/spi.c24
-rw-r--r--src/backend/tcop/pquery.c114
-rw-r--r--src/backend/utils/adt/numutils.c22
-rw-r--r--src/backend/utils/adt/tsquery_rewrite.c3
-rw-r--r--src/backend/utils/adt/tsvector_op.c3
-rw-r--r--src/backend/utils/adt/xml.c10
-rw-r--r--src/include/executor/executor.h6
-rw-r--r--src/include/executor/spi.h6
-rw-r--r--src/include/executor/spi_priv.h2
-rw-r--r--src/include/funcapi.h4
-rw-r--r--src/include/nodes/execnodes.h2
-rw-r--r--src/include/postgres.h27
-rw-r--r--src/include/tcop/pquery.h2
-rw-r--r--src/include/utils/builtins.h1
-rw-r--r--src/include/utils/portal.h11
-rw-r--r--src/pl/plperl/plperl.c25
-rw-r--r--src/pl/plpgsql/src/pl_exec.c20
-rw-r--r--src/pl/plpgsql/src/plpgsql.h2
-rw-r--r--src/pl/plpython/plpy_cursorobject.c18
-rw-r--r--src/pl/plpython/plpy_spi.c28
-rw-r--r--src/pl/tcl/pltcl.c19
-rw-r--r--src/test/regress/regress.c4
32 files changed, 273 insertions, 181 deletions
diff --git a/contrib/auto_explain/auto_explain.c b/contrib/auto_explain/auto_explain.c
index 76d18315677..6708d817fba 100644
--- a/contrib/auto_explain/auto_explain.c
+++ b/contrib/auto_explain/auto_explain.c
@@ -61,7 +61,7 @@ void _PG_fini(void);
static void explain_ExecutorStart(QueryDesc *queryDesc, int eflags);
static void explain_ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction,
- long count);
+ uint64 count);
static void explain_ExecutorFinish(QueryDesc *queryDesc);
static void explain_ExecutorEnd(QueryDesc *queryDesc);
@@ -257,7 +257,7 @@ explain_ExecutorStart(QueryDesc *queryDesc, int eflags)
* ExecutorRun hook: all we need do is track nesting depth
*/
static void
-explain_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, long count)
+explain_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
{
nesting_level++;
PG_TRY();
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 9ce60e696c9..3d9b8e45d9f 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -289,7 +289,7 @@ static void pgss_post_parse_analyze(ParseState *pstate, Query *query);
static void pgss_ExecutorStart(QueryDesc *queryDesc, int eflags);
static void pgss_ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction,
- long count);
+ uint64 count);
static void pgss_ExecutorFinish(QueryDesc *queryDesc);
static void pgss_ExecutorEnd(QueryDesc *queryDesc);
static void pgss_ProcessUtility(Node *parsetree, const char *queryString,
@@ -866,7 +866,7 @@ pgss_ExecutorStart(QueryDesc *queryDesc, int eflags)
* ExecutorRun hook: all we need do is track nesting depth
*/
static void
-pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, long count)
+pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
{
nested_level++;
PG_TRY();
@@ -1001,13 +1001,7 @@ pgss_ProcessUtility(Node *parsetree, const char *queryString,
/* parse command tag to retrieve the number of affected rows. */
if (completionTag &&
strncmp(completionTag, "COPY ", 5) == 0)
- {
-#ifdef HAVE_STRTOULL
- rows = strtoull(completionTag + 5, NULL, 10);
-#else
- rows = strtoul(completionTag + 5, NULL, 10);
-#endif
- }
+ rows = pg_strtouint64(completionTag + 5, NULL, 10);
else
rows = 0;
diff --git a/contrib/spi/refint.c b/contrib/spi/refint.c
index 26022107410..01dd717522c 100644
--- a/contrib/spi/refint.c
+++ b/contrib/spi/refint.c
@@ -593,7 +593,7 @@ check_foreign_key(PG_FUNCTION_ARGS)
else
{
#ifdef REFINT_VERBOSE
- elog(NOTICE, "%s: %d tuple(s) of %s are %s",
+ elog(NOTICE, "%s: " UINT64_FORMAT " tuple(s) of %s are %s",
trigger->tgname, SPI_processed, relname,
(action == 'c') ? "deleted" : "set to null");
#endif
diff --git a/contrib/tablefunc/tablefunc.c b/contrib/tablefunc/tablefunc.c
index 1ea4a635cd5..787c02d08fc 100644
--- a/contrib/tablefunc/tablefunc.c
+++ b/contrib/tablefunc/tablefunc.c
@@ -120,7 +120,7 @@ typedef struct
typedef struct crosstab_cat_desc
{
char *catname; /* full category name */
- int attidx; /* zero based */
+ uint64 attidx; /* zero based */
} crosstab_cat_desc;
#define MAX_CATNAME_LEN NAMEDATALEN
@@ -174,8 +174,8 @@ Datum
normal_rand(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
- int call_cntr;
- int max_calls;
+ uint64 call_cntr;
+ uint64 max_calls;
normal_rand_fctx *fctx;
float8 mean;
float8 stddev;
@@ -352,8 +352,8 @@ crosstab(PG_FUNCTION_ARGS)
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
Tuplestorestate *tupstore;
TupleDesc tupdesc;
- int call_cntr;
- int max_calls;
+ uint64 call_cntr;
+ uint64 max_calls;
AttInMetadata *attinmeta;
SPITupleTable *spi_tuptable;
TupleDesc spi_tupdesc;
@@ -364,7 +364,7 @@ crosstab(PG_FUNCTION_ARGS)
MemoryContext per_query_ctx;
MemoryContext oldcontext;
int ret;
- int proc;
+ uint64 proc;
/* check to see if caller supports us returning a tuplestore */
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
@@ -389,7 +389,7 @@ crosstab(PG_FUNCTION_ARGS)
proc = SPI_processed;
/* If no qualifying tuples, fall out early */
- if (ret != SPI_OK_SELECT || proc <= 0)
+ if (ret != SPI_OK_SELECT || proc == 0)
{
SPI_finish();
rsinfo->isDone = ExprEndResult;
@@ -708,7 +708,7 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
HTAB *crosstab_hash;
HASHCTL ctl;
int ret;
- int proc;
+ uint64 proc;
MemoryContext SPIcontext;
/* initialize the category hash table */
@@ -740,7 +740,7 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
{
SPITupleTable *spi_tuptable = SPI_tuptable;
TupleDesc spi_tupdesc = spi_tuptable->tupdesc;
- int i;
+ uint64 i;
/*
* The provided categories SQL query must always return one column:
@@ -800,7 +800,7 @@ get_crosstab_tuplestore(char *sql,
char **values;
HeapTuple tuple;
int ret;
- int proc;
+ uint64 proc;
/* initialize our tuplestore (while still in query context!) */
tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
@@ -823,8 +823,8 @@ get_crosstab_tuplestore(char *sql,
char *rowid;
char *lastrowid = NULL;
bool firstpass = true;
- int i,
- j;
+ uint64 i;
+ int j;
int result_ncols;
if (num_categories == 0)
@@ -1220,7 +1220,7 @@ build_tuplestore_recursively(char *key_fld,
{
TupleDesc tupdesc = attinmeta->tupdesc;
int ret;
- int proc;
+ uint64 proc;
int serial_column;
StringInfoData sql;
char **values;
@@ -1313,7 +1313,7 @@ build_tuplestore_recursively(char *key_fld,
HeapTuple spi_tuple;
SPITupleTable *tuptable = SPI_tuptable;
TupleDesc spi_tupdesc = tuptable->tupdesc;
- int i;
+ uint64 i;
StringInfoData branchstr;
StringInfoData chk_branchstr;
StringInfoData chk_current_key;
diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c
index 655c5322cdf..ac28996867b 100644
--- a/contrib/xml2/xpath.c
+++ b/contrib/xml2/xpath.c
@@ -553,8 +553,7 @@ xpath_table(PG_FUNCTION_ARGS)
int numpaths;
int ret;
- int proc;
- int i;
+ uint64 proc;
int j;
int rownr; /* For issuing multiple rows from one original
* document */
@@ -664,7 +663,6 @@ xpath_table(PG_FUNCTION_ARGS)
query_buf.data);
proc = SPI_processed;
- /* elog(DEBUG1,"xpath_table: SPI returned %d rows",proc); */
tuptable = SPI_tuptable;
spi_tupdesc = tuptable->tupdesc;
@@ -692,6 +690,8 @@ xpath_table(PG_FUNCTION_ARGS)
PG_TRY();
{
/* For each row i.e. document returned from SPI */
+ uint64 i;
+
for (i = 0; i < proc; i++)
{
char *pkey;
diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml
index c099fcfad3a..9ae7126ae7f 100644
--- a/doc/src/sgml/spi.sgml
+++ b/doc/src/sgml/spi.sgml
@@ -400,8 +400,8 @@ SPI_execute("INSERT INTO foo SELECT * FROM bar RETURNING *", false, 5);
typedef struct
{
MemoryContext tuptabcxt; /* memory context of result table */
- uint32 alloced; /* number of alloced vals */
- uint32 free; /* number of free vals */
+ uint64 alloced; /* number of alloced vals */
+ uint64 free; /* number of free vals */
TupleDesc tupdesc; /* row descriptor */
HeapTuple *vals; /* rows */
} SPITupleTable;
@@ -4116,14 +4116,14 @@ INSERT INTO a SELECT * FROM a;
PG_MODULE_MAGIC;
#endif
-int execq(text *sql, int cnt);
+int64 execq(text *sql, int cnt);
-int
+int64
execq(text *sql, int cnt)
{
char *command;
int ret;
- int proc;
+ uint64 proc;
/* Convert given text object to a C string */
command = text_to_cstring(sql);
@@ -4141,11 +4141,12 @@ execq(text *sql, int cnt)
TupleDesc tupdesc = SPI_tuptable-&gt;tupdesc;
SPITupleTable *tuptable = SPI_tuptable;
char buf[8192];
- int i, j;
+ uint64 j;
for (j = 0; j &lt; proc; j++)
{
HeapTuple tuple = tuptable-&gt;vals[j];
+ int i;
for (i = 1, buf[0] = 0; i &lt;= tupdesc-&gt;natts; i++)
snprintf(buf + strlen (buf), sizeof(buf) - strlen(buf), " %s%s",
@@ -4173,9 +4174,9 @@ execq(text *sql, int cnt)
a shared library (details are in <xref linkend="dfunc">.):
<programlisting>
-CREATE FUNCTION execq(text, integer) RETURNS integer
+CREATE FUNCTION execq(text, integer) RETURNS int8
AS '<replaceable>filename</replaceable>'
- LANGUAGE C;
+ LANGUAGE C STRICT;
</programlisting>
</para>
diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index fcb03313092..cb7a145ee5d 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -197,7 +197,7 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString,
/* save the rowcount if we're given a completionTag to fill */
if (completionTag)
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
- "SELECT %u", queryDesc->estate->es_processed);
+ "SELECT " UINT64_FORMAT, queryDesc->estate->es_processed);
/* and clean up */
ExecutorFinish(queryDesc);
diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
index 8c045c090b4..50a54e74633 100644
--- a/src/backend/commands/portalcmds.c
+++ b/src/backend/commands/portalcmds.c
@@ -148,7 +148,7 @@ PerformPortalFetch(FetchStmt *stmt,
char *completionTag)
{
Portal portal;
- long nprocessed;
+ uint64 nprocessed;
/*
* Disallow empty-string cursor name (conflicts with protocol-level
@@ -181,7 +181,7 @@ PerformPortalFetch(FetchStmt *stmt,
/* Return command status if wanted */
if (completionTag)
- snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %ld",
+ snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s " UINT64_FORMAT,
stmt->ismove ? "MOVE" : "FETCH",
nprocessed);
}
@@ -392,20 +392,14 @@ PersistHoldablePortal(Portal portal)
if (portal->atEnd)
{
/*
- * We can handle this case even if posOverflow: just force the
- * tuplestore forward to its end. The size of the skip request
- * here is arbitrary.
+ * Just force the tuplestore forward to its end. The size of the
+ * skip request here is arbitrary.
*/
while (tuplestore_skiptuples(portal->holdStore, 1000000, true))
/* continue */ ;
}
else
{
- if (portal->posOverflow) /* oops, cannot trust portalPos */
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("could not reposition held cursor")));
-
tuplestore_rescan(portal->holdStore);
if (!tuplestore_skiptuples(portal->holdStore,
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 76f7297c077..687256279ab 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -79,7 +79,7 @@ static void ExecutePlan(EState *estate, PlanState *planstate,
bool use_parallel_mode,
CmdType operation,
bool sendTuples,
- long numberTuples,
+ uint64 numberTuples,
ScanDirection direction,
DestReceiver *dest);
static bool ExecCheckRTEPerms(RangeTblEntry *rte);
@@ -278,7 +278,7 @@ standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
*/
void
ExecutorRun(QueryDesc *queryDesc,
- ScanDirection direction, long count)
+ ScanDirection direction, uint64 count)
{
if (ExecutorRun_hook)
(*ExecutorRun_hook) (queryDesc, direction, count);
@@ -288,7 +288,7 @@ ExecutorRun(QueryDesc *queryDesc,
void
standard_ExecutorRun(QueryDesc *queryDesc,
- ScanDirection direction, long count)
+ ScanDirection direction, uint64 count)
{
EState *estate;
CmdType operation;
@@ -1521,12 +1521,12 @@ ExecutePlan(EState *estate,
bool use_parallel_mode,
CmdType operation,
bool sendTuples,
- long numberTuples,
+ uint64 numberTuples,
ScanDirection direction,
DestReceiver *dest)
{
TupleTableSlot *slot;
- long current_tuple_count;
+ uint64 current_tuple_count;
/*
* initialize local variables
@@ -1542,7 +1542,7 @@ ExecutePlan(EState *estate,
* If a tuple count was supplied, we must force the plan to run without
* parallelism, because we might exit early.
*/
- if (numberTuples != 0)
+ if (numberTuples)
use_parallel_mode = false;
/*
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index c3cdad4abf7..6e14c9d2967 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -853,7 +853,7 @@ postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
else
{
/* Run regular commands to completion unless lazyEval */
- long count = (es->lazyEval) ? 1L : 0L;
+ uint64 count = (es->lazyEval) ? 1 : 0;
ExecutorRun(es->qd, ForwardScanDirection, count);
@@ -861,7 +861,7 @@ postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
* If we requested run to completion OR there was no tuple returned,
* command must be complete.
*/
- result = (count == 0L || es->qd->estate->es_processed == 0);
+ result = (count == 0 || es->qd->estate->es_processed == 0);
}
return result;
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 3357c0d2524..3d04c23b4e0 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -36,7 +36,7 @@
#include "utils/typcache.h"
-uint32 SPI_processed = 0;
+uint64 SPI_processed = 0;
Oid SPI_lastoid = InvalidOid;
SPITupleTable *SPI_tuptable = NULL;
int SPI_result;
@@ -56,12 +56,12 @@ static void _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan);
static int _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
Snapshot snapshot, Snapshot crosscheck_snapshot,
- bool read_only, bool fire_triggers, long tcount);
+ bool read_only, bool fire_triggers, uint64 tcount);
static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes,
Datum *Values, const char *Nulls);
-static int _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, long tcount);
+static int _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, uint64 tcount);
static void _SPI_error_callback(void *arg);
@@ -1991,10 +1991,10 @@ _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan)
static int
_SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
Snapshot snapshot, Snapshot crosscheck_snapshot,
- bool read_only, bool fire_triggers, long tcount)
+ bool read_only, bool fire_triggers, uint64 tcount)
{
int my_res = 0;
- uint32 my_processed = 0;
+ uint64 my_processed = 0;
Oid my_lastoid = InvalidOid;
SPITupleTable *my_tuptable = NULL;
int res = 0;
@@ -2218,8 +2218,8 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
if (IsA(stmt, CreateTableAsStmt))
{
Assert(strncmp(completionTag, "SELECT ", 7) == 0);
- _SPI_current->processed = strtoul(completionTag + 7,
- NULL, 10);
+ _SPI_current->processed = pg_strtouint64(completionTag + 7,
+ NULL, 10);
/*
* For historical reasons, if CREATE TABLE AS was spelled
@@ -2231,8 +2231,8 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
else if (IsA(stmt, CopyStmt))
{
Assert(strncmp(completionTag, "COPY ", 5) == 0);
- _SPI_current->processed = strtoul(completionTag + 5,
- NULL, 10);
+ _SPI_current->processed = pg_strtouint64(completionTag + 5,
+ NULL, 10);
}
}
@@ -2348,7 +2348,7 @@ _SPI_convert_params(int nargs, Oid *argtypes,
}
static int
-_SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, long tcount)
+_SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, uint64 tcount)
{
int operation = queryDesc->operation;
int eflags;
@@ -2460,7 +2460,7 @@ static void
_SPI_cursor_operation(Portal portal, FetchDirection direction, long count,
DestReceiver *dest)
{
- long nfetched;
+ uint64 nfetched;
/* Check that the portal is valid */
if (!PortalIsValid(portal))
@@ -2563,7 +2563,7 @@ _SPI_end_call(bool procmem)
static bool
_SPI_checktuples(void)
{
- uint32 processed = _SPI_current->processed;
+ uint64 processed = _SPI_current->processed;
SPITupleTable *tuptable = _SPI_current->tuptable;
bool failed = false;
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 6893b0f4239..fcdc4c347c7 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -39,16 +39,16 @@ static void ProcessQuery(PlannedStmt *plan,
DestReceiver *dest,
char *completionTag);
static void FillPortalStore(Portal portal, bool isTopLevel);
-static uint32 RunFromStore(Portal portal, ScanDirection direction, long count,
+static uint64 RunFromStore(Portal portal, ScanDirection direction, uint64 count,
DestReceiver *dest);
-static long PortalRunSelect(Portal portal, bool forward, long count,
+static uint64 PortalRunSelect(Portal portal, bool forward, long count,
DestReceiver *dest);
static void PortalRunUtility(Portal portal, Node *utilityStmt, bool isTopLevel,
DestReceiver *dest, char *completionTag);
static void PortalRunMulti(Portal portal, bool isTopLevel,
DestReceiver *dest, DestReceiver *altdest,
char *completionTag);
-static long DoPortalRunFetch(Portal portal,
+static uint64 DoPortalRunFetch(Portal portal,
FetchDirection fdirection,
long count,
DestReceiver *dest);
@@ -195,7 +195,8 @@ ProcessQuery(PlannedStmt *plan,
{
case CMD_SELECT:
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
- "SELECT %u", queryDesc->estate->es_processed);
+ "SELECT " UINT64_FORMAT,
+ queryDesc->estate->es_processed);
break;
case CMD_INSERT:
if (queryDesc->estate->es_processed == 1)
@@ -203,15 +204,18 @@ ProcessQuery(PlannedStmt *plan,
else
lastOid = InvalidOid;
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
- "INSERT %u %u", lastOid, queryDesc->estate->es_processed);
+ "INSERT %u " UINT64_FORMAT,
+ lastOid, queryDesc->estate->es_processed);
break;
case CMD_UPDATE:
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
- "UPDATE %u", queryDesc->estate->es_processed);
+ "UPDATE " UINT64_FORMAT,
+ queryDesc->estate->es_processed);
break;
case CMD_DELETE:
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
- "DELETE %u", queryDesc->estate->es_processed);
+ "DELETE " UINT64_FORMAT,
+ queryDesc->estate->es_processed);
break;
default:
strcpy(completionTag, "???");
@@ -548,7 +552,6 @@ PortalStart(Portal portal, ParamListInfo params,
portal->atStart = true;
portal->atEnd = false; /* allow fetches */
portal->portalPos = 0;
- portal->posOverflow = false;
PopActiveSnapshot();
break;
@@ -576,7 +579,6 @@ PortalStart(Portal portal, ParamListInfo params,
portal->atStart = true;
portal->atEnd = false; /* allow fetches */
portal->portalPos = 0;
- portal->posOverflow = false;
break;
case PORTAL_UTIL_SELECT:
@@ -598,7 +600,6 @@ PortalStart(Portal portal, ParamListInfo params,
portal->atStart = true;
portal->atEnd = false; /* allow fetches */
portal->portalPos = 0;
- portal->posOverflow = false;
break;
case PORTAL_MULTI_QUERY:
@@ -708,7 +709,7 @@ PortalRun(Portal portal, long count, bool isTopLevel,
char *completionTag)
{
bool result;
- uint32 nprocessed;
+ uint64 nprocessed;
ResourceOwner saveTopTransactionResourceOwner;
MemoryContext saveTopTransactionContext;
Portal saveActivePortal;
@@ -794,7 +795,7 @@ PortalRun(Portal portal, long count, bool isTopLevel,
{
if (strcmp(portal->commandTag, "SELECT") == 0)
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
- "SELECT %u", nprocessed);
+ "SELECT " UINT64_FORMAT, nprocessed);
else
strcpy(completionTag, portal->commandTag);
}
@@ -877,14 +878,14 @@ PortalRun(Portal portal, long count, bool isTopLevel,
*
* count <= 0 is interpreted as a no-op: the destination gets started up
* and shut down, but nothing else happens. Also, count == FETCH_ALL is
- * interpreted as "all rows".
+ * interpreted as "all rows". (cf FetchStmt.howMany)
*
* Caller must already have validated the Portal and done appropriate
* setup (cf. PortalRun).
*
* Returns number of rows processed (suitable for use in result tag)
*/
-static long
+static uint64
PortalRunSelect(Portal portal,
bool forward,
long count,
@@ -892,7 +893,7 @@ PortalRunSelect(Portal portal,
{
QueryDesc *queryDesc;
ScanDirection direction;
- uint32 nprocessed;
+ uint64 nprocessed;
/*
* NB: queryDesc will be NULL if we are fetching from a held cursor or a
@@ -926,7 +927,10 @@ PortalRunSelect(Portal portal,
if (forward)
{
if (portal->atEnd || count <= 0)
+ {
direction = NoMovementScanDirection;
+ count = 0; /* don't pass negative count to executor */
+ }
else
direction = ForwardScanDirection;
@@ -935,29 +939,22 @@ PortalRunSelect(Portal portal,
count = 0;
if (portal->holdStore)
- nprocessed = RunFromStore(portal, direction, count, dest);
+ nprocessed = RunFromStore(portal, direction, (uint64) count, dest);
else
{
PushActiveSnapshot(queryDesc->snapshot);
- ExecutorRun(queryDesc, direction, count);
+ ExecutorRun(queryDesc, direction, (uint64) count);
nprocessed = queryDesc->estate->es_processed;
PopActiveSnapshot();
}
if (!ScanDirectionIsNoMovement(direction))
{
- long oldPos;
-
if (nprocessed > 0)
portal->atStart = false; /* OK to go backward now */
- if (count == 0 ||
- (unsigned long) nprocessed < (unsigned long) count)
+ if (count == 0 || nprocessed < (uint64) count)
portal->atEnd = true; /* we retrieved 'em all */
- oldPos = portal->portalPos;
portal->portalPos += nprocessed;
- /* portalPos doesn't advance when we fall off the end */
- if (portal->portalPos < oldPos)
- portal->posOverflow = true;
}
}
else
@@ -969,7 +966,10 @@ PortalRunSelect(Portal portal,
errhint("Declare it with SCROLL option to enable backward scan.")));
if (portal->atStart || count <= 0)
+ {
direction = NoMovementScanDirection;
+ count = 0; /* don't pass negative count to executor */
+ }
else
direction = BackwardScanDirection;
@@ -978,11 +978,11 @@ PortalRunSelect(Portal portal,
count = 0;
if (portal->holdStore)
- nprocessed = RunFromStore(portal, direction, count, dest);
+ nprocessed = RunFromStore(portal, direction, (uint64) count, dest);
else
{
PushActiveSnapshot(queryDesc->snapshot);
- ExecutorRun(queryDesc, direction, count);
+ ExecutorRun(queryDesc, direction, (uint64) count);
nprocessed = queryDesc->estate->es_processed;
PopActiveSnapshot();
}
@@ -994,22 +994,14 @@ PortalRunSelect(Portal portal,
portal->atEnd = false; /* OK to go forward now */
portal->portalPos++; /* adjust for endpoint case */
}
- if (count == 0 ||
- (unsigned long) nprocessed < (unsigned long) count)
+ if (count == 0 || nprocessed < (uint64) count)
{
portal->atStart = true; /* we retrieved 'em all */
portal->portalPos = 0;
- portal->posOverflow = false;
}
else
{
- long oldPos;
-
- oldPos = portal->portalPos;
portal->portalPos -= nprocessed;
- if (portal->portalPos > oldPos ||
- portal->portalPos <= 0)
- portal->posOverflow = true;
}
}
}
@@ -1083,11 +1075,11 @@ FillPortalStore(Portal portal, bool isTopLevel)
* are run in the caller's memory context (since we have no estate). Watch
* out for memory leaks.
*/
-static uint32
-RunFromStore(Portal portal, ScanDirection direction, long count,
+static uint64
+RunFromStore(Portal portal, ScanDirection direction, uint64 count,
DestReceiver *dest)
{
- long current_tuple_count = 0;
+ uint64 current_tuple_count = 0;
TupleTableSlot *slot;
slot = MakeSingleTupleTableSlot(portal->tupDesc);
@@ -1136,7 +1128,7 @@ RunFromStore(Portal portal, ScanDirection direction, long count,
ExecDropSingleTupleTableSlot(slot);
- return (uint32) current_tuple_count;
+ return current_tuple_count;
}
/*
@@ -1375,15 +1367,19 @@ PortalRunMulti(Portal portal, bool isTopLevel,
*
* Note: we presently assume that no callers of this want isTopLevel = true.
*
+ * count <= 0 is interpreted as a no-op: the destination gets started up
+ * and shut down, but nothing else happens. Also, count == FETCH_ALL is
+ * interpreted as "all rows". (cf FetchStmt.howMany)
+ *
* Returns number of rows processed (suitable for use in result tag)
*/
-long
+uint64
PortalRunFetch(Portal portal,
FetchDirection fdirection,
long count,
DestReceiver *dest)
{
- long result;
+ uint64 result;
Portal saveActivePortal;
ResourceOwner saveResourceOwner;
MemoryContext savePortalContext;
@@ -1470,9 +1466,13 @@ PortalRunFetch(Portal portal,
* DoPortalRunFetch
* Guts of PortalRunFetch --- the portal context is already set up
*
+ * count <= 0 is interpreted as a no-op: the destination gets started up
+ * and shut down, but nothing else happens. Also, count == FETCH_ALL is
+ * interpreted as "all rows". (cf FetchStmt.howMany)
+ *
* Returns number of rows processed (suitable for use in result tag)
*/
-static long
+static uint64
DoPortalRunFetch(Portal portal,
FetchDirection fdirection,
long count,
@@ -1508,13 +1508,21 @@ DoPortalRunFetch(Portal portal,
{
/*
* Definition: Rewind to start, advance count-1 rows, return
- * next row (if any). In practice, if the goal is less than
- * halfway back to the start, it's better to scan from where
- * we are. In any case, we arrange to fetch the target row
- * going forwards.
+ * next row (if any).
+ *
+ * In practice, if the goal is less than halfway back to the
+ * start, it's better to scan from where we are.
+ *
+ * Also, if current portalPos is outside the range of "long",
+ * do it the hard way to avoid possible overflow of the count
+ * argument to PortalRunSelect. We must exclude exactly
+ * LONG_MAX, as well, lest the count look like FETCH_ALL.
+ *
+ * In any case, we arrange to fetch the target row going
+ * forwards.
*/
- if (portal->posOverflow || portal->portalPos == LONG_MAX ||
- count - 1 <= portal->portalPos / 2)
+ if ((uint64) (count - 1) <= portal->portalPos / 2 ||
+ portal->portalPos >= (uint64) LONG_MAX)
{
DoPortalRewind(portal);
if (count > 1)
@@ -1523,7 +1531,7 @@ DoPortalRunFetch(Portal portal,
}
else
{
- long pos = portal->portalPos;
+ long pos = (long) portal->portalPos;
if (portal->atEnd)
pos++; /* need one extra fetch if off end */
@@ -1609,7 +1617,7 @@ DoPortalRunFetch(Portal portal,
if (dest->mydest == DestNone)
{
/* MOVE 0 returns 0/1 based on if FETCH 0 would return a row */
- return on_row ? 1L : 0L;
+ return on_row ? 1 : 0;
}
else
{
@@ -1635,12 +1643,11 @@ DoPortalRunFetch(Portal portal,
*/
if (!forward && count == FETCH_ALL && dest->mydest == DestNone)
{
- long result = portal->portalPos;
+ uint64 result = portal->portalPos;
if (result > 0 && !portal->atEnd)
result--;
DoPortalRewind(portal);
- /* result is bogus if pos had overflowed, but it's best we can do */
return result;
}
@@ -1677,5 +1684,4 @@ DoPortalRewind(Portal portal)
portal->atStart = true;
portal->atEnd = false;
portal->portalPos = 0;
- portal->posOverflow = false;
}
diff --git a/src/backend/utils/adt/numutils.c b/src/backend/utils/adt/numutils.c
index 6b105964bd1..da100f7c0f2 100644
--- a/src/backend/utils/adt/numutils.c
+++ b/src/backend/utils/adt/numutils.c
@@ -388,3 +388,25 @@ pg_ltostr(char *str, int32 value)
return end;
}
+
+/*
+ * pg_strtouint64
+ * Converts 'str' into an unsigned 64-bit integer.
+ *
+ * This has the identical API to strtoul(3), except that it will handle
+ * 64-bit ints even where "long" is narrower than that.
+ *
+ * For the moment it seems sufficient to assume that the platform has
+ * such a function somewhere; let's not roll our own.
+ */
+uint64
+pg_strtouint64(const char *str, char **endptr, int base)
+{
+#ifdef WIN32
+ return _strtoui64(str, endptr, base);
+#elif defined(HAVE_STRTOULL) && SIZEOF_LONG < 8
+ return strtoull(str, endptr, base);
+#else
+ return strtoul(str, endptr, base);
+#endif
+}
diff --git a/src/backend/utils/adt/tsquery_rewrite.c b/src/backend/utils/adt/tsquery_rewrite.c
index 0870afd867f..28f328ddb31 100644
--- a/src/backend/utils/adt/tsquery_rewrite.c
+++ b/src/backend/utils/adt/tsquery_rewrite.c
@@ -260,7 +260,6 @@ tsquery_rewrite_query(PG_FUNCTION_ARGS)
SPIPlanPtr plan;
Portal portal;
bool isnull;
- int i;
if (query->size == 0)
{
@@ -294,6 +293,8 @@ tsquery_rewrite_query(PG_FUNCTION_ARGS)
while (SPI_processed > 0 && tree)
{
+ uint64 i;
+
for (i = 0; i < SPI_processed && tree; i++)
{
Datum qdata = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull);
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 186b3d337ad..f6d3fb5d7b4 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -1682,7 +1682,6 @@ static TSVectorStat *
ts_stat_sql(MemoryContext persistentContext, text *txt, text *ws)
{
char *query = text_to_cstring(txt);
- int i;
TSVectorStat *stat;
bool isnull;
Portal portal;
@@ -1746,6 +1745,8 @@ ts_stat_sql(MemoryContext persistentContext, text *txt, text *ws)
while (SPI_processed > 0)
{
+ uint64 i;
+
for (i = 0; i < SPI_processed; i++)
{
Datum data = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull);
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index 56179f822ed..7ed5bcb93dd 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -161,7 +161,7 @@ static const char *map_sql_catalog_to_xmlschema_types(List *nspid_list,
static const char *map_sql_type_to_xml_name(Oid typeoid, int typmod);
static const char *map_sql_typecoll_to_xmlschema_types(List *tupdesc_list);
static const char *map_sql_type_to_xmlschema_type(Oid typeoid, int typmod);
-static void SPI_sql_row_to_xmlelement(int rownum, StringInfo result,
+static void SPI_sql_row_to_xmlelement(uint64 rownum, StringInfo result,
char *tablename, bool nulls, bool tableforest,
const char *targetns, bool top_level);
@@ -2260,7 +2260,7 @@ _SPI_strdup(const char *s)
static List *
query_to_oid_list(const char *query)
{
- int i;
+ uint64 i;
List *list = NIL;
SPI_execute(query, true, 0);
@@ -2379,7 +2379,7 @@ cursor_to_xml(PG_FUNCTION_ARGS)
StringInfoData result;
Portal portal;
- int i;
+ uint64 i;
initStringInfo(&result);
@@ -2454,7 +2454,7 @@ query_to_xml_internal(const char *query, char *tablename,
{
StringInfo result;
char *xmltn;
- int i;
+ uint64 i;
if (tablename)
xmltn = map_sql_identifier_to_xml_name(tablename, true, false);
@@ -3532,7 +3532,7 @@ map_sql_type_to_xmlschema_type(Oid typeoid, int typmod)
* SPI cursor. See also SQL/XML:2008 section 9.10.
*/
static void
-SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename,
+SPI_sql_row_to_xmlelement(uint64 rownum, StringInfo result, char *tablename,
bool nulls, bool tableforest,
const char *targetns, bool top_level)
{
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 1a44085a2ce..44fac278a49 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -80,7 +80,7 @@ extern PGDLLIMPORT ExecutorStart_hook_type ExecutorStart_hook;
/* Hook for plugins to get control in ExecutorRun() */
typedef void (*ExecutorRun_hook_type) (QueryDesc *queryDesc,
ScanDirection direction,
- long count);
+ uint64 count);
extern PGDLLIMPORT ExecutorRun_hook_type ExecutorRun_hook;
/* Hook for plugins to get control in ExecutorFinish() */
@@ -175,9 +175,9 @@ extern TupleTableSlot *ExecFilterJunk(JunkFilter *junkfilter,
extern void ExecutorStart(QueryDesc *queryDesc, int eflags);
extern void standard_ExecutorStart(QueryDesc *queryDesc, int eflags);
extern void ExecutorRun(QueryDesc *queryDesc,
- ScanDirection direction, long count);
+ ScanDirection direction, uint64 count);
extern void standard_ExecutorRun(QueryDesc *queryDesc,
- ScanDirection direction, long count);
+ ScanDirection direction, uint64 count);
extern void ExecutorFinish(QueryDesc *queryDesc);
extern void standard_ExecutorFinish(QueryDesc *queryDesc);
extern void ExecutorEnd(QueryDesc *queryDesc);
diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h
index 8c3ca261237..1792fb12172 100644
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -21,8 +21,8 @@
typedef struct SPITupleTable
{
MemoryContext tuptabcxt; /* memory context of result table */
- uint32 alloced; /* # of alloced vals */
- uint32 free; /* # of free vals */
+ uint64 alloced; /* # of alloced vals */
+ uint64 free; /* # of free vals */
TupleDesc tupdesc; /* tuple descriptor */
HeapTuple *vals; /* tuples */
slist_node next; /* link for internal bookkeeping */
@@ -59,7 +59,7 @@ typedef struct _SPI_plan *SPIPlanPtr;
#define SPI_OK_UPDATE_RETURNING 13
#define SPI_OK_REWRITTEN 14
-extern PGDLLIMPORT uint32 SPI_processed;
+extern PGDLLIMPORT uint64 SPI_processed;
extern PGDLLIMPORT Oid SPI_lastoid;
extern PGDLLIMPORT SPITupleTable *SPI_tuptable;
extern PGDLLIMPORT int SPI_result;
diff --git a/src/include/executor/spi_priv.h b/src/include/executor/spi_priv.h
index 3187230c020..e8084dff091 100644
--- a/src/include/executor/spi_priv.h
+++ b/src/include/executor/spi_priv.h
@@ -21,7 +21,7 @@
typedef struct
{
/* current results */
- uint32 processed; /* by Executor */
+ uint64 processed; /* by Executor */
Oid lastoid;
SPITupleTable *tuptable; /* tuptable currently being built */
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index b6ae93fe0d0..e73a82427ca 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -62,7 +62,7 @@ typedef struct FuncCallContext
* call_cntr is initialized to 0 for you by SRF_FIRSTCALL_INIT(), and
* incremented for you every time SRF_RETURN_NEXT() is called.
*/
- uint32 call_cntr;
+ uint64 call_cntr;
/*
* OPTIONAL maximum number of calls
@@ -71,7 +71,7 @@ typedef struct FuncCallContext
* not set, you must provide alternative means to know when the function
* is done.
*/
- uint32 max_calls;
+ uint64 max_calls;
/*
* OPTIONAL pointer to result slot
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 064a0509c4d..d35ec810450 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -387,7 +387,7 @@ typedef struct EState
List *es_rowMarks; /* List of ExecRowMarks */
- uint32 es_processed; /* # of tuples processed */
+ uint64 es_processed; /* # of tuples processed */
Oid es_lastoid; /* last oid processed (by INSERT) */
int es_top_eflags; /* eflags passed to ExecutorStart */
diff --git a/src/include/postgres.h b/src/include/postgres.h
index 453147e1f0b..cde939b7cab 100644
--- a/src/include/postgres.h
+++ b/src/include/postgres.h
@@ -630,6 +630,33 @@ extern Datum Int64GetDatum(int64 X);
#endif
/*
+ * DatumGetUInt64
+ * Returns 64-bit unsigned integer value of a datum.
+ *
+ * Note: this macro hides whether int64 is pass by value or by reference.
+ */
+
+#ifdef USE_FLOAT8_BYVAL
+#define DatumGetUInt64(X) ((uint64) GET_8_BYTES(X))
+#else
+#define DatumGetUInt64(X) (* ((uint64 *) DatumGetPointer(X)))
+#endif
+
+/*
+ * UInt64GetDatum
+ * Returns datum representation for a 64-bit unsigned integer.
+ *
+ * Note: if int64 is pass by reference, this function returns a reference
+ * to palloc'd space.
+ */
+
+#ifdef USE_FLOAT8_BYVAL
+#define UInt64GetDatum(X) ((Datum) SET_8_BYTES(X))
+#else
+#define UInt64GetDatum(X) Int64GetDatum((int64) (X))
+#endif
+
+/*
* DatumGetFloat4
* Returns 4-byte floating point value of a datum.
*
diff --git a/src/include/tcop/pquery.h b/src/include/tcop/pquery.h
index 4f1fd139a36..e04fc4330d9 100644
--- a/src/include/tcop/pquery.h
+++ b/src/include/tcop/pquery.h
@@ -37,7 +37,7 @@ extern bool PortalRun(Portal portal, long count, bool isTopLevel,
DestReceiver *dest, DestReceiver *altdest,
char *completionTag);
-extern long PortalRunFetch(Portal portal,
+extern uint64 PortalRunFetch(Portal portal,
FetchDirection fdirection,
long count,
DestReceiver *dest);
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 115f8afb45b..59a00bbcbcf 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -292,6 +292,7 @@ extern void pg_ltoa(int32 l, char *a);
extern void pg_lltoa(int64 ll, char *a);
extern char *pg_ltostr_zeropad(char *str, int32 value, int32 minwidth);
extern char *pg_ltostr(char *str, int32 value);
+extern uint64 pg_strtouint64(const char *str, char **endptr, int base);
/*
* Per-opclass comparison functions for new btrees. These are
diff --git a/src/include/utils/portal.h b/src/include/utils/portal.h
index 4236215b796..7250c9c1bb3 100644
--- a/src/include/utils/portal.h
+++ b/src/include/utils/portal.h
@@ -166,15 +166,14 @@ typedef struct PortalData
* atStart, atEnd and portalPos indicate the current cursor position.
* portalPos is zero before the first row, N after fetching N'th row of
* query. After we run off the end, portalPos = # of rows in query, and
- * atEnd is true. If portalPos overflows, set posOverflow (this causes us
- * to stop relying on its value for navigation). Note that atStart
- * implies portalPos == 0, but not the reverse (portalPos could have
- * overflowed).
+ * atEnd is true. Note that atStart implies portalPos == 0, but not the
+ * reverse: we might have backed up only as far as the first row, not to
+ * the start. Also note that various code inspects atStart and atEnd, but
+ * only the portal movement routines should touch portalPos.
*/
bool atStart;
bool atEnd;
- bool posOverflow;
- long portalPos;
+ uint64 portalPos;
/* Presentation data, primarily used by the pg_cursors system view */
TimestampTz creation_time; /* time at which this portal was defined */
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index cd917ab8e46..269f7f33220 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -12,8 +12,9 @@
/* system stuff */
#include <ctype.h>
#include <fcntl.h>
-#include <unistd.h>
+#include <limits.h>
#include <locale.h>
+#include <unistd.h>
/* postgreSQL stuff */
#include "access/htup_details.h"
@@ -281,7 +282,7 @@ static Datum plperl_hash_to_datum(SV *src, TupleDesc td);
static void plperl_init_shared_libs(pTHX);
static void plperl_trusted_init(void);
static void plperl_untrusted_init(void);
-static HV *plperl_spi_execute_fetch_result(SPITupleTable *, int, int);
+static HV *plperl_spi_execute_fetch_result(SPITupleTable *, uint64, int);
static char *hek2cstr(HE *he);
static SV **hv_store_string(HV *hv, const char *key, SV *val);
static SV **hv_fetch_string(HV *hv, const char *key);
@@ -1472,7 +1473,7 @@ plperl_ref_from_pg_array(Datum arg, Oid typid)
hv = newHV();
(void) hv_store(hv, "array", 5, av, 0);
- (void) hv_store(hv, "typeoid", 7, newSViv(typid), 0);
+ (void) hv_store(hv, "typeoid", 7, newSVuv(typid), 0);
return sv_bless(newRV_noinc((SV *) hv),
gv_stashpv("PostgreSQL::InServer::ARRAY", 0));
@@ -3091,7 +3092,7 @@ plperl_spi_exec(char *query, int limit)
static HV *
-plperl_spi_execute_fetch_result(SPITupleTable *tuptable, int processed,
+plperl_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 processed,
int status)
{
HV *result;
@@ -3103,13 +3104,25 @@ plperl_spi_execute_fetch_result(SPITupleTable *tuptable, int processed,
hv_store_string(result, "status",
cstr2sv(SPI_result_code_string(status)));
hv_store_string(result, "processed",
- newSViv(processed));
+ (processed > (uint64) INT_MAX) ?
+ newSVnv((double) processed) :
+ newSViv((int) processed));
if (status > 0 && tuptable)
{
AV *rows;
SV *row;
- int i;
+ uint64 i;
+
+ /*
+ * av_extend's 2nd argument is declared I32. It's possible we could
+ * nonetheless push more than INT_MAX elements into a Perl array, but
+ * let's just fail instead of trying.
+ */
+ if (processed > (uint64) INT_MAX)
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("query result has too many rows to fit in a Perl array")));
rows = newAV();
av_extend(rows, processed);
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index bd58d5f444f..b63ecacdecf 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -1601,8 +1601,8 @@ exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
{
case PLPGSQL_GETDIAG_ROW_COUNT:
exec_assign_value(estate, var,
- UInt32GetDatum(estate->eval_processed),
- false, INT4OID, -1);
+ UInt64GetDatum(estate->eval_processed),
+ false, INT8OID, -1);
break;
case PLPGSQL_GETDIAG_RESULT_OID:
@@ -2856,7 +2856,7 @@ exec_stmt_return_query(PLpgSQL_execstate *estate,
PLpgSQL_stmt_return_query *stmt)
{
Portal portal;
- uint32 processed = 0;
+ uint64 processed = 0;
TupleConversionMap *tupmap;
if (!estate->retisset)
@@ -2887,7 +2887,7 @@ exec_stmt_return_query(PLpgSQL_execstate *estate,
while (true)
{
- int i;
+ uint64 i;
SPI_cursor_fetch(portal, true, 50);
if (SPI_processed == 0)
@@ -3579,7 +3579,7 @@ exec_stmt_execsql(PLpgSQL_execstate *estate,
if (stmt->into)
{
SPITupleTable *tuptab = SPI_tuptable;
- uint32 n = SPI_processed;
+ uint64 n = SPI_processed;
PLpgSQL_rec *rec = NULL;
PLpgSQL_row *row = NULL;
@@ -3769,7 +3769,7 @@ exec_stmt_dynexecute(PLpgSQL_execstate *estate,
if (stmt->into)
{
SPITupleTable *tuptab = SPI_tuptable;
- uint32 n = SPI_processed;
+ uint64 n = SPI_processed;
PLpgSQL_rec *rec = NULL;
PLpgSQL_row *row = NULL;
@@ -4043,7 +4043,7 @@ exec_stmt_fetch(PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt)
SPITupleTable *tuptab;
Portal portal;
char *curname;
- uint32 n;
+ uint64 n;
/* ----------
* Get the portal of the cursor by name
@@ -5151,7 +5151,7 @@ exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt,
SPITupleTable *tuptab;
bool found = false;
int rc = PLPGSQL_RC_OK;
- int n;
+ uint64 n;
/*
* Determine if we assign to a record or a row
@@ -5182,7 +5182,7 @@ exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt,
* If the query didn't return any rows, set the target to NULL and fall
* through with found = false.
*/
- if (n <= 0)
+ if (n == 0)
{
exec_move_row(estate, rec, row, NULL, tuptab->tupdesc);
exec_eval_cleanup(estate);
@@ -5195,7 +5195,7 @@ exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt,
*/
while (n > 0)
{
- int i;
+ uint64 i;
for (i = 0; i < n; i++)
{
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index a1e900d7336..2deece43eb7 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -820,7 +820,7 @@ typedef struct PLpgSQL_execstate
/* temporary state for results from evaluation of query or expr */
SPITupleTable *eval_tuptable;
- uint32 eval_processed;
+ uint64 eval_processed;
Oid eval_lastoid;
ExprContext *eval_econtext; /* for executing simple expressions */
diff --git a/src/pl/plpython/plpy_cursorobject.c b/src/pl/plpython/plpy_cursorobject.c
index 103571ba15c..44ba76e765e 100644
--- a/src/pl/plpython/plpy_cursorobject.c
+++ b/src/pl/plpython/plpy_cursorobject.c
@@ -6,6 +6,8 @@
#include "postgres.h"
+#include <limits.h>
+
#include "access/xact.h"
#include "mb/pg_wchar.h"
#include "utils/memutils.h"
@@ -446,11 +448,23 @@ PLy_cursor_fetch(PyObject *self, PyObject *args)
ret->status = PyInt_FromLong(SPI_OK_FETCH);
Py_DECREF(ret->nrows);
- ret->nrows = PyInt_FromLong(SPI_processed);
+ ret->nrows = (SPI_processed > (uint64) LONG_MAX) ?
+ PyFloat_FromDouble((double) SPI_processed) :
+ PyInt_FromLong((long) SPI_processed);
if (SPI_processed != 0)
{
- int i;
+ uint64 i;
+
+ /*
+ * PyList_New() and PyList_SetItem() use Py_ssize_t for list size
+ * and list indices; so we cannot support a result larger than
+ * PY_SSIZE_T_MAX.
+ */
+ if (SPI_processed > (uint64) PY_SSIZE_T_MAX)
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("query result has too many rows to fit in a Python list")));
Py_DECREF(ret->rows);
ret->rows = PyList_New(SPI_processed);
diff --git a/src/pl/plpython/plpy_spi.c b/src/pl/plpython/plpy_spi.c
index 58e78ecebcb..7d84629f48f 100644
--- a/src/pl/plpython/plpy_spi.c
+++ b/src/pl/plpython/plpy_spi.c
@@ -6,6 +6,8 @@
#include "postgres.h"
+#include <limits.h>
+
#include "access/htup_details.h"
#include "access/xact.h"
#include "catalog/pg_type.h"
@@ -29,7 +31,8 @@
static PyObject *PLy_spi_execute_query(char *query, long limit);
static PyObject *PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit);
-static PyObject *PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status);
+static PyObject *PLy_spi_execute_fetch_result(SPITupleTable *tuptable,
+ uint64 rows, int status);
static void PLy_spi_exception_set(PyObject *excclass, ErrorData *edata);
@@ -382,7 +385,7 @@ PLy_spi_execute_query(char *query, long limit)
}
static PyObject *
-PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
+PLy_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 rows, int status)
{
PLyResultObject *result;
volatile MemoryContext oldcontext;
@@ -394,16 +397,19 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
if (status > 0 && tuptable == NULL)
{
Py_DECREF(result->nrows);
- result->nrows = PyInt_FromLong(rows);
+ result->nrows = (rows > (uint64) LONG_MAX) ?
+ PyFloat_FromDouble((double) rows) :
+ PyInt_FromLong((long) rows);
}
else if (status > 0 && tuptable != NULL)
{
PLyTypeInfo args;
- int i;
MemoryContext cxt;
Py_DECREF(result->nrows);
- result->nrows = PyInt_FromLong(rows);
+ result->nrows = (rows > (uint64) LONG_MAX) ?
+ PyFloat_FromDouble((double) rows) :
+ PyInt_FromLong((long) rows);
cxt = AllocSetContextCreate(CurrentMemoryContext,
"PL/Python temp context",
@@ -419,6 +425,18 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
if (rows)
{
+ uint64 i;
+
+ /*
+ * PyList_New() and PyList_SetItem() use Py_ssize_t for list
+ * size and list indices; so we cannot support a result larger
+ * than PY_SSIZE_T_MAX.
+ */
+ if (rows > (uint64) PY_SSIZE_T_MAX)
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("query result has too many rows to fit in a Python list")));
+
Py_DECREF(result->rows);
result->rows = PyList_New(rows);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index 105b6186f64..5b27c731b6e 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -226,7 +226,7 @@ static int pltcl_process_SPI_result(Tcl_Interp *interp,
Tcl_Obj *loop_body,
int spi_rc,
SPITupleTable *tuptable,
- int ntuples);
+ uint64 ntuples);
static int pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[]);
static int pltcl_SPI_execute_plan(ClientData cdata, Tcl_Interp *interp,
@@ -235,7 +235,7 @@ static int pltcl_SPI_lastoid(ClientData cdata, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[]);
static void pltcl_set_tuple_values(Tcl_Interp *interp, const char *arrayname,
- int tupno, HeapTuple tuple, TupleDesc tupdesc);
+ uint64 tupno, HeapTuple tuple, TupleDesc tupdesc);
static Tcl_Obj *pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc);
@@ -481,7 +481,7 @@ pltcl_init_load_unknown(Tcl_Interp *interp)
int tcl_rc;
Tcl_DString unknown_src;
char *part;
- int i;
+ uint64 i;
int fno;
/************************************************************
@@ -2007,10 +2007,9 @@ pltcl_process_SPI_result(Tcl_Interp *interp,
Tcl_Obj *loop_body,
int spi_rc,
SPITupleTable *tuptable,
- int ntuples)
+ uint64 ntuples)
{
int my_rc = TCL_OK;
- int i;
int loop_rc;
HeapTuple *tuples;
TupleDesc tupdesc;
@@ -2021,7 +2020,7 @@ pltcl_process_SPI_result(Tcl_Interp *interp,
case SPI_OK_INSERT:
case SPI_OK_DELETE:
case SPI_OK_UPDATE:
- Tcl_SetObjResult(interp, Tcl_NewIntObj(ntuples));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(ntuples));
break;
case SPI_OK_UTILITY:
@@ -2060,6 +2059,8 @@ pltcl_process_SPI_result(Tcl_Interp *interp,
* There is a loop body - process all tuples and evaluate the
* body on each
*/
+ uint64 i;
+
for (i = 0; i < ntuples; i++)
{
pltcl_set_tuple_values(interp, arrayname, i,
@@ -2085,7 +2086,7 @@ pltcl_process_SPI_result(Tcl_Interp *interp,
if (my_rc == TCL_OK)
{
- Tcl_SetObjResult(interp, Tcl_NewIntObj(ntuples));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(ntuples));
}
break;
@@ -2472,7 +2473,7 @@ pltcl_SPI_lastoid(ClientData cdata, Tcl_Interp *interp,
**********************************************************************/
static void
pltcl_set_tuple_values(Tcl_Interp *interp, const char *arrayname,
- int tupno, HeapTuple tuple, TupleDesc tupdesc)
+ uint64 tupno, HeapTuple tuple, TupleDesc tupdesc)
{
int i;
char *outputstr;
@@ -2498,7 +2499,7 @@ pltcl_set_tuple_values(Tcl_Interp *interp, const char *arrayname,
{
arrptr = &arrayname;
nameptr = &attname;
- Tcl_SetVar2Ex(interp, arrayname, ".tupno", Tcl_NewIntObj(tupno), 0);
+ Tcl_SetVar2Ex(interp, arrayname, ".tupno", Tcl_NewWideIntObj(tupno), 0);
}
for (i = 0; i < tupdesc->natts; i++)
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 6367ce7d7ff..e7826a4513b 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -362,7 +362,7 @@ funny_dup17(PG_FUNCTION_ARGS)
*fieldval,
*fieldtype;
char *when;
- int inserted;
+ uint64 inserted;
int selected = 0;
int ret;
@@ -443,7 +443,7 @@ funny_dup17(PG_FUNCTION_ARGS)
))));
}
- elog(DEBUG4, "funny_dup17 (fired %s) on level %3d: %d/%d tuples inserted/selected",
+ elog(DEBUG4, "funny_dup17 (fired %s) on level %3d: " UINT64_FORMAT "/%d tuples inserted/selected",
when, *level, inserted, selected);
SPI_finish();