improve-handling-of-composites-in-%TYPE.patch
text/x-diff
Filename: improve-handling-of-composites-in-%TYPE.patch
Type: text/x-diff
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/pl/plpgsql/src/expected/plpgsql_record.out | 26 | 0 |
| src/pl/plpgsql/src/pl_comp.c | 11 | 35 |
| src/pl/plpgsql/src/sql/plpgsql_record.sql | 23 | 0 |
diff --git a/src/pl/plpgsql/src/expected/plpgsql_record.out b/src/pl/plpgsql/src/expected/plpgsql_record.out
index afb922df29..36d65e4286 100644
--- a/src/pl/plpgsql/src/expected/plpgsql_record.out
+++ b/src/pl/plpgsql/src/expected/plpgsql_record.out
@@ -306,6 +306,32 @@ NOTICE: r1 = (1,2)
ERROR: record "r1" has no field "nosuchfield"
CONTEXT: SQL expression "r1.nosuchfield"
PL/pgSQL function inline_code_block line 9 at RAISE
+-- check that type record can be passed through %type
+do $$
+declare r1 record;
+ r2 r1%type;
+begin
+ r2 := row(1,2);
+ raise notice 'r2 = %', r2;
+ r2 := row(3,4,5);
+ raise notice 'r2 = %', r2;
+end$$;
+NOTICE: r2 = (1,2)
+NOTICE: r2 = (3,4,5)
+-- arrays of record are not supported at the moment
+do $$
+declare r1 record[];
+begin
+end$$;
+ERROR: variable "r1" has pseudo-type record[]
+CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 2
+do $$
+declare r1 record;
+ r2 r1%type[];
+begin
+end$$;
+ERROR: variable "r2" has pseudo-type record[]
+CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 3
-- check repeated assignments to composite fields
create table some_table (id int, data text);
do $$
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index b745eaa3f8..c63719c796 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -1596,8 +1596,8 @@ plpgsql_parse_tripword(char *word1, char *word2, char *word3,
/* ----------
- * plpgsql_parse_wordtype The scanner found word%TYPE. word can be
- * a variable name or a basetype.
+ * plpgsql_parse_wordtype The scanner found word%TYPE. word should be
+ * a pre-existing variable name.
*
* Returns datatype struct, or NULL if no match found for word.
* ----------
@@ -1605,10 +1605,7 @@ plpgsql_parse_tripword(char *word1, char *word2, char *word3,
PLpgSQL_type *
plpgsql_parse_wordtype(char *ident)
{
- PLpgSQL_type *dtype;
PLpgSQL_nsitem *nse;
- TypeName *typeName;
- HeapTuple typeTup;
/*
* Do a lookup in the current namespace stack
@@ -1623,39 +1620,13 @@ plpgsql_parse_wordtype(char *ident)
{
case PLPGSQL_NSTYPE_VAR:
return ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
-
- /* XXX perhaps allow REC/ROW here? */
-
+ case PLPGSQL_NSTYPE_REC:
+ return ((PLpgSQL_rec *) (plpgsql_Datums[nse->itemno]))->datatype;
default:
return NULL;
}
}
- /*
- * Word wasn't found in the namespace stack. Try to find a data type with
- * that name, but ignore shell types and complex types.
- */
- typeName = makeTypeName(ident);
- typeTup = LookupTypeName(NULL, typeName, NULL, false);
- if (typeTup)
- {
- Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
-
- if (!typeStruct->typisdefined ||
- typeStruct->typrelid != InvalidOid)
- {
- ReleaseSysCache(typeTup);
- return NULL;
- }
-
- dtype = build_datatype(typeTup, -1,
- plpgsql_curr_compile->fn_input_collation,
- typeName);
-
- ReleaseSysCache(typeTup);
- return dtype;
- }
-
/*
* Nothing found - up to now it's a word without any special meaning for
* us.
@@ -1689,8 +1660,8 @@ plpgsql_parse_cwordtype(List *idents)
{
/*
* Do a lookup in the current namespace stack. We don't need to check
- * number of names matched, because we will only consider scalar
- * variables.
+ * number of names matched, because field references aren't supported
+ * here.
*/
nse = plpgsql_ns_lookup(plpgsql_ns_top(), false,
strVal(linitial(idents)),
@@ -1703,6 +1674,11 @@ plpgsql_parse_cwordtype(List *idents)
dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
goto done;
}
+ else if (nse != NULL && nse->itemtype == PLPGSQL_NSTYPE_REC)
+ {
+ dtype = ((PLpgSQL_rec *) (plpgsql_Datums[nse->itemno]))->datatype;
+ goto done;
+ }
/*
* First word could also be a table name
diff --git a/src/pl/plpgsql/src/sql/plpgsql_record.sql b/src/pl/plpgsql/src/sql/plpgsql_record.sql
index db655335b1..f0fd05ba48 100644
--- a/src/pl/plpgsql/src/sql/plpgsql_record.sql
+++ b/src/pl/plpgsql/src/sql/plpgsql_record.sql
@@ -199,6 +199,29 @@ begin
raise notice 'r1.nosuchfield = %', r1.nosuchfield;
end$$;
+-- check that type record can be passed through %type
+do $$
+declare r1 record;
+ r2 r1%type;
+begin
+ r2 := row(1,2);
+ raise notice 'r2 = %', r2;
+ r2 := row(3,4,5);
+ raise notice 'r2 = %', r2;
+end$$;
+
+-- arrays of record are not supported at the moment
+do $$
+declare r1 record[];
+begin
+end$$;
+
+do $$
+declare r1 record;
+ r2 r1%type[];
+begin
+end$$;
+
-- check repeated assignments to composite fields
create table some_table (id int, data text);