array/polymorphic function doc cleanup - Mailing list pgsql-patches

From Joe Conway
Subject array/polymorphic function doc cleanup
Date
Msg-id 3F329A12.6040306@joeconway.com
Whole thread Raw
Responses Re: array/polymorphic function doc cleanup  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-patches
I think this rounds off the documentation updates that I owed for array
and polymorphic function/aggregate changes. Let me know if you think I
missed anything major. In any case, please apply.

Thanks,

Joe
Index: doc/src/sgml/array.sgml
===================================================================
RCS file: /opt/src/cvs/pgsql-server/doc/src/sgml/array.sgml,v
retrieving revision 1.28
diff -c -r1.28 array.sgml
*** doc/src/sgml/array.sgml    27 Jun 2003 00:33:25 -0000    1.28
--- doc/src/sgml/array.sgml    7 Aug 2003 15:41:38 -0000
***************
*** 116,122 ****
      VALUES ('Carol',
      ARRAY[20000, 25000, 25000, 25000],
      ARRAY[['talk', 'consult'], ['meeting']]);
! ERROR:  Multidimensional arrays must have array expressions with matching dimensions
  </programlisting>
    Also notice that string literals are single quoted instead of double quoted.
   </para>
--- 116,122 ----
      VALUES ('Carol',
      ARRAY[20000, 25000, 25000, 25000],
      ARRAY[['talk', 'consult'], ['meeting']]);
! ERROR:  multidimensional arrays must have array expressions with matching dimensions
  </programlisting>
    Also notice that string literals are single quoted instead of double quoted.
   </para>
***************
*** 206,224 ****
   </para>

   <para>
-   Additionally, we can also access a single arbitrary array element of
-   a one-dimensional array with the <function>array_subscript</function>
-   function:
- <programlisting>
- SELECT array_subscript(pay_by_quarter, 2) FROM sal_emp WHERE name = 'Bill';
-  array_subscript
- -----------------
-            10000
- (1 row)
- </programlisting>
-  </para>
-
-  <para>
    An array value can be replaced completely:

  <programlisting>
--- 206,211 ----
***************
*** 233,247 ****
      WHERE name = 'Carol';
  </programlisting>

-   <note>
-    <para>
-     Anywhere you can use the <quote>curly braces</quote> array syntax,
-     you can also use the <command>ARRAY</command> expression syntax. The
-     remainder of this section will illustrate only one or the other, but
-     not both.
-    </para>
-   </note>
-
    An array may also be updated at a single element:

  <programlisting>
--- 220,225 ----
***************
*** 256,278 ****
      WHERE name = 'Carol';
  </programlisting>

-   A one-dimensional array may also be updated with the
-   <function>array_assign</function> function:
-
- <programlisting>
- UPDATE sal_emp SET pay_by_quarter = array_assign(pay_by_quarter, 4, 15000)
-     WHERE name = 'Bill';
- </programListing>
   </para>

   <para>
    An array can be enlarged by assigning to an element adjacent to
    those already present, or by assigning to a slice that is adjacent
!   to or overlaps the data already present.  For example, if an array
!   value currently has 4 elements, it will have five elements after an
!   update that assigns to <literal>array[5]</>.  Currently, enlargement in
!   this fashion is only allowed for one-dimensional arrays, not
!   multidimensional arrays.
   </para>

   <para>
--- 234,249 ----
      WHERE name = 'Carol';
  </programlisting>

   </para>

   <para>
    An array can be enlarged by assigning to an element adjacent to
    those already present, or by assigning to a slice that is adjacent
!   to or overlaps the data already present.  For example, if array
!   <literal>myarray</> currently has 4 elements, it will have five
!   elements after an update that assigns to <literal>myarray[5]</>.
!   Currently, enlargement in this fashion is only allowed for one-dimensional
!   arrays, not multidimensional arrays.
   </para>

   <para>
***************
*** 434,472 ****
  </programlisting>

    However, this quickly becomes tedious for large arrays, and is not
!   helpful if the size of the array is unknown. Although it is not built
!   into <productname>PostgreSQL</productname>,
!   there is an extension available that defines new functions and
!   operators for iterating over array values. Using this, the above
    query could be:

  <programlisting>
! SELECT * FROM sal_emp WHERE pay_by_quarter[1:4] *= 10000;
! </programlisting>
!
!   To search the entire array (not just specified slices), you could
!   use:
!
! <programlisting>
! SELECT * FROM sal_emp WHERE pay_by_quarter *= 10000;
  </programlisting>

    In addition, you could find rows where the array had all values
!   equal to 10 000 with:

  <programlisting>
! SELECT * FROM sal_emp WHERE pay_by_quarter **= 10000;
  </programlisting>

-   To install this optional module, look in the
-   <filename>contrib/array</filename> directory of the
-   <productname>PostgreSQL</productname> source distribution.
   </para>

   <tip>
    <para>
     Arrays are not sets; using arrays in the manner described in the
!    previous paragraph is often a sign of database misdesign.  The
     array field should generally be split off into a separate table.
     Tables can obviously be searched easily.
    </para>
--- 405,431 ----
  </programlisting>

    However, this quickly becomes tedious for large arrays, and is not
!   helpful if the size of the array is unknown. An alternative method is
!   described in <xref linkend="functions-comparisons">. Using this, the above
    query could be:

  <programlisting>
! SELECT * FROM sal_emp WHERE 10000 = ANY (pay_by_quarter);
  </programlisting>

    In addition, you could find rows where the array had all values
!   equal to 10000 with:

  <programlisting>
! SELECT * FROM sal_emp WHERE 10000 = ALL (pay_by_quarter);
  </programlisting>

   </para>

   <tip>
    <para>
     Arrays are not sets; using arrays in the manner described in the
!    previous paragraph may be a sign of database misdesign.  The
     array field should generally be split off into a separate table.
     Tables can obviously be searched easily.
    </para>
***************
*** 498,513 ****

    <para>
     As illustrated earlier in this chapter, arrays may also be represented
!    using the <command>ARRAY</command> expression syntax. This representation
!    of an array value consists of items that are interpreted according to the
!    I/O conversion rules for the array's element type, plus decoration that
!    indicates the array structure. The decoration consists of the keyword
!    <command>ARRAY</command> and square brackets (<literal>[</> and
     <literal>]</>) around the array values, plus delimiter characters between
     adjacent items. The delimiter character is always a comma (<literal>,</>).
     When representing multidimensional arrays, the keyword
!    <command>ARRAY</command> is only necessary for the outer level. For example,
!    <literal>'{{"hello world", "happy birthday"}}'</literal> could be written as:
  <programlisting>
  SELECT ARRAY[['hello world', 'happy birthday']];
                 array
--- 457,473 ----

    <para>
     As illustrated earlier in this chapter, arrays may also be represented
!    in many cases using the <command>ARRAY</command> expression syntax. This
!    representation of an array value consists of items that are interpreted
!    according to the I/O conversion rules for the array's element type, plus
!    decoration that indicates the array structure. The decoration consists of
!    the keyword <command>ARRAY</command> and square brackets (<literal>[</> and
     <literal>]</>) around the array values, plus delimiter characters between
     adjacent items. The delimiter character is always a comma (<literal>,</>).
     When representing multidimensional arrays, the keyword
!    <command>ARRAY</command> is only necessary for the outer level. For
!    example, <literal>'{{"hello world", "happy birthday"}}'</literal> could be
!    written as:
  <programlisting>
  SELECT ARRAY[['hello world', 'happy birthday']];
                 array
Index: doc/src/sgml/func.sgml
===================================================================
RCS file: /opt/src/cvs/pgsql-server/doc/src/sgml/func.sgml,v
retrieving revision 1.164
diff -c -r1.164 func.sgml
*** doc/src/sgml/func.sgml    4 Aug 2003 14:00:13 -0000    1.164
--- doc/src/sgml/func.sgml    7 Aug 2003 15:41:38 -0000
***************
*** 7044,7071 ****
        <tbody>
         <row>
      <entry> <literal>=</literal> </entry>
!     <entry>equals</entry>
      <entry><literal>ARRAY[1.1,2.1,3.1]::int[] = ARRAY[1,2,3]</literal></entry>
      <entry><literal>t</literal></entry>
         </row>
         <row>
      <entry> <literal>||</literal> </entry>
      <entry>array-to-array concatenation</entry>
      <entry><literal>ARRAY[1,2,3] || ARRAY[4,5,6]</literal></entry>
      <entry><literal>{{1,2,3},{4,5,6}}</literal></entry>
         </row>
         <row>
      <entry> <literal>||</literal> </entry>
      <entry>array-to-array concatenation</entry>
      <entry><literal>ARRAY[1,2,3] || ARRAY[[4,5,6],[7,8,9]]</literal></entry>
      <entry><literal>{{1,2,3},{4,5,6},{7,8,9}}</literal></entry>
         </row>
         <row>
      <entry> <literal>||</literal> </entry>
      <entry>element-to-array concatenation</entry>
      <entry><literal>3 || ARRAY[4,5,6]</literal></entry>
      <entry><literal>{3,4,5,6}</literal></entry>
         </row>
         <row>
      <entry> <literal>||</literal> </entry>
      <entry>array-to-element concatenation</entry>
--- 7044,7110 ----
        <tbody>
         <row>
      <entry> <literal>=</literal> </entry>
!     <entry>equal</entry>
      <entry><literal>ARRAY[1.1,2.1,3.1]::int[] = ARRAY[1,2,3]</literal></entry>
      <entry><literal>t</literal></entry>
         </row>
+
+        <row>
+     <entry> <literal>!=</literal> </entry>
+     <entry>not equal</entry>
+     <entry><literal>ARRAY[1,2,3] != ARRAY[1,2,4]</literal></entry>
+     <entry><literal>t</literal></entry>
+        </row>
+
+        <row>
+     <entry> <literal><</literal> </entry>
+     <entry>less than</entry>
+     <entry><literal>ARRAY[1,2,3] < ARRAY[1,2,4]</literal></entry>
+     <entry><literal>t</literal></entry>
+        </row>
+
+        <row>
+     <entry> <literal>></literal> </entry>
+     <entry>greater than</entry>
+     <entry><literal>ARRAY[1,4,3] > ARRAY[1,2,4]</literal></entry>
+     <entry><literal>t</literal></entry>
+        </row>
+
+        <row>
+     <entry> <literal><=</literal> </entry>
+     <entry>less than or equal</entry>
+     <entry><literal>ARRAY[1,2,3] <= ARRAY[1,2,3]</literal></entry>
+     <entry><literal>t</literal></entry>
+        </row>
+
+        <row>
+     <entry> <literal>>=</literal> </entry>
+     <entry>greater than or equal</entry>
+     <entry><literal>ARRAY[1,4,3] >= ARRAY[1,4,3]</literal></entry>
+     <entry><literal>t</literal></entry>
+        </row>
+
         <row>
      <entry> <literal>||</literal> </entry>
      <entry>array-to-array concatenation</entry>
      <entry><literal>ARRAY[1,2,3] || ARRAY[4,5,6]</literal></entry>
      <entry><literal>{{1,2,3},{4,5,6}}</literal></entry>
         </row>
+
         <row>
      <entry> <literal>||</literal> </entry>
      <entry>array-to-array concatenation</entry>
      <entry><literal>ARRAY[1,2,3] || ARRAY[[4,5,6],[7,8,9]]</literal></entry>
      <entry><literal>{{1,2,3},{4,5,6},{7,8,9}}</literal></entry>
         </row>
+
         <row>
      <entry> <literal>||</literal> </entry>
      <entry>element-to-array concatenation</entry>
      <entry><literal>3 || ARRAY[4,5,6]</literal></entry>
      <entry><literal>{3,4,5,6}</literal></entry>
         </row>
+
         <row>
      <entry> <literal>||</literal> </entry>
      <entry>array-to-element concatenation</entry>
Index: doc/src/sgml/plpgsql.sgml
===================================================================
RCS file: /opt/src/cvs/pgsql-server/doc/src/sgml/plpgsql.sgml,v
retrieving revision 1.19
diff -c -r1.19 plpgsql.sgml
*** doc/src/sgml/plpgsql.sgml    28 May 2003 16:03:55 -0000    1.19
--- doc/src/sgml/plpgsql.sgml    7 Aug 2003 18:12:23 -0000
***************
*** 464,482 ****
  </programlisting>
       </para>

      <sect2 id="plpgsql-declaration-aliases">
!      <title>Aliases for Function Parameters</title>

  <synopsis>
  <replaceable>name</replaceable> ALIAS FOR $<replaceable>n</replaceable>;
  </synopsis>

       <para>
-       Parameters passed to functions are named with the identifiers
-       <literal>$1</literal>, <literal>$2</literal>,
-       etc.  Optionally, aliases can be declared for <literal>$<replaceable>n</replaceable></literal>
-       parameter names for increased readability.  Either the alias or the
-       numeric identifier can then be used to refer to the parameter value.
        Some examples:
  <programlisting>
  CREATE FUNCTION sales_tax(real) RETURNS real AS '
--- 464,512 ----
  </programlisting>
       </para>

+     <sect2 id="plpgsql-polymorphic-functions">
+      <title>Polymorphic <acronym>PL/pgSQL</acronym> Functions</title>
+
+      <para>
+       <acronym>PL/pgSQL</acronym> Functions may be specified to accept, and
+       optionally return, the types <type>anyelement</type> or
+       <type>anyarray</type>, otherwise known as polymorphic types.
+       See <xref linkend="xfunc"> for a more detailed explanation
+       of polymorphic functions. An example is shown in
+       <xref linkend="plpgsql-declaration-aliases">
+      </para>
+     </sect2>
+
      <sect2 id="plpgsql-declaration-aliases">
!      <title>Default Identifiers and Aliases</title>
!
!      <para>
!       Parameters passed to functions are named with the identifiers
!       <literal>$1</literal>, <literal>$2</literal>, etc.
!      </para>
!
!      <para>
!       When the return type of a <application>PL/pgSQL</application>
!       function is declared a polymorphic type, <type>anyelement</type>
!       or <type>anyarray</type>, the return value is also named with an
!       identifier, <literal>$0</literal>. It is initialized to NULL, but
!       may be used to hold the return value as calculated by the function.
!       <literal>$0</literal> can be used by polymorphic functions to discover
!       their own return type, as discussed in
!       <xref linkend="plpgsql-declaration-type">
!      </para>
!
!      <para>
!       Aliases can optionally be declared for <literal>$<replaceable>n</replaceable>
!       </literal> identifiers for increased readability.  Either the alias or the
!       numeric identifier can then be used to refer to the value.
!      </para>

  <synopsis>
  <replaceable>name</replaceable> ALIAS FOR $<replaceable>n</replaceable>;
  </synopsis>

       <para>
        Some examples:
  <programlisting>
  CREATE FUNCTION sales_tax(real) RETURNS real AS '
***************
*** 505,510 ****
--- 535,553 ----
      RETURN in_t.f1 || in_t.f3 || in_t.f5 || in_t.f7;
  END;
  ' LANGUAGE plpgsql;
+
+ CREATE FUNCTION add_many_fields(anyelement, anyelement, anyelement)
+ RETURNS anyelement AS '
+ DECLARE
+     result ALIAS FOR $0;
+     first ALIAS FOR $1;
+     second ALIAS FOR $2;
+     third ALIAS FOR $3;
+ BEGIN
+     result := first + second + third;
+     RETURN result;
+ END;
+ ' LANGUAGE plpgsql;
  </programlisting>
       </para>
      </sect2>
***************
*** 536,541 ****
--- 579,593 ----
      from <type>integer</type> to <type>real</type>), you may not need
      to change your function definition.
     </para>
+
+    <para>
+     Similarly, using <literal>%TYPE</literal> allows you to define variables
+     within your function, without needing to know the data type of the
+     structure you are referencing in advance. This is important in polymorphic
+     functions in which the data type of the referenced item may change
+     from one call to the next.
+    </para>
+
    </sect2>

      <sect2 id="plpgsql-declaration-rowtypes">
Index: doc/src/sgml/xaggr.sgml
===================================================================
RCS file: /opt/src/cvs/pgsql-server/doc/src/sgml/xaggr.sgml,v
retrieving revision 1.20
diff -c -r1.20 xaggr.sgml
*** doc/src/sgml/xaggr.sgml    10 Apr 2003 01:22:44 -0000    1.20
--- doc/src/sgml/xaggr.sgml    7 Aug 2003 18:27:53 -0000
***************
*** 34,39 ****
--- 34,48 ----
    </para>

    <para>
+      <acronym>Aggregate</acronym> Functions may use polymorphic
+      <firstterm>state transition functions</firstterm> or
+      <firstterm>final functions</firstterm>. See <xref linkend="xfunc">
+      for a more detailed explanation of polymorphic functions.
+      <acronym>Aggregate</acronym> Functions may also be specified with a
+      polymorphic base type and state type.
+   </para>
+
+   <para>
     If we define an aggregate that does not use a final function,
     we have an aggregate that computes a running function of
     the column values from each row.  <function>sum</>  is  an
***************
*** 107,112 ****
--- 116,154 ----
      finalfunc = float8_avg,
      initcond = '{0,0}'
  );
+ </programlisting>
+   </para>
+
+   <para>
+    <function>array_accum</> is an example of a polymorphic aggregate:
+
+ <programlisting>
+ CREATE AGGREGATE array_accum (
+     sfunc = array_append,
+     basetype = anyelement,
+     stype = anyarray,
+     initcond = '{}'
+ );
+ </programlisting>
+
+    Here's the output using two different runtime data types as arguments:
+
+ <programlisting>
+ SELECT attrelid::regclass, array_accum(attname)
+ FROM pg_attribute WHERE attnum > 0
+ AND attrelid = 'pg_user'::regclass GROUP BY attrelid;
+  attrelid |                                 array_accum
+ ----------+-----------------------------------------------------------------------------
+  pg_user  | {usename,usesysid,usecreatedb,usesuper,usecatupd,passwd,valuntil,useconfig}
+ (1 row)
+
+ SELECT attrelid::regclass, array_accum(atttypid)
+ FROM pg_attribute WHERE attnum > 0
+ AND attrelid = 'pg_user'::regclass GROUP BY attrelid;
+  attrelid |         array_accum
+ ----------+------------------------------
+  pg_user  | {19,23,16,16,16,25,702,1009}
+ (1 row)
  </programlisting>
    </para>

Index: doc/src/sgml/xfunc.sgml
===================================================================
RCS file: /opt/src/cvs/pgsql-server/doc/src/sgml/xfunc.sgml,v
retrieving revision 1.70
diff -c -r1.70 xfunc.sgml
*** doc/src/sgml/xfunc.sgml    25 Jul 2003 20:17:49 -0000    1.70
--- doc/src/sgml/xfunc.sgml    7 Aug 2003 18:12:10 -0000
***************
*** 47,56 ****
    </para>

    <para>
     It's easiest to define <acronym>SQL</acronym>
!    functions, so we'll start with those.  Examples in this section
!    can also be found in <filename>funcs.sql</filename>
!    and <filename>funcs.c</filename> in the tutorial directory.
    </para>

    <para>
--- 47,76 ----
    </para>

    <para>
+      Many kinds of functions can be specified to accept, and
+      optionally return, the types <type>anyelement</type> or
+      <type>anyarray</type>, otherwise known as polymorphic types.
+      These datatypes are tied to each other and resolved to a deterministic
+      type at runtime. Each position (i.e. either argument or return type)
+      defined as <type>anyelement</type> can have any data type at runtime,
+      but they must all be the <emphasis>same</emphasis> runtime type. Each
+      position defined as <type>anyarray</type> can have any array data type
+      at runtime, but similarly they must all be the same. If there are
+      positions declared <type>anyarray</type> and others declared
+      <type>anyelement</type>, the runtime array type in the
+      <type>anyarray</type> positions must be an array of the runtime type
+      at the <type>anyelement</type> positions.
+   </para>
+
+   <para>
+      See the individual sections for each type of function to determine
+      if polymorphic functions are supported for that language.
+   </para>
+
+   <para>
     It's easiest to define <acronym>SQL</acronym>
!    functions, so we'll start with those.  Some examples in this section
!    can also be found in  <filename>funcs.c</filename> in the tutorial directory.
    </para>

    <para>
***************
*** 383,388 ****
--- 403,470 ----
     </sect2>

     <sect2>
+     <title>Polymorphic <acronym>SQL</acronym> Functions</title>
+
+     <para>
+      <acronym>SQL</acronym> Functions may be specified to accept, and
+      optionally return, the types <type>anyelement</type> or
+      <type>anyarray</type>, otherwise known as polymorphic types.
+      See <xref linkend="xfunc"> for a more detailed explanation
+      of polymorphic functions. Here is a polymorphic function
+      <function>make_array</function> that builds up an array from two
+      arbitrary data type elements:
+ <screen>
+ CREATE FUNCTION make_array(anyelement, anyelement) RETURNS anyarray AS '
+     SELECT ARRAY[$1, $2];
+ ' LANGUAGE SQL;
+
+ SELECT make_array(1, 2) AS intarray, make_array('a'::text, 'b') AS textarray;
+  intarray | textarray
+ ----------+-----------
+  {1,2}    | {a,b}
+ (1 row)
+ </screen>
+     </para>
+
+     <para>
+      Notice the use of the typecast <literal>'a'::text</literal>
+      to specify a runtime <type>text</type> type. This is
+      required if the runtime type would otherwise be resolved as
+      <type>unknown</type>, because there is currently no way
+      to delay resolution of the element type to the time of array
+      creation, and array of <type>unknown</type> is not a valid type.
+      Without the typecast, you will get errors like this:
+ <screen>
+ <computeroutput>
+ ERROR:  could not determine ANYARRAY/ANYELEMENT type because input is UNKNOWN
+ </computeroutput>
+ </screen>
+     </para>
+
+     <para>
+      It is permitted to have polymorphic arguments with a deterministic
+      return type, but the converse is not. For example:
+ <screen>
+ CREATE FUNCTION is_greater(anyelement, anyelement) RETURNS bool AS '
+     SELECT $1 > $2;
+ ' LANGUAGE SQL;
+
+ SELECT is_greater(1, 2);
+  is_greater
+ ------------
+  f
+ (1 row)
+
+ CREATE FUNCTION invalid_func() RETURNS anyelement AS '
+     SELECT 1;
+ ' LANGUAGE SQL;
+ ERROR:  cannot determine result datatype
+ DETAIL:  A function returning ANYARRAY or ANYELEMENT must have at least one argument of either type.
+ </screen>
+     </para>
+    </sect2>
+
+    <sect2>
      <title><acronym>SQL</acronym> Functions as Table Sources</title>

      <para>
***************
*** 1584,1589 ****
--- 1666,1793 ----
      AS '<replaceable>DIRECTORY</replaceable>/funcs', 'c_overpaid'
      LANGUAGE C;
  </programlisting>
+     </para>
+    </sect2>
+
+    <sect2>
+     <title>Polymorphic Arguments and Return Types</title>
+
+     <para>
+      C-Language functions may be specified to accept, and
+      optionally return, the types <type>anyelement</type> or
+      <type>anyarray</type>, otherwise known as polymorphic types.
+      See <xref linkend="xfunc"> for a more detailed explanation
+      of polymorphic functions. When function arguments or return types
+      are defined as polymorphic types, the function author cannot know
+      in advance what data type it will be called with, or
+      need to return. There are two exported routines in fmgr.c available
+      to allow a user defined function to discover the actual data types
+      of its arguments and the type it is expected to return. The routines are
+      declared in
+ <programlisting>
+ #include "fmgr.h"
+ </programlisting>
+      and are called get_fn_expr_rettype(FmgrInfo *flinfo) and
+      get_fn_expr_argtype(FmgrInfo *flinfo, int argnum). The structure
+      flinfo is normally accessed as fcinfo->flinfo. The parameter argnum
+      is zero based.
+     </para>
+
+     <para>
+      For example, suppose we want to write a function to accept a single
+      element of any type, and return a one-dimensional array of that type:
+
+ <programlisting>
+ PG_FUNCTION_INFO_V1(make_array);
+ Datum
+ make_array(PG_FUNCTION_ARGS)
+ {
+     ArrayType  *result;
+     Oid         element_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
+     Datum       element;
+     int16       typlen;
+     bool        typbyval;
+     char        typalign;
+     int         ndims;
+     int         dims[MAXDIM];
+     int         lbs[MAXDIM];
+
+     /* get the provided element */
+     element = PG_GETARG_DATUM(0);
+
+     /* we have one dimension */
+     ndims = 1;
+     /* and one element */
+     dims[0] = 1;
+     /* and lower bound is 1 */
+     lbs[0] = 1;
+
+     /* get required info about the element type */
+     get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
+
+     /* now build the array */
+     result = construct_md_array(&element, ndims, dims, lbs,
+                                 element_type, typlen, typbyval, typalign);
+
+     PG_RETURN_ARRAYTYPE_P(result);
+ }
+ </programlisting>
+     </para>
+
+     <para>
+      The following command declares the function
+      <function>make_array</function> in SQL:
+
+ <programlisting>
+ CREATE FUNCTION make_array(anyelement)
+     RETURNS anyarray
+     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'make_array'
+     LANGUAGE 'C' STRICT;
+ </programlisting>
+     </para>
+
+     <para>
+      The <function>make_array</function> function is then used as
+      in the following:
+ <programlisting>
+ select make_array('a'::text);
+  make_array
+ ------------
+  {a}
+ (1 row)
+
+ select make_array(1);
+  make_array
+ ------------
+  {1}
+ (1 row)
+
+ select make_array(1.1);
+  make_array
+ ------------
+  {1.1}
+ (1 row)
+ </programlisting>
+     </para>
+
+     <para>
+      Notice the use of the typecast <literal>'a'::text</literal>
+      to specify a runtime <type>text</type> type. This is
+      required if the runtime type would otherwise be resolved as
+      <type>unknown</type>, because there is currently no way
+      to delay resolution of the element type to the time of array
+      creation, and array of <type>unknown</type> is not a valid type.
+      Without the typecast, you will get errors like this:
+ <screen>
+ <computeroutput>
+ ERROR:  could not determine ANYARRAY/ANYELEMENT type because input is UNKNOWN
+ </computeroutput>
+ </screen>
+     </para>
+
+     <para>
+      It is permitted to have polymorphic arguments with a deterministic
+      return type, but the converse is not.
      </para>
     </sect2>


pgsql-patches by date:

Previous
From: "Marc G. Fournier"
Date:
Subject: Testing gateway
Next
From: Bruce Momjian
Date:
Subject: Re: fix compile warning in pg_id