Hi

2015-12-21 16:21 GMT+01:00 Artur Zakirov <a.zaki...@postgrespro.ru>:

> Hi.
> I have tried to do some review of this patch. Below are my comments.
>
> Introduction:
>
> This patch fixes and adds the following functionality:
> - %TYPE - now can be used for composite types.
> - %ARRAYTYPE - new functionality, provides the array type from a variable
> or table column.
> - %ELEMENTTYPE - new funcitonality, provides the element type of a given
> array.
>
> New regression tests are included in the patch. Changes to the
> documentation are not provided.
>
> Initial Run:
>
> The patch applies correctly to HEAD. Regression tests pass successfully,
> without errors. It seems that the patch work as you expected.
>
> Performance:
>
> It seems patch have not possible performance issues for the existing
> functionality.
>
> Coding:
>
> The style looks fine. I attached the patch that does some corrections in
> code and documentation. I have corrected indentation in pl_comp.c and
> "read_datatype" function in pl_gram.y. I think changes in "read_datatype"
> function would be better to avoid a code duplication. But I could be wrong
> of course.
>

I merged Artur's patch and appended examples to doc.



>
> Conclusion:
>
> The patch could be applied on master with documentation corrections. But
> I'm not sure that your task could be resloved only by adding %ARRAYTYPE and
> %ELEMENTTYPE. Maybe you will give some examples?
>

It fixes the most missed/known features related to this part of plpgsql,
what I found. But any ideas for this or follofup patches are welcome.

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 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;
+ 
+ 	switch (reftype_mode)
+ 	{
+ 		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:
+ 		{
+ 			/*
+ 			 * 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;
+ 			*/
+ 
+ 			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))));
+ 
+ 			return plpgsql_build_datatype(typoid, -1,
+ 							plpgsql_curr_compile->fn_input_collation);
+ 		}
+ 
+ 		default:
+ 			return NULL;
+ 	}
+ }
+ 
+ 
  
  /* ----------
   * plpgsql_parse_wordtype	The scanner found word%TYPE. word can be
*************** plpgsql_parse_tripword(char *word1, char
*** 1626,1632 ****
   * ----------
   */
  PLpgSQL_type *
! plpgsql_parse_wordtype(char *ident)
  {
  	PLpgSQL_type *dtype;
  	PLpgSQL_nsitem *nse;
--- 1681,1687 ----
   * ----------
   */
  PLpgSQL_type *
! plpgsql_parse_wordtype(char *ident, int reftype_mode)
  {
  	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;
  		}
--- 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.
+ 			 */
  			default:
  				return NULL;
  		}
*************** plpgsql_parse_wordtype(char *ident)
*** 1689,1695 ****
   * ----------
   */
  PLpgSQL_type *
! plpgsql_parse_cwordtype(List *idents)
  {
  	PLpgSQL_type *dtype = NULL;
  	PLpgSQL_nsitem *nse;
--- 1757,1763 ----
   * ----------
   */
  PLpgSQL_type *
! plpgsql_parse_cwordtype(List *idents, int reftype_mode)
  {
  	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;
  		}
  
  		/*
--- 1786,1809 ----
  								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_mode);
! 
! 				goto done;
! 			}
! 			else if (nse->itemtype == PLPGSQL_NSTYPE_ROW)
! 			{
! 				ref_type = ((PLpgSQL_row *) (plpgsql_Datums[nse->itemno]))->datatype;
! 				dtype = derive_type(ref_type, reftype_mode);
! 
! 				goto done;
! 			}
  		}
  
  		/*
*************** plpgsql_build_variable(const char *refna
*** 1903,1908 ****
--- 1985,1991 ----
  				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 841a8d6..2a197a2
*** 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_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;
  		}
  	}
  	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_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;
  		}
  	}
  	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_cwordtype(dtnames, PLPGSQL_REFTYPE_TYPE);
! 			else if (tok_is_keyword(tok, &yylval,
! 									K_ELEMENTTYPE, "elementtype"))
! 				result = plpgsql_parse_cwordtype(dtnames, PLPGSQL_REFTYPE_ELEMENT);
! 			else if (tok_is_keyword(tok, &yylval,
! 									K_ARRAYTYPE, "arraytype"))
! 				result = plpgsql_parse_cwordtype(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 683fdab..6e34605
*** 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 696fb61..5b1a074
*** a/src/pl/plpgsql/src/plpgsql.h
--- b/src/pl/plpgsql/src/plpgsql.h
*************** enum
*** 84,89 ****
--- 84,100 ----
  };
  
  /* ----------
+  * Possible modes for type references
+  * ----------
+  */
+ 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 */
+ };
+ 
+ /* ----------
   * 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_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,
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
new file mode 100644
index e30c579..b6e848b
*** a/src/test/regress/expected/plpgsql.out
--- b/src/test/regress/expected/plpgsql.out
*************** end;
*** 5573,5575 ****
--- 5573,5667 ----
  $$;
  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;
+ 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)
+ 
+ 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_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..46bad10
*** a/src/test/regress/sql/plpgsql.sql
--- b/src/test/regress/sql/plpgsql.sql
*************** exception when others then
*** 4386,4388 ****
--- 4386,4437 ----
    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;
+ 
+ select test_poly_element(1);
+ select test_poly_element('hoj'::text);
+ select test_poly_element((10,20)::test_composite_type);
+ 
+ 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_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

Reply via email to