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
Also notice that string literals are single quoted instead of double quoted.
--- 116,122 ----
VALUES ('Carol',
ARRAY[20000, 25000, 25000, 25000],
ARRAY[['talk', 'consult'], ['meeting']]);
! ERROR: multidimensional arrays must have array expressions with matching dimensions
Also notice that string literals are single quoted instead of double quoted.
***************
*** 206,224 ****
- Additionally, we can also access a single arbitrary array element of
- a one-dimensional array with the array_subscript
- function:
-
- SELECT array_subscript(pay_by_quarter, 2) FROM sal_emp WHERE name = 'Bill';
- array_subscript
- -----------------
- 10000
- (1 row)
-
-
-
-
An array value can be replaced completely:
--- 206,211 ----
***************
*** 233,247 ****
WHERE name = 'Carol';
-
-
- Anywhere you can use the curly braces
array syntax,
- you can also use the ARRAY expression syntax. The
- remainder of this section will illustrate only one or the other, but
- not both.
-
-
-
An array may also be updated at a single element:
--- 220,225 ----
***************
*** 256,278 ****
WHERE name = 'Carol';
- A one-dimensional array may also be updated with the
- array_assign function:
-
-
- UPDATE sal_emp SET pay_by_quarter = array_assign(pay_by_quarter, 4, 15000)
- WHERE name = 'Bill';
-
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 array[5]>. Currently, enlargement in
! this fashion is only allowed for one-dimensional arrays, not
! multidimensional arrays.
--- 234,249 ----
WHERE name = 'Carol';
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
! myarray> currently has 4 elements, it will have five
! elements after an update that assigns to myarray[5]>.
! Currently, enlargement in this fashion is only allowed for one-dimensional
! arrays, not multidimensional arrays.
***************
*** 434,472 ****
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 PostgreSQL,
! there is an extension available that defines new functions and
! operators for iterating over array values. Using this, the above
query could be:
! SELECT * FROM sal_emp WHERE pay_by_quarter[1:4] *= 10000;
!
!
! To search the entire array (not just specified slices), you could
! use:
!
!
! SELECT * FROM sal_emp WHERE pay_by_quarter *= 10000;
In addition, you could find rows where the array had all values
! equal to 10 000 with:
! SELECT * FROM sal_emp WHERE pay_by_quarter **= 10000;
- To install this optional module, look in the
- contrib/array directory of the
- PostgreSQL source distribution.
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.
--- 405,431 ----
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 . Using this, the above
query could be:
! SELECT * FROM sal_emp WHERE 10000 = ANY (pay_by_quarter);
In addition, you could find rows where the array had all values
! equal to 10000 with:
! SELECT * FROM sal_emp WHERE 10000 = ALL (pay_by_quarter);
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.
***************
*** 498,513 ****
As illustrated earlier in this chapter, arrays may also be represented
! using the ARRAY 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
! ARRAY and square brackets ([> and
]>) around the array values, plus delimiter characters between
adjacent items. The delimiter character is always a comma (,>).
When representing multidimensional arrays, the keyword
! ARRAY is only necessary for the outer level. For example,
! '{{"hello world", "happy birthday"}}' could be written as:
SELECT ARRAY[['hello world', 'happy birthday']];
array
--- 457,473 ----
As illustrated earlier in this chapter, arrays may also be represented
! in many cases using the ARRAY 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 ARRAY and square brackets ([> and
]>) around the array values, plus delimiter characters between
adjacent items. The delimiter character is always a comma (,>).
When representing multidimensional arrays, the keyword
! ARRAY is only necessary for the outer level. For
! example, '{{"hello world", "happy birthday"}}' could be
! written as:
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 ****
=
! equals
ARRAY[1.1,2.1,3.1]::int[] = ARRAY[1,2,3]
t
||
array-to-array concatenation
ARRAY[1,2,3] || ARRAY[4,5,6]
{{1,2,3},{4,5,6}}
||
array-to-array concatenation
ARRAY[1,2,3] || ARRAY[[4,5,6],[7,8,9]]
{{1,2,3},{4,5,6},{7,8,9}}
||
element-to-array concatenation
3 || ARRAY[4,5,6]
{3,4,5,6}
||
array-to-element concatenation
--- 7044,7110 ----
=
! equal
ARRAY[1.1,2.1,3.1]::int[] = ARRAY[1,2,3]
t
+
+
+ !=
+ not equal
+ ARRAY[1,2,3] != ARRAY[1,2,4]
+ t
+
+
+
+ <
+ less than
+ ARRAY[1,2,3] < ARRAY[1,2,4]
+ t
+
+
+
+ >
+ greater than
+ ARRAY[1,4,3] > ARRAY[1,2,4]
+ t
+
+
+
+ <=
+ less than or equal
+ ARRAY[1,2,3] <= ARRAY[1,2,3]
+ t
+
+
+
+ >=
+ greater than or equal
+ ARRAY[1,4,3] >= ARRAY[1,4,3]
+ t
+
+
||
array-to-array concatenation
ARRAY[1,2,3] || ARRAY[4,5,6]
{{1,2,3},{4,5,6}}
+
||
array-to-array concatenation
ARRAY[1,2,3] || ARRAY[[4,5,6],[7,8,9]]
{{1,2,3},{4,5,6},{7,8,9}}
+
||
element-to-array concatenation
3 || ARRAY[4,5,6]
{3,4,5,6}
+
||
array-to-element concatenation
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 ****
! Aliases for Function Parameters
name ALIAS FOR $n;
- Parameters passed to functions are named with the identifiers
- $1, $2,
- etc. Optionally, aliases can be declared for $n
- parameter names for increased readability. Either the alias or the
- numeric identifier can then be used to refer to the parameter value.
Some examples:
CREATE FUNCTION sales_tax(real) RETURNS real AS '
--- 464,512 ----
+
+ Polymorphic PL/pgSQL Functions
+
+
+ PL/pgSQL Functions may be specified to accept, and
+ optionally return, the types anyelement or
+ anyarray, otherwise known as polymorphic types.
+ See for a more detailed explanation
+ of polymorphic functions. An example is shown in
+
+
+
+
! Default Identifiers and Aliases
!
!
! Parameters passed to functions are named with the identifiers
! $1, $2, etc.
!
!
!
! When the return type of a PL/pgSQL
! function is declared a polymorphic type, anyelement
! or anyarray, the return value is also named with an
! identifier, $0. It is initialized to NULL, but
! may be used to hold the return value as calculated by the function.
! $0 can be used by polymorphic functions to discover
! their own return type, as discussed in
!
!
!
!
! Aliases can optionally be declared for $n
! identifiers for increased readability. Either the alias or the
! numeric identifier can then be used to refer to the value.
!
name ALIAS FOR $n;
Some examples:
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;
***************
*** 536,541 ****
--- 579,593 ----
from integer to real), you may not need
to change your function definition.
+
+
+ Similarly, using %TYPE 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.
+
+
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 ----
+ Aggregate Functions may use polymorphic
+ state transition functions or
+ final functions. See
+ for a more detailed explanation of polymorphic functions.
+ Aggregate Functions may also be specified with a
+ polymorphic base type and state type.
+
+
+
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. sum> is an
***************
*** 107,112 ****
--- 116,154 ----
finalfunc = float8_avg,
initcond = '{0,0}'
);
+
+
+
+
+ array_accum> is an example of a polymorphic aggregate:
+
+
+ CREATE AGGREGATE array_accum (
+ sfunc = array_append,
+ basetype = anyelement,
+ stype = anyarray,
+ initcond = '{}'
+ );
+
+
+ Here's the output using two different runtime data types as arguments:
+
+
+ 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)
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 ****
It's easiest to define SQL
! functions, so we'll start with those. Examples in this section
! can also be found in funcs.sql
! and funcs.c in the tutorial directory.
--- 47,76 ----
+ Many kinds of functions can be specified to accept, and
+ optionally return, the types anyelement or
+ anyarray, 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 anyelement can have any data type at runtime,
+ but they must all be the same runtime type. Each
+ position defined as anyarray can have any array data type
+ at runtime, but similarly they must all be the same. If there are
+ positions declared anyarray and others declared
+ anyelement, the runtime array type in the
+ anyarray positions must be an array of the runtime type
+ at the anyelement positions.
+
+
+
+ See the individual sections for each type of function to determine
+ if polymorphic functions are supported for that language.
+
+
+
It's easiest to define SQL
! functions, so we'll start with those. Some examples in this section
! can also be found in funcs.c in the tutorial directory.
***************
*** 383,388 ****
--- 403,470 ----
+ Polymorphic SQL Functions
+
+
+ SQL Functions may be specified to accept, and
+ optionally return, the types anyelement or
+ anyarray, otherwise known as polymorphic types.
+ See for a more detailed explanation
+ of polymorphic functions. Here is a polymorphic function
+ make_array that builds up an array from two
+ arbitrary data type elements:
+
+ 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)
+
+
+
+
+ Notice the use of the typecast 'a'::text
+ to specify a runtime text type. This is
+ required if the runtime type would otherwise be resolved as
+ unknown, because there is currently no way
+ to delay resolution of the element type to the time of array
+ creation, and array of unknown is not a valid type.
+ Without the typecast, you will get errors like this:
+
+
+ ERROR: could not determine ANYARRAY/ANYELEMENT type because input is UNKNOWN
+
+
+
+
+
+ It is permitted to have polymorphic arguments with a deterministic
+ return type, but the converse is not. For example:
+
+ 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.
+
+
+
+
+
SQL Functions as Table Sources
***************
*** 1584,1589 ****
--- 1666,1793 ----
AS 'DIRECTORY/funcs', 'c_overpaid'
LANGUAGE C;
+
+
+
+
+ Polymorphic Arguments and Return Types
+
+
+ C-Language functions may be specified to accept, and
+ optionally return, the types anyelement or
+ anyarray, otherwise known as polymorphic types.
+ See 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
+
+ #include "fmgr.h"
+
+ 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.
+
+
+
+ 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:
+
+
+ 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);
+ }
+
+
+
+
+ The following command declares the function
+ make_array in SQL:
+
+
+ CREATE FUNCTION make_array(anyelement)
+ RETURNS anyarray
+ AS 'DIRECTORY/funcs', 'make_array'
+ LANGUAGE 'C' STRICT;
+
+
+
+
+ The make_array function is then used as
+ in the following:
+
+ 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)
+
+
+
+
+ Notice the use of the typecast 'a'::text
+ to specify a runtime text type. This is
+ required if the runtime type would otherwise be resolved as
+ unknown, because there is currently no way
+ to delay resolution of the element type to the time of array
+ creation, and array of unknown is not a valid type.
+ Without the typecast, you will get errors like this:
+
+
+ ERROR: could not determine ANYARRAY/ANYELEMENT type because input is UNKNOWN
+
+
+
+
+
+ It is permitted to have polymorphic arguments with a deterministic
+ return type, but the converse is not.