From 6ffff0fd225432fe2ae4bd5abb7ff6113e255418 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Tue, 5 Jul 2022 10:26:36 +0200 Subject: [PATCH] Fix pg_prepared_statements.result_types for DML statements 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 | 2 ++ src/backend/commands/prepare.c | 20 ++++++++++++++------ src/test/regress/expected/prepare.out | 7 ++++++- src/test/regress/sql/prepare.sql | 4 ++++ 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index ef7ae7e8fdc..4f3f375a84a 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -11511,6 +11511,8 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx form of an array of regtype. The OID corresponding to an element of this array can be obtained by casting the regtype value to oid. + If the prepared statement does not provide a result (e.g., a DML + statement), then this field will be null. diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index d1deb97fffb..2333aae4673 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -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); diff --git a/src/test/regress/expected/prepare.out b/src/test/regress/expected/prepare.out index faf07f620bd..5815e17b39c 100644 --- a/src/test/regress/expected/prepare.out +++ b/src/test/regress/expected/prepare.out @@ -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; diff --git a/src/test/regress/sql/prepare.sql b/src/test/regress/sql/prepare.sql index 55eef91d2af..c6098dc95ce 100644 --- a/src/test/regress/sql/prepare.sql +++ b/src/test/regress/sql/prepare.sql @@ -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; -- 2.39.5