diff --git a/contrib/auto_explain/auto_explain.c b/contrib/auto_explain/auto_explain.c
index 76d183156772bde9b8fd4609fc13cabfe21ae4ae..6708d817fba43719663adb17e6a2321a4cd59053 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 9ce60e696c9261ecae80ccb5a374764a1993cf2d..3d9b8e45d9fa7db1420c85073483f0bbb7e26ff5 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 26022107410abdd795d43f00669fbd937fbe575c..01dd717522c42ecbe46878470bdbaa30864e13d5 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 1ea4a635cd5b07453c8b3ea9dc4b11f22f1e2833..787c02d08fcfd30e3e5914db522976dcef87e41f 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 655c5322cdf21a7f107c0a86cf3b4dc3626a5fdf..ac28996867b36aec60ca77ba5ba477cad5c005c1 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 c099fcfad3a7ce54a2fa50a46944cab51e8a8bdc..9ae7126ae7f144c0005eb16ca314056de2934232 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 fcb033130927cc07f4fc60dbcb1ca84629958c95..cb7a145ee5db8be8cdcc7a9572fc352541c3028d 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 8c045c090b453375c36648384a5ec8edbb06c2c9..50a54e746334245a69ffefbf9df691e618845a1e 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 76f7297c077f2bf3e0c9392848933f2b93333eb2..687256279abc7ea6578ad8df1099202b782b6764 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 c3cdad4abf738bb12648bde5a6f2cf2ec1615b30..6e14c9d29677d12d4f72271ff1d03e018f50609e 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 3357c0d25241222233dedd53523bb438ccec1b32..3d04c23b4e0cc9ab8e01d433a4936da7fd230291 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 6893b0f4239aa7702e902389402cc280e8e8a775..fcdc4c347c7919ebb4ef7f89c2f17c6f09f4a7e8 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 6b105964bd1be1fde83df0eac2cb8f8bffaf03c6..da100f7c0f2d3f0d6635be84d467eecc74de0dd7 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 0870afd867f510cf90263508bd7ef048fd5be93e..28f328ddb312dabba6c54b1aa13096b27fca36de 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 186b3d337ad9b26cfc30a432e18ea8743be0bebb..f6d3fb5d7b4a607bc7eb8702c948045b59ac14e2 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 56179f822ed2df51f902b5a88c4aec8ebea84a30..7ed5bcb93dd45bbb3c282913bc55110192371a1e 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 1a44085a2cee339ab25566d4f6de898639e1976a..44fac278a4957df8466e184ea69248b81313b9bb 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 8c3ca261237f91cedb4c666ee7b36db89bfd514d..1792fb12172c4e1c4d2107a7157ebb569ee7f240 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 3187230c0205b420b6dc613411e42be2539279ad..e8084dff0911677115f16a5dd7d67c30206baa92 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 b6ae93fe0d0643cd67b417ffa16c3bfa189100b0..e73a82427ca3dd0684e7c24621f74ade731e6432 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 064a0509c4d236924e3f6fb73891d9530776109a..d35ec810450f8702d31ca3f53e6eb16600b42edb 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 453147e1f0b8f27da705b76da4437c4adf4edb1b..cde939b7cab257a0df17dc9df64ad6edec3153f2 100644
--- a/src/include/postgres.h
+++ b/src/include/postgres.h
@@ -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.
diff --git a/src/include/tcop/pquery.h b/src/include/tcop/pquery.h
index 4f1fd139a3666e588231af1b48c51b9e74b46acc..e04fc4330d92f4f14493efa86619df0d79bfab2b 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 115f8afb45b61a5f9ae4cb6684f9b45c6d22e9bf..59a00bbcbcf8291c92f7c9b13b53861b1be2372c 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 4236215b79602f6461e828682a95b5d2f2593204..7250c9c1bb38f04015c9f0c970abd4df51a8e5c1 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 cd917ab8e46ddc13a293144184a3f45e71cab01c..269f7f332206d5b590ca648a31a20538bfa1a6dd 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 bd58d5f444fc741f54a18e8ad60eac62f589249c..b63ecacdecf7db228695f0947eb5465830362cac 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 a1e900d7336e7b079c75a7bf64926d183b5ff131..2deece43eb792aa83704f005d303360d642592e4 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 103571ba15cc0befd1fea5fede49f0dfc67c4b82..44ba76e765e2cdcd1f253b1799b9c7fd6926e74a 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 58e78ecebcb39139ee677727cf1b6807722ed03d..7d84629f48fcebaa1aaa98fcc7a3317704c97550 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 105b6186f64b8ca1ded782ef7618b5576c29f96c..5b27c731b6eb55d200455a567adaeb7341331890 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 6367ce7d7ffeb8297de00fc0b3d98d6a9dad1094..e7826a4513b3f69eb162172689dd36813185361f 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();