Hi I am sending updated version - the changes are related to fix comments.
2016-02-19 10:41 GMT+01:00 Artur Zakirov <a.zaki...@postgrespro.ru>: > It seems all fixes are done. I tested the patch and regression tests > passed. > > I think here Alvaro means that you should keep original comment without > the ROW. Like this: > > /* XXX perhaps allow REC here? */ I tried rewording this comment > > > >> >> 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 >> > > I am not sure, but it seems that new names is a little worse. I think > original names are good too. They accept a word and return the PLpgSQL_type > structure. > The "TYPE" word in this name was related to syntax %TYPE. And because new syntax allows more constructs, then the change name is correct. I am think. But choosing names is hard work. The new name little bit more strongly show relation to work with referenced types. > > >> > I noticed a little typo in the comment in the derive_type(): > /* Return base_type, when it is a array already */ > > should be: > /* Return base_type, when it is an array already */ > > fixed Regards Pavel > > -- > Artur Zakirov > Postgres Professional: http://www.postgrespro.com > Russian Postgres Company >
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..07569f7 *** 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 any base type controlled by reftype. + * + * This routine allows to take array type from an 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 an 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); ! } + /* + * XXX perhaps allow REC here? Currently PLpgSQL doesn't allow + * REC parameters, so REC support is not required. + */ 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