Hello,

one of our customers approached us and complained, that GET DIAGNOSTICS row_count returns invalid results if the number of rows is > 2^31. It's a bit complicated to test for this case, so I set up a separate instance with this patch, and inserted 2^32+x rows into a table. Internally, row_count it's a signed integer, the resulting number is negative:

diagnostics=# select testfunc_pg((2^31 + 50000)::bigint);
 testfunc_pg
-------------
 -2147433648
(1 row)


Going over 2^32 wraps around:

diagnostics=# select testfunc_pg((2^32 + 50000)::bigint);
 testfunc_pg
-------------
       50000
(1 row)



Attached patch expands the row_count to 64 bit.

diagnostics=# select testfunc_pg((2^32 + 50000)::bigint);
 testfunc_pg
-------------
  4295017296
(1 row)


I hope, I covered all the places which count the result set.


Regards,

--
                                Andreas 'ads' Scherbaum
German PostgreSQL User Group
European PostgreSQL User Group - Board of Directors
Volunteer Regional Contact, Germany - PostgreSQL Project
diff -ru postgresql-9.5.0.orig/src/backend/executor/spi.c postgresql-9.5.0/src/backend/executor/spi.c
--- postgresql-9.5.0.orig/src/backend/executor/spi.c	2016-01-04 22:29:34.000000000 +0100
+++ postgresql-9.5.0/src/backend/executor/spi.c	2016-01-27 01:30:06.099132294 +0100
@@ -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;
@@ -1994,7 +1994,7 @@
 				  bool read_only, bool fire_triggers, long tcount)
 {
 	int			my_res = 0;
-	uint32		my_processed = 0;
+	uint64		my_processed = 0;
 	Oid			my_lastoid = InvalidOid;
 	SPITupleTable *my_tuptable = NULL;
 	int			res = 0;
@@ -2562,7 +2562,7 @@
 static bool
 _SPI_checktuples(void)
 {
-	uint32		processed = _SPI_current->processed;
+	uint64		processed = _SPI_current->processed;
 	SPITupleTable *tuptable = _SPI_current->tuptable;
 	bool		failed = false;
 
diff -ru postgresql-9.5.0.orig/src/backend/tcop/pquery.c postgresql-9.5.0/src/backend/tcop/pquery.c
--- postgresql-9.5.0.orig/src/backend/tcop/pquery.c	2016-01-04 22:29:34.000000000 +0100
+++ postgresql-9.5.0/src/backend/tcop/pquery.c	2016-01-30 12:11:56.573841810 +0100
@@ -195,7 +195,7 @@
 		{
 			case CMD_SELECT:
 				snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
-						 "SELECT %u", queryDesc->estate->es_processed);
+						 "SELECT %lu", queryDesc->estate->es_processed);
 				break;
 			case CMD_INSERT:
 				if (queryDesc->estate->es_processed == 1)
@@ -203,15 +203,15 @@
 				else
 					lastOid = InvalidOid;
 				snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
-				   "INSERT %u %u", lastOid, queryDesc->estate->es_processed);
+				   "INSERT %u %lu", lastOid, queryDesc->estate->es_processed);
 				break;
 			case CMD_UPDATE:
 				snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
-						 "UPDATE %u", queryDesc->estate->es_processed);
+						 "UPDATE %lu", queryDesc->estate->es_processed);
 				break;
 			case CMD_DELETE:
 				snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
-						 "DELETE %u", queryDesc->estate->es_processed);
+						 "DELETE %lu", queryDesc->estate->es_processed);
 				break;
 			default:
 				strcpy(completionTag, "???");
@@ -892,7 +892,7 @@
 {
 	QueryDesc  *queryDesc;
 	ScanDirection direction;
-	uint32		nprocessed;
+	uint64		nprocessed;
 
 	/*
 	 * NB: queryDesc will be NULL if we are fetching from a held cursor or a
diff -ru postgresql-9.5.0.orig/src/include/executor/spi.h postgresql-9.5.0/src/include/executor/spi.h
--- postgresql-9.5.0.orig/src/include/executor/spi.h	2016-01-04 22:29:34.000000000 +0100
+++ postgresql-9.5.0/src/include/executor/spi.h	2016-01-27 01:34:46.388245129 +0100
@@ -59,7 +59,7 @@
 #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 -ru postgresql-9.5.0.orig/src/include/executor/spi_priv.h postgresql-9.5.0/src/include/executor/spi_priv.h
--- postgresql-9.5.0.orig/src/include/executor/spi_priv.h	2016-01-04 22:29:34.000000000 +0100
+++ postgresql-9.5.0/src/include/executor/spi_priv.h	2016-01-27 01:34:55.220056918 +0100
@@ -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 -ru postgresql-9.5.0.orig/src/include/nodes/execnodes.h postgresql-9.5.0/src/include/nodes/execnodes.h
--- postgresql-9.5.0.orig/src/include/nodes/execnodes.h	2016-01-04 22:29:34.000000000 +0100
+++ postgresql-9.5.0/src/include/nodes/execnodes.h	2016-01-27 01:32:04.711625720 +0100
@@ -387,7 +387,7 @@
 
 	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 -ru postgresql-9.5.0.orig/src/pl/plpgsql/src/pl_exec.c postgresql-9.5.0/src/pl/plpgsql/src/pl_exec.c
--- postgresql-9.5.0.orig/src/pl/plpgsql/src/pl_exec.c	2016-01-04 22:29:34.000000000 +0100
+++ postgresql-9.5.0/src/pl/plpgsql/src/pl_exec.c	2016-01-31 14:24:41.691784134 +0100
@@ -1642,8 +1642,10 @@
 		{
 			case PLPGSQL_GETDIAG_ROW_COUNT:
 				exec_assign_value(estate, var,
-								  UInt32GetDatum(estate->eval_processed),
-								  false, INT4OID, -1);
+								  /* Int64GetDatum() instead of UInt64GetDatum(),
+								     because there is no UInt64GetDatum() */
+								  Int64GetDatum(estate->eval_processed),
+								  false, INT8OID, -1);
 				break;
 
 			case PLPGSQL_GETDIAG_RESULT_OID:
@@ -2906,7 +2908,7 @@
 					   PLpgSQL_stmt_return_query *stmt)
 {
 	Portal		portal;
-	uint32		processed = 0;
+	uint64		processed = 0;
 	TupleConversionMap *tupmap;
 
 	if (!estate->retisset)
@@ -3630,7 +3632,7 @@
 	if (stmt->into)
 	{
 		SPITupleTable *tuptab = SPI_tuptable;
-		uint32		n = SPI_processed;
+		uint64		n = SPI_processed;
 		PLpgSQL_rec *rec = NULL;
 		PLpgSQL_row *row = NULL;
 
@@ -3820,7 +3822,7 @@
 	if (stmt->into)
 	{
 		SPITupleTable *tuptab = SPI_tuptable;
-		uint32		n = SPI_processed;
+		uint64		n = SPI_processed;
 		PLpgSQL_rec *rec = NULL;
 		PLpgSQL_row *row = NULL;
 
@@ -4092,7 +4094,7 @@
 	SPITupleTable *tuptab;
 	Portal		portal;
 	char	   *curname;
-	uint32		n;
+	uint64		n;
 
 	/* ----------
 	 * Get the portal of the cursor by name
@@ -5192,8 +5194,8 @@
 	PLpgSQL_row *row = NULL;
 	SPITupleTable *tuptab;
 	bool		found = false;
-	int			rc = PLPGSQL_RC_OK;
-	int			n;
+	int		rc = PLPGSQL_RC_OK;
+	int64		n;
 
 	/*
 	 * Determine if we assign to a record or a row
diff -ru postgresql-9.5.0.orig/src/pl/plpgsql/src/plpgsql.h postgresql-9.5.0/src/pl/plpgsql/src/plpgsql.h
--- postgresql-9.5.0.orig/src/pl/plpgsql/src/plpgsql.h	2016-01-04 22:29:34.000000000 +0100
+++ postgresql-9.5.0/src/pl/plpgsql/src/plpgsql.h	2016-01-27 00:30:27.612711562 +0100
@@ -802,7 +802,7 @@
 
 	/* 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 */
 
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to