Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit43b46aa

Browse files
committed
Clean up some edge cases in plpgsql's %TYPE parsing.
Support referencing a composite-type variable in %TYPE.Remove the undocumented, untested, and pretty useless abilityto have the subject of %TYPE be an (unqualified) type name.You get the same result by just not writing %TYPE.Add or adjust some test cases to improve code coverage here.Discussion:https://postgr.es/m/716852.1704402127@sss.pgh.pa.us
1 parentdbad1c5 commit43b46aa

File tree

5 files changed

+119
-46
lines changed

5 files changed

+119
-46
lines changed

‎src/pl/plpgsql/src/expected/plpgsql_record.out

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,52 @@ NOTICE: r1 = (1,2)
306306
ERROR: record "r1" has no field "nosuchfield"
307307
CONTEXT: SQL expression "r1.nosuchfield"
308308
PL/pgSQL function inline_code_block line 9 at RAISE
309+
-- check %type with block-qualified variable names
310+
do $$
311+
<<blk>>
312+
declare
313+
v int;
314+
r two_int8s;
315+
v1 v%type;
316+
v2 blk.v%type;
317+
r1 r%type;
318+
r2 blk.r%type;
319+
begin
320+
raise notice '%', pg_typeof(v1);
321+
raise notice '%', pg_typeof(v2);
322+
raise notice '%', pg_typeof(r1);
323+
raise notice '%', pg_typeof(r2);
324+
end$$;
325+
NOTICE: integer
326+
NOTICE: integer
327+
NOTICE: two_int8s
328+
NOTICE: two_int8s
329+
-- check that type record can be passed through %type
330+
do $$
331+
declare r1 record;
332+
r2 r1%type;
333+
begin
334+
r2 := row(1,2);
335+
raise notice 'r2 = %', r2;
336+
r2 := row(3,4,5);
337+
raise notice 'r2 = %', r2;
338+
end$$;
339+
NOTICE: r2 = (1,2)
340+
NOTICE: r2 = (3,4,5)
341+
-- arrays of record are not supported at the moment
342+
do $$
343+
declare r1 record[];
344+
begin
345+
end$$;
346+
ERROR: variable "r1" has pseudo-type record[]
347+
CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 2
348+
do $$
349+
declare r1 record;
350+
r2 r1%type[];
351+
begin
352+
end$$;
353+
ERROR: variable "r2" has pseudo-type record[]
354+
CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 3
309355
-- check repeated assignments to composite fields
310356
create table some_table (id int, data text);
311357
do $$

‎src/pl/plpgsql/src/pl_comp.c

Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,19 +1596,16 @@ plpgsql_parse_tripword(char *word1, char *word2, char *word3,
15961596

15971597

15981598
/* ----------
1599-
* plpgsql_parse_wordtypeThe scanner found word%TYPE. wordcan be
1600-
*a variable name or a basetype.
1599+
* plpgsql_parse_wordtypeThe scanner found word%TYPE. wordshould be
1600+
*apre-existingvariable name.
16011601
*
16021602
* Returns datatype struct, or NULL if no match found for word.
16031603
* ----------
16041604
*/
16051605
PLpgSQL_type*
16061606
plpgsql_parse_wordtype(char*ident)
16071607
{
1608-
PLpgSQL_type*dtype;
16091608
PLpgSQL_nsitem*nse;
1610-
TypeName*typeName;
1611-
HeapTupletypeTup;
16121609

16131610
/*
16141611
* Do a lookup in the current namespace stack
@@ -1623,39 +1620,13 @@ plpgsql_parse_wordtype(char *ident)
16231620
{
16241621
casePLPGSQL_NSTYPE_VAR:
16251622
return ((PLpgSQL_var*) (plpgsql_Datums[nse->itemno]))->datatype;
1626-
1627-
/* XXX perhaps allow REC/ROW here? */
1628-
1623+
casePLPGSQL_NSTYPE_REC:
1624+
return ((PLpgSQL_rec*) (plpgsql_Datums[nse->itemno]))->datatype;
16291625
default:
16301626
returnNULL;
16311627
}
16321628
}
16331629

1634-
/*
1635-
* Word wasn't found in the namespace stack. Try to find a data type with
1636-
* that name, but ignore shell types and complex types.
1637-
*/
1638-
typeName=makeTypeName(ident);
1639-
typeTup=LookupTypeName(NULL,typeName,NULL, false);
1640-
if (typeTup)
1641-
{
1642-
Form_pg_typetypeStruct= (Form_pg_type)GETSTRUCT(typeTup);
1643-
1644-
if (!typeStruct->typisdefined||
1645-
typeStruct->typrelid!=InvalidOid)
1646-
{
1647-
ReleaseSysCache(typeTup);
1648-
returnNULL;
1649-
}
1650-
1651-
dtype=build_datatype(typeTup,-1,
1652-
plpgsql_curr_compile->fn_input_collation,
1653-
typeName);
1654-
1655-
ReleaseSysCache(typeTup);
1656-
returndtype;
1657-
}
1658-
16591630
/*
16601631
* Nothing found - up to now it's a word without any special meaning for
16611632
* us.
@@ -1666,13 +1637,17 @@ plpgsql_parse_wordtype(char *ident)
16661637

16671638
/* ----------
16681639
* plpgsql_parse_cwordtypeSame lookup for compositeword%TYPE
1640+
*
1641+
* Here, we allow either a block-qualified variable name, or a reference
1642+
* to a column of some table.
16691643
* ----------
16701644
*/
16711645
PLpgSQL_type*
16721646
plpgsql_parse_cwordtype(List*idents)
16731647
{
16741648
PLpgSQL_type*dtype=NULL;
16751649
PLpgSQL_nsitem*nse;
1650+
intnnames;
16761651
constchar*fldname;
16771652
OidclassOid;
16781653
HeapTupleclasstup=NULL;
@@ -1688,21 +1663,27 @@ plpgsql_parse_cwordtype(List *idents)
16881663
if (list_length(idents)==2)
16891664
{
16901665
/*
1691-
* Do a lookup in the current namespace stack. We don't need to check
1692-
* number of names matched, because we will only consider scalar
1693-
* variables.
1666+
* Do a lookup in the current namespace stack
16941667
*/
16951668
nse=plpgsql_ns_lookup(plpgsql_ns_top(), false,
16961669
strVal(linitial(idents)),
16971670
strVal(lsecond(idents)),
16981671
NULL,
1699-
NULL);
1672+
&nnames);
17001673

17011674
if (nse!=NULL&&nse->itemtype==PLPGSQL_NSTYPE_VAR)
17021675
{
1676+
/* Block-qualified reference to scalar variable. */
17031677
dtype= ((PLpgSQL_var*) (plpgsql_Datums[nse->itemno]))->datatype;
17041678
gotodone;
17051679
}
1680+
elseif (nse!=NULL&&nse->itemtype==PLPGSQL_NSTYPE_REC&&
1681+
nnames==2)
1682+
{
1683+
/* Block-qualified reference to record variable. */
1684+
dtype= ((PLpgSQL_rec*) (plpgsql_Datums[nse->itemno]))->datatype;
1685+
gotodone;
1686+
}
17061687

17071688
/*
17081689
* First word could also be a table name
@@ -1716,6 +1697,12 @@ plpgsql_parse_cwordtype(List *idents)
17161697
{
17171698
RangeVar*relvar;
17181699

1700+
/*
1701+
* We could check for a block-qualified reference to a field of a
1702+
* record variable, but %TYPE is documented as applying to variables,
1703+
* not fields of variables. Things would get rather ambiguous if we
1704+
* allowed either interpretation.
1705+
*/
17191706
relvar=makeRangeVar(strVal(linitial(idents)),
17201707
strVal(lsecond(idents)),
17211708
-1);

‎src/pl/plpgsql/src/sql/plpgsql_record.sql

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,46 @@ begin
199199
raise notice'r1.nosuchfield = %',r1.nosuchfield;
200200
end$$;
201201

202+
-- check %type with block-qualified variable names
203+
do $$
204+
<<blk>>
205+
declare
206+
vint;
207+
r two_int8s;
208+
v1 v%type;
209+
v2blk.v%type;
210+
r1 r%type;
211+
r2blk.r%type;
212+
begin
213+
raise notice'%', pg_typeof(v1);
214+
raise notice'%', pg_typeof(v2);
215+
raise notice'%', pg_typeof(r1);
216+
raise notice'%', pg_typeof(r2);
217+
end$$;
218+
219+
-- check that type record can be passed through %type
220+
do $$
221+
declare r1 record;
222+
r2 r1%type;
223+
begin
224+
r2 := row(1,2);
225+
raise notice'r2 = %', r2;
226+
r2 := row(3,4,5);
227+
raise notice'r2 = %', r2;
228+
end$$;
229+
230+
-- arrays of record are not supported at the moment
231+
do $$
232+
declare r1 record[];
233+
begin
234+
end$$;
235+
236+
do $$
237+
declare r1 record;
238+
r2 r1%type[];
239+
begin
240+
end$$;
241+
202242
-- check repeated assignments to composite fields
203243
createtablesome_table (idint, datatext);
204244

‎src/test/regress/expected/plpgsql.out

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5795,18 +5795,18 @@ SELECT * FROM get_from_partitioned_table(1) AS t;
57955795
(1 row)
57965796

57975797
CREATE OR REPLACE FUNCTION list_partitioned_table()
5798-
RETURNS SETOF partitioned_table.a%TYPE AS $$
5798+
RETURNS SETOFpublic.partitioned_table.a%TYPE AS $$
57995799
DECLARE
5800-
row partitioned_table%ROWTYPE;
5801-
a_val partitioned_table.a%TYPE;
5800+
rowpublic.partitioned_table%ROWTYPE;
5801+
a_valpublic.partitioned_table.a%TYPE;
58025802
BEGIN
5803-
FOR row IN SELECT * FROM partitioned_table ORDER BY a LOOP
5803+
FOR row IN SELECT * FROMpublic.partitioned_table ORDER BY a LOOP
58045804
a_val := row.a;
58055805
RETURN NEXT a_val;
58065806
END LOOP;
58075807
RETURN;
58085808
END; $$ LANGUAGE plpgsql;
5809-
NOTICE: type reference partitioned_table.a%TYPE converted to integer
5809+
NOTICE: type referencepublic.partitioned_table.a%TYPE converted to integer
58105810
SELECT * FROM list_partitioned_table() AS t;
58115811
t
58125812
---

‎src/test/regress/sql/plpgsql.sql

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4734,12 +4734,12 @@ END; $$ LANGUAGE plpgsql;
47344734
SELECT*FROM get_from_partitioned_table(1)AS t;
47354735

47364736
CREATE OR REPLACEFUNCTIONlist_partitioned_table()
4737-
RETURNS SETOFpartitioned_table.a%TYPEAS $$
4737+
RETURNS SETOFpublic.partitioned_table.a%TYPEAS $$
47384738
DECLARE
4739-
row partitioned_table%ROWTYPE;
4740-
a_valpartitioned_table.a%TYPE;
4739+
rowpublic.partitioned_table%ROWTYPE;
4740+
a_valpublic.partitioned_table.a%TYPE;
47414741
BEGIN
4742-
FOR rowINSELECT*FROM partitioned_tableORDER BY a LOOP
4742+
FOR rowINSELECT*FROMpublic.partitioned_tableORDER BY a LOOP
47434743
a_val :=row.a;
47444744
RETURN NEXT a_val;
47454745
END LOOP;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp