Hi
2016-02-24 22:18 GMT+01:00 Peter Eisentraut <[email protected]>:
> On 1/18/16 4:21 PM, Robert Haas wrote:
> > One idea that occurs to me is: If you can DECLARE BAR FOO%TYPE, but
> > then you want to make BAR an array of that type rather than a scalar,
> > why not write that as DECLARE BAR FOO%TYPE[]? That seems quite
> > natural to me.
>
> Right, and it's arguably dubious that that doesn't already work.
> Unfortunately, these % things are just random plpgsql parser hacks, not
> real types. Maybe this should be done in the main PostgreSQL parser
> with parameter hooks, if we wanted this feature to be available outside
> plpgsql as well.
>
> > I think the part of this patch that makes %TYPE work for more kinds of
> > types is probably a good idea, although I haven't carefully studied
> > exactly what it does.
>
> I agree that this should be more general. For instance, this patch
> would allow you to get the element type of an array-typed variable, but
> there is no way to get the element type of just another type. If we
> could do something like
>
> DECLARE
> var ELEMENT OF point;
>
> (not necessary that syntax)
>
> then
>
> DECLARE
> var ELEMENT OF othervar%TYPE;
>
> should just fall into place.
>
>
I am sending update of this patch. The basic concept is same, syntax was
changed per your and Robert requirement.
Regards
Pavel
diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml
new file mode 100644
index 9786242..5587839
*** a/doc/src/sgml/plpgsql.sgml
--- b/doc/src/sgml/plpgsql.sgml
*************** url varchar;
*** 322,334 ****
myrow tablename%ROWTYPE;
myfield tablename.columnname%TYPE;
arow RECORD;
</programlisting>
</para>
<para>
The general syntax of a variable declaration is:
<synopsis>
! <replaceable>name</replaceable> <optional> CONSTANT </optional> <replaceable>type</replaceable> <optional> COLLATE <replaceable>collation_name</replaceable> </optional> <optional> NOT NULL </optional> <optional> { DEFAULT | := | = } <replaceable>expression</replaceable> </optional>;
</synopsis>
The <literal>DEFAULT</> clause, if given, specifies the initial value assigned
to the variable when the block is entered. If the <literal>DEFAULT</> clause
--- 322,336 ----
myrow tablename%ROWTYPE;
myfield tablename.columnname%TYPE;
arow RECORD;
+ myarray tablename.columnname%TYPE[];
+ myelement ELEMENT OF arrayparam%TYPE;
</programlisting>
</para>
<para>
The general syntax of a variable declaration is:
<synopsis>
! <replaceable>name</replaceable> <optional> CONSTANT </optional> <optional> ELEMENT OF </optional> <replaceable>type</replaceable> <optional> COLLATE <replaceable>collation_name</replaceable> </optional> <optional> NOT NULL </optional> <optional> { DEFAULT | := | = } <replaceable>expression</replaceable> </optional>;
</synopsis>
The <literal>DEFAULT</> clause, if given, specifies the initial value assigned
to the variable when the block is entered. If the <literal>DEFAULT</> clause
*************** arow RECORD;
*** 337,342 ****
--- 339,347 ----
The <literal>CONSTANT</> option prevents the variable from being
assigned to after initialization, so that its value will remain constant
for the duration of the block.
+ The <literal>ELEMENT OF</> ensure using the element type of a given array type.
+ This construct is valuable in polymorphic functions, since the data types needed
+ for internal variables can change from one call to the next call.
The <literal>COLLATE</> option specifies a collation to use for the
variable (see <xref linkend="plpgsql-declaration-collation">).
If <literal>NOT NULL</>
*************** user_id users.user_id%TYPE;
*** 611,616 ****
--- 616,666 ----
change from one call to the next. Appropriate variables can be
created by applying <literal>%TYPE</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%TYPE[] 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);
+
+
+ CREATE OR REPLACE FUNCTION bubble_sort(a anyarray)
+ RETURNS anyarray AS $$
+ DECLARE
+ aux ELEMENT OF a%TYPE;
+ 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;
+
+ SELECT bubble_sort(ARRAY[3,2,4,6,1]);
+ </programlisting>
</para>
</sect2>
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
new file mode 100644
index 2aeab96..b77117e
*** a/src/pl/plpgsql/src/pl_comp.c
--- b/src/pl/plpgsql/src/pl_comp.c
*************** plpgsql_parse_wordtype(char *ident)
*** 1646,1653 ****
case PLPGSQL_NSTYPE_VAR:
return ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
! /* XXX perhaps allow REC/ROW here? */
default:
return NULL;
}
--- 1646,1660 ----
case PLPGSQL_NSTYPE_VAR:
return ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
! case PLPGSQL_NSTYPE_ROW:
! {
! return ((PLpgSQL_row *) (plpgsql_Datums[nse->itemno]))->datatype;
! }
+ /*
+ * XXX perhaps allow REC here? Currently PLpgSQL doesn't allow
+ * REC parameters, so REC support is not required.
+ */
default:
return NULL;
}
*************** 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;
}
/*
--- 1725,1742 ----
NULL,
NULL);
! if (nse != NULL)
{
! if (nse->itemtype == PLPGSQL_NSTYPE_VAR)
! {
! dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
! goto done;
! }
! else if (nse->itemtype == PLPGSQL_NSTYPE_ROW)
! {
! dtype = ((PLpgSQL_row *) (plpgsql_Datums[nse->itemno]))->datatype;
! goto done;
! }
}
/*
*************** plpgsql_parse_cwordrowtype(List *idents)
*** 1852,1857 ****
--- 1867,1925 ----
}
/*
+ * This routine is used for generating element or array type from base type.
+ * The options to_element_type and to_array_type can be used together, when
+ * we would to ensure valid result. The array array type is original type, so
+ * this direction is safe. The element of scalar type is not allowed, but if
+ * we do "to array" transformation first, then this direction should be safe
+ * too. This design is tolerant, because we should to support a design of
+ * polymorphic parameters, where a array value can be passed as anyelement
+ * or anyarray parameter.
+ */
+ PLpgSQL_type *
+ plpgsql_derive_type(PLpgSQL_type *base_type,
+ bool to_element_type, bool to_array_type)
+ {
+ Oid typid = base_type->typoid;
+
+ if (to_array_type)
+ {
+ /* do nothing if base_type is a array already */
+ if (!OidIsValid(get_element_type(typid)))
+ {
+ Oid array_typid = get_array_type(typid);
+
+ if (!OidIsValid(array_typid))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("could not find array type for data type %s",
+ format_type_be(typid))));
+ typid = array_typid;
+ }
+ }
+
+ if (to_element_type)
+ {
+ Oid element_typid = get_element_type(typid);
+
+ if (!OidIsValid(element_typid))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("referenced variable should be an array, not type %s",
+ format_type_be(typid))));
+ typid = element_typid;
+ }
+
+ /* when type is changed, construct new datatype */
+ if (typid != base_type->typoid)
+ return plpgsql_build_datatype(typid, -1,
+ plpgsql_curr_compile->fn_input_collation);
+
+ /* return original base_type, when any change is not required */
+ return base_type;
+ }
+
+ /*
* plpgsql_build_variable - build a datum-array entry of a given
* datatype
*
*************** plpgsql_build_variable(const char *refna
*** 1903,1908 ****
--- 1971,1977 ----
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 df09575..5a05fed
*** a/src/pl/plpgsql/src/pl_gram.y
--- b/src/pl/plpgsql/src/pl_gram.y
*************** static void check_raise_parameters(PLp
*** 270,275 ****
--- 270,276 ----
%token <keyword> K_DETAIL
%token <keyword> K_DIAGNOSTICS
%token <keyword> K_DUMP
+ %token <keyword> K_ELEMENT
%token <keyword> K_ELSE
%token <keyword> K_ELSIF
%token <keyword> K_END
*************** static void check_raise_parameters(PLp
*** 303,308 ****
--- 304,310 ----
%token <keyword> K_NOT
%token <keyword> K_NOTICE
%token <keyword> K_NULL
+ %token <keyword> K_OF
%token <keyword> K_OPEN
%token <keyword> K_OPTION
%token <keyword> K_OR
*************** unreserved_keyword :
*** 2408,2413 ****
--- 2410,2416 ----
| K_DETAIL
| K_DIAGNOSTICS
| K_DUMP
+ | K_ELEMENT
| K_ELSIF
| K_ERRCODE
| K_ERROR
*************** unreserved_keyword :
*** 2429,2434 ****
--- 2432,2438 ----
| K_NEXT
| K_NO
| K_NOTICE
+ | K_OF
| K_OPEN
| K_OPTION
| K_PERFORM
*************** read_sql_construct(int until,
*** 2684,2697 ****
return expr;
}
static PLpgSQL_type *
read_datatype(int tok)
{
StringInfoData ds;
char *type_name;
int startlocation;
! PLpgSQL_type *result;
int parenlevel = 0;
/* Should only be called while parsing DECLARE sections */
Assert(plpgsql_IdentifierLookup == IDENTIFIER_LOOKUP_DECLARE);
--- 2688,2745 ----
return expr;
}
+ /*
+ * Returns true when following two tokens after %TYPE/%ROWTYPE are []
+ */
+ static bool
+ array_type_is_required(void)
+ {
+ int tok = yylex();
+
+ if (tok == '[')
+ {
+ tok = yylex();
+ if (tok != ']')
+ yyerror("syntax error, expected \"]\"");
+
+ return true;
+ }
+ else
+ plpgsql_push_back_token(tok);
+
+ return false;
+ }
+
+ /*
+ * Returns true when type is introducted by ELEMENT OF tokens
+ */
+ static bool
+ element_type_is_required(int tok)
+ {
+ if (tok_is_keyword(tok, &yylval,
+ K_ELEMENT, "element"))
+ {
+ tok = yylex();
+ if (!tok_is_keyword(tok, &yylval, K_OF, "of"))
+ yyerror("syntax error, expected \"OF\"");
+
+ tok = yylex();
+ return true;
+ }
+
+ return false;
+ }
+
static PLpgSQL_type *
read_datatype(int tok)
{
StringInfoData ds;
char *type_name;
int startlocation;
! PLpgSQL_type *result = NULL;
int parenlevel = 0;
+ bool to_element_type = false;
+ bool to_array_type = false;
/* Should only be called while parsing DECLARE sections */
Assert(plpgsql_IdentifierLookup == IDENTIFIER_LOOKUP_DECLARE);
*************** read_datatype(int tok)
*** 2700,2705 ****
--- 2748,2758 ----
if (tok == YYEMPTY)
tok = yylex();
+ /*
+ * The request of element type can be first.
+ */
+ to_element_type = element_type_is_required(tok);
+
startlocation = yylloc;
/*
*************** read_datatype(int tok)
*** 2718,2739 ****
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))
{
char *dtname = pstrdup(yylval.keyword);
-
tok = yylex();
if (tok == '%')
{
--- 2771,2794 ----
K_TYPE, "type"))
{
result = plpgsql_parse_wordtype(dtname);
}
else if (tok_is_keyword(tok, &yylval,
K_ROWTYPE, "rowtype"))
{
result = plpgsql_parse_wordrowtype(dtname);
! }
!
! if (result != NULL)
! {
! to_array_type = array_type_is_required();
! return plpgsql_derive_type(result,
! to_element_type, to_array_type);
}
}
}
else if (plpgsql_token_is_unreserved_keyword(tok))
{
char *dtname = pstrdup(yylval.keyword);
tok = yylex();
if (tok == '%')
{
*************** read_datatype(int tok)
*** 2742,2763 ****
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)
{
List *dtnames = yylval.cword.idents;
-
tok = yylex();
if (tok == '%')
{
--- 2797,2820 ----
K_TYPE, "type"))
{
result = plpgsql_parse_wordtype(dtname);
}
else if (tok_is_keyword(tok, &yylval,
K_ROWTYPE, "rowtype"))
{
result = plpgsql_parse_wordrowtype(dtname);
! }
!
! if (result != NULL)
! {
! to_array_type = array_type_is_required();
! return plpgsql_derive_type(result,
! to_element_type, to_array_type);
}
}
}
else if (tok == T_CWORD)
{
List *dtnames = yylval.cword.idents;
tok = yylex();
if (tok == '%')
{
*************** read_datatype(int tok)
*** 2766,2780 ****
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;
}
}
}
--- 2823,2840 ----
K_TYPE, "type"))
{
result = plpgsql_parse_cwordtype(dtnames);
}
else if (tok_is_keyword(tok, &yylval,
K_ROWTYPE, "rowtype"))
{
result = plpgsql_parse_cwordrowtype(dtnames);
! }
!
! if (result != NULL)
! {
! to_array_type = array_type_is_required();
! return plpgsql_derive_type(result,
! to_element_type, to_array_type);
}
}
}
*************** read_datatype(int tok)
*** 2817,2823 ****
plpgsql_push_back_token(tok);
! return result;
}
static PLpgSQL_stmt *
--- 2877,2884 ----
plpgsql_push_back_token(tok);
! return plpgsql_derive_type(result,
! to_element_type, to_array_type);
}
static PLpgSQL_stmt *
diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c
new file mode 100644
index bb0f25b..82959a9
*** a/src/pl/plpgsql/src/pl_scanner.c
--- b/src/pl/plpgsql/src/pl_scanner.c
*************** static const ScanKeyword unreserved_keyw
*** 116,121 ****
--- 116,122 ----
PG_KEYWORD("detail", K_DETAIL, UNRESERVED_KEYWORD)
PG_KEYWORD("diagnostics", K_DIAGNOSTICS, UNRESERVED_KEYWORD)
PG_KEYWORD("dump", K_DUMP, UNRESERVED_KEYWORD)
+ PG_KEYWORD("element", K_ELEMENT, UNRESERVED_KEYWORD)
PG_KEYWORD("elseif", K_ELSIF, UNRESERVED_KEYWORD)
PG_KEYWORD("elsif", K_ELSIF, UNRESERVED_KEYWORD)
PG_KEYWORD("errcode", K_ERRCODE, UNRESERVED_KEYWORD)
*************** static const ScanKeyword unreserved_keyw
*** 138,143 ****
--- 139,145 ----
PG_KEYWORD("next", K_NEXT, UNRESERVED_KEYWORD)
PG_KEYWORD("no", K_NO, UNRESERVED_KEYWORD)
PG_KEYWORD("notice", K_NOTICE, UNRESERVED_KEYWORD)
+ PG_KEYWORD("of", K_OF, UNRESERVED_KEYWORD)
PG_KEYWORD("open", K_OPEN, UNRESERVED_KEYWORD)
PG_KEYWORD("option", K_OPTION, UNRESERVED_KEYWORD)
PG_KEYWORD("perform", K_PERFORM, UNRESERVED_KEYWORD)
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
new file mode 100644
index a1e900d..f3c563c
*** a/src/pl/plpgsql/src/plpgsql.h
--- b/src/pl/plpgsql/src/plpgsql.h
*************** typedef struct
*** 281,286 ****
--- 281,287 ----
char *refname;
int lineno;
+ PLpgSQL_type *datatype;
TupleDesc rowtupdesc;
/*
*************** extern PLpgSQL_type *plpgsql_parse_wordt
*** 965,970 ****
--- 966,973 ----
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_derive_type(PLpgSQL_type *base_type,
+ bool to_element_type, bool to_array_type);
extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod,
Oid collation);
extern PLpgSQL_variable *plpgsql_build_variable(const char *refname, int lineno,
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
new file mode 100644
index e30c579..2cb207e
*** a/src/test/regress/expected/plpgsql.out
--- b/src/test/regress/expected/plpgsql.out
*************** end;
*** 5573,5575 ****
--- 5573,5729 ----
$$;
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 domain array_domain as int[];
+ create domain int_domain as 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%type[];
+ 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%type[] 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)
+
+ -- should fail, there are no array type for scalar domain
+ select test_poly_element(1::int_domain);
+ ERROR: could not find array type for data type int_domain
+ select test_array_init(1::int_domain, 10);
+ ERROR: could not find array type for data type int_domain
+ create or replace function test_poly_array(x anyarray)
+ returns anyelement as $$
+ declare result element of x%type;
+ 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)
+
+ select test_poly_array(ARRAY[1,2,3,4]::array_domain);
+ NOTICE: integer 1
+ test_poly_array
+ -----------------
+ 1
+ (1 row)
+
+ drop function test_simple(anyelement);
+ drop type test_composite_type;
+ drop domain array_domain;
+ drop domain int_domain;
+ drop function test_poly_element(anyelement);
+ drop function test_array_init(anyelement, int);
+ drop function test_poly_array(anyarray);
+ -- should fail, syntax errors
+ create or replace function test_poly_array(x anyarray)
+ returns anyelement as $$
+ declare result element x%type;
+ begin
+ return result;
+ end;
+ $$ language plpgsql;
+ ERROR: syntax error, expected "OF" at or near "x"
+ LINE 3: declare result element x%type;
+ ^
+ create or replace function test_poly_array(x anyarray)
+ returns anyelement as $$
+ declare result x%type[;
+ begin
+ return result;
+ end;
+ $$ language plpgsql;
+ ERROR: syntax error, expected "]" at or near ";"
+ LINE 3: declare result x%type[;
+ ^
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
new file mode 100644
index 7ffef89..0e16260
*** a/src/test/regress/sql/plpgsql.sql
--- b/src/test/regress/sql/plpgsql.sql
*************** exception when others then
*** 4386,4388 ****
--- 4386,4482 ----
null; -- do nothing
end;
$$;
+
+
+ -- test referenced types
+ create type test_composite_type as (x int, y int);
+ create domain array_domain as int[];
+ create domain int_domain as 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%type[];
+ 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%type[] 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);
+
+ -- should fail, there are no array type for scalar domain
+ select test_poly_element(1::int_domain);
+ select test_array_init(1::int_domain, 10);
+
+ create or replace function test_poly_array(x anyarray)
+ returns anyelement as $$
+ declare result element of x%type;
+ 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]);
+ select test_poly_array(ARRAY[1,2,3,4]::array_domain);
+
+ drop function test_simple(anyelement);
+ drop type test_composite_type;
+ drop domain array_domain;
+ drop domain int_domain;
+
+ drop function test_poly_element(anyelement);
+ drop function test_array_init(anyelement, int);
+ drop function test_poly_array(anyarray);
+
+ -- should fail, syntax errors
+ create or replace function test_poly_array(x anyarray)
+ returns anyelement as $$
+ declare result element x%type;
+ begin
+ return result;
+ end;
+ $$ language plpgsql;
+
+ create or replace function test_poly_array(x anyarray)
+ returns anyelement as $$
+ declare result x%type[;
+ begin
+ return result;
+ end;
+ $$ language plpgsql;
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers