]> granicus.if.org Git - postgresql/commitdiff
Widen query numbers-of-tuples-processed counters to uint64.
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 12 Mar 2016 21:05:10 +0000 (16:05 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 12 Mar 2016 21:05:29 +0000 (16:05 -0500)
This patch widens SPI_processed, EState's es_processed field, PortalData's
portalPos field, FuncCallContext's call_cntr and max_calls fields,
ExecutorRun's count argument, PortalRunFetch's result, and the max number
of rows in a SPITupleTable to uint64, and deals with (I hope) all the
ensuing fallout.  Some of these values were declared uint32 before, and
others "long".

I also removed PortalData's posOverflow field, since that logic seems
pretty useless given that portalPos is now always 64 bits.

The user-visible results are that command tags for SELECT etc will
correctly report tuple counts larger than 4G, as will plpgsql's GET
GET DIAGNOSTICS ... ROW_COUNT command.  Queries processing more tuples
than that are still not exactly the norm, but they're becoming more
common.

Most values associated with FETCH/MOVE distances, such as PortalRun's count
argument and the count argument of most SPI functions that have one, remain
declared as "long".  It's not clear whether it would be worth promoting
those to int64; but it would definitely be a large dollop of additional
API churn on top of this, and it would only help 32-bit platforms which
seem relatively less likely to see any benefit.

Andreas Scherbaum, reviewed by Christian Ullrich, additional hacking by me

32 files changed:
contrib/auto_explain/auto_explain.c
contrib/pg_stat_statements/pg_stat_statements.c
contrib/spi/refint.c
contrib/tablefunc/tablefunc.c
contrib/xml2/xpath.c
doc/src/sgml/spi.sgml
src/backend/commands/createas.c
src/backend/commands/portalcmds.c
src/backend/executor/execMain.c
src/backend/executor/functions.c
src/backend/executor/spi.c
src/backend/tcop/pquery.c
src/backend/utils/adt/numutils.c
src/backend/utils/adt/tsquery_rewrite.c
src/backend/utils/adt/tsvector_op.c
src/backend/utils/adt/xml.c
src/include/executor/executor.h
src/include/executor/spi.h
src/include/executor/spi_priv.h
src/include/funcapi.h
src/include/nodes/execnodes.h
src/include/postgres.h
src/include/tcop/pquery.h
src/include/utils/builtins.h
src/include/utils/portal.h
src/pl/plperl/plperl.c
src/pl/plpgsql/src/pl_exec.c
src/pl/plpgsql/src/plpgsql.h
src/pl/plpython/plpy_cursorobject.c
src/pl/plpython/plpy_spi.c
src/pl/tcl/pltcl.c
src/test/regress/regress.c

index 76d183156772bde9b8fd4609fc13cabfe21ae4ae..6708d817fba43719663adb17e6a2321a4cd59053 100644 (file)
@@ -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();
index 9ce60e696c9261ecae80ccb5a374764a1993cf2d..3d9b8e45d9fa7db1420c85073483f0bbb7e26ff5 100644 (file)
@@ -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;
 
index 26022107410abdd795d43f00669fbd937fbe575c..01dd717522c42ecbe46878470bdbaa30864e13d5 100644 (file)
@@ -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
index 1ea4a635cd5b07453c8b3ea9dc4b11f22f1e2833..787c02d08fcfd30e3e5914db522976dcef87e41f 100644 (file)
@@ -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;
index 655c5322cdf21a7f107c0a86cf3b4dc3626a5fdf..ac28996867b36aec60ca77ba5ba477cad5c005c1 100644 (file)
@@ -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;
index c099fcfad3a7ce54a2fa50a46944cab51e8a8bdc..9ae7126ae7f144c0005eb16ca314056de2934232 100644 (file)
@@ -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>
 
index fcb033130927cc07f4fc60dbcb1ca84629958c95..cb7a145ee5db8be8cdcc7a9572fc352541c3028d 100644 (file)
@@ -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);
index 8c045c090b453375c36648384a5ec8edbb06c2c9..50a54e746334245a69ffefbf9df691e618845a1e 100644 (file)
@@ -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,
index 76f7297c077f2bf3e0c9392848933f2b93333eb2..687256279abc7ea6578ad8df1099202b782b6764 100644 (file)
@@ -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;
 
        /*
index c3cdad4abf738bb12648bde5a6f2cf2ec1615b30..6e14c9d29677d12d4f72271ff1d03e018f50609e 100644 (file)
@@ -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;
index 3357c0d25241222233dedd53523bb438ccec1b32..3d04c23b4e0cc9ab8e01d433a4936da7fd230291 100644 (file)
@@ -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;
 
index 6893b0f4239aa7702e902389402cc280e8e8a775..fcdc4c347c7919ebb4ef7f89c2f17c6f09f4a7e8 100644 (file)
@@ -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;
 }
index 6b105964bd1be1fde83df0eac2cb8f8bffaf03c6..da100f7c0f2d3f0d6635be84d467eecc74de0dd7 100644 (file)
@@ -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
+}
index 0870afd867f510cf90263508bd7ef048fd5be93e..28f328ddb312dabba6c54b1aa13096b27fca36de 100644 (file)
@@ -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);
index 186b3d337ad9b26cfc30a432e18ea8743be0bebb..f6d3fb5d7b4a607bc7eb8702c948045b59ac14e2 100644 (file)
@@ -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);
index 56179f822ed2df51f902b5a88c4aec8ebea84a30..7ed5bcb93dd45bbb3c282913bc55110192371a1e 100644 (file)
@@ -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)
 {
index 1a44085a2cee339ab25566d4f6de898639e1976a..44fac278a4957df8466e184ea69248b81313b9bb 100644 (file)
@@ -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);
index 8c3ca261237f91cedb4c666ee7b36db89bfd514d..1792fb12172c4e1c4d2107a7157ebb569ee7f240 100644 (file)
@@ -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;
index 3187230c0205b420b6dc613411e42be2539279ad..e8084dff0911677115f16a5dd7d67c30206baa92 100644 (file)
@@ -21,7 +21,7 @@
 typedef struct
 {
        /* current results */
-       uint32          processed;              /* by Executor */
+       uint64          processed;              /* by Executor */
        Oid                     lastoid;
        SPITupleTable *tuptable;        /* tuptable currently being built */
 
index b6ae93fe0d0643cd67b417ffa16c3bfa189100b0..e73a82427ca3dd0684e7c24621f74ade731e6432 100644 (file)
@@ -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
index 064a0509c4d236924e3f6fb73891d9530776109a..d35ec810450f8702d31ca3f53e6eb16600b42edb 100644 (file)
@@ -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 */
index 453147e1f0b8f27da705b76da4437c4adf4edb1b..cde939b7cab257a0df17dc9df64ad6edec3153f2 100644 (file)
@@ -629,6 +629,33 @@ typedef Datum *DatumPtr;
 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.
index 4f1fd139a3666e588231af1b48c51b9e74b46acc..e04fc4330d92f4f14493efa86619df0d79bfab2b 100644 (file)
@@ -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);
index 115f8afb45b61a5f9ae4cb6684f9b45c6d22e9bf..59a00bbcbcf8291c92f7c9b13b53861b1be2372c 100644 (file)
@@ -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
index 4236215b79602f6461e828682a95b5d2f2593204..7250c9c1bb38f04015c9f0c970abd4df51a8e5c1 100644 (file)
@@ -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 */
index cd917ab8e46ddc13a293144184a3f45e71cab01c..269f7f332206d5b590ca648a31a20538bfa1a6dd 100644 (file)
@@ -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);
index bd58d5f444fc741f54a18e8ad60eac62f589249c..b63ecacdecf7db228695f0947eb5465830362cac 100644 (file)
@@ -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++)
                {
index a1e900d7336e7b079c75a7bf64926d183b5ff131..2deece43eb792aa83704f005d303360d642592e4 100644 (file)
@@ -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 */
 
index 103571ba15cc0befd1fea5fede49f0dfc67c4b82..44ba76e765e2cdcd1f253b1799b9c7fd6926e74a 100644 (file)
@@ -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);
index 58e78ecebcb39139ee677727cf1b6807722ed03d..7d84629f48fcebaa1aaa98fcc7a3317704c97550 100644 (file)
@@ -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);
 
index 105b6186f64b8ca1ded782ef7618b5576c29f96c..5b27c731b6eb55d200455a567adaeb7341331890 100644 (file)
@@ -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++)
index 6367ce7d7ffeb8297de00fc0b3d98d6a9dad1094..e7826a4513b3f69eb162172689dd36813185361f 100644 (file)
@@ -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();