On Tue, Sep 17, 2019 at 01:06:18PM +0900, Michael Paquier wrote:
> On Tue, Sep 17, 2019 at 09:23:45AM +0530, Amit Kapila wrote:
>> If you want to use the same size array, then you might want to just
>> memset the previous array rather than first freeing it and then again
>> allocating it.  This is not a big point, so any which way is fine.
> 
> Sure.  This is less expensive though, so changed it the way you
> are suggesting on my local branch.

I am attaching an updated patch for now that I would like to commit.
Are there more comments about the shape of the patch, the name of the
columns for the function, etc.?
--
Michael
diff --git a/contrib/pageinspect/expected/page.out b/contrib/pageinspect/expected/page.out
index 6a09d46a57..c8f6e1b4c6 100644
--- a/contrib/pageinspect/expected/page.out
+++ b/contrib/pageinspect/expected/page.out
@@ -86,80 +86,55 @@ SELECT * FROM fsm_page_contents(get_raw_page('test1', 'fsm', 0));
 -- always be the same in all test runs. we show raw flags by
 -- default: HEAP_XMIN_COMMITTED and HEAP_XMIN_INVALID.
 VACUUM FREEZE test1;
-SELECT t_infomask, t_infomask2, flags
+SELECT t_infomask, t_infomask2, raw_flags, combined_flags
 FROM heap_page_items(get_raw_page('test1', 0)),
-     LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2) m(flags);
- t_infomask | t_infomask2 |                           flags                           
-------------+-------------+-----------------------------------------------------------
-       2816 |           2 | {HEAP_XMAX_INVALID,HEAP_XMIN_COMMITTED,HEAP_XMIN_INVALID}
+     LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2) m(raw_flags, combined_flags);
+ t_infomask | t_infomask2 |                         raw_flags                         |   combined_flags   
+------------+-------------+-----------------------------------------------------------+--------------------
+       2816 |           2 | {HEAP_XMIN_COMMITTED,HEAP_XMIN_INVALID,HEAP_XMAX_INVALID} | {HEAP_XMIN_FROZEN}
 (1 row)
 
 -- output the decoded flag HEAP_XMIN_FROZEN instead
-SELECT t_infomask, t_infomask2, flags
+SELECT t_infomask, t_infomask2, raw_flags, combined_flags
 FROM heap_page_items(get_raw_page('test1', 0)),
-     LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2, true) m(flags);
- t_infomask | t_infomask2 |                flags                 
-------------+-------------+--------------------------------------
-       2816 |           2 | {HEAP_XMAX_INVALID,HEAP_XMIN_FROZEN}
+     LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2) m(raw_flags, combined_flags);
+ t_infomask | t_infomask2 |                         raw_flags                         |   combined_flags   
+------------+-------------+-----------------------------------------------------------+--------------------
+       2816 |           2 | {HEAP_XMIN_COMMITTED,HEAP_XMIN_INVALID,HEAP_XMAX_INVALID} | {HEAP_XMIN_FROZEN}
 (1 row)
 
 -- tests for decoding of combined flags
 -- HEAP_XMAX_SHR_LOCK = (HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)
-SELECT heap_tuple_infomask_flags(x'0050'::int, 0, true);
- heap_tuple_infomask_flags 
----------------------------
- {HEAP_XMAX_SHR_LOCK}
-(1 row)
-
-SELECT heap_tuple_infomask_flags(x'0050'::int, 0, false);
-          heap_tuple_infomask_flags          
----------------------------------------------
- {HEAP_XMAX_EXCL_LOCK,HEAP_XMAX_KEYSHR_LOCK}
+SELECT * FROM heap_tuple_infomask_flags(x'0050'::int, 0);
+                  raw_flags                  |    combined_flags    
+---------------------------------------------+----------------------
+ {HEAP_XMAX_KEYSHR_LOCK,HEAP_XMAX_EXCL_LOCK} | {HEAP_XMAX_SHR_LOCK}
 (1 row)
 
 -- HEAP_XMIN_FROZEN = (HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID)
-SELECT heap_tuple_infomask_flags(x'0300'::int, 0, true);
- heap_tuple_infomask_flags 
----------------------------
- {HEAP_XMIN_FROZEN}
-(1 row)
-
-SELECT heap_tuple_infomask_flags(x'0300'::int, 0, false);
-        heap_tuple_infomask_flags        
------------------------------------------
- {HEAP_XMIN_COMMITTED,HEAP_XMIN_INVALID}
+SELECT * FROM heap_tuple_infomask_flags(x'0300'::int, 0);
+                raw_flags                |   combined_flags   
+-----------------------------------------+--------------------
+ {HEAP_XMIN_COMMITTED,HEAP_XMIN_INVALID} | {HEAP_XMIN_FROZEN}
 (1 row)
 
 -- HEAP_MOVED = (HEAP_MOVED_IN | HEAP_MOVED_OFF)
-SELECT heap_tuple_infomask_flags(x'C000'::int, 0, true);
- heap_tuple_infomask_flags 
----------------------------
- {HEAP_MOVED}
+SELECT * FROM heap_tuple_infomask_flags(x'C000'::int, 0);
+           raw_flags            | combined_flags 
+--------------------------------+----------------
+ {HEAP_MOVED_OFF,HEAP_MOVED_IN} | {HEAP_MOVED}
 (1 row)
 
-SELECT heap_tuple_infomask_flags(x'C000'::int, 0, false);
-   heap_tuple_infomask_flags    
---------------------------------
- {HEAP_MOVED_IN,HEAP_MOVED_OFF}
-(1 row)
-
--- HEAP_LOCKED_UPGRADED = (HEAP_XMAX_IS_MULTI | HEAP_XMAX_LOCK_ONLY)
-SELECT heap_tuple_infomask_flags(x'1080'::int, 0, true);
- heap_tuple_infomask_flags 
----------------------------
- {HEAP_LOCKED_UPGRADED}
-(1 row)
-
-SELECT heap_tuple_infomask_flags(x'1080'::int, 0, false);
-        heap_tuple_infomask_flags         
-------------------------------------------
- {HEAP_XMAX_LOCK_ONLY,HEAP_XMAX_IS_MULTI}
+SELECT * FROM heap_tuple_infomask_flags(x'C000'::int, 0);
+           raw_flags            | combined_flags 
+--------------------------------+----------------
+ {HEAP_MOVED_OFF,HEAP_MOVED_IN} | {HEAP_MOVED}
 (1 row)
 
 -- test all flags of t_infomask and t_infomask2
-SELECT unnest(heap_tuple_infomask_flags(x'FFFF'::int, x'FFFF'::int, false))
-  AS flags ORDER BY 1;
-         flags         
+SELECT unnest(raw_flags)
+  FROM heap_tuple_infomask_flags(x'FFFF'::int, x'FFFF'::int) ORDER BY 1;
+        unnest         
 -----------------------
  HEAP_COMBOCID
  HEAP_HASEXTERNAL
@@ -182,85 +157,28 @@ SELECT unnest(heap_tuple_infomask_flags(x'FFFF'::int, x'FFFF'::int, false))
  HEAP_XMIN_INVALID
 (19 rows)
 
-SELECT unnest(heap_tuple_infomask_flags(x'FFFF'::int, x'FFFF'::int, true))
-  AS flags ORDER BY 1;
-        flags        
----------------------
- HEAP_COMBOCID
- HEAP_HASEXTERNAL
- HEAP_HASNULL
- HEAP_HASOID_OLD
- HEAP_HASVARWIDTH
- HEAP_HOT_UPDATED
- HEAP_KEYS_UPDATED
+SELECT unnest(combined_flags)
+  FROM heap_tuple_infomask_flags(x'FFFF'::int, x'FFFF'::int) ORDER BY 1;
+       unnest       
+--------------------
  HEAP_MOVED
- HEAP_ONLY_TUPLE
- HEAP_UPDATED
- HEAP_XMAX_COMMITTED
- HEAP_XMAX_INVALID
- HEAP_XMAX_IS_MULTI
- HEAP_XMAX_LOCK_ONLY
  HEAP_XMAX_SHR_LOCK
  HEAP_XMIN_FROZEN
-(16 rows)
+(3 rows)
 
-SELECT unnest(heap_tuple_infomask_flags(-1, -1, false))
-  AS flags ORDER BY 1;
-         flags         
------------------------
- HEAP_COMBOCID
- HEAP_HASEXTERNAL
- HEAP_HASNULL
- HEAP_HASOID_OLD
- HEAP_HASVARWIDTH
- HEAP_HOT_UPDATED
- HEAP_KEYS_UPDATED
- HEAP_MOVED_IN
- HEAP_MOVED_OFF
- HEAP_ONLY_TUPLE
- HEAP_UPDATED
- HEAP_XMAX_COMMITTED
- HEAP_XMAX_EXCL_LOCK
- HEAP_XMAX_INVALID
- HEAP_XMAX_IS_MULTI
- HEAP_XMAX_KEYSHR_LOCK
- HEAP_XMAX_LOCK_ONLY
- HEAP_XMIN_COMMITTED
- HEAP_XMIN_INVALID
-(19 rows)
+-- no flags at all
+SELECT * FROM heap_tuple_infomask_flags(0, 0);
+ raw_flags | combined_flags 
+-----------+----------------
+ {}        | {}
+(1 row)
 
-SELECT unnest(heap_tuple_infomask_flags(-1, -1, true))
-  AS flags ORDER BY 1;
-        flags        
----------------------
- HEAP_COMBOCID
- HEAP_HASEXTERNAL
- HEAP_HASNULL
- HEAP_HASOID_OLD
- HEAP_HASVARWIDTH
- HEAP_HOT_UPDATED
- HEAP_KEYS_UPDATED
- HEAP_MOVED
- HEAP_ONLY_TUPLE
- HEAP_UPDATED
- HEAP_XMAX_COMMITTED
- HEAP_XMAX_INVALID
- HEAP_XMAX_IS_MULTI
- HEAP_XMAX_LOCK_ONLY
- HEAP_XMAX_SHR_LOCK
- HEAP_XMIN_FROZEN
-(16 rows)
-
--- no flags
-SELECT unnest(heap_tuple_infomask_flags(0, 0, false));
- unnest 
---------
-(0 rows)
-
-SELECT unnest(heap_tuple_infomask_flags(0, 0, true));
- unnest 
---------
-(0 rows)
+-- no combined flags
+SELECT * FROM heap_tuple_infomask_flags(x'0010'::int, 0);
+        raw_flags        | combined_flags 
+-------------------------+----------------
+ {HEAP_XMAX_KEYSHR_LOCK} | {}
+(1 row)
 
 DROP TABLE test1;
 -- check that using any of these functions with a partitioned table or index
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index 68f16cd400..2cad296e22 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -507,99 +507,117 @@ PG_FUNCTION_INFO_V1(heap_tuple_infomask_flags);
 Datum
 heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 {
+#define HEAP_TUPLE_INFOMASK_COLS 2
+	Datum		values[HEAP_TUPLE_INFOMASK_COLS];
+	bool		nulls[HEAP_TUPLE_INFOMASK_COLS];
 	uint16		t_infomask = PG_GETARG_INT16(0);
 	uint16		t_infomask2 = PG_GETARG_INT16(1);
-	bool		decode_combined = PG_GETARG_BOOL(2);
 	int			cnt = 0;
 	ArrayType  *a;
 	int			bitcnt;
-	Datum	   *d;
+	Datum	   *flags;
+	TupleDesc	tupdesc;
+	HeapTuple	tuple;
 
 	if (!superuser())
 		ereport(ERROR,
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 				 errmsg("must be superuser to use raw page functions")));
 
+	/* Build a tuple descriptor for our result type */
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
+
 	bitcnt = pg_popcount((const char *) &t_infomask, sizeof(uint16)) +
 		pg_popcount((const char *) &t_infomask2, sizeof(uint16));
 
-	/* If no flags, return an empty array */
-	if (bitcnt <= 0)
-		PG_RETURN_POINTER(construct_empty_array(TEXTOID));
+	/* Initialize values and NULL flags arrays */
+	MemSet(values, 0, sizeof(values));
+	MemSet(nulls, 0, sizeof(nulls));
 
-	d = (Datum *) palloc0(sizeof(Datum) * bitcnt);
+	/* If no flags, return a set of empty arrays */
+	if (bitcnt <= 0)
+	{
+		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
+		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
+		tuple = heap_form_tuple(tupdesc, values, nulls);
+		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	}
+
+	/* build set of raw flags */
+	flags = (Datum *) palloc0(sizeof(Datum) * bitcnt);
 
 	/* decode t_infomask */
 	if ((t_infomask & HEAP_HASNULL) != 0)
-		d[cnt++] = CStringGetTextDatum("HEAP_HASNULL");
+		flags[cnt++] = CStringGetTextDatum("HEAP_HASNULL");
 	if ((t_infomask & HEAP_HASVARWIDTH) != 0)
-		d[cnt++] = CStringGetTextDatum("HEAP_HASVARWIDTH");
+		flags[cnt++] = CStringGetTextDatum("HEAP_HASVARWIDTH");
 	if ((t_infomask & HEAP_HASEXTERNAL) != 0)
-		d[cnt++] = CStringGetTextDatum("HEAP_HASEXTERNAL");
+		flags[cnt++] = CStringGetTextDatum("HEAP_HASEXTERNAL");
 	if ((t_infomask & HEAP_HASOID_OLD) != 0)
-		d[cnt++] = CStringGetTextDatum("HEAP_HASOID_OLD");
+		flags[cnt++] = CStringGetTextDatum("HEAP_HASOID_OLD");
+	if ((t_infomask & HEAP_XMAX_KEYSHR_LOCK) != 0)
+		flags[cnt++] = CStringGetTextDatum("HEAP_XMAX_KEYSHR_LOCK");
 	if ((t_infomask & HEAP_COMBOCID) != 0)
-		d[cnt++] = CStringGetTextDatum("HEAP_COMBOCID");
+		flags[cnt++] = CStringGetTextDatum("HEAP_COMBOCID");
+	if ((t_infomask & HEAP_XMAX_EXCL_LOCK) != 0)
+		flags[cnt++] = CStringGetTextDatum("HEAP_XMAX_EXCL_LOCK");
+	if ((t_infomask & HEAP_XMAX_LOCK_ONLY) != 0)
+		flags[cnt++] = CStringGetTextDatum("HEAP_XMAX_LOCK_ONLY");
+	if ((t_infomask & HEAP_XMIN_COMMITTED) != 0)
+		flags[cnt++] = CStringGetTextDatum("HEAP_XMIN_COMMITTED");
+	if ((t_infomask & HEAP_XMIN_INVALID) != 0)
+		flags[cnt++] = CStringGetTextDatum("HEAP_XMIN_INVALID");
 	if ((t_infomask & HEAP_XMAX_COMMITTED) != 0)
-		d[cnt++] = CStringGetTextDatum("HEAP_XMAX_COMMITTED");
+		flags[cnt++] = CStringGetTextDatum("HEAP_XMAX_COMMITTED");
 	if ((t_infomask & HEAP_XMAX_INVALID) != 0)
-		d[cnt++] = CStringGetTextDatum("HEAP_XMAX_INVALID");
+		flags[cnt++] = CStringGetTextDatum("HEAP_XMAX_INVALID");
+	if ((t_infomask & HEAP_XMAX_IS_MULTI) != 0)
+		flags[cnt++] = CStringGetTextDatum("HEAP_XMAX_IS_MULTI");
 	if ((t_infomask & HEAP_UPDATED) != 0)
-		d[cnt++] = CStringGetTextDatum("HEAP_UPDATED");
-
-	/* decode combined masks of t_infomaks */
-	if (decode_combined && (t_infomask & HEAP_XMAX_SHR_LOCK) != 0)
-		d[cnt++] = CStringGetTextDatum("HEAP_XMAX_SHR_LOCK");
-	else
-	{
-		if ((t_infomask & HEAP_XMAX_EXCL_LOCK) != 0)
-			d[cnt++] = CStringGetTextDatum("HEAP_XMAX_EXCL_LOCK");
-		if ((t_infomask & HEAP_XMAX_KEYSHR_LOCK) != 0)
-			d[cnt++] = CStringGetTextDatum("HEAP_XMAX_KEYSHR_LOCK");
-	}
-
-	if (decode_combined && (t_infomask & HEAP_XMIN_FROZEN) != 0)
-		d[cnt++] = CStringGetTextDatum("HEAP_XMIN_FROZEN");
-	else
-	{
-		if ((t_infomask & HEAP_XMIN_COMMITTED) != 0)
-			d[cnt++] = CStringGetTextDatum("HEAP_XMIN_COMMITTED");
-		if ((t_infomask & HEAP_XMIN_INVALID) != 0)
-			d[cnt++] = CStringGetTextDatum("HEAP_XMIN_INVALID");
-	}
-
-	if (decode_combined && (t_infomask & HEAP_MOVED) != 0)
-		d[cnt++] = CStringGetTextDatum("HEAP_MOVED");
-	else
-	{
-		if ((t_infomask & HEAP_MOVED_IN) != 0)
-			d[cnt++] = CStringGetTextDatum("HEAP_MOVED_IN");
-		if ((t_infomask & HEAP_MOVED_OFF) != 0)
-			d[cnt++] = CStringGetTextDatum("HEAP_MOVED_OFF");
-	}
-
-	if (decode_combined && HEAP_LOCKED_UPGRADED(t_infomask))
-		d[cnt++] = CStringGetTextDatum("HEAP_LOCKED_UPGRADED");
-	else
-	{
-		if (HEAP_XMAX_IS_LOCKED_ONLY(t_infomask))
-			d[cnt++] = CStringGetTextDatum("HEAP_XMAX_LOCK_ONLY");
-		if ((t_infomask & HEAP_XMAX_IS_MULTI) != 0)
-			d[cnt++] = CStringGetTextDatum("HEAP_XMAX_IS_MULTI");
-	}
+		flags[cnt++] = CStringGetTextDatum("HEAP_UPDATED");
+	if ((t_infomask & HEAP_MOVED_OFF) != 0)
+		flags[cnt++] = CStringGetTextDatum("HEAP_MOVED_OFF");
+	if ((t_infomask & HEAP_MOVED_IN) != 0)
+		flags[cnt++] = CStringGetTextDatum("HEAP_MOVED_IN");
 
 	/* decode t_infomask2 */
 	if ((t_infomask2 & HEAP_KEYS_UPDATED) != 0)
-		d[cnt++] = CStringGetTextDatum("HEAP_KEYS_UPDATED");
+		flags[cnt++] = CStringGetTextDatum("HEAP_KEYS_UPDATED");
 	if ((t_infomask2 & HEAP_HOT_UPDATED) != 0)
-		d[cnt++] = CStringGetTextDatum("HEAP_HOT_UPDATED");
+		flags[cnt++] = CStringGetTextDatum("HEAP_HOT_UPDATED");
 	if ((t_infomask2 & HEAP_ONLY_TUPLE) != 0)
-		d[cnt++] = CStringGetTextDatum("HEAP_ONLY_TUPLE");
+		flags[cnt++] = CStringGetTextDatum("HEAP_ONLY_TUPLE");
 
+	/* build value */
 	Assert(cnt <= bitcnt);
-	a = construct_array(d, cnt, TEXTOID, -1, false, 'i');
+	a = construct_array(flags, cnt, TEXTOID, -1, false, 'i');
+	values[0] = PointerGetDatum(a);
 
-	pfree(d);
+	/*
+	 * Build set of combined flags.  Use the same array as previously,
+	 * this keeps the code simple.
+	 */
+	cnt = 0;
+	MemSet(flags, 0, sizeof(Datum) * bitcnt);
 
-	PG_RETURN_POINTER(a);
+	/* decode combined masks of t_infomask */
+	if ((t_infomask & HEAP_XMAX_SHR_LOCK) == HEAP_XMAX_SHR_LOCK)
+		flags[cnt++] = CStringGetTextDatum("HEAP_XMAX_SHR_LOCK");
+	if ((t_infomask & HEAP_XMIN_FROZEN) == HEAP_XMIN_FROZEN)
+		flags[cnt++] = CStringGetTextDatum("HEAP_XMIN_FROZEN");
+	if ((t_infomask & HEAP_MOVED) == HEAP_MOVED)
+		flags[cnt++] = CStringGetTextDatum("HEAP_MOVED");
+
+	/* Build an empty array if there are no combined flags */
+	if (cnt == 0)
+		a = construct_empty_array(TEXTOID);
+	else
+		a = construct_array(flags, cnt, TEXTOID, -1, false, 'i');
+	pfree(flags);
+	values[1] = PointerGetDatum(a);
+
+	/* Returns the record as Datum */
+	tuple = heap_form_tuple(tupdesc, values, nulls);
+	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
 }
diff --git a/contrib/pageinspect/pageinspect--1.7--1.8.sql b/contrib/pageinspect/pageinspect--1.7--1.8.sql
index 7e85677d6c..2a7c4b3516 100644
--- a/contrib/pageinspect/pageinspect--1.7--1.8.sql
+++ b/contrib/pageinspect/pageinspect--1.7--1.8.sql
@@ -9,7 +9,8 @@
 CREATE FUNCTION heap_tuple_infomask_flags(
        t_infomask integer,
        t_infomask2 integer,
-       decode_combined boolean DEFAULT false)
-RETURNS text[]
+       raw_flags OUT text[],
+       combined_flags OUT text[])
+RETURNS record
 AS 'MODULE_PATHNAME', 'heap_tuple_infomask_flags'
 LANGUAGE C STRICT PARALLEL SAFE;
diff --git a/contrib/pageinspect/sql/page.sql b/contrib/pageinspect/sql/page.sql
index 0319b5fa11..a78fd56b1c 100644
--- a/contrib/pageinspect/sql/page.sql
+++ b/contrib/pageinspect/sql/page.sql
@@ -36,42 +36,34 @@ SELECT * FROM fsm_page_contents(get_raw_page('test1', 'fsm', 0));
 -- default: HEAP_XMIN_COMMITTED and HEAP_XMIN_INVALID.
 VACUUM FREEZE test1;
 
-SELECT t_infomask, t_infomask2, flags
+SELECT t_infomask, t_infomask2, raw_flags, combined_flags
 FROM heap_page_items(get_raw_page('test1', 0)),
-     LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2) m(flags);
+     LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2) m(raw_flags, combined_flags);
 
 -- output the decoded flag HEAP_XMIN_FROZEN instead
-SELECT t_infomask, t_infomask2, flags
+SELECT t_infomask, t_infomask2, raw_flags, combined_flags
 FROM heap_page_items(get_raw_page('test1', 0)),
-     LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2, true) m(flags);
+     LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2) m(raw_flags, combined_flags);
 
 -- tests for decoding of combined flags
 -- HEAP_XMAX_SHR_LOCK = (HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)
-SELECT heap_tuple_infomask_flags(x'0050'::int, 0, true);
-SELECT heap_tuple_infomask_flags(x'0050'::int, 0, false);
+SELECT * FROM heap_tuple_infomask_flags(x'0050'::int, 0);
 -- HEAP_XMIN_FROZEN = (HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID)
-SELECT heap_tuple_infomask_flags(x'0300'::int, 0, true);
-SELECT heap_tuple_infomask_flags(x'0300'::int, 0, false);
+SELECT * FROM heap_tuple_infomask_flags(x'0300'::int, 0);
 -- HEAP_MOVED = (HEAP_MOVED_IN | HEAP_MOVED_OFF)
-SELECT heap_tuple_infomask_flags(x'C000'::int, 0, true);
-SELECT heap_tuple_infomask_flags(x'C000'::int, 0, false);
--- HEAP_LOCKED_UPGRADED = (HEAP_XMAX_IS_MULTI | HEAP_XMAX_LOCK_ONLY)
-SELECT heap_tuple_infomask_flags(x'1080'::int, 0, true);
-SELECT heap_tuple_infomask_flags(x'1080'::int, 0, false);
+SELECT * FROM heap_tuple_infomask_flags(x'C000'::int, 0);
+SELECT * FROM heap_tuple_infomask_flags(x'C000'::int, 0);
 
 -- test all flags of t_infomask and t_infomask2
-SELECT unnest(heap_tuple_infomask_flags(x'FFFF'::int, x'FFFF'::int, false))
-  AS flags ORDER BY 1;
-SELECT unnest(heap_tuple_infomask_flags(x'FFFF'::int, x'FFFF'::int, true))
-  AS flags ORDER BY 1;
-SELECT unnest(heap_tuple_infomask_flags(-1, -1, false))
-  AS flags ORDER BY 1;
-SELECT unnest(heap_tuple_infomask_flags(-1, -1, true))
-  AS flags ORDER BY 1;
+SELECT unnest(raw_flags)
+  FROM heap_tuple_infomask_flags(x'FFFF'::int, x'FFFF'::int) ORDER BY 1;
+SELECT unnest(combined_flags)
+  FROM heap_tuple_infomask_flags(x'FFFF'::int, x'FFFF'::int) ORDER BY 1;
 
--- no flags
-SELECT unnest(heap_tuple_infomask_flags(0, 0, false));
-SELECT unnest(heap_tuple_infomask_flags(0, 0, true));
+-- no flags at all
+SELECT * FROM heap_tuple_infomask_flags(0, 0);
+-- no combined flags
+SELECT * FROM heap_tuple_infomask_flags(x'0010'::int, 0);
 
 DROP TABLE test1;
 
diff --git a/doc/src/sgml/pageinspect.sgml b/doc/src/sgml/pageinspect.sgml
index a7da3364a1..e009682ed6 100644
--- a/doc/src/sgml/pageinspect.sgml
+++ b/doc/src/sgml/pageinspect.sgml
@@ -244,7 +244,7 @@ test=# SELECT * FROM heap_page_item_attrs(get_raw_page('pg_class', 0), 'pg_class
 
    <varlistentry>
     <term>
-     <function>heap_tuple_infomask_flags(t_infomask integer, t_infomask2 integer, decode_combined bool) returns text[]</function>
+     <function>heap_tuple_infomask_flags(t_infomask integer, t_infomask2 integer) returns record</function>
      <indexterm>
       <primary>heap_tuple_infomask_flags</primary>
      </indexterm>
@@ -255,21 +255,21 @@ test=# SELECT * FROM heap_page_item_attrs(get_raw_page('pg_class', 0), 'pg_class
       <structfield>t_infomask</structfield> and
       <structfield>t_infomask2</structfield> returned by
       <function>heap_page_items</function> into a human-readable
-      array of flag names.  For example:
+      set of arrays make of flag names, with one column for all
+      the flags and one column for combined flags. For example:
 <screen>
-test=# SELECT t_ctid, heap_tuple_infomask_flags(t_infomask, t_infomask2) AS flags
-         FROM heap_page_items(get_raw_page('pg_class', 0))
+test=# SELECT t_ctid, raw_flags, combined_flags
+         FROM heap_page_items(get_raw_page('pg_class', 0)),
+           LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2)
          WHERE t_infomask IS NOT NULL OR t_infomask2 IS NOT NULL;
 </screen>
       This function should be called with the same arguments as the return
       attributes of <function>heap_page_items</function>.
      </para>
      <para>
-      If <parameter>decode_combined</parameter> is <literal>true</literal>,
-      combined flags like <literal>HEAP_XMIN_FROZEN</literal> are
-      returned instead of raw flags (<literal>HEAP_XMIN_COMMITTED</literal>
-      and <literal>HEAP_XMIN_INVALID</literal> in this case). Default value
-      is <literal>false</literal>.
+      Combined flags are displayed for source-level macros that take into
+      account the value of more than one raw bit, such as
+      <literal>HEAP_XMIN_FROZEN</litetal>.
      </para>
      <para>
       See <filename>src/include/access/htup_details.h</filename> for

Attachment: signature.asc
Description: PGP signature

Reply via email to