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 <acronym>PL/pgSQL</acronym> 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 <acronym>SQL</acronym> 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. + + + + + <acronym>SQL</acronym> 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.