Fix pg_prepared_statements.result_types for DML statements
authorPeter Eisentraut <[email protected]>
Tue, 5 Jul 2022 08:26:36 +0000 (10:26 +0200)
committerPeter Eisentraut <[email protected]>
Tue, 5 Jul 2022 08:26:36 +0000 (10:26 +0200)
Amendment to 84ad713cf85aeffee5dd39f62d49a1b9e34632da: Not all
prepared statements have a result descriptor.  As currently coded,
this would crash when reading pg_prepared_statements.  Make those
cases return null for result_types instead.  Also add a test case for
it.

doc/src/sgml/catalogs.sgml
src/backend/commands/prepare.c
src/test/regress/expected/prepare.out
src/test/regress/sql/prepare.sql

index ef7ae7e8fdca6b4624b2d648c310bd7aa89cc4fa..4f3f375a84a1ad2396d53c6b80e8aea4b3b159aa 100644 (file)
@@ -11511,6 +11511,8 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
        form of an array of <type>regtype</type>. The OID corresponding
        to an element of this array can be obtained by casting the
        <type>regtype</type> value to <type>oid</type>.
+       If the prepared statement does not provide a result (e.g., a DML
+       statement), then this field will be null.
       </para></entry>
      </row>
 
index d1deb97fffb79e87b51381571e9715b09f9093a1..2333aae4673eeef4178704fffada9f8cffccfd88 100644 (file)
@@ -684,15 +684,10 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
        while ((prep_stmt = hash_seq_search(&hash_seq)) != NULL)
        {
            TupleDesc   result_desc;
-           Oid        *result_types;
            Datum       values[8];
            bool        nulls[8];
 
            result_desc = prep_stmt->plansource->resultDesc;
-           result_types = (Oid *) palloc(result_desc->natts * sizeof(Oid));
-
-           for (int i = 0; i < result_desc->natts; i++)
-               result_types[i] = result_desc->attrs[i].atttypid;
 
            MemSet(nulls, 0, sizeof(nulls));
 
@@ -701,7 +696,20 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
            values[2] = TimestampTzGetDatum(prep_stmt->prepare_time);
            values[3] = build_regtype_array(prep_stmt->plansource->param_types,
                                            prep_stmt->plansource->num_params);
-           values[4] = build_regtype_array(result_types, result_desc->natts);
+           if (result_desc)
+           {
+               Oid        *result_types;
+
+               result_types = (Oid *) palloc(result_desc->natts * sizeof(Oid));
+               for (int i = 0; i < result_desc->natts; i++)
+                   result_types[i] = result_desc->attrs[i].atttypid;
+               values[4] = build_regtype_array(result_types, result_desc->natts);
+           }
+           else
+           {
+               /* no result descriptor (for example, DML statement) */
+               nulls[4] = true;
+           }
            values[5] = BoolGetDatum(prep_stmt->from_sql);
            values[6] = Int64GetDatumFast(prep_stmt->plansource->num_generic_plans);
            values[7] = Int64GetDatumFast(prep_stmt->plansource->num_custom_plans);
index faf07f620bd3cf8d6353fa001a5056ca2d87c4bc..5815e17b39cc8c933b2c4ba9d00ecfbb96206bcd 100644 (file)
@@ -159,6 +159,9 @@ PREPARE q6 AS
     SELECT * FROM tenk1 WHERE unique1 = $1 AND stringu1 = $2;
 PREPARE q7(unknown) AS
     SELECT * FROM road WHERE thepath = $1;
+-- DML statements
+PREPARE q8 AS
+    UPDATE tenk1 SET stringu1 = $2 WHERE unique1 = $1;
 SELECT name, statement, parameter_types, result_types FROM pg_prepared_statements
     ORDER BY name;
  name |                            statement                             |                  parameter_types                   |                                                       result_types                                                       
@@ -177,7 +180,9 @@ SELECT name, statement, parameter_types, result_types FROM pg_prepared_statement
       |     SELECT * FROM tenk1 WHERE unique1 = $1 AND stringu1 = $2;    |                                                    | 
  q7   | PREPARE q7(unknown) AS                                          +| {path}                                             | {text,path}
       |     SELECT * FROM road WHERE thepath = $1;                       |                                                    | 
-(5 rows)
+ q8   | PREPARE q8 AS                                                   +| {integer,name}                                     | 
+      |     UPDATE tenk1 SET stringu1 = $2 WHERE unique1 = $1;           |                                                    | 
+(6 rows)
 
 -- test DEALLOCATE ALL;
 DEALLOCATE ALL;
index 55eef91d2af0c61251f97e79b32dd371e047e78a..c6098dc95ceee7cf2be3d8f18cd1bc7a519eec7f 100644 (file)
@@ -71,6 +71,10 @@ PREPARE q6 AS
 PREPARE q7(unknown) AS
     SELECT * FROM road WHERE thepath = $1;
 
+-- DML statements
+PREPARE q8 AS
+    UPDATE tenk1 SET stringu1 = $2 WHERE unique1 = $1;
+
 SELECT name, statement, parameter_types, result_types FROM pg_prepared_statements
     ORDER BY name;