Hi 2016-01-18 21:37 GMT+01:00 Alvaro Herrera <alvhe...@2ndquadrant.com>:
> > diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c > > new file mode 100644 > > index 1ae4bb7..c819517 > > *** a/src/pl/plpgsql/src/pl_comp.c > > --- b/src/pl/plpgsql/src/pl_comp.c > > *************** plpgsql_parse_tripword(char *word1, char > > *** 1617,1622 **** > > --- 1617,1677 ---- > > return false; > > } > > > > + /* > > + * Derive type from ny base type controlled by reftype_mode > > + */ > > + static PLpgSQL_type * > > + derive_type(PLpgSQL_type *base_type, int reftype_mode) > > + { > > + Oid typoid; > > I think you should add a typedef to the REFTYPE enum, and have this > function take that type rather than int. > done > > > + case PLPGSQL_REFTYPE_ARRAY: > > + { > > + /* > > + * Question: can we allow anyelement (array or > nonarray) -> array direction. > > + * if yes, then probably we have to modify > enforce_generic_type_consistency, > > + * parse_coerce.c where still is check on scalar > type -> raise error > > + * ERROR: 42704: could not find array type for > data type integer[] > > + * > > + if > (OidIsValid(get_element_type(base_type->typoid))) > > + return base_type; > > + */ > > I think it would be better to resolve this question outside a code > comment. > done > > > + typoid = get_array_type(base_type->typoid); > > + if (!OidIsValid(typoid)) > > + ereport(ERROR, > > + > (errcode(ERRCODE_DATATYPE_MISMATCH), > > + errmsg("there are not > array type for type %s", > > + > format_type_be(base_type->typoid)))); > > nodeFuncs.c uses this wording: > errmsg("could not find array type for data type %s", > which I think you should adopt. > sure, fixed > > > --- 1681,1687 ---- > > * ---------- > > */ > > PLpgSQL_type * > > ! plpgsql_parse_wordtype(char *ident, int reftype_mode) > > { > > PLpgSQL_type *dtype; > > PLpgSQL_nsitem *nse; > > Use the typedef'ed enum, as above. > > > --- 1699,1721 ---- > > switch (nse->itemtype) > > { > > case PLPGSQL_NSTYPE_VAR: > > ! { > > ! dtype = ((PLpgSQL_var *) > (plpgsql_Datums[nse->itemno]))->datatype; > > ! return derive_type(dtype, reftype_mode); > > ! } > > > > ! case PLPGSQL_NSTYPE_ROW: > > ! { > > ! dtype = ((PLpgSQL_row *) > (plpgsql_Datums[nse->itemno]))->datatype; > > ! return derive_type(dtype, reftype_mode); > > ! } > > > > + /* > > + * XXX perhaps allow REC here? Probably it has not > any sense, because > > + * in this moment, because PLpgSQL doesn't support > rec parameters, so > > + * there should not be any rec polymorphic > parameter, and any work can > > + * be done inside function. > > + */ > > I think you should remove from the "?" onwards in that comment, i.e. > just keep what was already in the original comment (minus the ROW) > I tried to fix it, not sure if understood well. > > > --- 1757,1763 ---- > > * ---------- > > */ > > PLpgSQL_type * > > ! plpgsql_parse_cwordtype(List *idents, int reftype_mode) > > { > > PLpgSQL_type *dtype = NULL; > > PLpgSQL_nsitem *nse; > > Typedef. > > > --- 2720,2737 ---- > > tok = yylex(); > > if (tok_is_keyword(tok, &yylval, > > K_TYPE, "type")) > > ! result = plpgsql_parse_wordtype(dtname, > PLPGSQL_REFTYPE_TYPE); > > ! else if (tok_is_keyword(tok, &yylval, > > ! > K_ELEMENTTYPE, "elementtype")) > > ! result = plpgsql_parse_wordtype(dtname, > PLPGSQL_REFTYPE_ELEMENT); > > ! else if (tok_is_keyword(tok, &yylval, > > ! > K_ARRAYTYPE, "arraytype")) > > ! result = plpgsql_parse_wordtype(dtname, > PLPGSQL_REFTYPE_ARRAY); > > else if (tok_is_keyword(tok, &yylval, > > > K_ROWTYPE, "rowtype")) > > result = plpgsql_parse_wordrowtype(dtname); > > ! if (result) > > ! return result; > > } > > This plpgsql parser stuff is pretty tiresome. (Not this patch's fault > -- just saying.) > > > > *************** extern bool plpgsql_parse_dblword(char * > > *** 961,968 **** > > PLwdatum *wdatum, PLcword > *cword); > > extern bool plpgsql_parse_tripword(char *word1, char *word2, char > *word3, > > PLwdatum *wdatum, PLcword > *cword); > > ! extern PLpgSQL_type *plpgsql_parse_wordtype(char *ident); > > ! extern PLpgSQL_type *plpgsql_parse_cwordtype(List *idents); > > extern PLpgSQL_type *plpgsql_parse_wordrowtype(char *ident); > > extern PLpgSQL_type *plpgsql_parse_cwordrowtype(List *idents); > > extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod, > > --- 973,980 ---- > > PLwdatum *wdatum, PLcword > *cword); > > extern bool plpgsql_parse_tripword(char *word1, char *word2, char > *word3, > > PLwdatum *wdatum, PLcword > *cword); > > ! extern PLpgSQL_type *plpgsql_parse_wordtype(char *ident, int > reftype_mode); > > ! extern PLpgSQL_type *plpgsql_parse_cwordtype(List *idents, int > reftype_mode); > > extern PLpgSQL_type *plpgsql_parse_wordrowtype(char *ident); > > extern PLpgSQL_type *plpgsql_parse_cwordrowtype(List *idents); > > extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod, > > By the way, these functions are misnamed after this patch. They are > called "wordtype" and "cwordtype" originally because they accept > "word%TYPE" and "compositeword%TYPE", but after the patch they not only > accept TYPE at the right of the percent sign but also ELEMENTTYPE and > ARRAYTYPE. Not sure that this is something we want to be too strict > about. > Understand - used name ***reftype instead ****type > > > *** a/src/test/regress/expected/plpgsql.out > > --- b/src/test/regress/expected/plpgsql.out > > *************** end; > > *** 5573,5575 **** > > --- 5573,5667 ---- > > I think you should also add your array_init() example to the test set. > done Thank you for your comment Attached updated patch Regards Pavel > > > -- > Álvaro Herrera http://www.2ndQuadrant.com/ > PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services >
diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml new file mode 100644 index 9786242..140c81f *** a/doc/src/sgml/plpgsql.sgml --- b/doc/src/sgml/plpgsql.sgml *************** SELECT merge_fields(t.*) FROM table1 t W *** 710,715 **** --- 710,792 ---- </para> </sect2> + <sect2 id="plpgsql-declaration-arraytype"> + <title>Array Types</title> + + <synopsis> + <replaceable>variable</replaceable>%ARRAYTYPE + </synopsis> + + <para> + <literal>%ARRAYTYPE</literal> provides the array type from a variable or + table column. <literal>%ARRAYTYPE</literal> is particularly valuable in + polymorphic functions, since the data types needed for internal variables can + change from one call to the next. Appropriate variables can be + created by applying <literal>%ARRAYTYPE</literal> to the function's + arguments or result placeholders: + <programlisting> + CREATE OR REPLACE FUNCTION array_init(v anyelement, size integer) + RETURNS anyarray AS $$ + DECLARE + result v%ARRAYTYPE DEFAULT '{}'; + BEGIN + -- prefer builtin function array_fill + FOR i IN 1 .. size + LOOP + result := result || v; + END LOOP; + RETURN result; + END; + $$ LANGUAGE plpgsql; + + SELECT array_init(0::numeric, 10); + SELECT array_init(''::varchar, 10); + </programlisting> + </para> + </sect2> + + <sect2 id="plpgsql-declaration-elementtype"> + <title>Array Element Types</title> + + <synopsis> + <replaceable>variable</replaceable>%ELEMENTTYPE + </synopsis> + + <para> + <literal>%ELEMENTTYPE</literal> provides the element type of a given + array. <literal>%ELEMENTTYPE</literal> is particularly valuable in polymorphic + functions, since the data types needed for internal variables can + change from one call to the next. Appropriate variables can be + created by applying <literal>%ELEMENTTYPE</literal> to the function's + arguments or result placeholders: + <programlisting> + CREATE OR REPLACE FUNCTION bubble_sort(a anyarray) + RETURNS anyarray AS $$ + DECLARE + aux a%ELEMENTTYPE; + repeat_again boolean DEFAULT true; + BEGIN + -- Don't use this code for large arrays! + -- use builtin sort + WHILE repeat_again + LOOP + repeat_again := false; + FOR i IN array_lower(a, 1) .. array_upper(a, 1) + LOOP + IF a[i] > a[i+1] THEN + aux := a[i+1]; + a[i+1] := a[i]; a[i] := aux; + repeat_again := true; + END IF; + END LOOP; + END LOOP; + RETURN a; + END; + $$ LANGUAGE plpgsql; + </programlisting> + </para> + </sect2> + <sect2 id="plpgsql-declaration-collation"> <title>Collation of <application>PL/pgSQL</application> Variables</title> diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c new file mode 100644 index ebe152d..98f74c3 *** a/src/pl/plpgsql/src/pl_comp.c --- b/src/pl/plpgsql/src/pl_comp.c *************** plpgsql_parse_tripword(char *word1, char *** 1617,1632 **** return false; } /* ---------- ! * plpgsql_parse_wordtype The scanner found word%TYPE. word can be ! * a variable name or a basetype. * * Returns datatype struct, or NULL if no match found for word. * ---------- */ PLpgSQL_type * ! plpgsql_parse_wordtype(char *ident) { PLpgSQL_type *dtype; PLpgSQL_nsitem *nse; --- 1617,1683 ---- return false; } + /* + * Derive type from ny base type controlled by reftype. + * + * This routine allows to take array type from array variable. This behave + * is not consistent with enforce_generic_type_consistency, where same task + * fails on ERROR: 42704: could not find array type for data type xxxxxxx[]. + */ + static PLpgSQL_type * + derive_type(PLpgSQL_type *base_type, PLpgSQL_reftype reftype) + { + Oid typoid; + + switch (reftype) + { + case PLPGSQL_REFTYPE_TYPE: + return base_type; + + case PLPGSQL_REFTYPE_ELEMENT: + { + typoid = get_element_type(base_type->typoid); + if (!OidIsValid(typoid)) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("referenced variable should be an array, not type %s", + format_type_be(base_type->typoid)))); + + return plpgsql_build_datatype(typoid, -1, + plpgsql_curr_compile->fn_input_collation); + } + + case PLPGSQL_REFTYPE_ARRAY: + { + /* Return base_type, when it is a array already */ + if (OidIsValid(get_element_type(base_type->typoid))) + return base_type; + + typoid = get_array_type(base_type->typoid); + if (!OidIsValid(typoid)) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("could not find array type for data type %s", + format_type_be(base_type->typoid)))); + + return plpgsql_build_datatype(typoid, -1, + plpgsql_curr_compile->fn_input_collation); + } + + default: + return NULL; /* keep compiler quiet */ + } + } /* ---------- ! * plpgsql_parse_wordreftype The scanner found word%TYPE or word%ARRAYTYPE ! * or word%ELEMENTTYPE. word can be a variable name or a basetype. * * Returns datatype struct, or NULL if no match found for word. * ---------- */ PLpgSQL_type * ! plpgsql_parse_wordreftype(char *ident, PLpgSQL_reftype reftype) { PLpgSQL_type *dtype; PLpgSQL_nsitem *nse; *************** plpgsql_parse_wordtype(char *ident) *** 1644,1653 **** switch (nse->itemtype) { case PLPGSQL_NSTYPE_VAR: ! return ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype; ! /* XXX perhaps allow REC/ROW here? */ default: return NULL; } --- 1695,1715 ---- switch (nse->itemtype) { case PLPGSQL_NSTYPE_VAR: ! { ! dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype; ! return derive_type(dtype, reftype); ! } ! case PLPGSQL_NSTYPE_ROW: ! { ! dtype = ((PLpgSQL_row *) (plpgsql_Datums[nse->itemno]))->datatype; ! return derive_type(dtype, reftype); ! } + /* + * PLpgSQL doesn't support REC parameters, so we should not to + * support REC here. + */ default: return NULL; } *************** plpgsql_parse_wordtype(char *ident) *** 1685,1695 **** /* ---------- ! * plpgsql_parse_cwordtype Same lookup for compositeword%TYPE * ---------- */ PLpgSQL_type * ! plpgsql_parse_cwordtype(List *idents) { PLpgSQL_type *dtype = NULL; PLpgSQL_nsitem *nse; --- 1747,1758 ---- /* ---------- ! * plpgsql_parse_cwordreftype Same lookup for compositeword%TYPE ! * compositeword%ARRAYTYPE or compositeword%ELEMENTTYPE * ---------- */ PLpgSQL_type * ! plpgsql_parse_cwordreftype(List *idents, PLpgSQL_reftype reftype) { PLpgSQL_type *dtype = NULL; PLpgSQL_nsitem *nse; *************** plpgsql_parse_cwordtype(List *idents) *** 1718,1727 **** NULL, NULL); ! if (nse != NULL && nse->itemtype == PLPGSQL_NSTYPE_VAR) { ! dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype; ! goto done; } /* --- 1781,1804 ---- NULL, NULL); ! if (nse != NULL) { ! PLpgSQL_type *ref_type; ! ! if (nse->itemtype == PLPGSQL_NSTYPE_VAR) ! { ! ref_type = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype; ! dtype = derive_type(ref_type, reftype); ! ! goto done; ! } ! else if (nse->itemtype == PLPGSQL_NSTYPE_ROW) ! { ! ref_type = ((PLpgSQL_row *) (plpgsql_Datums[nse->itemno]))->datatype; ! dtype = derive_type(ref_type, reftype); ! ! goto done; ! } } /* *************** plpgsql_build_variable(const char *refna *** 1903,1908 **** --- 1980,1986 ---- row->dtype = PLPGSQL_DTYPE_ROW; row->refname = pstrdup(refname); row->lineno = lineno; + row->datatype = dtype; plpgsql_adddatum((PLpgSQL_datum *) row); if (add2namespace) diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y new file mode 100644 index b14c22d..5048f54 *** a/src/pl/plpgsql/src/pl_gram.y --- b/src/pl/plpgsql/src/pl_gram.y *************** static void check_raise_parameters(PLp *** 248,253 **** --- 248,254 ---- %token <keyword> K_ALIAS %token <keyword> K_ALL %token <keyword> K_ARRAY + %token <keyword> K_ARRAYTYPE %token <keyword> K_ASSERT %token <keyword> K_BACKWARD %token <keyword> K_BEGIN *************** static void check_raise_parameters(PLp *** 270,275 **** --- 271,277 ---- %token <keyword> K_DETAIL %token <keyword> K_DIAGNOSTICS %token <keyword> K_DUMP + %token <keyword> K_ELEMENTTYPE %token <keyword> K_ELSE %token <keyword> K_ELSIF %token <keyword> K_END *************** unreserved_keyword : *** 2390,2395 **** --- 2392,2398 ---- K_ABSOLUTE | K_ALIAS | K_ARRAY + | K_ARRAYTYPE | K_ASSERT | K_BACKWARD | K_CLOSE *************** unreserved_keyword : *** 2408,2413 **** --- 2411,2417 ---- | K_DETAIL | K_DIAGNOSTICS | K_DUMP + | K_ELEMENTTYPE | K_ELSIF | K_ERRCODE | K_ERROR *************** read_datatype(int tok) *** 2690,2696 **** StringInfoData ds; char *type_name; int startlocation; ! PLpgSQL_type *result; int parenlevel = 0; /* Should only be called while parsing DECLARE sections */ --- 2694,2700 ---- StringInfoData ds; char *type_name; int startlocation; ! PLpgSQL_type *result = 0; int parenlevel = 0; /* Should only be called while parsing DECLARE sections */ *************** read_datatype(int tok) *** 2703,2710 **** startlocation = yylloc; /* ! * If we have a simple or composite identifier, check for %TYPE ! * and %ROWTYPE constructs. */ if (tok == T_WORD) { --- 2707,2714 ---- startlocation = yylloc; /* ! * If we have a simple or composite identifier, check for %TYPE, ! * %ELEMENTTYPE, %ARRAYTYPE and %ROWTYPE constructs. */ if (tok == T_WORD) { *************** read_datatype(int tok) *** 2716,2733 **** tok = yylex(); if (tok_is_keyword(tok, &yylval, K_TYPE, "type")) ! { ! result = plpgsql_parse_wordtype(dtname); ! if (result) ! return result; ! } else if (tok_is_keyword(tok, &yylval, K_ROWTYPE, "rowtype")) - { result = plpgsql_parse_wordrowtype(dtname); ! if (result) ! return result; ! } } } else if (plpgsql_token_is_unreserved_keyword(tok)) --- 2720,2737 ---- tok = yylex(); if (tok_is_keyword(tok, &yylval, K_TYPE, "type")) ! result = plpgsql_parse_wordreftype(dtname, PLPGSQL_REFTYPE_TYPE); ! else if (tok_is_keyword(tok, &yylval, ! K_ELEMENTTYPE, "elementtype")) ! result = plpgsql_parse_wordreftype(dtname, PLPGSQL_REFTYPE_ELEMENT); ! else if (tok_is_keyword(tok, &yylval, ! K_ARRAYTYPE, "arraytype")) ! result = plpgsql_parse_wordreftype(dtname, PLPGSQL_REFTYPE_ARRAY); else if (tok_is_keyword(tok, &yylval, K_ROWTYPE, "rowtype")) result = plpgsql_parse_wordrowtype(dtname); ! if (result) ! return result; } } else if (plpgsql_token_is_unreserved_keyword(tok)) *************** read_datatype(int tok) *** 2740,2757 **** tok = yylex(); if (tok_is_keyword(tok, &yylval, K_TYPE, "type")) ! { ! result = plpgsql_parse_wordtype(dtname); ! if (result) ! return result; ! } else if (tok_is_keyword(tok, &yylval, K_ROWTYPE, "rowtype")) - { result = plpgsql_parse_wordrowtype(dtname); ! if (result) ! return result; ! } } } else if (tok == T_CWORD) --- 2744,2761 ---- tok = yylex(); if (tok_is_keyword(tok, &yylval, K_TYPE, "type")) ! result = plpgsql_parse_wordreftype(dtname, PLPGSQL_REFTYPE_TYPE); ! else if (tok_is_keyword(tok, &yylval, ! K_ELEMENTTYPE, "elementtype")) ! result = plpgsql_parse_wordreftype(dtname, PLPGSQL_REFTYPE_ELEMENT); ! else if (tok_is_keyword(tok, &yylval, ! K_ARRAYTYPE, "arraytype")) ! result = plpgsql_parse_wordreftype(dtname, PLPGSQL_REFTYPE_ARRAY); else if (tok_is_keyword(tok, &yylval, K_ROWTYPE, "rowtype")) result = plpgsql_parse_wordrowtype(dtname); ! if (result) ! return result; } } else if (tok == T_CWORD) *************** read_datatype(int tok) *** 2764,2781 **** tok = yylex(); if (tok_is_keyword(tok, &yylval, K_TYPE, "type")) ! { ! result = plpgsql_parse_cwordtype(dtnames); ! if (result) ! return result; ! } else if (tok_is_keyword(tok, &yylval, K_ROWTYPE, "rowtype")) - { result = plpgsql_parse_cwordrowtype(dtnames); ! if (result) ! return result; ! } } } --- 2768,2785 ---- tok = yylex(); if (tok_is_keyword(tok, &yylval, K_TYPE, "type")) ! result = plpgsql_parse_cwordreftype(dtnames, PLPGSQL_REFTYPE_TYPE); ! else if (tok_is_keyword(tok, &yylval, ! K_ELEMENTTYPE, "elementtype")) ! result = plpgsql_parse_cwordreftype(dtnames, PLPGSQL_REFTYPE_ELEMENT); ! else if (tok_is_keyword(tok, &yylval, ! K_ARRAYTYPE, "arraytype")) ! result = plpgsql_parse_cwordreftype(dtnames, PLPGSQL_REFTYPE_ARRAY); else if (tok_is_keyword(tok, &yylval, K_ROWTYPE, "rowtype")) result = plpgsql_parse_cwordrowtype(dtnames); ! if (result) ! return result; } } diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c new file mode 100644 index bb0f25b..9a5c54a *** a/src/pl/plpgsql/src/pl_scanner.c --- b/src/pl/plpgsql/src/pl_scanner.c *************** static const ScanKeyword unreserved_keyw *** 98,103 **** --- 98,104 ---- PG_KEYWORD("absolute", K_ABSOLUTE, UNRESERVED_KEYWORD) PG_KEYWORD("alias", K_ALIAS, UNRESERVED_KEYWORD) PG_KEYWORD("array", K_ARRAY, UNRESERVED_KEYWORD) + PG_KEYWORD("arraytype", K_ARRAYTYPE, UNRESERVED_KEYWORD) PG_KEYWORD("assert", K_ASSERT, UNRESERVED_KEYWORD) PG_KEYWORD("backward", K_BACKWARD, UNRESERVED_KEYWORD) PG_KEYWORD("close", K_CLOSE, UNRESERVED_KEYWORD) *************** static const ScanKeyword unreserved_keyw *** 116,121 **** --- 117,123 ---- PG_KEYWORD("detail", K_DETAIL, UNRESERVED_KEYWORD) PG_KEYWORD("diagnostics", K_DIAGNOSTICS, UNRESERVED_KEYWORD) PG_KEYWORD("dump", K_DUMP, UNRESERVED_KEYWORD) + PG_KEYWORD("elementtype", K_ELEMENTTYPE, UNRESERVED_KEYWORD) PG_KEYWORD("elseif", K_ELSIF, UNRESERVED_KEYWORD) PG_KEYWORD("elsif", K_ELSIF, UNRESERVED_KEYWORD) PG_KEYWORD("errcode", K_ERRCODE, UNRESERVED_KEYWORD) diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h new file mode 100644 index f4e9f62..41c3d74 *** a/src/pl/plpgsql/src/plpgsql.h --- b/src/pl/plpgsql/src/plpgsql.h *************** enum *** 84,89 **** --- 84,100 ---- }; /* ---------- + * Possible modes for type references + * ---------- + */ + typedef enum + { + PLPGSQL_REFTYPE_TYPE, /* use type of some variable */ + PLPGSQL_REFTYPE_ELEMENT, /* use a element type of referenced variable */ + PLPGSQL_REFTYPE_ARRAY /* use a array type of referenced variable */ + } PLpgSQL_reftype; + + /* ---------- * Execution tree node types * ---------- */ *************** typedef struct *** 281,286 **** --- 292,298 ---- char *refname; int lineno; + PLpgSQL_type *datatype; TupleDesc rowtupdesc; /* *************** extern bool plpgsql_parse_dblword(char * *** 961,968 **** PLwdatum *wdatum, PLcword *cword); extern bool plpgsql_parse_tripword(char *word1, char *word2, char *word3, PLwdatum *wdatum, PLcword *cword); ! extern PLpgSQL_type *plpgsql_parse_wordtype(char *ident); ! extern PLpgSQL_type *plpgsql_parse_cwordtype(List *idents); extern PLpgSQL_type *plpgsql_parse_wordrowtype(char *ident); extern PLpgSQL_type *plpgsql_parse_cwordrowtype(List *idents); extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod, --- 973,980 ---- PLwdatum *wdatum, PLcword *cword); extern bool plpgsql_parse_tripword(char *word1, char *word2, char *word3, PLwdatum *wdatum, PLcword *cword); ! extern PLpgSQL_type *plpgsql_parse_wordreftype(char *ident, PLpgSQL_reftype reftype); ! extern PLpgSQL_type *plpgsql_parse_cwordreftype(List *idents, PLpgSQL_reftype reftype); extern PLpgSQL_type *plpgsql_parse_wordrowtype(char *ident); extern PLpgSQL_type *plpgsql_parse_cwordrowtype(List *idents); extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod, diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out new file mode 100644 index e30c579..1d6117e *** a/src/test/regress/expected/plpgsql.out --- b/src/test/regress/expected/plpgsql.out *************** end; *** 5573,5575 **** --- 5573,5692 ---- $$; ERROR: unhandled assertion CONTEXT: PL/pgSQL function inline_code_block line 3 at ASSERT + -- test referenced types + create type test_composite_type as (x int, y int); + create or replace function test_simple(src anyelement) + returns anyelement as $$ + declare dest src%type; + begin + dest := src; + return dest; + end; + $$ language plpgsql; + select test_simple(10); + test_simple + ------------- + 10 + (1 row) + + select test_simple('hoj'::text); + test_simple + ------------- + hoj + (1 row) + + select test_simple((10,20)::test_composite_type); + test_simple + ------------- + (10,20) + (1 row) + + create or replace function test_poly_element(x anyelement) + returns anyarray as $$ + declare result x%arraytype; + begin + result := ARRAY[x]; + raise notice '% %', pg_typeof(result), result; + return result; + end; + $$ language plpgsql; + create or replace function test_array_init(v anyelement, size integer) + returns anyarray as $$ + declare result v%arraytype default '{}'; + begin + -- prefer builtin function array_fill + for i in 1 .. size + loop + result := result || v; + end loop; + return result; + end; + $$ language plpgsql; + select test_poly_element(1); + NOTICE: integer[] {1} + test_poly_element + ------------------- + {1} + (1 row) + + select test_poly_element('hoj'::text); + NOTICE: text[] {hoj} + test_poly_element + ------------------- + {hoj} + (1 row) + + select test_poly_element((10,20)::test_composite_type); + NOTICE: test_composite_type[] {"(10,20)"} + test_poly_element + ------------------- + {"(10,20)"} + (1 row) + + select test_array_init(1.0::numeric, 10); + test_array_init + ------------------------------------------- + {1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0} + (1 row) + + select test_array_init(1::int, 10); + test_array_init + ----------------------- + {1,1,1,1,1,1,1,1,1,1} + (1 row) + + create or replace function test_poly_array(x anyarray) + returns anyelement as $$ + declare result x%elementtype; + begin + result := x[1]; + raise notice '% %', pg_typeof(result), result; + return result; + end; + $$ language plpgsql; + select test_poly_array(ARRAY[1]); + NOTICE: integer 1 + test_poly_array + ----------------- + 1 + (1 row) + + select test_poly_array(ARRAY['hoj'::text]); + NOTICE: text hoj + test_poly_array + ----------------- + hoj + (1 row) + + select test_poly_array(ARRAY[(10,20)::test_composite_type]); + NOTICE: test_composite_type (10,20) + test_poly_array + ----------------- + (10,20) + (1 row) + + drop function test_simple(anyelement); + drop type test_composite_type; + drop function test_poly_element(anyelement); + drop function test_array_init(anyelement, int); + drop function test_poly_array(anyarray); diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql new file mode 100644 index 7ffef89..85b8174 *** a/src/test/regress/sql/plpgsql.sql --- b/src/test/regress/sql/plpgsql.sql *************** exception when others then *** 4386,4388 **** --- 4386,4455 ---- null; -- do nothing end; $$; + + -- test referenced types + create type test_composite_type as (x int, y int); + + create or replace function test_simple(src anyelement) + returns anyelement as $$ + declare dest src%type; + begin + dest := src; + return dest; + end; + $$ language plpgsql; + + select test_simple(10); + select test_simple('hoj'::text); + select test_simple((10,20)::test_composite_type); + + create or replace function test_poly_element(x anyelement) + returns anyarray as $$ + declare result x%arraytype; + begin + result := ARRAY[x]; + raise notice '% %', pg_typeof(result), result; + return result; + end; + $$ language plpgsql; + + create or replace function test_array_init(v anyelement, size integer) + returns anyarray as $$ + declare result v%arraytype default '{}'; + begin + -- prefer builtin function array_fill + for i in 1 .. size + loop + result := result || v; + end loop; + return result; + end; + $$ language plpgsql; + + select test_poly_element(1); + select test_poly_element('hoj'::text); + select test_poly_element((10,20)::test_composite_type); + + select test_array_init(1.0::numeric, 10); + select test_array_init(1::int, 10); + + create or replace function test_poly_array(x anyarray) + returns anyelement as $$ + declare result x%elementtype; + begin + result := x[1]; + raise notice '% %', pg_typeof(result), result; + return result; + end; + $$ language plpgsql; + + + select test_poly_array(ARRAY[1]); + select test_poly_array(ARRAY['hoj'::text]); + select test_poly_array(ARRAY[(10,20)::test_composite_type]); + + drop function test_simple(anyelement); + drop type test_composite_type; + drop function test_poly_element(anyelement); + drop function test_array_init(anyelement, int); + drop function test_poly_array(anyarray);
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers