Index: doc/src/sgml/array.sgml
===================================================================
RCS file: /opt/src/cvs/pgsql-server/doc/src/sgml/array.sgml,v
retrieving revision 1.25
diff -c -r1.25 array.sgml
*** doc/src/sgml/array.sgml 13 Mar 2003 01:30:26 -0000 1.25
--- doc/src/sgml/array.sgml 9 Jun 2003 02:13:32 -0000
***************
*** 60,73 ****
! A limitation of the present array implementation is that individual
! elements of an array cannot be SQL null values. The entire array can be set
! to null, but you can't have an array with some elements null and some
! not. Fixing this is on the to-do list.
--- 60,133 ----
+
+ A limitation of the present array implementation is that individual
+ elements of an array cannot be SQL null values. The entire array can be set
+ to null, but you can't have an array with some elements null and some
+ not.
+
+
+ This can lead to surprising results. For example, the result of the
+ previous two inserts looks like this:
+
+ SELECT * FROM sal_emp;
+ name | pay_by_quarter | schedule
+ -------+---------------------------+--------------------
+ Bill | {10000,10000,10000,10000} | {{meeting},{""}}
+ Carol | {20000,25000,25000,25000} | {{talk},{meeting}}
+ (2 rows)
+
+ Because the [2][2] element of
+ schedule is missing in each of the
+ INSERT statements, the [1][2]
+ element is discarded.
+
+
+
+
+ Fixing this is on the to-do list.
+
+
+
+
+ The ARRAY expression syntax may also be used:
+
+ INSERT INTO sal_emp
+ VALUES ('Bill',
+ ARRAY[10000, 10000, 10000, 10000],
+ ARRAY[['meeting', 'lunch'], ['','']]);
+
+ INSERT INTO sal_emp
+ VALUES ('Carol',
+ ARRAY[20000, 25000, 25000, 25000],
+ ARRAY[['talk', 'consult'], ['meeting', '']]);
+ SELECT * FROM sal_emp;
+ name | pay_by_quarter | schedule
+ -------+---------------------------+-------------------------------
+ Bill | {10000,10000,10000,10000} | {{meeting,lunch},{"",""}}
+ Carol | {20000,25000,25000,25000} | {{talk,consult},{meeting,""}}
+ (2 rows)
+
+ Note that with this syntax, multidimensional arrays must have matching
+ extents for each dimension. This eliminates the missing-array-elements
+ problem above. For example:
+
+ INSERT INTO sal_emp
+ 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.
+
+
! The examples in the rest of this section are based on the
! ARRAY expression syntax INSERTs.
+
***************
*** 132,142 ****
with the same result. An array subscripting operation is always taken to
! represent an array slice if any of the subscripts are written in the
! form
lower:upper.
A lower bound of 1 is assumed for any subscript where only one value
! is specified.
--- 192,221 ----
with the same result. An array subscripting operation is always taken to
! represent an array slice if any of the subscripts are written in the form
lower:upper.
A lower bound of 1 is assumed for any subscript where only one value
! is specified; another example follows:
!
! SELECT schedule[1:2][2] FROM sal_emp WHERE name = 'Bill';
! schedule
! ---------------------------
! {{meeting,lunch},{"",""}}
! (1 row)
!
!
!
!
! 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)
!
***************
*** 147,153 ****
WHERE name = 'Carol';
! or updated at a single element:
UPDATE sal_emp SET pay_by_quarter[4] = 15000
--- 226,248 ----
WHERE name = 'Carol';
! or using the ARRAY expression syntax:
!
!
! UPDATE sal_emp SET pay_by_quarter = ARRAY[25000,25000,27000,27000]
! 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:
UPDATE sal_emp SET pay_by_quarter[4] = 15000
***************
*** 160,165 ****
--- 255,268 ----
UPDATE sal_emp SET pay_by_quarter[1:2] = '{27000,27000}'
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';
+
***************
*** 179,184 ****
--- 282,369 ----
+ An array can also be enlarged by using the concatenation operator,
+ ||.
+
+ SELECT ARRAY[1,2] || ARRAY[3,4];
+ ?column?
+ ---------------
+ {{1,2},{3,4}}
+ (1 row)
+
+ SELECT ARRAY[5,6] || ARRAY[[1,2],[3,4]];
+ ?column?
+ ---------------------
+ {{5,6},{1,2},{3,4}}
+ (1 row)
+
+
+ The concatenation operator allows a single element to be pushed on to the
+ beginning or end of a one-dimensional array. It also allows two
+ N>-dimensional arrays, or an N>-dimensional
+ and an N+1>-dimensional array. In the former case, the two
+ N>-dimension arrays become outer elements of an
+ N+1>-dimensional array. In the latter, the
+ N>-dimensional array is added as either the first or last
+ outer element of the N+1>-dimensional array.
+
+ The array is extended in the direction of the push. Hence, by pushing
+ onto the beginning of an array with a one-based subscript, a zero-based
+ subscript array is created:
+
+
+ SELECT array_dims(t.f) FROM (SELECT 1 || ARRAY[2,3] AS f) AS t;
+ array_dims
+ ------------
+ [0:2]
+ (1 row)
+
+
+
+
+ An array can also be enlarged by using the functions
+ array_prepend, array_append,
+ or array_cat. The first two only support one-dimensional
+ arrays, but array_cat supports multidimensional arrays.
+
+ Note that the concatenation operator discussed above is preferred over
+ direct use of these functions. In fact, the functions are primarily for use
+ in implementing the concatenation operator. However, they may be directly
+ useful in the creation of user-defined aggregates. Some examples:
+
+
+ SELECT array_prepend(1, ARRAY[2,3]);
+ array_prepend
+ ---------------
+ {1,2,3}
+ (1 row)
+
+ SELECT array_append(ARRAY[1,2], 3);
+ array_append
+ --------------
+ {1,2,3}
+ (1 row)
+
+ SELECT array_cat(ARRAY[1,2], ARRAY[3,4]);
+ array_cat
+ ---------------
+ {{1,2},{3,4}}
+ (1 row)
+
+ SELECT array_cat(ARRAY[[1,2],[3,4]], ARRAY[5,6]);
+ array_cat
+ ---------------------
+ {{1,2},{3,4},{5,6}}
+ (1 row)
+
+ SELECT array_cat(ARRAY[5,6], ARRAY[[1,2],[3,4]]);
+ array_cat
+ ---------------------
+ {{5,6},{1,2},{3,4}}
+
+
+
+
The syntax for CREATE TABLE allows fixed-length
arrays to be defined:
***************
*** 194,199 ****
--- 379,394 ----
+ An alternative syntax for one-dimensional arrays may be used.
+ pay_by_quarter could have been defined as:
+
+ pay_by_quarter integer ARRAY[4],
+
+ This syntax may only be used with the integer
+ constant to denote the array size.
+
+
+
Actually, the current implementation does not enforce the declared
number of dimensions either. Arrays of a particular element type are
all considered to be of the same type, regardless of size or number
***************
*** 300,305 ****
--- 495,566 ----
is not ignored, however: after skipping leading whitespace, everything
up to the next right brace or delimiter is taken as the item value.
+
+
+ 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
+ ------------------------------------
+ {{"hello world","happy birthday"}}
+ (1 row)
+
+ or it also could be written as:
+
+ SELECT ARRAY[ARRAY['hello world', 'happy birthday']];
+ array
+ ------------------------------------
+ {{"hello world","happy birthday"}}
+ (1 row)
+
+
+
+
+ A final method to represent an array, is through an
+ ARRAY sub-select expression. For example:
+
+ SELECT ARRAY(SELECT oid FROM pg_proc WHERE proname LIKE 'bytea%');
+ ?column?
+ -------------------------------------------------------------
+ {2011,1954,1948,1952,1951,1244,1950,2005,1949,1953,2006,31}
+ (1 row)
+
+ The sub-select may only return a single column. The
+ resulting one-dimensional array will have an element for each row in the
+ sub-select result, with an element type matching that of the sub-select's
+ target column.
+
+
+
+ Arrays may be cast from one type to another in similar fashion to other
+ data types:
+
+
+ SELECT ARRAY[1,2,3]::oid[];
+ array
+ ---------
+ {1,2,3}
+ (1 row)
+
+ SELECT CAST(ARRAY[1,2,3] AS float8[]);
+ array
+ ---------
+ {1,2,3}
+ (1 row)
+
+
+
+
***************
*** 316,321 ****
--- 577,590 ----
Alternatively, you can use backslash-escaping to protect all data characters
that would otherwise be taken as array syntax or ignorable white space.
+
+
+
+ The discussion in the preceding paragraph with respect to double quoting does
+ not pertain to the ARRAY expression syntax. In that case,
+ each element is quoted exactly as any other literal value of the element type.
+
+
The array output routine will put double quotes around element values
Index: doc/src/sgml/func.sgml
===================================================================
RCS file: /opt/src/cvs/pgsql-server/doc/src/sgml/func.sgml,v
retrieving revision 1.154
diff -c -r1.154 func.sgml
*** doc/src/sgml/func.sgml 5 May 2003 15:08:49 -0000 1.154
--- doc/src/sgml/func.sgml 9 Jun 2003 01:53:35 -0000
***************
*** 6962,6967 ****
--- 6962,7164 ----
+
+ Array Functions
+
+
+ shows the operators
+ available for the array types.
+
+
+
+ array Operators
+
+
+
+ Operator
+ Description
+ Example
+ Result
+
+
+
+
+ =
+ 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
+ ARRAY[4,5,6] || 7
+ {4,5,6,7}
+
+
+
+
+
+
+ shows the functions
+ available for use with array types. See
+ for more discussion and examples for the use of these functions.
+
+
+
+ array Functions
+
+
+
+ Function
+ Return Type
+ Description
+ Example
+ Result
+
+
+
+
+
+
+ array_append
+ (anyarray, anyelement)
+
+
+ anyarray
+
+ append an element to the end of an array, returning
+ NULL for NULL inputs
+
+ array_append(ARRAY[1,2], 3)
+ {1,2,3}
+
+
+
+
+ array_cat
+ (anyarray, anyarray)
+
+
+ anyarray
+
+ concatenate two arrays, returning NULL
+ for NULL inputs
+
+ array_cat(ARRAY[1,2,3], ARRAY[4,5,6])
+ {{1,2,3},{4,5,6}}
+
+
+
+
+ array_dims
+ (anyarray)
+
+
+ text
+
+ returns a text representation of array dimension lower and upper bounds,
+ generating an ERROR for NULL inputs
+
+ array_dims(array[[1,2,3],[4,5,6]])
+ [1:2][1:3]
+
+
+
+
+ array_lower
+ (anyarray, integer)
+
+
+ integer
+
+ returns lower bound of the requested array dimension, returning
+ NULL for NULL inputs
+
+ array_lower(array_prepend(0, ARRAY[1,2,3]), 1)
+ 0
+
+
+
+
+ array_prepend
+ (anyelement, anyarray)
+
+
+ anyarray
+
+ append an element to the beginning of an array, returning
+ NULL for NULL inputs
+
+ array_prepend(1, ARRAY[2,3])
+ {1,2,3}
+
+
+
+
+ array_to_string
+ (anyarray, text)
+
+
+ text
+
+ concatenates array elements using provided delimiter, returning
+ NULL for NULL inputs
+
+ array_to_string(array[1.1,2.2,3.3]::numeric(4,2)[],'~^~')
+ 1.10~^~2.20~^~3.30
+
+
+
+
+ array_upper
+ (anyarray, integer)
+
+
+ integer
+
+ returns upper bound of the requested array dimension, returning
+ NULL for NULL inputs
+
+ array_upper(array_append(ARRAY[1,2,3], 4), 1)
+ 4
+
+
+
+
+ string_to_array
+ (text, text)
+
+
+ text[]
+
+ splits string into array elements using provided delimiter, returning
+ NULL for NULL inputs
+
+ string_to_array('1.10~^~2.20~^~3.30','~^~')::float8[]
+ {1.1,2.2,3.3}
+
+
+
+
+
Aggregate Functions
Index: src/backend/catalog/pg_aggregate.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/catalog/pg_aggregate.c,v
retrieving revision 1.56
diff -c -r1.56 pg_aggregate.c
*** src/backend/catalog/pg_aggregate.c 18 Sep 2002 21:35:20 -0000 1.56
--- src/backend/catalog/pg_aggregate.c 9 Jun 2003 01:31:10 -0000
***************
*** 50,59 ****
Oid finalfn = InvalidOid; /* can be omitted */
Oid finaltype;
Oid fnArgs[FUNC_MAX_ARGS];
! int nargs;
Oid procOid;
TupleDesc tupDesc;
int i;
ObjectAddress myself,
referenced;
--- 50,65 ----
Oid finalfn = InvalidOid; /* can be omitted */
Oid finaltype;
Oid fnArgs[FUNC_MAX_ARGS];
! int nargs_transfn;
! int nargs_finalfn;
Oid procOid;
TupleDesc tupDesc;
int i;
+ Oid rettype;
+ Oid *true_oid_array_transfn;
+ Oid *true_oid_array_finalfn;
+ bool retset;
+ FuncDetailCode fdresult;
ObjectAddress myself,
referenced;
***************
*** 68,91 ****
MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
fnArgs[0] = aggTransType;
if (aggBaseType == ANYOID)
! nargs = 1;
else
{
fnArgs[1] = aggBaseType;
! nargs = 2;
}
! transfn = LookupFuncName(aggtransfnName, nargs, fnArgs);
if (!OidIsValid(transfn))
! func_error("AggregateCreate", aggtransfnName, nargs, fnArgs, NULL);
tup = SearchSysCache(PROCOID,
ObjectIdGetDatum(transfn),
0, 0, 0);
if (!HeapTupleIsValid(tup))
! func_error("AggregateCreate", aggtransfnName, nargs, fnArgs, NULL);
proc = (Form_pg_proc) GETSTRUCT(tup);
- if (proc->prorettype != aggTransType)
- elog(ERROR, "return type of transition function %s is not %s",
- NameListToString(aggtransfnName), format_type_be(aggTransType));
/*
* If the transfn is strict and the initval is NULL, make sure input
--- 74,122 ----
MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
fnArgs[0] = aggTransType;
if (aggBaseType == ANYOID)
! nargs_transfn = 1;
else
{
fnArgs[1] = aggBaseType;
! nargs_transfn = 2;
}
!
! /*
! * func_get_detail looks up the function in the catalogs, does
! * disambiguation for polymorphic functions, handles inheritance, and
! * returns the funcid and type and set or singleton status of the
! * function's return value. it also returns the true argument types
! * to the function.
! */
! fdresult = func_get_detail(aggtransfnName, NIL, nargs_transfn, fnArgs,
! &transfn, &rettype, &retset,
! &true_oid_array_transfn);
!
! /* only valid case is a normal function */
! if (fdresult != FUNCDETAIL_NORMAL)
! func_error("AggregateCreate", aggtransfnName, nargs_transfn, fnArgs, NULL);
!
if (!OidIsValid(transfn))
! func_error("AggregateCreate", aggtransfnName, nargs_transfn, fnArgs, NULL);
!
! /*
! * enforce consistency with ANYARRAY and ANYELEMENT argument
! * and return types, possibly modifying return type along the way
! */
! rettype = enforce_generic_type_consistency(fnArgs, true_oid_array_transfn,
! nargs_transfn, rettype);
!
! if (rettype != aggTransType)
! elog(ERROR, "return type of transition function %s is not %s",
! NameListToString(aggtransfnName), format_type_be(aggTransType));
!
tup = SearchSysCache(PROCOID,
ObjectIdGetDatum(transfn),
0, 0, 0);
if (!HeapTupleIsValid(tup))
! func_error("AggregateCreate", aggtransfnName,
! nargs_transfn, fnArgs, NULL);
proc = (Form_pg_proc) GETSTRUCT(tup);
/*
* If the transfn is strict and the initval is NULL, make sure input
***************
*** 105,121 ****
{
MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
fnArgs[0] = aggTransType;
! finalfn = LookupFuncName(aggfinalfnName, 1, fnArgs);
! if (!OidIsValid(finalfn))
func_error("AggregateCreate", aggfinalfnName, 1, fnArgs, NULL);
! tup = SearchSysCache(PROCOID,
! ObjectIdGetDatum(finalfn),
! 0, 0, 0);
! if (!HeapTupleIsValid(tup))
func_error("AggregateCreate", aggfinalfnName, 1, fnArgs, NULL);
! proc = (Form_pg_proc) GETSTRUCT(tup);
! finaltype = proc->prorettype;
! ReleaseSysCache(tup);
}
else
{
--- 136,161 ----
{
MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
fnArgs[0] = aggTransType;
! nargs_finalfn = 1;
!
! fdresult = func_get_detail(aggfinalfnName, NIL, 1, fnArgs,
! &finalfn, &rettype, &retset,
! &true_oid_array_finalfn);
!
! /* only valid case is a normal function */
! if (fdresult != FUNCDETAIL_NORMAL)
func_error("AggregateCreate", aggfinalfnName, 1, fnArgs, NULL);
!
! if (!OidIsValid(finalfn))
func_error("AggregateCreate", aggfinalfnName, 1, fnArgs, NULL);
!
! /*
! * enforce consistency with ANYARRAY and ANYELEMENT argument
! * and return types, possibly modifying return type along the way
! */
! finaltype = enforce_generic_type_consistency(fnArgs,
! true_oid_array_finalfn,
! nargs_finalfn, rettype);
}
else
{
***************
*** 125,130 ****
--- 165,191 ----
finaltype = aggTransType;
}
Assert(OidIsValid(finaltype));
+
+ /*
+ * special disallowed cases:
+ * 1) if finaltype is polymorphic, basetype cannot be ANY
+ * 2) if finaltype is polymorphic, both args to transfn must be
+ * polymorphic
+ */
+ if (finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID)
+ {
+ if (aggBaseType == ANYOID)
+ elog(ERROR, "aggregate with base type ANY must have a " \
+ "non-polymorphic return type");
+
+ if (nargs_transfn > 1 && (
+ (true_oid_array_transfn[0] != ANYARRAYOID &&
+ true_oid_array_transfn[0] != ANYELEMENTOID) ||
+ (true_oid_array_transfn[1] != ANYARRAYOID &&
+ true_oid_array_transfn[1] != ANYELEMENTOID)))
+ elog(ERROR, "aggregate with polymorphic return type requires " \
+ "state function with both arguments polymorphic");
+ }
/*
* Everything looks okay. Try to create the pg_proc entry for the
Index: src/backend/commands/aggregatecmds.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/commands/aggregatecmds.c,v
retrieving revision 1.5
diff -c -r1.5 aggregatecmds.c
*** src/backend/commands/aggregatecmds.c 4 Sep 2002 20:31:14 -0000 1.5
--- src/backend/commands/aggregatecmds.c 9 Jun 2003 01:31:10 -0000
***************
*** 119,125 ****
baseTypeId = typenameTypeId(baseType);
transTypeId = typenameTypeId(transType);
! if (get_typtype(transTypeId) == 'p')
elog(ERROR, "Aggregate transition datatype cannot be %s",
format_type_be(transTypeId));
--- 119,127 ----
baseTypeId = typenameTypeId(baseType);
transTypeId = typenameTypeId(transType);
! if (get_typtype(transTypeId) == 'p' &&
! transTypeId != ANYARRAYOID &&
! transTypeId != ANYELEMENTOID)
elog(ERROR, "Aggregate transition datatype cannot be %s",
format_type_be(transTypeId));
Index: src/backend/executor/execQual.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/executor/execQual.c,v
retrieving revision 1.130
diff -c -r1.130 execQual.c
*** src/backend/executor/execQual.c 28 May 2003 22:32:49 -0000 1.130
--- src/backend/executor/execQual.c 9 Jun 2003 01:42:58 -0000
***************
*** 1528,1544 ****
{
/* Check other sub-arrays are compatible */
if (elem_ndims != ARR_NDIM(array))
! elog(ERROR, "Multiple dimension arrays must have array "
"expressions with matching number of dimensions");
if (memcmp(elem_dims, ARR_DIMS(array),
elem_ndims * sizeof(int)) != 0)
! elog(ERROR, "Multiple dimension arrays must have array "
"expressions with matching dimensions");
if (memcmp(elem_lbs, ARR_LBOUND(array),
elem_ndims * sizeof(int)) != 0)
! elog(ERROR, "Multiple dimension arrays must have array "
"expressions with matching dimensions");
}
--- 1528,1544 ----
{
/* Check other sub-arrays are compatible */
if (elem_ndims != ARR_NDIM(array))
! elog(ERROR, "Multidimensional arrays must have array "
"expressions with matching number of dimensions");
if (memcmp(elem_dims, ARR_DIMS(array),
elem_ndims * sizeof(int)) != 0)
! elog(ERROR, "Multidimensional arrays must have array "
"expressions with matching dimensions");
if (memcmp(elem_lbs, ARR_LBOUND(array),
elem_ndims * sizeof(int)) != 0)
! elog(ERROR, "Multidimensional arrays must have array "
"expressions with matching dimensions");
}
Index: src/backend/executor/nodeAgg.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/executor/nodeAgg.c,v
retrieving revision 1.105
diff -c -r1.105 nodeAgg.c
*** src/backend/executor/nodeAgg.c 30 May 2003 20:23:10 -0000 1.105
--- src/backend/executor/nodeAgg.c 9 Jun 2003 01:31:10 -0000
***************
*** 58,63 ****
--- 58,64 ----
#include "executor/executor.h"
#include "executor/nodeAgg.h"
#include "miscadmin.h"
+ #include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
***************
*** 212,218 ****
static void agg_fill_hash_table(AggState *aggstate);
static TupleTableSlot *agg_retrieve_hash_table(AggState *aggstate);
static Datum GetAggInitVal(Datum textInitVal, Oid transtype);
!
/*
* Initialize all aggregates for a new group of input values.
--- 213,219 ----
static void agg_fill_hash_table(AggState *aggstate);
static TupleTableSlot *agg_retrieve_hash_table(AggState *aggstate);
static Datum GetAggInitVal(Datum textInitVal, Oid transtype);
! static Oid resolve_type(Oid type_to_resolve, Oid context_type);
/*
* Initialize all aggregates for a new group of input values.
***************
*** 351,364 ****
fcinfo.context = NULL;
fcinfo.resultinfo = NULL;
fcinfo.isnull = false;
-
fcinfo.flinfo = &peraggstate->transfn;
fcinfo.nargs = 2;
fcinfo.arg[0] = pergroupstate->transValue;
fcinfo.argnull[0] = pergroupstate->transValueIsNull;
fcinfo.arg[1] = newVal;
fcinfo.argnull[1] = isNull;
-
newVal = FunctionCallInvoke(&fcinfo);
/*
--- 352,363 ----
***************
*** 1176,1182 ****
--- 1175,1195 ----
AclResult aclresult;
Oid transfn_oid,
finalfn_oid;
+ FuncExpr *transfnexpr,
+ *finalfnexpr;
Datum textInitVal;
+ List *fargs;
+ Oid agg_rt_type;
+ Oid *transfn_arg_types;
+ List *transfn_args = NIL;
+ int transfn_nargs;
+ Oid transfn_ret_type;
+ Oid *finalfn_arg_types = NULL;
+ List *finalfn_args = NIL;
+ Oid finalfn_ret_type = InvalidOid;
+ int finalfn_nargs = 0;
+ Node *arg0;
+ Node *arg1;
int i;
/* Look for a previous duplicate aggregate */
***************
*** 1224,1229 ****
--- 1237,1402 ----
&peraggstate->transtypeLen,
&peraggstate->transtypeByVal);
+ peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
+ peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
+
+ /* get the runtime aggregate argument type */
+ fargs = aggref->args;
+ agg_rt_type = exprType((Node *) nth(0, fargs));
+
+ /* get the transition function argument and return types */
+ transfn_ret_type = get_func_rettype(transfn_oid);
+ transfn_arg_types = get_func_argtypes(transfn_oid, &transfn_nargs);
+
+ /* resolve any polymorphic types */
+ if (transfn_nargs == 2)
+ /* base type was not ANY */
+ {
+ if (transfn_arg_types[1] == ANYARRAYOID ||
+ transfn_arg_types[1] == ANYELEMENTOID)
+ transfn_arg_types[1] = agg_rt_type;
+
+ transfn_arg_types[0] = resolve_type(transfn_arg_types[0],
+ agg_rt_type);
+
+ /*
+ * Build arg list to use on the transfn FuncExpr node. We really
+ * only care that the node type is correct so that the transfn
+ * can discover the actual argument types at runtime using
+ * get_fn_expr_argtype()
+ */
+ arg0 = (Node *) makeRelabelType((Expr *) NULL, transfn_arg_types[0],
+ -1, COERCE_DONTCARE);
+ arg1 = (Node *) makeRelabelType((Expr *) NULL, transfn_arg_types[1],
+ -1, COERCE_DONTCARE);
+ transfn_args = makeList2(arg0, arg1);
+
+ /*
+ * the state transition function always returns the same type
+ * as its first argument
+ */
+ if (transfn_ret_type == ANYARRAYOID ||
+ transfn_ret_type == ANYELEMENTOID)
+ transfn_ret_type = transfn_arg_types[0];
+ }
+ else if (transfn_nargs == 1)
+ /*
+ * base type was ANY, therefore the aggregate return type should
+ * be non-polymorphic
+ */
+ {
+ Oid finaltype = get_func_rettype(aggref->aggfnoid);
+
+ /*
+ * this should have been prevented in AggregateCreate,
+ * but check anyway
+ */
+ if (finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID)
+ elog(ERROR, "aggregate with base type ANY must have a " \
+ "non-polymorphic return type");
+
+ /* see if we have a final function */
+ if (OidIsValid(finalfn_oid))
+ {
+ finalfn_arg_types = get_func_argtypes(finalfn_oid, &finalfn_nargs);
+ if (finalfn_nargs != 1)
+ elog(ERROR, "final function takes unexpected number " \
+ "of arguments: %d", finalfn_nargs);
+
+ /*
+ * final function argument is always the same as the state
+ * function return type
+ */
+ if (finalfn_arg_types[0] != ANYARRAYOID &&
+ finalfn_arg_types[0] != ANYELEMENTOID)
+ {
+ /* if it is not ambiguous, use it */
+ transfn_ret_type = finalfn_arg_types[0];
+ }
+ else
+ {
+ /* if it is ambiguous, try to derive it */
+ finalfn_ret_type = finaltype;
+ finalfn_arg_types[0] = resolve_type(finalfn_arg_types[0],
+ finalfn_ret_type);
+ transfn_ret_type = finalfn_arg_types[0];
+ }
+ }
+ else
+ transfn_ret_type = finaltype;
+
+ transfn_arg_types[0] = resolve_type(transfn_arg_types[0],
+ transfn_ret_type);
+
+ /*
+ * Build arg list to use on the transfn FuncExpr node. We really
+ * only care that the node type is correct so that the transfn
+ * can discover the actual argument types at runtime using
+ * get_fn_expr_argtype()
+ */
+ arg0 = (Node *) makeRelabelType((Expr *) NULL, transfn_arg_types[0],
+ -1, COERCE_DONTCARE);
+ transfn_args = makeList1(arg0);
+ }
+ else
+ elog(ERROR, "state transition function takes unexpected number " \
+ "of arguments: %d", transfn_nargs);
+
+ if (OidIsValid(finalfn_oid))
+ {
+ /* get the final function argument and return types */
+ if (finalfn_ret_type == InvalidOid)
+ finalfn_ret_type = get_func_rettype(finalfn_oid);
+
+ if (!finalfn_arg_types)
+ {
+ finalfn_arg_types = get_func_argtypes(finalfn_oid, &finalfn_nargs);
+ if (finalfn_nargs != 1)
+ elog(ERROR, "final function takes unexpected number " \
+ "of arguments: %d", finalfn_nargs);
+ }
+
+ /*
+ * final function argument is always the same as the state
+ * function return type, which by now should have been resolved
+ */
+ if (finalfn_arg_types[0] == ANYARRAYOID ||
+ finalfn_arg_types[0] == ANYELEMENTOID)
+ finalfn_arg_types[0] = transfn_ret_type;
+
+ /*
+ * Build arg list to use on the finalfn FuncExpr node. We really
+ * only care that the node type is correct so that the finalfn
+ * can discover the actual argument type at runtime using
+ * get_fn_expr_argtype()
+ */
+ arg0 = (Node *) makeRelabelType((Expr *) NULL, finalfn_arg_types[0],
+ -1, COERCE_DONTCARE);
+ finalfn_args = makeList1(arg0);
+
+ finalfn_ret_type = resolve_type(finalfn_ret_type,
+ finalfn_arg_types[0]);
+ }
+
+ fmgr_info(transfn_oid, &peraggstate->transfn);
+ transfnexpr = (FuncExpr *) make_funcclause(transfn_oid,
+ transfn_ret_type,
+ false, /* cannot be a set */
+ COERCE_DONTCARE, /* to match any user expr */
+ transfn_args);
+ peraggstate->transfn.fn_expr = (Node *) transfnexpr;
+
+ if (OidIsValid(finalfn_oid))
+ {
+ fmgr_info(finalfn_oid, &peraggstate->finalfn);
+ finalfnexpr = (FuncExpr *) make_funcclause(finalfn_oid,
+ finalfn_ret_type,
+ false, /* cannot be a set */
+ COERCE_DONTCARE, /* to match any user expr */
+ finalfn_args);
+ peraggstate->finalfn.fn_expr = (Node *) finalfnexpr;
+ }
+
/*
* initval is potentially null, so don't try to access it as a
* struct field. Must do it the hard way with SysCacheGetAttr.
***************
*** 1236,1249 ****
peraggstate->initValue = (Datum) 0;
else
peraggstate->initValue = GetAggInitVal(textInitVal,
! aggform->aggtranstype);
!
! peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
! peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
!
! fmgr_info(transfn_oid, &peraggstate->transfn);
! if (OidIsValid(finalfn_oid))
! fmgr_info(finalfn_oid, &peraggstate->finalfn);
/*
* If the transfn is strict and the initval is NULL, make sure
--- 1409,1415 ----
peraggstate->initValue = (Datum) 0;
else
peraggstate->initValue = GetAggInitVal(textInitVal,
! transfn_arg_types[0]);
/*
* If the transfn is strict and the initval is NULL, make sure
***************
*** 1454,1457 ****
--- 1620,1656 ----
elog(ERROR, "Aggregate function %u called as normal function",
fcinfo->flinfo->fn_oid);
return (Datum) 0; /* keep compiler quiet */
+ }
+
+ static Oid
+ resolve_type(Oid type_to_resolve, Oid context_type)
+ {
+ Oid resolved_type;
+
+ if (context_type == ANYARRAYOID || context_type == ANYELEMENTOID)
+ resolved_type = type_to_resolve;
+ else if (type_to_resolve == ANYARRAYOID)
+ /* any array */
+ {
+ Oid context_type_arraytype = get_array_type(context_type);
+
+ if (context_type_arraytype != InvalidOid)
+ resolved_type = context_type_arraytype;
+ else
+ resolved_type = context_type;
+ }
+ else if (type_to_resolve == ANYELEMENTOID)
+ /* any element */
+ {
+ Oid context_type_elemtype = get_element_type(context_type);
+
+ if (context_type_elemtype != InvalidOid)
+ resolved_type = context_type_elemtype;
+ else
+ resolved_type = context_type;
+ }
+ else
+ resolved_type = type_to_resolve;
+
+ return resolved_type;
}
Index: src/backend/executor/nodeSubplan.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/executor/nodeSubplan.c,v
retrieving revision 1.45
diff -c -r1.45 nodeSubplan.c
*** src/backend/executor/nodeSubplan.c 8 Apr 2003 23:20:01 -0000 1.45
--- src/backend/executor/nodeSubplan.c 9 Jun 2003 01:31:10 -0000
***************
*** 28,50 ****
#include "utils/datum.h"
#include "utils/lsyscache.h"
-
- typedef struct ArrayBuildState
- {
- MemoryContext mcontext; /* where all the temp stuff is kept */
- Datum *dvalues; /* array of accumulated Datums */
- /*
- * The allocated size of dvalues[] is always a multiple of
- * ARRAY_ELEMS_CHUNKSIZE
- */
- #define ARRAY_ELEMS_CHUNKSIZE 64
- int nelems; /* number of valid Datums in dvalues[] */
- Oid element_type; /* data type of the Datums */
- int16 typlen; /* needed info about datatype */
- bool typbyval;
- char typalign;
- } ArrayBuildState;
-
static Datum ExecHashSubPlan(SubPlanState *node,
ExprContext *econtext,
bool *isNull);
--- 28,33 ----
***************
*** 54,66 ****
static void buildSubPlanHash(SubPlanState *node);
static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot);
static bool tupleAllNulls(HeapTuple tuple);
- static ArrayBuildState *accumArrayResult(ArrayBuildState *astate,
- Datum dvalue, bool disnull,
- Oid element_type,
- MemoryContext rcontext);
- static Datum makeArrayResult(ArrayBuildState *astate,
- MemoryContext rcontext);
-
/* ----------------------------------------------------------------
* ExecSubPlan
--- 37,42 ----
***************
*** 224,229 ****
--- 200,206 ----
PlanState *planstate = node->planstate;
SubLinkType subLinkType = subplan->subLinkType;
bool useOr = subplan->useOr;
+ bool isExpr = subplan->isExpr;
MemoryContext oldcontext;
TupleTableSlot *slot;
Datum result;
***************
*** 292,297 ****
--- 269,279 ----
bool rownull = false;
int col = 1;
List *plst;
+ int numelems;
+ int elemnum;
+ Datum dvalue;
+ Datum *dvalues = NULL;
+ bool disnull;
if (subLinkType == EXISTS_SUBLINK)
{
***************
*** 329,337 ****
if (subLinkType == ARRAY_SUBLINK)
{
- Datum dvalue;
- bool disnull;
-
found = true;
/* stash away current value */
dvalue = heap_getattr(tup, 1, tdesc, &disnull);
--- 311,316 ----
***************
*** 349,446 ****
found = true;
/*
! * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining
! * operators for columns of tuple.
*/
! plst = subplan->paramIds;
! foreach(lst, node->exprs)
{
! ExprState *exprstate = (ExprState *) lfirst(lst);
! int paramid = lfirsti(plst);
! ParamExecData *prmdata;
! Datum expresult;
! bool expnull;
!
! /*
! * Load up the Param representing this column of the sub-select.
! */
! prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
! Assert(prmdata->execPlan == NULL);
! prmdata->value = heap_getattr(tup, col, tdesc,
! &(prmdata->isnull));
! /*
! * Now we can eval the combining operator for this column.
! */
! expresult = ExecEvalExprSwitchContext(exprstate, econtext,
! &expnull, NULL);
!
! /*
! * Combine the result into the row result as appropriate.
! */
! if (col == 1)
{
! rowresult = expresult;
! rownull = expnull;
}
! else if (useOr)
{
! /* combine within row per OR semantics */
! if (expnull)
! rownull = true;
! else if (DatumGetBool(expresult))
{
! rowresult = BoolGetDatum(true);
! rownull = false;
! break; /* needn't look at any more columns */
}
}
else
{
! /* combine within row per AND semantics */
! if (expnull)
! rownull = true;
! else if (!DatumGetBool(expresult))
! {
! rowresult = BoolGetDatum(false);
! rownull = false;
! break; /* needn't look at any more columns */
! }
}
- plst = lnext(plst);
- col++;
}
! if (subLinkType == ANY_SUBLINK)
{
! /* combine across rows per OR semantics */
! if (rownull)
! *isNull = true;
! else if (DatumGetBool(rowresult))
{
! result = BoolGetDatum(true);
! *isNull = false;
! break; /* needn't look at any more rows */
}
! }
! else if (subLinkType == ALL_SUBLINK)
! {
! /* combine across rows per AND semantics */
! if (rownull)
! *isNull = true;
! else if (!DatumGetBool(rowresult))
{
! result = BoolGetDatum(false);
! *isNull = false;
! break; /* needn't look at any more rows */
}
- }
- else
- {
- /* must be MULTIEXPR_SUBLINK */
- result = rowresult;
- *isNull = rownull;
}
}
--- 328,490 ----
found = true;
/*
! * When isExpr is true, we have either a scalar expression or an
! * array. In the former case, this is no different than the !isExpr
! * case. In the latter case, iterate over the elements as if they
! * were from multiple input tuples.
*/
! if (!isExpr)
! numelems = 1;
! else
{
! Oid expr_typeid = tdesc->attrs[0]->atttypid;
! if (expr_typeid != subplan->exprtype)
{
! subplan->exprtype = expr_typeid;
! subplan->elemtype = get_element_type(expr_typeid);
!
! if (subplan->elemtype != InvalidOid)
! get_typlenbyvalalign(subplan->elemtype,
! &subplan->elmlen,
! &subplan->elmbyval,
! &subplan->elmalign);
}
!
! /* get current value */
! dvalue = heap_getattr(tup, 1, tdesc, &disnull);
!
! /* XXX this will need work if/when arrays support NULL elements */
! if (!disnull)
{
! if (subplan->elemtype != InvalidOid)
! {
! ArrayType *v = DatumGetArrayTypeP(dvalue);
!
! deconstruct_array(v, subplan->elemtype, subplan->elmlen,
! subplan->elmbyval, subplan->elmalign,
! &dvalues, &numelems);
! }
! else
{
! numelems = 1;
! dvalues = (Datum *) palloc(numelems * sizeof(Datum));
! dvalues[0] = dvalue;
}
}
else
{
! numelems = 1;
! dvalues = (Datum *) palloc(numelems * sizeof(Datum));
! dvalues[0] = (Datum) 0;
}
}
! for (elemnum = 0; elemnum < numelems; elemnum++)
{
! /*
! * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining
! * operators for columns of tuple.
! */
! col = 1;
! plst = subplan->paramIds;
! foreach(lst, node->exprs)
{
! ExprState *exprstate = (ExprState *) lfirst(lst);
! int paramid = lfirsti(plst);
! ParamExecData *prmdata;
! Datum expresult;
! bool expnull;
!
! /*
! * Load up the Param representing this column of the sub-select.
! */
! prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
! Assert(prmdata->execPlan == NULL);
!
! if (!isExpr)
! prmdata->value = heap_getattr(tup, col, tdesc,
! &(prmdata->isnull));
! else
! {
! prmdata->value = dvalues[elemnum];
! prmdata->isnull = disnull;
! }
!
! /*
! * Now we can eval the combining operator for this column.
! */
! expresult = ExecEvalExprSwitchContext(exprstate, econtext,
! &expnull, NULL);
!
! /*
! * Combine the result into the row result as appropriate.
! */
! if (col == 1)
! {
! rowresult = expresult;
! rownull = expnull;
! }
! else if (useOr)
! {
! /* combine within row per OR semantics */
! if (expnull)
! rownull = true;
! else if (DatumGetBool(expresult))
! {
! rowresult = BoolGetDatum(true);
! rownull = false;
! break; /* needn't look at any more columns */
! }
! }
! else
! {
! /* combine within row per AND semantics */
! if (expnull)
! rownull = true;
! else if (!DatumGetBool(expresult))
! {
! rowresult = BoolGetDatum(false);
! rownull = false;
! break; /* needn't look at any more columns */
! }
! }
!
! plst = lnext(plst);
! col++;
}
!
! if (subLinkType == ANY_SUBLINK)
{
! /* combine across rows per OR semantics */
! if (rownull)
! *isNull = true;
! else if (DatumGetBool(rowresult))
! {
! result = BoolGetDatum(true);
! *isNull = false;
! break; /* needn't look at any more rows */
! }
! }
! else if (subLinkType == ALL_SUBLINK)
! {
! /* combine across rows per AND semantics */
! if (rownull)
! *isNull = true;
! else if (!DatumGetBool(rowresult))
! {
! result = BoolGetDatum(false);
! *isNull = false;
! break; /* needn't look at any more rows */
! }
! }
! else
! {
! /* must be MULTIEXPR_SUBLINK */
! result = rowresult;
! *isNull = rownull;
}
}
}
***************
*** 478,483 ****
--- 522,528 ----
buildSubPlanHash(SubPlanState *node)
{
SubPlan *subplan = (SubPlan *) node->xprstate.expr;
+ bool isExpr = subplan->isExpr;
PlanState *planstate = node->planstate;
int ncols = length(node->exprs);
ExprContext *innerecontext = node->innerecontext;
***************
*** 485,490 ****
--- 530,536 ----
MemoryContext oldcontext;
int nbuckets;
TupleTableSlot *slot;
+ TupleTableSlot *arrslot = NULL;
Assert(subplan->subLinkType == ANY_SUBLINK);
Assert(!subplan->useOr);
***************
*** 562,604 ****
{
HeapTuple tup = slot->val;
TupleDesc tdesc = slot->ttc_tupleDescriptor;
! int col = 1;
List *plst;
bool isnew;
/*
! * Load up the Params representing the raw sub-select outputs,
! * then form the projection tuple to store in the hashtable.
*/
! foreach(plst, subplan->paramIds)
{
! int paramid = lfirsti(plst);
! ParamExecData *prmdata;
! prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]);
! Assert(prmdata->execPlan == NULL);
! prmdata->value = heap_getattr(tup, col, tdesc,
! &(prmdata->isnull));
! col++;
! }
! slot = ExecProject(node->projRight, NULL);
! tup = slot->val;
- /*
- * If result contains any nulls, store separately or not at all.
- * (Since we know the projection tuple has no junk columns, we
- * can just look at the overall hasnull info bit, instead of
- * groveling through the columns.)
- */
- if (HeapTupleNoNulls(tup))
- {
- (void) LookupTupleHashEntry(node->hashtable, slot, &isnew);
- node->havehashrows = true;
}
! else if (node->hashnulls)
{
! (void) LookupTupleHashEntry(node->hashnulls, slot, &isnew);
! node->havenullrows = true;
}
/*
--- 608,746 ----
{
HeapTuple tup = slot->val;
TupleDesc tdesc = slot->ttc_tupleDescriptor;
! TupleDesc arrtdesc = NULL;
List *plst;
bool isnew;
+ int numelems;
+ int elemnum;
+ Datum dvalue;
+ Datum *dvalues = NULL;
+ bool disnull;
/*
! * When isExpr is true, we have either a scalar expression or an
! * array. In the former case, this is no different than the !isExpr
! * case. In the latter case, iterate over the elements as if they
! * were from multiple input tuples.
*/
! if (!isExpr)
! numelems = 1;
! else
{
! Oid expr_typeid = tdesc->attrs[0]->atttypid;
! if (expr_typeid != subplan->exprtype)
! {
! subplan->exprtype = expr_typeid;
! subplan->elemtype = get_element_type(expr_typeid);
!
! if (subplan->elemtype != InvalidOid)
! get_typlenbyvalalign(subplan->elemtype,
! &subplan->elmlen,
! &subplan->elmbyval,
! &subplan->elmalign);
! }
!
! /* get current value */
! dvalue = heap_getattr(tup, 1, tdesc, &disnull);
!
! if (subplan->elemtype != InvalidOid)
! {
! TupleTable tupleTable;
! ArrayType *v = DatumGetArrayTypeP(dvalue);
!
! arrtdesc = CreateTemplateTupleDesc(1, false);
! TupleDescInitEntry(arrtdesc, 1, "elem", subplan->elemtype,
! -1, 0, false);
!
! tupleTable = ExecCreateTupleTable(1);
! arrslot = ExecAllocTableSlot(tupleTable);
! ExecSetSlotDescriptor(arrslot, arrtdesc, true);
!
! /* XXX this will need work if/when arrays support NULL elements */
! if (!disnull)
! {
! deconstruct_array(v, subplan->elemtype, subplan->elmlen,
! subplan->elmbyval, subplan->elmalign,
! &dvalues, &numelems);
! }
! else
! {
! numelems = 1;
! dvalues = (Datum *) palloc(numelems * sizeof(Datum));
! dvalues[0] = (Datum) 0;
! }
! }
! else
! {
! numelems = 1;
! dvalues = (Datum *) palloc(numelems * sizeof(Datum));
! dvalues[0] = dvalue;
! }
}
!
! for (elemnum = 0; elemnum < numelems; elemnum++)
{
! int col = 1;
!
! if (!isExpr || subplan->elemtype == InvalidOid)
! {
! /*
! * Load up the Params representing the raw sub-select outputs,
! * then form the projection tuple to store in the hashtable.
! */
! foreach(plst, subplan->paramIds)
! {
! int paramid = lfirsti(plst);
! ParamExecData *prmdata;
!
! prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]);
! Assert(prmdata->execPlan == NULL);
!
! prmdata->value = heap_getattr(tup, col, tdesc,
! &(prmdata->isnull));
!
! col++;
! }
! slot = ExecProject(node->projRight, NULL);
! tup = slot->val;
! }
! else
! {
! /*
! * For array type expressions, we need to build up our own
! * tuple and slot
! */
! char nullflag;
!
! nullflag = disnull ? 'n' : ' ';
! tup = heap_formtuple(arrtdesc, &dvalues[elemnum], &nullflag);
! arrslot = ExecStoreTuple(tup, arrslot, InvalidBuffer, true);
! }
!
! /*
! * If result contains any nulls, store separately or not at all.
! * (Since we know the projection tuple has no junk columns, we
! * can just look at the overall hasnull info bit, instead of
! * groveling through the columns.)
! */
! if (HeapTupleNoNulls(tup))
! {
! if (!isExpr)
! (void) LookupTupleHashEntry(node->hashtable, slot, &isnew);
! else
! (void) LookupTupleHashEntry(node->hashtable, arrslot, &isnew);
! node->havehashrows = true;
! }
! else if (node->hashnulls)
! {
! if (!isExpr)
! (void) LookupTupleHashEntry(node->hashnulls, slot, &isnew);
! else
! (void) LookupTupleHashEntry(node->hashnulls, arrslot, &isnew);
! node->havenullrows = true;
! }
}
/*
***************
*** 615,620 ****
--- 757,764 ----
* have the potential for a double free attempt.
*/
ExecClearTuple(node->projRight->pi_slot);
+ if (arrslot)
+ ExecClearTuple(arrslot);
MemoryContextSwitchTo(oldcontext);
}
***************
*** 1084,1185 ****
prm->execPlan = node;
parent->chgParam = bms_add_member(parent->chgParam, paramid);
}
- }
-
- /*
- * accumArrayResult - accumulate one (more) Datum for an ARRAY_SUBLINK
- *
- * astate is working state (NULL on first call)
- * rcontext is where to keep working state
- */
- static ArrayBuildState *
- accumArrayResult(ArrayBuildState *astate,
- Datum dvalue, bool disnull,
- Oid element_type,
- MemoryContext rcontext)
- {
- MemoryContext arr_context,
- oldcontext;
-
- if (astate == NULL)
- {
- /* First time through --- initialize */
-
- /* Make a temporary context to hold all the junk */
- arr_context = AllocSetContextCreate(rcontext,
- "ARRAY_SUBLINK Result",
- ALLOCSET_DEFAULT_MINSIZE,
- ALLOCSET_DEFAULT_INITSIZE,
- ALLOCSET_DEFAULT_MAXSIZE);
- oldcontext = MemoryContextSwitchTo(arr_context);
- astate = (ArrayBuildState *) palloc(sizeof(ArrayBuildState));
- astate->mcontext = arr_context;
- astate->dvalues = (Datum *)
- palloc(ARRAY_ELEMS_CHUNKSIZE * sizeof(Datum));
- astate->nelems = 0;
- astate->element_type = element_type;
- get_typlenbyvalalign(element_type,
- &astate->typlen,
- &astate->typbyval,
- &astate->typalign);
- }
- else
- {
- oldcontext = MemoryContextSwitchTo(astate->mcontext);
- Assert(astate->element_type == element_type);
- /* enlarge dvalues[] if needed */
- if ((astate->nelems % ARRAY_ELEMS_CHUNKSIZE) == 0)
- astate->dvalues = (Datum *)
- repalloc(astate->dvalues,
- (astate->nelems + ARRAY_ELEMS_CHUNKSIZE) * sizeof(Datum));
- }
-
- if (disnull)
- elog(ERROR, "NULL elements not allowed in Arrays");
-
- /* Use datumCopy to ensure pass-by-ref stuff is copied into mcontext */
- astate->dvalues[astate->nelems++] =
- datumCopy(dvalue, astate->typbyval, astate->typlen);
-
- MemoryContextSwitchTo(oldcontext);
-
- return astate;
- }
-
- /*
- * makeArrayResult - produce final result of ARRAY_SUBLINK
- *
- * astate is working state (not NULL)
- * rcontext is where to construct result
- */
- static Datum
- makeArrayResult(ArrayBuildState *astate,
- MemoryContext rcontext)
- {
- ArrayType *result;
- int dims[1];
- int lbs[1];
- MemoryContext oldcontext;
-
- /* Build the final array result in rcontext */
- oldcontext = MemoryContextSwitchTo(rcontext);
-
- dims[0] = astate->nelems;
- lbs[0] = 1;
-
- result = construct_md_array(astate->dvalues,
- 1,
- dims,
- lbs,
- astate->element_type,
- astate->typlen,
- astate->typbyval,
- astate->typalign);
-
- MemoryContextSwitchTo(oldcontext);
-
- /* Clean up all the junk */
- MemoryContextDelete(astate->mcontext);
-
- return PointerGetDatum(result);
}
--- 1228,1231 ----
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.251
diff -c -r1.251 copyfuncs.c
*** src/backend/nodes/copyfuncs.c 28 May 2003 16:03:56 -0000 1.251
--- src/backend/nodes/copyfuncs.c 9 Jun 2003 01:31:10 -0000
***************
*** 727,732 ****
--- 727,733 ----
COPY_NODE_FIELD(target);
COPY_SCALAR_FIELD(aggstar);
COPY_SCALAR_FIELD(aggdistinct);
+ COPY_NODE_FIELD(args);
return newnode;
}
***************
*** 825,830 ****
--- 826,832 ----
COPY_SCALAR_FIELD(subLinkType);
COPY_SCALAR_FIELD(useOr);
+ COPY_SCALAR_FIELD(isExpr);
COPY_NODE_FIELD(lefthand);
COPY_NODE_FIELD(operName);
COPY_OIDLIST_FIELD(operOids);
***************
*** 843,848 ****
--- 845,856 ----
COPY_SCALAR_FIELD(subLinkType);
COPY_SCALAR_FIELD(useOr);
+ COPY_SCALAR_FIELD(isExpr);
+ COPY_SCALAR_FIELD(exprtype);
+ COPY_SCALAR_FIELD(elemtype);
+ COPY_SCALAR_FIELD(elmlen);
+ COPY_SCALAR_FIELD(elmbyval);
+ COPY_SCALAR_FIELD(elmalign);
COPY_NODE_FIELD(exprs);
COPY_INTLIST_FIELD(paramIds);
COPY_NODE_FIELD(plan);
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.194
diff -c -r1.194 equalfuncs.c
*** src/backend/nodes/equalfuncs.c 28 May 2003 16:03:56 -0000 1.194
--- src/backend/nodes/equalfuncs.c 9 Jun 2003 01:31:10 -0000
***************
*** 204,209 ****
--- 204,210 ----
COMPARE_NODE_FIELD(target);
COMPARE_SCALAR_FIELD(aggstar);
COMPARE_SCALAR_FIELD(aggdistinct);
+ COMPARE_NODE_FIELD(args);
return true;
}
***************
*** 300,305 ****
--- 301,307 ----
{
COMPARE_SCALAR_FIELD(subLinkType);
COMPARE_SCALAR_FIELD(useOr);
+ COMPARE_SCALAR_FIELD(isExpr);
COMPARE_NODE_FIELD(lefthand);
COMPARE_NODE_FIELD(operName);
COMPARE_OIDLIST_FIELD(operOids);
***************
*** 313,318 ****
--- 315,326 ----
{
COMPARE_SCALAR_FIELD(subLinkType);
COMPARE_SCALAR_FIELD(useOr);
+ COMPARE_SCALAR_FIELD(isExpr);
+ COMPARE_SCALAR_FIELD(exprtype);
+ COMPARE_SCALAR_FIELD(elemtype);
+ COMPARE_SCALAR_FIELD(elmlen);
+ COMPARE_SCALAR_FIELD(elmbyval);
+ COMPARE_SCALAR_FIELD(elmalign);
COMPARE_NODE_FIELD(exprs);
COMPARE_INTLIST_FIELD(paramIds);
/* should compare plans, but have to settle for comparing plan IDs */
Index: src/backend/nodes/outfuncs.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/outfuncs.c,v
retrieving revision 1.206
diff -c -r1.206 outfuncs.c
*** src/backend/nodes/outfuncs.c 28 May 2003 16:03:56 -0000 1.206
--- src/backend/nodes/outfuncs.c 9 Jun 2003 01:31:10 -0000
***************
*** 615,620 ****
--- 615,621 ----
WRITE_NODE_FIELD(target);
WRITE_BOOL_FIELD(aggstar);
WRITE_BOOL_FIELD(aggdistinct);
+ WRITE_NODE_FIELD(args);
}
static void
***************
*** 700,705 ****
--- 701,707 ----
WRITE_ENUM_FIELD(subLinkType, SubLinkType);
WRITE_BOOL_FIELD(useOr);
+ WRITE_BOOL_FIELD(isExpr);
WRITE_NODE_FIELD(lefthand);
WRITE_NODE_FIELD(operName);
WRITE_OIDLIST_FIELD(operOids);
***************
*** 713,718 ****
--- 715,726 ----
WRITE_ENUM_FIELD(subLinkType, SubLinkType);
WRITE_BOOL_FIELD(useOr);
+ WRITE_BOOL_FIELD(isExpr);
+ WRITE_OID_FIELD(exprtype);
+ WRITE_OID_FIELD(elemtype);
+ WRITE_INT_FIELD(elmlen);
+ WRITE_BOOL_FIELD(elmbyval);
+ WRITE_CHAR_FIELD(elmalign);
WRITE_NODE_FIELD(exprs);
WRITE_INTLIST_FIELD(paramIds);
WRITE_NODE_FIELD(plan);
Index: src/backend/nodes/readfuncs.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/readfuncs.c,v
retrieving revision 1.153
diff -c -r1.153 readfuncs.c
*** src/backend/nodes/readfuncs.c 6 May 2003 00:20:32 -0000 1.153
--- src/backend/nodes/readfuncs.c 9 Jun 2003 01:31:10 -0000
***************
*** 415,420 ****
--- 415,421 ----
READ_NODE_FIELD(target);
READ_BOOL_FIELD(aggstar);
READ_BOOL_FIELD(aggdistinct);
+ READ_NODE_FIELD(args);
READ_DONE();
}
***************
*** 544,549 ****
--- 545,551 ----
READ_ENUM_FIELD(subLinkType, SubLinkType);
READ_BOOL_FIELD(useOr);
+ READ_BOOL_FIELD(isExpr);
READ_NODE_FIELD(lefthand);
READ_NODE_FIELD(operName);
READ_OIDLIST_FIELD(operOids);
Index: src/backend/optimizer/plan/subselect.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/optimizer/plan/subselect.c,v
retrieving revision 1.75
diff -c -r1.75 subselect.c
*** src/backend/optimizer/plan/subselect.c 29 Apr 2003 22:13:09 -0000 1.75
--- src/backend/optimizer/plan/subselect.c 9 Jun 2003 01:31:10 -0000
***************
*** 67,73 ****
static List *convert_sublink_opers(List *lefthand, List *operOids,
List *targetlist, int rtindex,
! List **righthandIds);
static bool subplan_is_hashable(SubLink *slink, SubPlan *node);
static Node *replace_correlation_vars_mutator(Node *node, void *context);
static Node *process_sublinks_mutator(Node *node, bool *isTopQual);
--- 67,73 ----
static List *convert_sublink_opers(List *lefthand, List *operOids,
List *targetlist, int rtindex,
! bool isExpr, List **righthandIds);
static bool subplan_is_hashable(SubLink *slink, SubPlan *node);
static Node *replace_correlation_vars_mutator(Node *node, void *context);
static Node *process_sublinks_mutator(Node *node, bool *isTopQual);
***************
*** 240,245 ****
--- 240,251 ----
*/
node->subLinkType = slink->subLinkType;
node->useOr = slink->useOr;
+ node->isExpr = slink->isExpr;
+ node->exprtype = InvalidOid;
+ node->elemtype = InvalidOid;
+ node->elmlen = 0;
+ node->elmbyval = false;
+ node->elmalign = '\0';
node->exprs = NIL;
node->paramIds = NIL;
node->useHashTable = false;
***************
*** 316,322 ****
exprs = convert_sublink_opers(lefthand,
slink->operOids,
plan->targetlist,
! 0,
&node->paramIds);
node->setParam = listCopy(node->paramIds);
PlannerInitPlan = lappend(PlannerInitPlan, node);
--- 322,328 ----
exprs = convert_sublink_opers(lefthand,
slink->operOids,
plan->targetlist,
! 0, node->isExpr,
&node->paramIds);
node->setParam = listCopy(node->paramIds);
PlannerInitPlan = lappend(PlannerInitPlan, node);
***************
*** 399,405 ****
node->exprs = convert_sublink_opers(lefthand,
slink->operOids,
plan->targetlist,
! 0,
&node->paramIds);
/*
--- 405,411 ----
node->exprs = convert_sublink_opers(lefthand,
slink->operOids,
plan->targetlist,
! 0, node->isExpr,
&node->paramIds);
/*
***************
*** 444,450 ****
static List *
convert_sublink_opers(List *lefthand, List *operOids,
List *targetlist, int rtindex,
! List **righthandIds)
{
List *result = NIL;
List *lst;
--- 450,456 ----
static List *
convert_sublink_opers(List *lefthand, List *operOids,
List *targetlist, int rtindex,
! bool isExpr, List **righthandIds)
{
List *result = NIL;
List *lst;
***************
*** 499,511 ****
* are not expecting to have to resolve unknown Params, so
* it's okay to pass a null pstate.)
*/
! result = lappend(result,
! make_op_expr(NULL,
! tup,
! leftop,
! rightop,
! exprType(leftop),
! te->resdom->restype));
ReleaseSysCache(tup);
--- 505,542 ----
* are not expecting to have to resolve unknown Params, so
* it's okay to pass a null pstate.)
*/
! if (!isExpr)
! {
! result = lappend(result,
! make_op_expr(NULL,
! tup,
! leftop,
! rightop,
! exprType(leftop),
! te->resdom->restype));
! }
! else
! {
! Oid exprtype = te->resdom->restype;
! Oid elemtype = get_element_type(exprtype);
!
! if (elemtype != InvalidOid)
! result = lappend(result,
! make_op_expr(NULL,
! tup,
! leftop,
! rightop,
! exprType(leftop),
! elemtype));
! else
! result = lappend(result,
! make_op_expr(NULL,
! tup,
! leftop,
! rightop,
! exprType(leftop),
! exprtype));
! }
ReleaseSysCache(tup);
***************
*** 616,628 ****
/*
* The sublink type must be "= ANY" --- that is, an IN operator.
* (We require the operator name to be unqualified, which may be
! * overly paranoid, or may not be.)
*/
if (sublink->subLinkType != ANY_SUBLINK)
return NULL;
if (length(sublink->operName) != 1 ||
strcmp(strVal(lfirst(sublink->operName)), "=") != 0)
return NULL;
/*
* The sub-select must not refer to any Vars of the parent query.
* (Vars of higher levels should be okay, though.)
--- 647,663 ----
/*
* The sublink type must be "= ANY" --- that is, an IN operator.
* (We require the operator name to be unqualified, which may be
! * overly paranoid, or may not be.) It must not be an Expression
! * sublink.
*/
if (sublink->subLinkType != ANY_SUBLINK)
return NULL;
if (length(sublink->operName) != 1 ||
strcmp(strVal(lfirst(sublink->operName)), "=") != 0)
return NULL;
+ if (sublink->isExpr)
+ return NULL;
+
/*
* The sub-select must not refer to any Vars of the parent query.
* (Vars of higher levels should be okay, though.)
***************
*** 675,681 ****
exprs = convert_sublink_opers(sublink->lefthand,
sublink->operOids,
subselect->targetList,
! rtindex,
&ininfo->sub_targetlist);
return (Node *) make_ands_explicit(exprs);
}
--- 710,716 ----
exprs = convert_sublink_opers(sublink->lefthand,
sublink->operOids,
subselect->targetList,
! rtindex, sublink->isExpr,
&ininfo->sub_targetlist);
return (Node *) make_ands_explicit(exprs);
}
Index: src/backend/optimizer/util/clauses.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/optimizer/util/clauses.c,v
retrieving revision 1.138
diff -c -r1.138 clauses.c
*** src/backend/optimizer/util/clauses.c 28 May 2003 22:32:49 -0000 1.138
--- src/backend/optimizer/util/clauses.c 9 Jun 2003 01:31:10 -0000
***************
*** 133,138 ****
--- 133,160 ----
}
/*****************************************************************************
+ * FUNCTION clause functions
+ *****************************************************************************/
+
+ /*
+ * make_funcclause
+ * Creates a function clause given its function info and argument list.
+ */
+ Expr *
+ make_funcclause(Oid funcid, Oid funcresulttype, bool funcretset,
+ CoercionForm funcformat, List *funcargs)
+ {
+ FuncExpr *expr = makeNode(FuncExpr);
+
+ expr->funcid = funcid;
+ expr->funcresulttype = funcresulttype;
+ expr->funcretset = funcretset;
+ expr->funcformat = funcformat;
+ expr->args = funcargs;
+ return (Expr *) expr;
+ }
+
+ /*****************************************************************************
* NOT clause functions
*****************************************************************************/
Index: src/backend/parser/gram.y
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/parser/gram.y,v
retrieving revision 2.416
diff -c -r2.416 gram.y
*** src/backend/parser/gram.y 29 May 2003 20:40:36 -0000 2.416
--- src/backend/parser/gram.y 9 Jun 2003 01:31:10 -0000
***************
*** 5490,5495 ****
--- 5490,5496 ----
{
SubLink *n = makeNode(SubLink);
n->subLinkType = ANY_SUBLINK;
+ n->isExpr = false;
n->lefthand = $1;
n->operName = makeList1(makeString("="));
n->subselect = $3;
***************
*** 5500,5505 ****
--- 5501,5507 ----
/* Make an IN node */
SubLink *n = makeNode(SubLink);
n->subLinkType = ANY_SUBLINK;
+ n->isExpr = false;
n->lefthand = $1;
n->operName = makeList1(makeString("="));
n->subselect = $4;
***************
*** 5511,5516 ****
--- 5513,5519 ----
{
SubLink *n = makeNode(SubLink);
n->subLinkType = $3;
+ n->isExpr = false;
n->lefthand = $1;
n->operName = $2;
n->subselect = $4;
***************
*** 5521,5526 ****
--- 5524,5530 ----
{
SubLink *n = makeNode(SubLink);
n->subLinkType = MULTIEXPR_SUBLINK;
+ n->isExpr = false;
n->lefthand = $1;
n->operName = $2;
n->subselect = $3;
***************
*** 5904,5909 ****
--- 5908,5914 ----
{
SubLink *n = (SubLink *)$3;
n->subLinkType = ANY_SUBLINK;
+ n->isExpr = false;
n->lefthand = makeList1($1);
n->operName = makeList1(makeString("="));
$$ = (Node *)n;
***************
*** 5931,5936 ****
--- 5936,5942 ----
{
/* Make an IN node */
SubLink *n = (SubLink *)$4;
+ n->isExpr = false;
n->subLinkType = ANY_SUBLINK;
n->lefthand = makeList1($1);
n->operName = makeList1(makeString("="));
***************
*** 5957,5967 ****
--- 5963,6000 ----
{
SubLink *n = makeNode(SubLink);
n->subLinkType = $3;
+ n->isExpr = false;
n->lefthand = makeList1($1);
n->operName = $2;
n->subselect = $4;
$$ = (Node *)n;
}
+ | a_expr qual_all_Op sub_type '(' a_expr ')' %prec Op
+ {
+ SubLink *n = makeNode(SubLink);
+ SelectStmt *s = makeNode(SelectStmt);
+ ResTarget *r = makeNode(ResTarget);
+
+ r->name = NULL;
+ r->indirection = NIL;
+ r->val = (Node *)$5;
+
+ s->distinctClause = NIL;
+ s->targetList = makeList1(r);
+ s->into = NULL;
+ s->intoColNames = NIL;
+ s->fromClause = NIL;
+ s->whereClause = NULL;
+ s->groupClause = NIL;
+ s->havingClause = NULL;
+
+ n->subLinkType = $3;
+ n->isExpr = true;
+ n->lefthand = makeList1($1);
+ n->operName = $2;
+ n->subselect = (Node *) s;
+ $$ = (Node *)n;
+ }
| UNIQUE select_with_parens %prec Op
{
/* Not sure how to get rid of the parentheses
***************
*** 6538,6543 ****
--- 6571,6577 ----
{
SubLink *n = makeNode(SubLink);
n->subLinkType = EXPR_SUBLINK;
+ n->isExpr = false;
n->lefthand = NIL;
n->operName = NIL;
n->subselect = $1;
***************
*** 6547,6552 ****
--- 6581,6587 ----
{
SubLink *n = makeNode(SubLink);
n->subLinkType = EXISTS_SUBLINK;
+ n->isExpr = false;
n->lefthand = NIL;
n->operName = NIL;
n->subselect = $2;
***************
*** 6556,6561 ****
--- 6591,6597 ----
{
SubLink *n = makeNode(SubLink);
n->subLinkType = ARRAY_SUBLINK;
+ n->isExpr = false;
n->lefthand = NIL;
n->operName = NIL;
n->subselect = $2;
***************
*** 6730,6735 ****
--- 6766,6772 ----
in_expr: select_with_parens
{
SubLink *n = makeNode(SubLink);
+ n->isExpr = false;
n->subselect = $1;
/* other fields will be filled later */
$$ = (Node *)n;
Index: src/backend/parser/parse_coerce.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/parser/parse_coerce.c,v
retrieving revision 2.97
diff -c -r2.97 parse_coerce.c
*** src/backend/parser/parse_coerce.c 26 May 2003 00:11:27 -0000 2.97
--- src/backend/parser/parse_coerce.c 9 Jun 2003 01:31:10 -0000
***************
*** 859,865 ****
/* Get the element type based on the array type, if we have one */
if (OidIsValid(array_typeid))
{
! array_typelem = get_element_type(array_typeid);
if (!OidIsValid(array_typelem))
elog(ERROR, "Argument declared ANYARRAY is not an array: %s",
format_type_be(array_typeid));
--- 859,869 ----
/* Get the element type based on the array type, if we have one */
if (OidIsValid(array_typeid))
{
! if (array_typeid != ANYARRAYOID)
! array_typelem = get_element_type(array_typeid);
! else
! array_typelem = ANYELEMENTOID;
!
if (!OidIsValid(array_typelem))
elog(ERROR, "Argument declared ANYARRAY is not an array: %s",
format_type_be(array_typeid));
***************
*** 919,925 ****
{
if (!OidIsValid(array_typeid))
{
! array_typeid = get_array_type(elem_typeid);
if (!OidIsValid(array_typeid))
elog(ERROR, "Cannot find array type for datatype %s",
format_type_be(elem_typeid));
--- 923,933 ----
{
if (!OidIsValid(array_typeid))
{
! if (elem_typeid != ANYELEMENTOID)
! array_typeid = get_array_type(elem_typeid);
! else
! array_typeid = ANYARRAYOID;
!
if (!OidIsValid(array_typeid))
elog(ERROR, "Cannot find array type for datatype %s",
format_type_be(elem_typeid));
***************
*** 1169,1174 ****
--- 1177,1187 ----
/* Somewhat-fast path for domain -> base type case */
if (srctype == targettype)
return true;
+
+ /* Last of the fast-paths: check for matching polymorphic arrays */
+ if (targettype == ANYARRAYOID)
+ if (get_element_type(srctype) != InvalidOid)
+ return true;
/* Else look in pg_cast */
tuple = SearchSysCache(CASTSOURCETARGET,
Index: src/backend/parser/parse_expr.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/parser/parse_expr.c,v
retrieving revision 1.148
diff -c -r1.148 parse_expr.c
*** src/backend/parser/parse_expr.c 29 Apr 2003 22:13:10 -0000 1.148
--- src/backend/parser/parse_expr.c 9 Jun 2003 01:42:58 -0000
***************
*** 436,441 ****
--- 436,442 ----
sublink->operName = NIL;
sublink->operOids = NIL;
sublink->useOr = FALSE;
+ sublink->isExpr = FALSE;
}
else if (sublink->subLinkType == EXPR_SUBLINK ||
sublink->subLinkType == ARRAY_SUBLINK)
***************
*** 463,468 ****
--- 464,470 ----
sublink->operName = NIL;
sublink->operOids = NIL;
sublink->useOr = FALSE;
+ sublink->isExpr = FALSE;
}
else
{
***************
*** 538,547 ****
* here, because make_subplan() will insert type
* coercion calls if needed.
*/
! optup = oper(op,
! exprType(lexpr),
! exprType((Node *) tent->expr),
! false);
opform = (Form_pg_operator) GETSTRUCT(optup);
if (opform->oprresult != BOOLOID)
--- 540,569 ----
* here, because make_subplan() will insert type
* coercion calls if needed.
*/
! if (!sublink->isExpr)
! {
! optup = oper(op,
! exprType(lexpr),
! exprType((Node *) tent->expr),
! false);
! }
! else
! {
! Oid exprtype = exprType((Node *) tent->expr);
! Oid elemtype = get_element_type(exprtype);
!
! if (elemtype != InvalidOid)
! optup = oper(op,
! exprType(lexpr),
! elemtype,
! false);
! else
! optup = oper(op,
! exprType(lexpr),
! exprtype,
! false);
! }
!
opform = (Form_pg_operator) GETSTRUCT(optup);
if (opform->oprresult != BOOLOID)
***************
*** 743,749 ****
ArrayExpr *e = (ArrayExpr *) lfirst(element);
if (!IsA(e, ArrayExpr))
! elog(ERROR, "Multi-dimensional ARRAY[] must be built from nested array expressions");
if (ndims == 0)
ndims = e->ndims;
else if (e->ndims != ndims)
--- 765,771 ----
ArrayExpr *e = (ArrayExpr *) lfirst(element);
if (!IsA(e, ArrayExpr))
! elog(ERROR, "Multidimensional ARRAY[] must be built from nested array expressions");
if (ndims == 0)
ndims = e->ndims;
else if (e->ndims != ndims)
Index: src/backend/parser/parse_func.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/parser/parse_func.c,v
retrieving revision 1.148
diff -c -r1.148 parse_func.c
*** src/backend/parser/parse_func.c 26 May 2003 00:11:27 -0000 1.148
--- src/backend/parser/parse_func.c 9 Jun 2003 01:31:10 -0000
***************
*** 335,340 ****
--- 335,341 ----
aggref->target = lfirst(fargs);
aggref->aggstar = agg_star;
aggref->aggdistinct = agg_distinct;
+ aggref->args = fargs;
retval = (Node *) aggref;
Index: src/backend/parser/parse_oper.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/parser/parse_oper.c,v
retrieving revision 1.64
diff -c -r1.64 parse_oper.c
*** src/backend/parser/parse_oper.c 26 May 2003 00:11:27 -0000 1.64
--- src/backend/parser/parse_oper.c 9 Jun 2003 01:31:10 -0000
***************
*** 137,142 ****
--- 137,169 ----
equality_oper(Oid argtype, bool noError)
{
Operator optup;
+ Oid elem_type = get_element_type(argtype);
+
+ if (OidIsValid(elem_type))
+ {
+ bool found = false;
+ /*
+ * If the datatype is an array, look for an "=" operator for the
+ * element datatype. We require it to be an exact or binary-compatible
+ * match, since most callers are not prepared to cope with adding any
+ * run-time type coercion steps.
+ */
+ optup = equality_oper(elem_type, true);
+ if (optup != NULL)
+ {
+ found = true;
+ ReleaseSysCache(optup);
+ }
+
+ if (!found)
+ {
+ if (!noError)
+ elog(ERROR, "Unable to identify an equality operator for " \
+ "array type's element type %s",
+ format_type_be(elem_type));
+ return NULL;
+ }
+ }
/*
* Look for an "=" operator for the datatype. We require it to be
***************
*** 175,180 ****
--- 202,234 ----
ordering_oper(Oid argtype, bool noError)
{
Operator optup;
+ Oid elem_type = get_element_type(argtype);
+
+ if (OidIsValid(elem_type))
+ {
+ bool found = false;
+ /*
+ * If the datatype is an array, find the array element type's equality
+ * operator, and use its lsortop (it *must* be mergejoinable). We use
+ * this definition because for sorting and grouping purposes, it's
+ * important that the equality and ordering operators are consistent.
+ */
+ optup = ordering_oper(elem_type, true);
+ if (optup != NULL)
+ {
+ found = true;
+ ReleaseSysCache(optup);
+ }
+
+ if (!found)
+ {
+ if (!noError)
+ elog(ERROR, "Unable to identify an ordering operator for " \
+ "array type's element type %s",
+ format_type_be(elem_type));
+ return NULL;
+ }
+ }
/*
* Find the type's equality operator, and use its lsortop (it *must*
***************
*** 215,220 ****
--- 269,289 ----
Oid result;
optup = equality_oper(argtype, false);
+ result = oprfuncid(optup);
+ ReleaseSysCache(optup);
+ return result;
+ }
+
+ /*
+ * ordering_oper_funcid - convenience routine for oprfuncid(ordering_oper())
+ */
+ Oid
+ ordering_oper_funcid(Oid argtype)
+ {
+ Operator optup;
+ Oid result;
+
+ optup = ordering_oper(argtype, false);
result = oprfuncid(optup);
ReleaseSysCache(optup);
return result;
Index: src/backend/utils/adt/acl.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/adt/acl.c,v
retrieving revision 1.86
diff -c -r1.86 acl.c
*** src/backend/utils/adt/acl.c 24 Jan 2003 21:53:29 -0000 1.86
--- src/backend/utils/adt/acl.c 9 Jun 2003 01:31:10 -0000
***************
*** 720,732 ****
aidat = ACL_DAT(acl);
for (i = 0; i < num; ++i)
{
! if (aip->ai_grantee == aidat[i].ai_grantee &&
! aip->ai_privs == aidat[i].ai_privs)
PG_RETURN_BOOL(true);
}
PG_RETURN_BOOL(false);
}
/*
* has_table_privilege variants
--- 720,740 ----
aidat = ACL_DAT(acl);
for (i = 0; i < num; ++i)
{
! if (aclitemeq(aip, &aidat[i]))
PG_RETURN_BOOL(true);
}
PG_RETURN_BOOL(false);
}
+ /*
+ * user-facing version of aclitemeq() for use as the
+ * aclitem equality operator
+ */
+ Datum
+ aclitem_eq(PG_FUNCTION_ARGS)
+ {
+ PG_RETURN_BOOL(aclitemeq(PG_GETARG_ACLITEM_P(0), PG_GETARG_ACLITEM_P(1)));
+ }
/*
* has_table_privilege variants
Index: src/backend/utils/adt/array_userfuncs.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/adt/array_userfuncs.c,v
retrieving revision 1.1
diff -c -r1.1 array_userfuncs.c
*** src/backend/utils/adt/array_userfuncs.c 8 Apr 2003 23:20:02 -0000 1.1
--- src/backend/utils/adt/array_userfuncs.c 9 Jun 2003 01:46:03 -0000
***************
*** 18,52 ****
#include "utils/lsyscache.h"
#include "utils/syscache.h"
-
- /*-----------------------------------------------------------------------------
- * singleton_array :
- * Form a multi-dimensional array given one starting element.
- *
- * - first argument is the datum with which to build the array
- * - second argument is the number of dimensions the array should have;
- * defaults to 1 if no second argument is provided
- *----------------------------------------------------------------------------
- */
- Datum
- singleton_array(PG_FUNCTION_ARGS)
- {
- Oid elem_type = get_fn_expr_argtype(fcinfo, 0);
- int ndims;
-
- if (elem_type == InvalidOid)
- elog(ERROR, "Cannot determine input datatype");
-
- if (PG_NARGS() == 2)
- ndims = PG_GETARG_INT32(1);
- else
- ndims = 1;
-
- PG_RETURN_ARRAYTYPE_P(create_singleton_array(elem_type,
- PG_GETARG_DATUM(0),
- ndims));
- }
-
/*-----------------------------------------------------------------------------
* array_push :
* push an element onto either end of a one-dimensional array
--- 18,23 ----
***************
*** 70,75 ****
--- 41,47 ----
Oid arg1_typeid = get_fn_expr_argtype(fcinfo, 1);
Oid arg0_elemid;
Oid arg1_elemid;
+ ArrayMetaState *my_extra;
if (arg0_typeid == InvalidOid || arg1_typeid == InvalidOid)
elog(ERROR, "array_push: cannot determine input data types");
***************
*** 95,122 ****
PG_RETURN_NULL(); /* keep compiler quiet */
}
! /* Sanity check: do we have a one-dimensional array */
! if (ARR_NDIM(v) != 1)
! elog(ERROR, "Arrays greater than one-dimension are not supported");
!
! lb = ARR_LBOUND(v);
! dimv = ARR_DIMS(v);
! if (arg0_elemid != InvalidOid)
{
! /* append newelem */
! int ub = dimv[0] + lb[0] - 1;
! indx = ub + 1;
}
else
{
! /* prepend newelem */
! indx = lb[0] - 1;
}
! get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
! result = array_set(v, 1, &indx, newelem, -1,
! typlen, typbyval, typalign, &isNull);
PG_RETURN_ARRAYTYPE_P(result);
}
--- 67,127 ----
PG_RETURN_NULL(); /* keep compiler quiet */
}
! if (ARR_NDIM(v) == 1)
{
! lb = ARR_LBOUND(v);
! dimv = ARR_DIMS(v);
!
! if (arg0_elemid != InvalidOid)
! {
! /* append newelem */
! int ub = dimv[0] + lb[0] - 1;
! indx = ub + 1;
! }
! else
! {
! /* prepend newelem */
! indx = lb[0] - 1;
! }
}
+ else if (ARR_NDIM(v) == 0)
+ indx = 1;
else
+ elog(ERROR, "only empty and one-dimensional arrays are supported");
+
+
+ /*
+ * We arrange to look up info about element type only once per series
+ * of calls, assuming the element type doesn't change underneath us.
+ */
+ my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
+ if (my_extra == NULL)
{
! fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(ArrayMetaState));
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! my_extra->element_type = InvalidOid;
}
! if (my_extra->element_type != element_type)
! {
! /* Get info about element type */
! get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
! my_extra->element_type = element_type;
! my_extra->typlen = typlen;
! my_extra->typbyval = typbyval;
! my_extra->typalign = typalign;
! }
! else
! {
! typlen = my_extra->typlen;
! typbyval = my_extra->typbyval;
! typalign = my_extra->typalign;
! }
!
! result = array_set(v, 1, &indx, newelem, -1, typlen, typbyval,
! typalign, &isNull);
PG_RETURN_ARRAYTYPE_P(result);
}
***************
*** 145,157 ****
/*
* We must have one of the following combinations of inputs:
! * 1) two arrays with ndims1 == ndims2
! * 2) ndims1 == ndims2 - 1
! * 3) ndims1 == ndims2 + 1
*/
ndims1 = ARR_NDIM(v1);
ndims2 = ARR_NDIM(v2);
if (ndims1 != ndims2 && ndims1 != ndims2 - 1 && ndims1 != ndims2 + 1)
elog(ERROR, "Cannot concatenate incompatible arrays of %d and "
"%d dimensions", ndims1, ndims2);
--- 150,177 ----
/*
* We must have one of the following combinations of inputs:
! * 1) one empty array, and one non-empty array
! * 2) both arrays empty
! * 3) two arrays with ndims1 == ndims2
! * 4) ndims1 == ndims2 - 1
! * 5) ndims1 == ndims2 + 1
*/
ndims1 = ARR_NDIM(v1);
ndims2 = ARR_NDIM(v2);
+ /*
+ * short circuit - if one input array is empty, and the other is not,
+ * we return the non-empty one as the result
+ *
+ * if both are empty, return the first one
+ */
+ if (ndims1 == 0 && ndims2 > 0)
+ PG_RETURN_ARRAYTYPE_P(v2);
+
+ if (ndims2 == 0)
+ PG_RETURN_ARRAYTYPE_P(v1);
+
+ /* the rest fall into combo 2, 3, or 4 */
if (ndims1 != ndims2 && ndims1 != ndims2 - 1 && ndims1 != ndims2 + 1)
elog(ERROR, "Cannot concatenate incompatible arrays of %d and "
"%d dimensions", ndims1, ndims2);
***************
*** 266,412 ****
PG_RETURN_ARRAYTYPE_P(result);
}
- /*----------------------------------------------------------------------------
- * array_accum :
- * accumulator to build a 1-D array from input values -- this can be used
- * to create custom aggregates.
- *
- * This function is not marked strict, so we have to be careful about nulls.
- *----------------------------------------------------------------------------
- */
- Datum
- array_accum(PG_FUNCTION_ARGS)
- {
- /* return NULL if both arguments are NULL */
- if (PG_ARGISNULL(0) && PG_ARGISNULL(1))
- PG_RETURN_NULL();
-
- /* create a new 1-D array from the new element if the array is NULL */
- if (PG_ARGISNULL(0))
- {
- Oid tgt_type = get_fn_expr_rettype(fcinfo);
- Oid tgt_elem_type;
-
- if (tgt_type == InvalidOid)
- elog(ERROR, "Cannot determine target array type");
- tgt_elem_type = get_element_type(tgt_type);
- if (tgt_elem_type == InvalidOid)
- elog(ERROR, "Target type is not an array");
-
- PG_RETURN_ARRAYTYPE_P(create_singleton_array(tgt_elem_type,
- PG_GETARG_DATUM(1),
- 1));
- }
-
- /* return the array if the new element is NULL */
- if (PG_ARGISNULL(1))
- PG_RETURN_ARRAYTYPE_P(PG_GETARG_ARRAYTYPE_P_COPY(0));
-
- /*
- * Otherwise this is equivalent to array_push. We hack the call a little
- * so that array_push can see the fn_expr information.
- */
- return array_push(fcinfo);
- }
-
- /*-----------------------------------------------------------------------------
- * array_assign :
- * assign an element of an array to a new value and return the
- * redefined array
- *----------------------------------------------------------------------------
- */
- Datum
- array_assign(PG_FUNCTION_ARGS)
- {
- ArrayType *v;
- int idx_to_chg;
- Datum newelem;
- int *dimv,
- *lb, ub;
- ArrayType *result;
- bool isNull;
- Oid element_type;
- int16 typlen;
- bool typbyval;
- char typalign;
-
- v = PG_GETARG_ARRAYTYPE_P(0);
- idx_to_chg = PG_GETARG_INT32(1);
- newelem = PG_GETARG_DATUM(2);
-
- /* Sanity check: do we have a one-dimensional array */
- if (ARR_NDIM(v) != 1)
- elog(ERROR, "Arrays greater than one-dimension are not supported");
-
- lb = ARR_LBOUND(v);
- dimv = ARR_DIMS(v);
- ub = dimv[0] + lb[0] - 1;
- if (idx_to_chg < lb[0] || idx_to_chg > ub)
- elog(ERROR, "Cannot alter nonexistent array element: %d", idx_to_chg);
-
- element_type = ARR_ELEMTYPE(v);
- /* Sanity check: do we have a non-zero element type */
- if (element_type == 0)
- elog(ERROR, "Invalid array element type: %u", element_type);
-
- get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
-
- result = array_set(v, 1, &idx_to_chg, newelem, -1,
- typlen, typbyval, typalign, &isNull);
-
- PG_RETURN_ARRAYTYPE_P(result);
- }
-
- /*-----------------------------------------------------------------------------
- * array_subscript :
- * return specific element of an array
- *----------------------------------------------------------------------------
- */
- Datum
- array_subscript(PG_FUNCTION_ARGS)
- {
- ArrayType *v;
- int idx;
- int *dimv,
- *lb, ub;
- Datum result;
- bool isNull;
- Oid element_type;
- int16 typlen;
- bool typbyval;
- char typalign;
-
- v = PG_GETARG_ARRAYTYPE_P(0);
- idx = PG_GETARG_INT32(1);
-
- /* Sanity check: do we have a one-dimensional array */
- if (ARR_NDIM(v) != 1)
- elog(ERROR, "Arrays greater than one-dimension are not supported");
-
- lb = ARR_LBOUND(v);
- dimv = ARR_DIMS(v);
- ub = dimv[0] + lb[0] - 1;
- if (idx < lb[0] || idx > ub)
- elog(ERROR, "Cannot return nonexistent array element: %d", idx);
-
- element_type = ARR_ELEMTYPE(v);
- /* Sanity check: do we have a non-zero element type */
- if (element_type == 0)
- elog(ERROR, "Invalid array element type: %u", element_type);
-
- get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
-
- result = array_ref(v, 1, &idx, -1, typlen, typbyval, typalign, &isNull);
-
- PG_RETURN_DATUM(result);
- }
/*
! * actually does the work for singleton_array(), and array_accum() if it is
! * given a null input array.
*/
ArrayType *
! create_singleton_array(Oid element_type, Datum element, int ndims)
{
Datum dvalues[1];
int16 typlen;
--- 286,300 ----
PG_RETURN_ARRAYTYPE_P(result);
}
/*
! * used by text_to_array() in varlena.c
*/
ArrayType *
! create_singleton_array(FunctionCallInfo fcinfo,
! Oid element_type,
! Datum element,
! int ndims)
{
Datum dvalues[1];
int16 typlen;
***************
*** 415,420 ****
--- 303,309 ----
int dims[MAXDIM];
int lbs[MAXDIM];
int i;
+ ArrayMetaState *my_extra;
if (element_type == 0)
elog(ERROR, "Invalid array element type: %u", element_type);
***************
*** 429,435 ****
lbs[i] = 1;
}
! get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
return construct_md_array(dvalues, ndims, dims, lbs, element_type,
typlen, typbyval, typalign);
--- 318,352 ----
lbs[i] = 1;
}
! /*
! * We arrange to look up info about element type only once per series
! * of calls, assuming the element type doesn't change underneath us.
! */
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! if (my_extra == NULL)
! {
! fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(ArrayMetaState));
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! my_extra->element_type = InvalidOid;
! }
!
! if (my_extra->element_type != element_type)
! {
! /* Get info about element type */
! get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
!
! my_extra->element_type = element_type;
! my_extra->typlen = typlen;
! my_extra->typbyval = typbyval;
! my_extra->typalign = typalign;
! }
! else
! {
! typlen = my_extra->typlen;
! typbyval = my_extra->typbyval;
! typalign = my_extra->typalign;
! }
return construct_md_array(dvalues, ndims, dims, lbs, element_type,
typlen, typbyval, typalign);
Index: src/backend/utils/adt/arrayfuncs.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/adt/arrayfuncs.c,v
retrieving revision 1.89
diff -c -r1.89 arrayfuncs.c
*** src/backend/utils/adt/arrayfuncs.c 9 May 2003 23:01:45 -0000 1.89
--- src/backend/utils/adt/arrayfuncs.c 9 Jun 2003 01:31:10 -0000
***************
*** 21,28 ****
--- 21,30 ----
#include "catalog/pg_type.h"
#include "libpq/pqformat.h"
#include "parser/parse_coerce.h"
+ #include "parser/parse_oper.h"
#include "utils/array.h"
#include "utils/builtins.h"
+ #include "utils/datum.h"
#include "utils/memutils.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
***************
*** 70,85 ****
#define RETURN_NULL(type) do { *isNull = true; return (type) 0; } while (0)
- /* I/O function selector for system_cache_lookup */
- typedef enum IOFuncSelector
- {
- IOFunc_input,
- IOFunc_output,
- IOFunc_receive,
- IOFunc_send
- } IOFuncSelector;
-
-
static int ArrayCount(char *str, int *dim, char typdelim);
static Datum *ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim,
FmgrInfo *inputproc, Oid typelem, int32 typmod,
--- 72,77 ----
***************
*** 93,102 ****
static void CopyArrayEls(char *p, Datum *values, int nitems,
int typlen, bool typbyval, char typalign,
bool freedata);
- static void system_cache_lookup(Oid element_type, IOFuncSelector which_func,
- int *typlen, bool *typbyval,
- char *typdelim, Oid *typelem,
- Oid *proc, char *typalign);
static Datum ArrayCast(char *value, bool byval, int len);
static int ArrayCastAndSet(Datum src,
int typlen, bool typbyval, char typalign,
--- 85,90 ----
***************
*** 119,125 ****
char *destPtr,
int *st, int *endp, char *srcPtr,
int typlen, bool typbyval, char typalign);
!
/*---------------------------------------------------------------------
* array_in :
--- 107,113 ----
char *destPtr,
int *st, int *endp, char *srcPtr,
int typlen, bool typbyval, char typalign);
! static int array_cmp(FunctionCallInfo fcinfo);
/*---------------------------------------------------------------------
* array_in :
***************
*** 154,165 ****
dim[MAXDIM],
lBound[MAXDIM];
char typalign;
! /* Get info about element type, including its input conversion proc */
! system_cache_lookup(element_type, IOFunc_input,
! &typlen, &typbyval, &typdelim,
! &typelem, &typinput, &typalign);
! fmgr_info(typinput, &inputproc);
/* Make a modifiable copy of the input */
/* XXX why are we allocating an extra 2 bytes here? */
--- 142,190 ----
dim[MAXDIM],
lBound[MAXDIM];
char typalign;
+ ArrayMetaState *my_extra;
! /*
! * We arrange to look up info about element type, including its input
! * conversion proc only once per series of calls, assuming the element
! * type doesn't change underneath us.
! */
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! if (my_extra == NULL)
! {
! fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(ArrayMetaState));
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! my_extra->element_type = InvalidOid;
! }
!
! if (my_extra->element_type != element_type)
! {
! /* Get info about element type, including its input conversion proc */
! get_type_metadata(element_type, IOFunc_input,
! &typlen, &typbyval, &typdelim,
! &typelem, &typinput, &typalign);
! fmgr_info(typinput, &inputproc);
!
! my_extra->element_type = element_type;
! my_extra->typlen = typlen;
! my_extra->typbyval = typbyval;
! my_extra->typdelim = typdelim;
! my_extra->typelem = typelem;
! my_extra->typiofunc = typinput;
! my_extra->typalign = typalign;
! my_extra->proc = inputproc;
! }
! else
! {
! typlen = my_extra->typlen;
! typbyval = my_extra->typbyval;
! typdelim = my_extra->typdelim;
! typelem = my_extra->typelem;
! typinput = my_extra->typiofunc;
! typalign = my_extra->typalign;
! inputproc = my_extra->proc;
! }
/* Make a modifiable copy of the input */
/* XXX why are we allocating an extra 2 bytes here? */
***************
*** 636,647 ****
indx[MAXDIM];
int ndim,
*dim;
element_type = ARR_ELEMTYPE(v);
! system_cache_lookup(element_type, IOFunc_output,
! &typlen, &typbyval, &typdelim,
! &typelem, &typoutput, &typalign);
! fmgr_info(typoutput, &outputproc);
ndim = ARR_NDIM(v);
dim = ARR_DIMS(v);
--- 661,711 ----
indx[MAXDIM];
int ndim,
*dim;
+ ArrayMetaState *my_extra;
element_type = ARR_ELEMTYPE(v);
!
! /*
! * We arrange to look up info about element type, including its input
! * conversion proc only once per series of calls, assuming the element
! * type doesn't change underneath us.
! */
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! if (my_extra == NULL)
! {
! fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(ArrayMetaState));
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! my_extra->element_type = InvalidOid;
! }
!
! if (my_extra->element_type != element_type)
! {
! /* Get info about element type, including its output conversion proc */
! get_type_metadata(element_type, IOFunc_output,
! &typlen, &typbyval, &typdelim,
! &typelem, &typoutput, &typalign);
! fmgr_info(typoutput, &outputproc);
!
! my_extra->element_type = element_type;
! my_extra->typlen = typlen;
! my_extra->typbyval = typbyval;
! my_extra->typdelim = typdelim;
! my_extra->typelem = typelem;
! my_extra->typiofunc = typoutput;
! my_extra->typalign = typalign;
! my_extra->proc = outputproc;
! }
! else
! {
! typlen = my_extra->typlen;
! typbyval = my_extra->typbyval;
! typdelim = my_extra->typdelim;
! typelem = my_extra->typelem;
! typoutput = my_extra->typiofunc;
! typalign = my_extra->typalign;
! outputproc = my_extra->proc;
! }
ndim = ARR_NDIM(v);
dim = ARR_DIMS(v);
***************
*** 800,805 ****
--- 864,870 ----
dim[MAXDIM],
lBound[MAXDIM];
char typalign;
+ ArrayMetaState *my_extra;
/* Get the array header information */
ndim = pq_getmsgint(buf, 4);
***************
*** 831,844 ****
PG_RETURN_ARRAYTYPE_P(retval);
}
! /* Get info about element type, including its receive conversion proc */
! system_cache_lookup(element_type, IOFunc_receive,
! &typlen, &typbyval, &typdelim,
! &typelem, &typreceive, &typalign);
! if (!OidIsValid(typreceive))
! elog(ERROR, "No binary input function available for type %s",
! format_type_be(element_type));
! fmgr_info(typreceive, &receiveproc);
dataPtr = ReadArrayBinary(buf, nitems, &receiveproc, typelem,
typlen, typbyval, typalign,
--- 896,945 ----
PG_RETURN_ARRAYTYPE_P(retval);
}
! /*
! * We arrange to look up info about element type, including its receive
! * conversion proc only once per series of calls, assuming the element
! * type doesn't change underneath us.
! */
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! if (my_extra == NULL)
! {
! fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(ArrayMetaState));
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! my_extra->element_type = InvalidOid;
! }
!
! if (my_extra->element_type != element_type)
! {
! /* Get info about element type, including its receive conversion proc */
! get_type_metadata(element_type, IOFunc_receive,
! &typlen, &typbyval, &typdelim,
! &typelem, &typreceive, &typalign);
! if (!OidIsValid(typreceive))
! elog(ERROR, "No binary input function available for type %s",
! format_type_be(element_type));
! fmgr_info(typreceive, &receiveproc);
!
! my_extra->element_type = element_type;
! my_extra->typlen = typlen;
! my_extra->typbyval = typbyval;
! my_extra->typdelim = typdelim;
! my_extra->typelem = typelem;
! my_extra->typiofunc = typreceive;
! my_extra->typalign = typalign;
! my_extra->proc = receiveproc;
! }
! else
! {
! typlen = my_extra->typlen;
! typbyval = my_extra->typbyval;
! typdelim = my_extra->typdelim;
! typelem = my_extra->typelem;
! typreceive = my_extra->typiofunc;
! typalign = my_extra->typalign;
! receiveproc = my_extra->proc;
! }
dataPtr = ReadArrayBinary(buf, nitems, &receiveproc, typelem,
typlen, typbyval, typalign,
***************
*** 976,990 ****
int ndim,
*dim;
StringInfoData buf;
/* Get information about the element type and the array dimensions */
element_type = ARR_ELEMTYPE(v);
! system_cache_lookup(element_type, IOFunc_send, &typlen, &typbyval,
! &typdelim, &typelem, &typsend, &typalign);
! if (!OidIsValid(typsend))
! elog(ERROR, "No binary output function available for type %s",
! format_type_be(element_type));
! fmgr_info(typsend, &sendproc);
ndim = ARR_NDIM(v);
dim = ARR_DIMS(v);
--- 1077,1130 ----
int ndim,
*dim;
StringInfoData buf;
+ ArrayMetaState *my_extra;
/* Get information about the element type and the array dimensions */
element_type = ARR_ELEMTYPE(v);
!
! /*
! * We arrange to look up info about element type, including its send
! * proc only once per series of calls, assuming the element
! * type doesn't change underneath us.
! */
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! if (my_extra == NULL)
! {
! fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(ArrayMetaState));
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! my_extra->element_type = InvalidOid;
! }
!
! if (my_extra->element_type != element_type)
! {
! /* Get info about element type, including its send proc */
! get_type_metadata(element_type, IOFunc_send, &typlen, &typbyval,
! &typdelim, &typelem, &typsend, &typalign);
! if (!OidIsValid(typsend))
! elog(ERROR, "No binary output function available for type %s",
! format_type_be(element_type));
! fmgr_info(typsend, &sendproc);
!
! my_extra->element_type = element_type;
! my_extra->typlen = typlen;
! my_extra->typbyval = typbyval;
! my_extra->typdelim = typdelim;
! my_extra->typelem = typelem;
! my_extra->typiofunc = typsend;
! my_extra->typalign = typalign;
! my_extra->proc = sendproc;
! }
! else
! {
! typlen = my_extra->typlen;
! typbyval = my_extra->typbyval;
! typdelim = my_extra->typdelim;
! typelem = my_extra->typelem;
! typsend = my_extra->typiofunc;
! typalign = my_extra->typalign;
! sendproc = my_extra->proc;
! }
ndim = ARR_NDIM(v);
dim = ARR_DIMS(v);
***************
*** 1476,1481 ****
--- 1616,1641 ----
array = DatumGetArrayTypeP(PointerGetDatum(array));
ndim = ARR_NDIM(array);
+
+ /*
+ * if number of dims is zero, i.e. an empty array, create an array
+ * with nSubscripts dimensions, and set the lower bounds to the supplied
+ * subscripts
+ */
+ if (ndim == 0)
+ {
+ Oid elmtype = ARR_ELEMTYPE(array);
+
+ for (i = 0; i < nSubscripts; i++)
+ {
+ dim[i] = 1;
+ lb[i] = indx[i];
+ }
+
+ return construct_md_array(&dataValue, nSubscripts, dim, lb, elmtype,
+ elmlen, elmbyval, elmalign);
+ }
+
if (ndim != nSubscripts || ndim <= 0 || ndim > MAXDIM)
elog(ERROR, "Invalid array subscripts");
***************
*** 1632,1637 ****
--- 1792,1822 ----
/* note: we assume srcArray contains no toasted elements */
ndim = ARR_NDIM(array);
+
+ /*
+ * if number of dims is zero, i.e. an empty array, create an array
+ * with nSubscripts dimensions, and set the upper and lower bounds
+ * to the supplied subscripts
+ */
+ if (ndim == 0)
+ {
+ Datum *dvalues;
+ int nelems;
+ Oid elmtype = ARR_ELEMTYPE(array);
+
+ deconstruct_array(srcArray, elmtype, elmlen, elmbyval, elmalign,
+ &dvalues, &nelems);
+
+ for (i = 0; i < nSubscripts; i++)
+ {
+ dim[i] = 1 + upperIndx[i] - lowerIndx[i];
+ lb[i] = lowerIndx[i];
+ }
+
+ return construct_md_array(dvalues, nSubscripts, dim, lb, elmtype,
+ elmlen, elmbyval, elmalign);
+ }
+
if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM)
elog(ERROR, "Invalid array subscripts");
***************
*** 1811,1816 ****
--- 1996,2008 ----
Oid typelem;
Oid proc;
char *s;
+ typedef struct {
+ ArrayMetaState *inp_extra;
+ ArrayMetaState *ret_extra;
+ } am_extra;
+ am_extra *my_extra;
+ ArrayMetaState *inp_extra;
+ ArrayMetaState *ret_extra;
/* Get input array */
if (fcinfo->nargs < 1)
***************
*** 1829,1839 ****
if (nitems <= 0)
PG_RETURN_ARRAYTYPE_P(v);
! /* Lookup source and result types. Unneeded variables are reused. */
! system_cache_lookup(inpType, IOFunc_input, &inp_typlen, &inp_typbyval,
! &typdelim, &typelem, &proc, &inp_typalign);
! system_cache_lookup(retType, IOFunc_input, &typlen, &typbyval,
! &typdelim, &typelem, &proc, &typalign);
/* Allocate temporary array for new values */
values = (Datum *) palloc(nitems * sizeof(Datum));
--- 2021,2101 ----
if (nitems <= 0)
PG_RETURN_ARRAYTYPE_P(v);
! /*
! * We arrange to look up info about input and return element types only
! * once per series of calls, assuming the element type doesn't change
! * underneath us.
! */
! my_extra = (am_extra *) fcinfo->flinfo->fn_extra;
! if (my_extra == NULL)
! {
! fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(am_extra));
! my_extra = (am_extra *) fcinfo->flinfo->fn_extra;
!
! my_extra->inp_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(ArrayMetaState));
! inp_extra = my_extra->inp_extra;
! inp_extra->element_type = InvalidOid;
!
! my_extra->ret_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(ArrayMetaState));
! ret_extra = my_extra->ret_extra;
! ret_extra->element_type = InvalidOid;
! }
! else
! {
! inp_extra = my_extra->inp_extra;
! ret_extra = my_extra->ret_extra;
! }
!
! if (inp_extra->element_type != inpType)
! {
! /* Lookup source and result types. Unneeded variables are reused. */
! get_type_metadata(inpType, IOFunc_input, &inp_typlen, &inp_typbyval,
! &typdelim, &typelem, &proc, &inp_typalign);
!
! inp_extra->element_type = inpType;
! inp_extra->typlen = inp_typlen;
! inp_extra->typbyval = inp_typbyval;
! inp_extra->typdelim = typdelim;
! inp_extra->typelem = typelem;
! inp_extra->typiofunc = proc;
! inp_extra->typalign = inp_typalign;
! }
! else
! {
! inp_typlen = inp_extra->typlen;
! inp_typbyval = inp_extra->typbyval;
! typdelim = inp_extra->typdelim;
! typelem = inp_extra->typelem;
! proc = inp_extra->typiofunc;
! inp_typalign = inp_extra->typalign;
! }
!
! if (ret_extra->element_type != retType)
! {
! /* Lookup source and result types. Unneeded variables are reused. */
! get_type_metadata(retType, IOFunc_input, &typlen, &typbyval,
! &typdelim, &typelem, &proc, &typalign);
!
! ret_extra->element_type = retType;
! ret_extra->typlen = typlen;
! ret_extra->typbyval = typbyval;
! ret_extra->typdelim = typdelim;
! ret_extra->typelem = typelem;
! ret_extra->typiofunc = proc;
! ret_extra->typalign = typalign;
! }
! else
! {
! typlen = ret_extra->typlen;
! typbyval = ret_extra->typbyval;
! typdelim = ret_extra->typdelim;
! typelem = ret_extra->typelem;
! proc = ret_extra->typiofunc;
! typalign = ret_extra->typalign;
! }
/* Allocate temporary array for new values */
values = (Datum *) palloc(nitems * sizeof(Datum));
***************
*** 2049,2056 ****
* compares two arrays for equality
* result :
* returns true if the arrays are equal, false otherwise.
- *
- * XXX bitwise equality is pretty bogus ...
*-----------------------------------------------------------------------------
*/
Datum
--- 2311,2316 ----
***************
*** 2058,2069 ****
{
ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
bool result = true;
! if (ARR_SIZE(array1) != ARR_SIZE(array2))
! result = false;
! else if (memcmp(array1, array2, ARR_SIZE(array1)) != 0)
result = false;
/* Avoid leaking memory when handed toasted input. */
PG_FREE_IF_COPY(array1, 0);
--- 2318,2435 ----
{
ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
+ char *p1 = (char *) ARR_DATA_PTR(array1);
+ char *p2 = (char *) ARR_DATA_PTR(array2);
+ int ndims1 = ARR_NDIM(array1);
+ int ndims2 = ARR_NDIM(array2);
+ int *dims1 = ARR_DIMS(array1);
+ int *dims2 = ARR_DIMS(array2);
+ int nitems1 = ArrayGetNItems(ndims1, dims1);
+ int nitems2 = ArrayGetNItems(ndims2, dims2);
+ Oid element_type = ARR_ELEMTYPE(array1);
+ FmgrInfo *ae_fmgr_info = fcinfo->flinfo;
bool result = true;
+ int typlen;
+ bool typbyval;
+ char typdelim;
+ Oid typelem;
+ char typalign;
+ Oid typiofunc;
+ int i;
+ ArrayMetaState *my_extra;
+ FunctionCallInfoData locfcinfo;
! /* fast path if the arrays do not have the same number of elements */
! if (nitems1 != nitems2)
result = false;
+ else
+ {
+ /*
+ * We arrange to look up the equality function only once per series of
+ * calls, assuming the element type doesn't change underneath us.
+ */
+ my_extra = (ArrayMetaState *) ae_fmgr_info->fn_extra;
+ if (my_extra == NULL)
+ {
+ ae_fmgr_info->fn_extra = MemoryContextAlloc(ae_fmgr_info->fn_mcxt,
+ sizeof(ArrayMetaState));
+ my_extra = (ArrayMetaState *) ae_fmgr_info->fn_extra;
+ my_extra->element_type = InvalidOid;
+ }
+
+ if (my_extra->element_type != element_type)
+ {
+ Oid opfuncid = equality_oper_funcid(element_type);
+
+ if (OidIsValid(opfuncid))
+ fmgr_info_cxt(opfuncid, &my_extra->proc, ae_fmgr_info->fn_mcxt);
+ else
+ elog(ERROR,
+ "array_eq: cannot find equality operator for type: %u",
+ element_type);
+
+ get_type_metadata(element_type, IOFunc_output,
+ &typlen, &typbyval, &typdelim,
+ &typelem, &typiofunc, &typalign);
+
+ my_extra->element_type = element_type;
+ my_extra->typlen = typlen;
+ my_extra->typbyval = typbyval;
+ my_extra->typdelim = typdelim;
+ my_extra->typelem = typelem;
+ my_extra->typiofunc = typiofunc;
+ my_extra->typalign = typalign;
+ }
+ else
+ {
+ typlen = my_extra->typlen;
+ typbyval = my_extra->typbyval;
+ typdelim = my_extra->typdelim;
+ typelem = my_extra->typelem;
+ typiofunc = my_extra->typiofunc;
+ typalign = my_extra->typalign;
+ }
+
+ /*
+ * apply the operator to each pair of array elements.
+ */
+ MemSet(&locfcinfo, 0, sizeof(locfcinfo));
+ locfcinfo.flinfo = &my_extra->proc;
+ locfcinfo.nargs = 2;
+
+ /* Loop over source data */
+ for (i = 0; i < nitems1; i++)
+ {
+ Datum elt1;
+ Datum elt2;
+ bool oprresult;
+
+ /* Get element pair */
+ elt1 = fetch_att(p1, typbyval, typlen);
+ elt2 = fetch_att(p2, typbyval, typlen);
+
+ p1 = att_addlength(p1, typlen, PointerGetDatum(p1));
+ p1 = (char *) att_align(p1, typalign);
+
+ p2 = att_addlength(p2, typlen, PointerGetDatum(p2));
+ p2 = (char *) att_align(p2, typalign);
+
+ /*
+ * Apply the operator to the element pair
+ */
+ locfcinfo.arg[0] = elt1;
+ locfcinfo.arg[1] = elt2;
+ locfcinfo.argnull[0] = false;
+ locfcinfo.argnull[1] = false;
+ locfcinfo.isnull = false;
+ oprresult = DatumGetBool(FunctionCallInvoke(&locfcinfo));
+ if (!oprresult)
+ {
+ result = false;
+ break;
+ }
+ }
+ }
/* Avoid leaking memory when handed toasted input. */
PG_FREE_IF_COPY(array1, 0);
***************
*** 2073,2125 ****
}
! /***************************************************************************/
! /******************| Support Routines |*****************/
! /***************************************************************************/
! static void
! system_cache_lookup(Oid element_type,
! IOFuncSelector which_func,
! int *typlen,
! bool *typbyval,
! char *typdelim,
! Oid *typelem,
! Oid *proc,
! char *typalign)
! {
! HeapTuple typeTuple;
! Form_pg_type typeStruct;
!
! typeTuple = SearchSysCache(TYPEOID,
! ObjectIdGetDatum(element_type),
! 0, 0, 0);
! if (!HeapTupleIsValid(typeTuple))
! elog(ERROR, "cache lookup failed for type %u", element_type);
! typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
!
! *typlen = typeStruct->typlen;
! *typbyval = typeStruct->typbyval;
! *typdelim = typeStruct->typdelim;
! *typelem = typeStruct->typelem;
! *typalign = typeStruct->typalign;
! switch (which_func)
! {
! case IOFunc_input:
! *proc = typeStruct->typinput;
! break;
! case IOFunc_output:
! *proc = typeStruct->typoutput;
! break;
! case IOFunc_receive:
! *proc = typeStruct->typreceive;
! break;
! case IOFunc_send:
! *proc = typeStruct->typsend;
! break;
}
! ReleaseSysCache(typeTuple);
}
/*
* Fetch array element at pointer, converted correctly to a Datum
*/
--- 2439,2628 ----
}
! /*-----------------------------------------------------------------------------
! * array-array bool operators:
! * Given two arrays, iterate comparison operators
! * over the array. Uses logic similar to text comparison
! * functions, except element-by-element instead of
! * character-by-character.
! *----------------------------------------------------------------------------
! */
! Datum
! array_ne(PG_FUNCTION_ARGS)
! {
! PG_RETURN_BOOL(!DatumGetBool(array_eq(fcinfo)));
! }
! Datum
! array_lt(PG_FUNCTION_ARGS)
! {
! PG_RETURN_BOOL(array_cmp(fcinfo) < 0);
! }
!
! Datum
! array_gt(PG_FUNCTION_ARGS)
! {
! PG_RETURN_BOOL(array_cmp(fcinfo) > 0);
! }
!
! Datum
! array_le(PG_FUNCTION_ARGS)
! {
! PG_RETURN_BOOL(array_cmp(fcinfo) <= 0);
! }
!
! Datum
! array_ge(PG_FUNCTION_ARGS)
! {
! PG_RETURN_BOOL(array_cmp(fcinfo) >= 0);
! }
!
! Datum
! btarraycmp(PG_FUNCTION_ARGS)
! {
! PG_RETURN_INT32(array_cmp(fcinfo));
! }
!
! /*
! * array_cmp()
! * Internal comparison function for arrays.
! *
! * Returns -1, 0 or 1
! */
! static int
! array_cmp(FunctionCallInfo fcinfo)
! {
! ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
! ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
! FmgrInfo *ac_fmgr_info = fcinfo->flinfo;
! Datum opresult;
! int result = 0;
! Oid element_type = InvalidOid;
! int typlen;
! bool typbyval;
! char typdelim;
! Oid typelem;
! char typalign;
! Oid typiofunc;
! Datum *dvalues1;
! int nelems1;
! Datum *dvalues2;
! int nelems2;
! int min_nelems;
! int i;
! typedef struct
! {
! Oid element_type;
! int typlen;
! bool typbyval;
! char typdelim;
! Oid typelem;
! Oid typiofunc;
! char typalign;
! FmgrInfo eqproc;
! FmgrInfo ordproc;
! } ac_extra;
! ac_extra *my_extra;
!
! element_type = ARR_ELEMTYPE(array1);
!
! /*
! * We arrange to look up the element type operator function only once
! * per series of calls, assuming the element type and opname don't
! * change underneath us.
! */
! my_extra = (ac_extra *) ac_fmgr_info->fn_extra;
! if (my_extra == NULL)
! {
! ac_fmgr_info->fn_extra = MemoryContextAlloc(ac_fmgr_info->fn_mcxt,
! sizeof(ac_extra));
! my_extra = (ac_extra *) ac_fmgr_info->fn_extra;
! my_extra->element_type = InvalidOid;
! }
!
! if (my_extra->element_type != element_type)
! {
! Oid eqfuncid = equality_oper_funcid(element_type);
! Oid ordfuncid = ordering_oper_funcid(element_type);
!
! fmgr_info_cxt(eqfuncid, &my_extra->eqproc, ac_fmgr_info->fn_mcxt);
! fmgr_info_cxt(ordfuncid, &my_extra->ordproc, ac_fmgr_info->fn_mcxt);
!
! if (my_extra->eqproc.fn_nargs != 2)
! elog(ERROR, "Equality operator does not take 2 arguments: %u",
! eqfuncid);
! if (my_extra->ordproc.fn_nargs != 2)
! elog(ERROR, "Ordering operator does not take 2 arguments: %u",
! ordfuncid);
!
! get_type_metadata(element_type, IOFunc_output,
! &typlen, &typbyval, &typdelim,
! &typelem, &typiofunc, &typalign);
!
! my_extra->element_type = element_type;
! my_extra->typlen = typlen;
! my_extra->typbyval = typbyval;
! my_extra->typdelim = typdelim;
! my_extra->typelem = typelem;
! my_extra->typiofunc = InvalidOid;
! my_extra->typalign = typalign;
! }
! else
! {
! typlen = my_extra->typlen;
! typbyval = my_extra->typbyval;
! typalign = my_extra->typalign;
! }
!
! /* extract a C array of arg array datums */
! deconstruct_array(array1, element_type, typlen, typbyval, typalign,
! &dvalues1, &nelems1);
!
! deconstruct_array(array2, element_type, typlen, typbyval, typalign,
! &dvalues2, &nelems2);
!
! min_nelems = Min(nelems1, nelems2);
! for (i = 0; i < min_nelems; i++)
! {
! /* are they equal */
! opresult = FunctionCall2(&my_extra->eqproc,
! dvalues1[i], dvalues2[i]);
!
! if (!DatumGetBool(opresult))
! {
! /* nope, see if arg1 is less than arg2 */
! opresult = FunctionCall2(&my_extra->ordproc,
! dvalues1[i], dvalues2[i]);
! if (DatumGetBool(opresult))
! {
! /* arg1 is less than arg2 */
! result = -1;
! break;
! }
! else
! {
! /* arg1 is greater than arg2 */
! result = 1;
! break;
! }
! }
}
!
! if ((result == 0) && (nelems1 != nelems2))
! result = (nelems1 < nelems2) ? -1 : 1;
!
! /* Avoid leaking memory when handed toasted input. */
! PG_FREE_IF_COPY(array1, 0);
! PG_FREE_IF_COPY(array2, 1);
!
! return result;
}
+
+ /***************************************************************************/
+ /******************| Support Routines |*****************/
+ /***************************************************************************/
+
/*
* Fetch array element at pointer, converted correctly to a Datum
*/
***************
*** 2423,2428 ****
--- 2926,2943 ----
if (tgt_elem_type == InvalidOid)
elog(ERROR, "Target type is not an array");
+ /*
+ * We don't deal with domain constraints yet, so bail out.
+ * This isn't currently a problem, because we also don't
+ * support arrays of domain type elements either. But in the
+ * future we might. At that point consideration should be given
+ * to removing the check below and adding a domain constraints
+ * check to the coercion.
+ */
+ if (getBaseType(tgt_elem_type) != tgt_elem_type)
+ elog(ERROR, "array coercion to domain type elements not " \
+ "currently supported");
+
if (!find_coercion_pathway(tgt_elem_type, src_elem_type,
COERCION_EXPLICIT, &funcId))
{
***************
*** 2439,2448 ****
}
/*
! * If it's binary-compatible, return the array unmodified.
*/
if (my_extra->coerce_finfo.fn_oid == InvalidOid)
! PG_RETURN_ARRAYTYPE_P(src);
/*
* Use array_map to apply the function to each array element.
--- 2954,2969 ----
}
/*
! * If it's binary-compatible, modify the element type in the array header,
! * but otherwise leave the array as we received it.
*/
if (my_extra->coerce_finfo.fn_oid == InvalidOid)
! {
! ArrayType *result = DatumGetArrayTypePCopy(PG_GETARG_DATUM(0));
!
! ARR_ELEMTYPE(result) = my_extra->desttype;
! PG_RETURN_ARRAYTYPE_P(result);
! }
/*
* Use array_map to apply the function to each array element.
***************
*** 2453,2456 ****
--- 2974,3092 ----
locfcinfo.arg[0] = PointerGetDatum(src);
return array_map(&locfcinfo, my_extra->srctype, my_extra->desttype);
+ }
+
+ /*
+ * accumArrayResult - accumulate one (more) Datum for an ARRAY_SUBLINK
+ *
+ * astate is working state (NULL on first call)
+ * rcontext is where to keep working state
+ */
+ ArrayBuildState *
+ accumArrayResult(ArrayBuildState *astate,
+ Datum dvalue, bool disnull,
+ Oid element_type,
+ MemoryContext rcontext)
+ {
+ MemoryContext arr_context,
+ oldcontext;
+
+ if (astate == NULL)
+ {
+ /* First time through --- initialize */
+
+ /* Make a temporary context to hold all the junk */
+ arr_context = AllocSetContextCreate(rcontext,
+ "accumArrayResult",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+ oldcontext = MemoryContextSwitchTo(arr_context);
+ astate = (ArrayBuildState *) palloc(sizeof(ArrayBuildState));
+ astate->mcontext = arr_context;
+ astate->dvalues = (Datum *)
+ palloc(ARRAY_ELEMS_CHUNKSIZE * sizeof(Datum));
+ astate->nelems = 0;
+ astate->element_type = element_type;
+ get_typlenbyvalalign(element_type,
+ &astate->typlen,
+ &astate->typbyval,
+ &astate->typalign);
+ }
+ else
+ {
+ oldcontext = MemoryContextSwitchTo(astate->mcontext);
+ Assert(astate->element_type == element_type);
+ /* enlarge dvalues[] if needed */
+ if ((astate->nelems % ARRAY_ELEMS_CHUNKSIZE) == 0)
+ astate->dvalues = (Datum *)
+ repalloc(astate->dvalues,
+ (astate->nelems + ARRAY_ELEMS_CHUNKSIZE) * sizeof(Datum));
+ }
+
+ if (disnull)
+ elog(ERROR, "NULL elements not allowed in Arrays");
+
+ /* Use datumCopy to ensure pass-by-ref stuff is copied into mcontext */
+ astate->dvalues[astate->nelems++] =
+ datumCopy(dvalue, astate->typbyval, astate->typlen);
+
+ MemoryContextSwitchTo(oldcontext);
+
+ return astate;
+ }
+
+ /*
+ * makeArrayResult - produce final result of accumArrayResult
+ *
+ * astate is working state (not NULL)
+ * rcontext is where to construct result
+ */
+ Datum
+ makeArrayResult(ArrayBuildState *astate,
+ MemoryContext rcontext)
+ {
+ int dims[1];
+ int lbs[1];
+
+ dims[0] = astate->nelems;
+ lbs[0] = 1;
+
+ return makeMdArrayResult(astate, 1, dims, lbs, rcontext);
+ }
+
+ /*
+ * makeMdArrayResult - produce md final result of accumArrayResult
+ *
+ * astate is working state (not NULL)
+ * rcontext is where to construct result
+ */
+ Datum
+ makeMdArrayResult(ArrayBuildState *astate,
+ int ndims,
+ int *dims,
+ int *lbs,
+ MemoryContext rcontext)
+ {
+ ArrayType *result;
+ MemoryContext oldcontext;
+
+ /* Build the final array result in rcontext */
+ oldcontext = MemoryContextSwitchTo(rcontext);
+
+ result = construct_md_array(astate->dvalues,
+ ndims,
+ dims,
+ lbs,
+ astate->element_type,
+ astate->typlen,
+ astate->typbyval,
+ astate->typalign);
+
+ MemoryContextSwitchTo(oldcontext);
+
+ /* Clean up all the junk */
+ MemoryContextDelete(astate->mcontext);
+
+ return PointerGetDatum(result);
}
Index: src/backend/utils/adt/varlena.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/adt/varlena.c,v
retrieving revision 1.98
diff -c -r1.98 varlena.c
*** src/backend/utils/adt/varlena.c 15 May 2003 15:50:19 -0000 1.98
--- src/backend/utils/adt/varlena.c 9 Jun 2003 01:31:10 -0000
***************
*** 19,29 ****
--- 19,32 ----
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "access/tuptoaster.h"
+ #include "catalog/pg_type.h"
#include "lib/stringinfo.h"
#include "libpq/crypt.h"
#include "libpq/pqformat.h"
+ #include "utils/array.h"
#include "utils/builtins.h"
#include "utils/pg_locale.h"
+ #include "utils/lsyscache.h"
typedef struct varlena unknown;
***************
*** 1983,1990 ****
if (fldnum == 1) /* first field - just return the input
* string */
PG_RETURN_TEXT_P(inputstring);
! else
! /* otherwise return an empty string */
PG_RETURN_TEXT_P(PG_STR_GET_TEXT(""));
}
--- 1986,1992 ----
if (fldnum == 1) /* first field - just return the input
* string */
PG_RETURN_TEXT_P(inputstring);
! else /* otherwise return an empty string */
PG_RETURN_TEXT_P(PG_STR_GET_TEXT(""));
}
***************
*** 2004,2011 ****
if (fldnum == 1) /* first field - just return the input
* string */
PG_RETURN_TEXT_P(inputstring);
! else
! /* otherwise return an empty string */
PG_RETURN_TEXT_P(PG_STR_GET_TEXT(""));
}
else if ((start_posn != 0) && (end_posn == 0))
--- 2006,2012 ----
if (fldnum == 1) /* first field - just return the input
* string */
PG_RETURN_TEXT_P(inputstring);
! else /* otherwise return an empty string */
PG_RETURN_TEXT_P(PG_STR_GET_TEXT(""));
}
else if ((start_posn != 0) && (end_posn == 0))
***************
*** 2026,2031 ****
--- 2027,2217 ----
result_text = text_substring(PointerGetDatum(inputstring), start_posn + fldsep_len, end_posn - start_posn - fldsep_len, false);
PG_RETURN_TEXT_P(result_text);
}
+ }
+
+ /*
+ * text_to_array
+ * parse input string
+ * return text array of elements
+ * based on provided field separator
+ */
+ Datum
+ text_to_array(PG_FUNCTION_ARGS)
+ {
+ text *inputstring = PG_GETARG_TEXT_P(0);
+ int inputstring_len = TEXTLEN(inputstring);
+ text *fldsep = PG_GETARG_TEXT_P(1);
+ int fldsep_len = TEXTLEN(fldsep);
+ int fldnum;
+ int start_posn = 0;
+ int end_posn = 0;
+ text *result_text = NULL;
+ ArrayBuildState *astate = NULL;
+ MemoryContext oldcontext = CurrentMemoryContext;
+
+ /* return NULL for empty input string */
+ if (inputstring_len < 1)
+ PG_RETURN_NULL();
+
+ /* empty field separator
+ * return one element, 1D, array using the input string */
+ if (fldsep_len < 1)
+ PG_RETURN_ARRAYTYPE_P(create_singleton_array(fcinfo, TEXTOID,
+ CStringGetDatum(inputstring), 1));
+
+ /* start with end position holding the initial start position */
+ end_posn = 0;
+ for (fldnum=1;;fldnum++) /* field number is 1 based */
+ {
+ Datum dvalue;
+ bool disnull = false;
+
+ start_posn = end_posn;
+ end_posn = text_position(PointerGetDatum(inputstring),
+ PointerGetDatum(fldsep),
+ fldnum);
+
+ if ((start_posn == 0) && (end_posn == 0)) /* fldsep not found */
+ {
+ if (fldnum == 1)
+ {
+ /* first element
+ * return one element, 1D, array using the input string */
+ PG_RETURN_ARRAYTYPE_P(create_singleton_array(fcinfo, TEXTOID,
+ CStringGetDatum(inputstring), 1));
+ }
+ else
+ {
+ /* otherwise create array and exit */
+ PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate, oldcontext));
+ }
+ }
+ else if ((start_posn != 0) && (end_posn == 0))
+ {
+ /* last field requested */
+ result_text = text_substring(PointerGetDatum(inputstring), start_posn + fldsep_len, -1, true);
+ }
+ else if ((start_posn == 0) && (end_posn != 0))
+ {
+ /* first field requested */
+ result_text = LEFT(inputstring, fldsep);
+ }
+ else
+ {
+ /* prior to last field requested */
+ result_text = text_substring(PointerGetDatum(inputstring), start_posn + fldsep_len, end_posn - start_posn - fldsep_len, false);
+ }
+
+ /* stash away current value */
+ dvalue = PointerGetDatum(result_text);
+ astate = accumArrayResult(astate, dvalue,
+ disnull, TEXTOID, oldcontext);
+
+ }
+
+ /* never reached -- keep compiler quiet */
+ PG_RETURN_NULL();
+ }
+
+ /*
+ * array_to_text
+ * concatenate Cstring representation of input array elements
+ * using provided field separator
+ */
+ Datum
+ array_to_text(PG_FUNCTION_ARGS)
+ {
+ ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
+ char *fldsep = PG_TEXTARG_GET_STR(1);
+ int nitems, *dims, ndims;
+ char *p;
+ Oid element_type;
+ int typlen;
+ bool typbyval;
+ char typdelim;
+ Oid typoutput,
+ typelem;
+ FmgrInfo outputproc;
+ char typalign;
+ StringInfo result_str = makeStringInfo();
+ int i;
+ ArrayMetaState *my_extra;
+
+ p = ARR_DATA_PTR(v);
+ ndims = ARR_NDIM(v);
+ dims = ARR_DIMS(v);
+ nitems = ArrayGetNItems(ndims, dims);
+
+ /* if there are no elements, return an empty string */
+ if (nitems == 0)
+ PG_RETURN_TEXT_P(PG_STR_GET_TEXT(""));
+
+ element_type = ARR_ELEMTYPE(v);
+
+ /*
+ * We arrange to look up info about element type, including its output
+ * conversion proc only once per series of calls, assuming the element
+ * type doesn't change underneath us.
+ */
+ my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
+ if (my_extra == NULL)
+ {
+ fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
+ sizeof(ArrayMetaState));
+ my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
+ my_extra->element_type = InvalidOid;
+ }
+
+ if (my_extra->element_type != element_type)
+ {
+ /* Get info about element type, including its output conversion proc */
+ get_type_metadata(element_type, IOFunc_output,
+ &typlen, &typbyval, &typdelim,
+ &typelem, &typoutput, &typalign);
+ fmgr_info(typoutput, &outputproc);
+
+ my_extra->element_type = element_type;
+ my_extra->typlen = typlen;
+ my_extra->typbyval = typbyval;
+ my_extra->typdelim = typdelim;
+ my_extra->typelem = typelem;
+ my_extra->typiofunc = typoutput;
+ my_extra->typalign = typalign;
+ my_extra->proc = outputproc;
+ }
+ else
+ {
+ typlen = my_extra->typlen;
+ typbyval = my_extra->typbyval;
+ typdelim = my_extra->typdelim;
+ typelem = my_extra->typelem;
+ typoutput = my_extra->typiofunc;
+ typalign = my_extra->typalign;
+ outputproc = my_extra->proc;
+ }
+
+ for (i = 0; i < nitems; i++)
+ {
+ Datum itemvalue;
+ char *value;
+
+ itemvalue = fetch_att(p, typbyval, typlen);
+
+ value = DatumGetCString(FunctionCall3(&outputproc,
+ itemvalue,
+ ObjectIdGetDatum(typelem),
+ Int32GetDatum(-1)));
+
+ if (i > 0)
+ appendStringInfo(result_str, "%s%s", fldsep, value);
+ else
+ appendStringInfo(result_str, "%s", value);
+
+ p = att_addlength(p, typlen, PointerGetDatum(p));
+ p = (char *) att_align(p, typalign);
+ }
+
+ PG_RETURN_TEXT_P(PG_STR_GET_TEXT(result_str->data));
}
#define HEXBASE 16
Index: src/backend/utils/cache/lsyscache.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/cache/lsyscache.c,v
retrieving revision 1.95
diff -c -r1.95 lsyscache.c
*** src/backend/utils/cache/lsyscache.c 26 May 2003 00:11:27 -0000 1.95
--- src/backend/utils/cache/lsyscache.c 9 Jun 2003 01:31:10 -0000
***************
*** 625,630 ****
--- 625,664 ----
}
/*
+ * get_func_argtypes
+ * Given procedure id, return the function's argument types.
+ * Also pass back the number of arguments.
+ */
+ Oid *
+ get_func_argtypes(Oid funcid, int *nargs)
+ {
+ HeapTuple tp;
+ Form_pg_proc procstruct;
+ Oid *result = NULL;
+ int i;
+
+ tp = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "Function OID %u does not exist", funcid);
+
+ procstruct = (Form_pg_proc) GETSTRUCT(tp);
+ *nargs = (int) procstruct->pronargs;
+
+ if (*nargs > 0)
+ {
+ result = (Oid *) palloc(*nargs * sizeof(Oid));
+
+ for (i = 0; i < *nargs; i++)
+ result[i] = procstruct->proargtypes[i];
+ }
+
+ ReleaseSysCache(tp);
+ return result;
+ }
+
+ /*
* get_func_retset
* Given procedure id, return the function's proretset flag.
*/
***************
*** 994,999 ****
--- 1028,1083 ----
*typbyval = typtup->typbyval;
*typalign = typtup->typalign;
ReleaseSysCache(tp);
+ }
+
+ /*
+ * get_type_metadata
+ *
+ * A six-fer: given the type OID, return typlen, typbyval, typalign,
+ * typdelim, typelem, IO function Oid. The IO function
+ * returned is controlled by IOFuncSelector
+ */
+ void
+ get_type_metadata(Oid element_type,
+ IOFuncSelector which_func,
+ int *typlen,
+ bool *typbyval,
+ char *typdelim,
+ Oid *typelem,
+ Oid *proc,
+ char *typalign)
+ {
+ HeapTuple typeTuple;
+ Form_pg_type typeStruct;
+
+ typeTuple = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(element_type),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typeTuple))
+ elog(ERROR, "cache lookup failed for type %u", element_type);
+ typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
+
+ *typlen = typeStruct->typlen;
+ *typbyval = typeStruct->typbyval;
+ *typdelim = typeStruct->typdelim;
+ *typelem = typeStruct->typelem;
+ *typalign = typeStruct->typalign;
+ switch (which_func)
+ {
+ case IOFunc_input:
+ *proc = typeStruct->typinput;
+ break;
+ case IOFunc_output:
+ *proc = typeStruct->typoutput;
+ break;
+ case IOFunc_receive:
+ *proc = typeStruct->typreceive;
+ break;
+ case IOFunc_send:
+ *proc = typeStruct->typsend;
+ break;
+ }
+ ReleaseSysCache(typeTuple);
}
#ifdef NOT_USED
Index: src/backend/utils/fmgr/fmgr.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/fmgr/fmgr.c,v
retrieving revision 1.68
diff -c -r1.68 fmgr.c
*** src/backend/utils/fmgr/fmgr.c 8 Apr 2003 23:20:02 -0000 1.68
--- src/backend/utils/fmgr/fmgr.c 9 Jun 2003 01:31:10 -0000
***************
*** 1673,1675 ****
--- 1673,1701 ----
return exprType((Node *) nth(argnum, args));
}
+
+ /*
+ * Get the OID of the function or operator
+ *
+ * Returns InvalidOid if information is not available
+ */
+ Oid
+ get_fn_expr_functype(FunctionCallInfo fcinfo)
+ {
+ Node *expr;
+
+ /*
+ * can't return anything useful if we have no FmgrInfo or if
+ * its fn_expr node has not been initialized
+ */
+ if (!fcinfo || !fcinfo->flinfo || !fcinfo->flinfo->fn_expr)
+ return InvalidOid;
+
+ expr = fcinfo->flinfo->fn_expr;
+ if (IsA(expr, FuncExpr))
+ return ((FuncExpr *) expr)->funcid;
+ else if (IsA(expr, OpExpr))
+ return ((OpExpr *) expr)->opno;
+ else
+ return InvalidOid;
+ }
Index: src/include/fmgr.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/fmgr.h,v
retrieving revision 1.27
diff -c -r1.27 fmgr.h
*** src/include/fmgr.h 8 Apr 2003 23:20:04 -0000 1.27
--- src/include/fmgr.h 9 Jun 2003 01:31:10 -0000
***************
*** 18,23 ****
--- 18,24 ----
#ifndef FMGR_H
#define FMGR_H
+ #include "nodes/nodes.h"
/*
* All functions that can be called directly by fmgr must have this signature.
***************
*** 372,385 ****
Datum arg6, Datum arg7, Datum arg8,
Datum arg9);
-
/*
* Routines in fmgr.c
*/
extern Pg_finfo_record *fetch_finfo_record(void *filehandle, char *funcname);
! extern Oid fmgr_internal_function(const char *proname);
! extern Oid get_fn_expr_rettype(FunctionCallInfo fcinfo);
! extern Oid get_fn_expr_argtype(FunctionCallInfo fcinfo, int argnum);
/*
* Routines in dfmgr.c
--- 373,386 ----
Datum arg6, Datum arg7, Datum arg8,
Datum arg9);
/*
* Routines in fmgr.c
*/
extern Pg_finfo_record *fetch_finfo_record(void *filehandle, char *funcname);
! extern Oid fmgr_internal_function(const char *proname);
! extern Oid get_fn_expr_rettype(FunctionCallInfo fcinfo);
! extern Oid get_fn_expr_argtype(FunctionCallInfo fcinfo, int argnum);
! extern Oid get_fn_expr_functype(FunctionCallInfo fcinfo);
/*
* Routines in dfmgr.c
Index: src/include/catalog/pg_amop.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/catalog/pg_amop.h,v
retrieving revision 1.49
diff -c -r1.49 pg_amop.h
*** src/include/catalog/pg_amop.h 26 May 2003 00:11:27 -0000 1.49
--- src/include/catalog/pg_amop.h 9 Jun 2003 01:31:10 -0000
***************
*** 418,423 ****
--- 418,432 ----
DATA(insert ( 2098 4 f 2335 ));
DATA(insert ( 2098 5 f 2336 ));
+ /*
+ * btree array_ops
+ */
+
+ DATA(insert ( 397 1 f 1072 ));
+ DATA(insert ( 397 2 f 1074 ));
+ DATA(insert ( 397 3 f 1070 ));
+ DATA(insert ( 397 4 f 1075 ));
+ DATA(insert ( 397 5 f 1073 ));
/*
* hash index _ops
Index: src/include/catalog/pg_amproc.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/catalog/pg_amproc.h,v
retrieving revision 1.37
diff -c -r1.37 pg_amproc.h
*** src/include/catalog/pg_amproc.h 26 May 2003 00:11:27 -0000 1.37
--- src/include/catalog/pg_amproc.h 9 Jun 2003 01:31:10 -0000
***************
*** 78,83 ****
--- 78,84 ----
/* btree */
+ DATA(insert ( 397 1 398 ));
DATA(insert ( 421 1 357 ));
DATA(insert ( 423 1 1596 ));
DATA(insert ( 424 1 1693 ));
Index: src/include/catalog/pg_opclass.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/catalog/pg_opclass.h,v
retrieving revision 1.50
diff -c -r1.50 pg_opclass.h
*** src/include/catalog/pg_opclass.h 28 May 2003 16:04:00 -0000 1.50
--- src/include/catalog/pg_opclass.h 9 Jun 2003 02:48:16 -0000
***************
*** 87,92 ****
--- 87,94 ----
*/
DATA(insert OID = 421 ( 403 abstime_ops PGNSP PGUID 702 t 0 ));
+ DATA(insert OID = 397 ( 403 array_ops PGNSP PGUID 2277 t 0 ));
+ #define ARRAY_BTREE_OPS_OID 397
DATA(insert OID = 422 ( 402 bigbox_ops PGNSP PGUID 603 f 0 ));
DATA(insert OID = 423 ( 403 bit_ops PGNSP PGUID 1560 t 0 ));
DATA(insert OID = 424 ( 403 bool_ops PGNSP PGUID 16 t 0 ));
Index: src/include/catalog/pg_operator.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/catalog/pg_operator.h,v
retrieving revision 1.114
diff -c -r1.114 pg_operator.h
*** src/include/catalog/pg_operator.h 26 May 2003 00:11:27 -0000 1.114
--- src/include/catalog/pg_operator.h 9 Jun 2003 01:31:10 -0000
***************
*** 116,125 ****
DATA(insert OID = 97 ( "<" PGNSP PGUID b f 23 23 16 521 525 0 0 0 0 int4lt scalarltsel scalarltjoinsel ));
DATA(insert OID = 98 ( "=" PGNSP PGUID b t 25 25 16 98 531 664 664 664 666 texteq eqsel eqjoinsel ));
! DATA(insert OID = 329 ( "=" PGNSP PGUID b f 2277 2277 16 329 0 0 0 0 0 array_eq eqsel eqjoinsel ));
! DATA(insert OID = 349 ( "||" PGNSP PGUID b f 2277 2283 2277 0 0 0 0 0 0 array_append - - ));
! DATA(insert OID = 374 ( "||" PGNSP PGUID b f 2283 2277 2277 0 0 0 0 0 0 array_prepend - - ));
! DATA(insert OID = 375 ( "||" PGNSP PGUID b f 2277 2277 2277 0 0 0 0 0 0 array_cat - - ));
DATA(insert OID = 352 ( "=" PGNSP PGUID b t 28 28 16 352 0 0 0 0 0 xideq eqsel eqjoinsel ));
DATA(insert OID = 353 ( "=" PGNSP PGUID b t 28 23 16 0 0 0 0 0 0 xideqint4 eqsel eqjoinsel ));
--- 116,130 ----
DATA(insert OID = 97 ( "<" PGNSP PGUID b f 23 23 16 521 525 0 0 0 0 int4lt scalarltsel scalarltjoinsel ));
DATA(insert OID = 98 ( "=" PGNSP PGUID b t 25 25 16 98 531 664 664 664 666 texteq eqsel eqjoinsel ));
! DATA(insert OID = 1070 ( "=" PGNSP PGUID b f 2277 2277 16 1070 1071 1072 1072 1072 1073 array_eq eqsel eqjoinsel ));
! DATA(insert OID = 1071 ( "<>" PGNSP PGUID b f 2277 2277 16 1071 1070 0 0 0 0 array_ne neqsel neqjoinsel ));
! DATA(insert OID = 1072 ( "<" PGNSP PGUID b f 2277 2277 16 1073 1075 0 0 0 0 array_lt scalarltsel scalarltjoinsel ));
! DATA(insert OID = 1073 ( ">" PGNSP PGUID b f 2277 2277 16 1072 1074 0 0 0 0 array_gt scalargtsel scalargtjoinsel ));
! DATA(insert OID = 1074 ( "<=" PGNSP PGUID b f 2277 2277 16 1075 1073 0 0 0 0 array_le scalarltsel scalarltjoinsel ));
! DATA(insert OID = 1075 ( ">=" PGNSP PGUID b f 2277 2277 16 1074 1072 0 0 0 0 array_ge scalargtsel scalargtjoinsel ));
! DATA(insert OID = 349 ( "||" PGNSP PGUID b f 2277 2283 2277 0 0 0 0 0 0 array_append - - ));
! DATA(insert OID = 374 ( "||" PGNSP PGUID b f 2283 2277 2277 0 0 0 0 0 0 array_prepend - - ));
! DATA(insert OID = 375 ( "||" PGNSP PGUID b f 2277 2277 2277 0 0 0 0 0 0 array_cat - - ));
DATA(insert OID = 352 ( "=" PGNSP PGUID b t 28 28 16 352 0 0 0 0 0 xideq eqsel eqjoinsel ));
DATA(insert OID = 353 ( "=" PGNSP PGUID b t 28 23 16 0 0 0 0 0 0 xideqint4 eqsel eqjoinsel ));
***************
*** 425,430 ****
--- 430,436 ----
DATA(insert OID = 966 ( "+" PGNSP PGUID b f 1034 1033 1034 0 0 0 0 0 0 aclinsert - - ));
DATA(insert OID = 967 ( "-" PGNSP PGUID b f 1034 1033 1034 0 0 0 0 0 0 aclremove - - ));
DATA(insert OID = 968 ( "~" PGNSP PGUID b f 1034 1033 16 0 0 0 0 0 0 aclcontains - - ));
+ DATA(insert OID = 974 ( "=" PGNSP PGUID b f 1033 1033 16 0 0 0 0 0 0 aclitemeq eqsel eqjoinsel ));
/* additional geometric operators - thomas 1997-07-09 */
DATA(insert OID = 969 ( "@@" PGNSP PGUID l f 0 601 600 0 0 0 0 0 0 lseg_center - - ));
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/catalog/pg_proc.h,v
retrieving revision 1.302
diff -c -r1.302 pg_proc.h
*** src/include/catalog/pg_proc.h 26 May 2003 00:11:27 -0000 1.302
--- src/include/catalog/pg_proc.h 9 Jun 2003 01:52:28 -0000
***************
*** 758,763 ****
--- 758,765 ----
DESCR("btree less-equal-greater");
DATA(insert OID = 360 ( bttextcmp PGNSP PGUID 12 f f t f i 2 23 "25 25" bttextcmp - _null_ ));
DESCR("btree less-equal-greater");
+ DATA(insert OID = 398 ( btarraycmp PGNSP PGUID 12 f f t f i 2 23 "2277 2277" btarraycmp - _null_ ));
+ DESCR("btree less-equal-greater");
DATA(insert OID = 361 ( lseg_distance PGNSP PGUID 12 f f t f i 2 701 "601 601" lseg_distance - _null_ ));
DESCR("distance between");
***************
*** 984,997 ****
DATA(insert OID = 743 ( text_ge PGNSP PGUID 12 f f t f i 2 16 "25 25" text_ge - _null_ ));
DESCR("greater-than-or-equal");
- DATA(insert OID = 744 ( array_eq PGNSP PGUID 12 f f t f i 2 16 "2277 2277" array_eq - _null_ ));
- DESCR("array equal");
-
DATA(insert OID = 745 ( current_user PGNSP PGUID 12 f f t f s 0 19 "" current_user - _null_ ));
DESCR("current user name");
DATA(insert OID = 746 ( session_user PGNSP PGUID 12 f f t f s 0 19 "" session_user - _null_ ));
DESCR("session user name");
DATA(insert OID = 747 ( array_dims PGNSP PGUID 12 f f t f i 1 25 "2277" array_dims - _null_ ));
DESCR("array dimensions");
DATA(insert OID = 750 ( array_in PGNSP PGUID 12 f f t f s 3 2277 "2275 26 23" array_in - _null_ ));
--- 986,1008 ----
DATA(insert OID = 743 ( text_ge PGNSP PGUID 12 f f t f i 2 16 "25 25" text_ge - _null_ ));
DESCR("greater-than-or-equal");
DATA(insert OID = 745 ( current_user PGNSP PGUID 12 f f t f s 0 19 "" current_user - _null_ ));
DESCR("current user name");
DATA(insert OID = 746 ( session_user PGNSP PGUID 12 f f t f s 0 19 "" session_user - _null_ ));
DESCR("session user name");
+ DATA(insert OID = 744 ( array_eq PGNSP PGUID 12 f f t f i 2 16 "2277 2277" array_eq - _null_ ));
+ DESCR("array equal");
+ DATA(insert OID = 390 ( array_ne PGNSP PGUID 12 f f t f i 2 16 "2277 2277" array_ne - _null_ ));
+ DESCR("array not equal");
+ DATA(insert OID = 391 ( array_lt PGNSP PGUID 12 f f t f i 2 16 "2277 2277" array_lt - _null_ ));
+ DESCR("array less than");
+ DATA(insert OID = 392 ( array_gt PGNSP PGUID 12 f f t f i 2 16 "2277 2277" array_gt - _null_ ));
+ DESCR("array greater than");
+ DATA(insert OID = 393 ( array_le PGNSP PGUID 12 f f t f i 2 16 "2277 2277" array_le - _null_ ));
+ DESCR("array less than or equal");
+ DATA(insert OID = 396 ( array_ge PGNSP PGUID 12 f f t f i 2 16 "2277 2277" array_ge - _null_ ));
+ DESCR("array greater than or equal");
DATA(insert OID = 747 ( array_dims PGNSP PGUID 12 f f t f i 1 25 "2277" array_dims - _null_ ));
DESCR("array dimensions");
DATA(insert OID = 750 ( array_in PGNSP PGUID 12 f f t f s 3 2277 "2275 26 23" array_in - _null_ ));
***************
*** 1002,1023 ****
DESCR("array lower dimension");
DATA(insert OID = 2092 ( array_upper PGNSP PGUID 12 f f t f i 2 23 "2277 23" array_upper - _null_ ));
DESCR("array upper dimension");
- DATA(insert OID = 377 ( singleton_array PGNSP PGUID 12 f f t f i 1 2277 "2283" singleton_array - _null_ ));
- DESCR("create array from single element");
DATA(insert OID = 378 ( array_append PGNSP PGUID 12 f f t f i 2 2277 "2277 2283" array_push - _null_ ));
DESCR("append element onto end of array");
DATA(insert OID = 379 ( array_prepend PGNSP PGUID 12 f f t f i 2 2277 "2283 2277" array_push - _null_ ));
DESCR("prepend element onto front of array");
- DATA(insert OID = 380 ( array_accum PGNSP PGUID 12 f f f f i 2 2277 "2277 2283" array_accum - _null_ ));
- DESCR("push element onto end of array, creating array if needed");
- DATA(insert OID = 381 ( array_assign PGNSP PGUID 12 f f t f i 3 2277 "2277 23 2283" array_assign - _null_ ));
- DESCR("assign specific array element");
- DATA(insert OID = 382 ( array_subscript PGNSP PGUID 12 f f t f i 2 2283 "2277 23" array_subscript - _null_ ));
- DESCR("return specific array element");
DATA(insert OID = 383 ( array_cat PGNSP PGUID 12 f f t f i 2 2277 "2277 2277" array_cat - _null_ ));
DESCR("concatenate two arrays");
DATA(insert OID = 384 ( array_coerce PGNSP PGUID 12 f f t f i 1 2277 "2277" array_type_coerce - _null_ ));
DESCR("coerce array type to another array type");
DATA(insert OID = 760 ( smgrin PGNSP PGUID 12 f f t f s 1 210 "2275" smgrin - _null_ ));
DESCR("I/O");
--- 1013,1030 ----
DESCR("array lower dimension");
DATA(insert OID = 2092 ( array_upper PGNSP PGUID 12 f f t f i 2 23 "2277 23" array_upper - _null_ ));
DESCR("array upper dimension");
DATA(insert OID = 378 ( array_append PGNSP PGUID 12 f f t f i 2 2277 "2277 2283" array_push - _null_ ));
DESCR("append element onto end of array");
DATA(insert OID = 379 ( array_prepend PGNSP PGUID 12 f f t f i 2 2277 "2283 2277" array_push - _null_ ));
DESCR("prepend element onto front of array");
DATA(insert OID = 383 ( array_cat PGNSP PGUID 12 f f t f i 2 2277 "2277 2277" array_cat - _null_ ));
DESCR("concatenate two arrays");
DATA(insert OID = 384 ( array_coerce PGNSP PGUID 12 f f t f i 1 2277 "2277" array_type_coerce - _null_ ));
DESCR("coerce array type to another array type");
+ DATA(insert OID = 394 ( string_to_array PGNSP PGUID 12 f f t f i 2 1009 "25 25" text_to_array - _null_ ));
+ DESCR("split delimited text into text[]");
+ DATA(insert OID = 395 ( array_to_string PGNSP PGUID 12 f f t f i 2 25 "2277 25" array_to_text - _null_ ));
+ DESCR("concatenate array elements, using delimiter, into text");
DATA(insert OID = 760 ( smgrin PGNSP PGUID 12 f f t f s 1 210 "2275" smgrin - _null_ ));
DESCR("I/O");
***************
*** 1318,1323 ****
--- 1325,1332 ----
DESCR("remove ACL item");
DATA(insert OID = 1037 ( aclcontains PGNSP PGUID 12 f f t f s 2 16 "1034 1033" aclcontains - _null_ ));
DESCR("does ACL contain item?");
+ DATA(insert OID = 1062 ( aclitemeq PGNSP PGUID 12 f f t f s 2 16 "1033 1033" aclitem_eq - _null_ ));
+ DESCR("equality operator for ACL items");
DATA(insert OID = 1038 ( seteval PGNSP PGUID 12 f f t t v 1 23 "26" seteval - _null_ ));
DESCR("internal function supporting PostQuel-style sets");
DATA(insert OID = 1044 ( bpcharin PGNSP PGUID 12 f f t f i 3 1042 "2275 26 23" bpcharin - _null_ ));
Index: src/include/nodes/primnodes.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/nodes/primnodes.h,v
retrieving revision 1.82
diff -c -r1.82 primnodes.h
*** src/include/nodes/primnodes.h 6 May 2003 00:20:33 -0000 1.82
--- src/include/nodes/primnodes.h 9 Jun 2003 01:31:10 -0000
***************
*** 225,230 ****
--- 225,231 ----
Expr *target; /* expression we are aggregating on */
bool aggstar; /* TRUE if argument was really '*' */
bool aggdistinct; /* TRUE if it's agg(DISTINCT ...) */
+ List *args; /* arguments to the aggregate */
} Aggref;
/* ----------------
***************
*** 357,371 ****
/* ----------------
* SubLink
*
! * A SubLink represents a subselect appearing in an expression, and in some
! * cases also the combining operator(s) just above it. The subLinkType
! * indicates the form of the expression represented:
* EXISTS_SUBLINK EXISTS(SELECT ...)
* ALL_SUBLINK (lefthand) op ALL (SELECT ...)
* ANY_SUBLINK (lefthand) op ANY (SELECT ...)
* MULTIEXPR_SUBLINK (lefthand) op (SELECT ...)
* EXPR_SUBLINK (SELECT with single targetlist item ...)
* ARRAY_SUBLINK ARRAY(SELECT with single targetlist item ...)
* For ALL, ANY, and MULTIEXPR, the lefthand is a list of expressions of the
* same length as the subselect's targetlist. MULTIEXPR will *always* have
* a list with more than one entry; if the subselect has just one target
--- 358,376 ----
/* ----------------
* SubLink
*
! * A SubLink represents a subselect, or an expression, appearing in an
! * expression, and in some cases also the combining operator(s) just above
! * it. The subLinkType indicates the form of the expression represented:
* EXISTS_SUBLINK EXISTS(SELECT ...)
* ALL_SUBLINK (lefthand) op ALL (SELECT ...)
* ANY_SUBLINK (lefthand) op ANY (SELECT ...)
* MULTIEXPR_SUBLINK (lefthand) op (SELECT ...)
* EXPR_SUBLINK (SELECT with single targetlist item ...)
* ARRAY_SUBLINK ARRAY(SELECT with single targetlist item ...)
+ * If an expression is used in place of the subselect, it is transformed
+ * into a simple "(SELECT expr)" in gram.y. This is to allow arrays to be
+ * used as if they were the result of a single column subselect. If the
+ * expression is scalar, it is treated as a one element array.
* For ALL, ANY, and MULTIEXPR, the lefthand is a list of expressions of the
* same length as the subselect's targetlist. MULTIEXPR will *always* have
* a list with more than one entry; if the subselect has just one target
***************
*** 414,419 ****
--- 419,426 ----
SubLinkType subLinkType; /* EXISTS, ALL, ANY, MULTIEXPR, EXPR */
bool useOr; /* TRUE to combine column results with
* "OR" not "AND" */
+ bool isExpr; /* TRUE if the subselect is really derived
+ * from a single expression */
List *lefthand; /* list of outer-query expressions on the
* left */
List *operName; /* originally specified operator name */
***************
*** 455,460 ****
--- 462,476 ----
SubLinkType subLinkType; /* EXISTS, ALL, ANY, MULTIEXPR, EXPR */
bool useOr; /* TRUE to combine column results with
* "OR" not "AND" */
+ bool isExpr; /* TRUE if the subselect is really derived
+ * from a single expression */
+ /* runtime cache for single array expressions */
+ Oid exprtype; /* array and element type, and other info
+ * needed deconstruct the array */
+ Oid elemtype;
+ int16 elmlen;
+ bool elmbyval;
+ char elmalign;
/* The combining operators, transformed to executable expressions: */
List *exprs; /* list of OpExpr expression trees */
List *paramIds; /* IDs of Params embedded in the above */
Index: src/include/optimizer/clauses.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/optimizer/clauses.h,v
retrieving revision 1.63
diff -c -r1.63 clauses.h
*** src/include/optimizer/clauses.h 28 May 2003 16:04:02 -0000 1.63
--- src/include/optimizer/clauses.h 9 Jun 2003 01:31:10 -0000
***************
*** 28,33 ****
--- 28,36 ----
extern Node *get_leftop(Expr *clause);
extern Node *get_rightop(Expr *clause);
+ extern Expr *make_funcclause(Oid funcid, Oid funcresulttype, bool funcretset,
+ CoercionForm funcformat, List *funcargs);
+
extern bool not_clause(Node *clause);
extern Expr *make_notclause(Expr *notclause);
extern Expr *get_notclausearg(Expr *notclause);
Index: src/include/parser/parse_oper.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/parser/parse_oper.h,v
retrieving revision 1.25
diff -c -r1.25 parse_oper.h
*** src/include/parser/parse_oper.h 29 Apr 2003 22:13:11 -0000 1.25
--- src/include/parser/parse_oper.h 9 Jun 2003 01:31:10 -0000
***************
*** 44,49 ****
--- 44,50 ----
/* Convenience routines for common calls on the above */
extern Oid compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError);
extern Oid equality_oper_funcid(Oid argtype);
+ extern Oid ordering_oper_funcid(Oid argtype);
extern Oid ordering_oper_opid(Oid argtype);
/* Extract operator OID or underlying-function OID from an Operator tuple */
Index: src/include/utils/acl.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/utils/acl.h,v
retrieving revision 1.51
diff -c -r1.51 acl.h
*** src/include/utils/acl.h 23 Jan 2003 23:39:07 -0000 1.51
--- src/include/utils/acl.h 9 Jun 2003 01:31:10 -0000
***************
*** 188,193 ****
--- 188,194 ----
extern Datum aclinsert(PG_FUNCTION_ARGS);
extern Datum aclremove(PG_FUNCTION_ARGS);
extern Datum aclcontains(PG_FUNCTION_ARGS);
+ extern Datum aclitem_eq(PG_FUNCTION_ARGS);
/*
* prototypes for functions in aclchk.c
Index: src/include/utils/array.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/utils/array.h,v
retrieving revision 1.38
diff -c -r1.38 array.h
*** src/include/utils/array.h 8 May 2003 22:19:57 -0000 1.38
--- src/include/utils/array.h 9 Jun 2003 01:47:03 -0000
***************
*** 32,37 ****
--- 32,68 ----
Oid elemtype; /* element type OID */
} ArrayType;
+ typedef struct ArrayBuildState
+ {
+ MemoryContext mcontext; /* where all the temp stuff is kept */
+ Datum *dvalues; /* array of accumulated Datums */
+ /*
+ * The allocated size of dvalues[] is always a multiple of
+ * ARRAY_ELEMS_CHUNKSIZE
+ */
+ #define ARRAY_ELEMS_CHUNKSIZE 64
+ int nelems; /* number of valid Datums in dvalues[] */
+ Oid element_type; /* data type of the Datums */
+ int16 typlen; /* needed info about datatype */
+ bool typbyval;
+ char typalign;
+ } ArrayBuildState;
+
+ /*
+ * structure to cache type metadata needed for array manipulation
+ */
+ typedef struct ArrayMetaState
+ {
+ Oid element_type;
+ int typlen;
+ bool typbyval;
+ char typdelim;
+ Oid typelem;
+ Oid typiofunc;
+ char typalign;
+ FmgrInfo proc;
+ } ArrayMetaState;
+
/*
* fmgr macros for array objects
*/
***************
*** 86,96 ****
extern Datum array_send(PG_FUNCTION_ARGS);
extern Datum array_length_coerce(PG_FUNCTION_ARGS);
extern Datum array_eq(PG_FUNCTION_ARGS);
extern Datum array_dims(PG_FUNCTION_ARGS);
extern Datum array_lower(PG_FUNCTION_ARGS);
extern Datum array_upper(PG_FUNCTION_ARGS);
- extern Datum array_assign(PG_FUNCTION_ARGS);
- extern Datum array_subscript(PG_FUNCTION_ARGS);
extern Datum array_type_coerce(PG_FUNCTION_ARGS);
extern Datum array_ref(ArrayType *array, int nSubscripts, int *indx,
--- 117,131 ----
extern Datum array_send(PG_FUNCTION_ARGS);
extern Datum array_length_coerce(PG_FUNCTION_ARGS);
extern Datum array_eq(PG_FUNCTION_ARGS);
+ extern Datum array_ne(PG_FUNCTION_ARGS);
+ extern Datum array_lt(PG_FUNCTION_ARGS);
+ extern Datum array_gt(PG_FUNCTION_ARGS);
+ extern Datum array_le(PG_FUNCTION_ARGS);
+ extern Datum array_ge(PG_FUNCTION_ARGS);
+ extern Datum btarraycmp(PG_FUNCTION_ARGS);
extern Datum array_dims(PG_FUNCTION_ARGS);
extern Datum array_lower(PG_FUNCTION_ARGS);
extern Datum array_upper(PG_FUNCTION_ARGS);
extern Datum array_type_coerce(PG_FUNCTION_ARGS);
extern Datum array_ref(ArrayType *array, int nSubscripts, int *indx,
***************
*** 124,130 ****
Oid elmtype,
int elmlen, bool elmbyval, char elmalign,
Datum **elemsp, int *nelemsp);
!
/*
* prototypes for functions defined in arrayutils.c
--- 159,172 ----
Oid elmtype,
int elmlen, bool elmbyval, char elmalign,
Datum **elemsp, int *nelemsp);
! extern ArrayBuildState *accumArrayResult(ArrayBuildState *astate,
! Datum dvalue, bool disnull,
! Oid element_type,
! MemoryContext rcontext);
! extern Datum makeArrayResult(ArrayBuildState *astate,
! MemoryContext rcontext);
! extern Datum makeMdArrayResult(ArrayBuildState *astate, int ndims,
! int *dims, int *lbs, MemoryContext rcontext);
/*
* prototypes for functions defined in arrayutils.c
***************
*** 141,152 ****
/*
* prototypes for functions defined in array_userfuncs.c
*/
- extern Datum singleton_array(PG_FUNCTION_ARGS);
extern Datum array_push(PG_FUNCTION_ARGS);
- extern Datum array_accum(PG_FUNCTION_ARGS);
extern Datum array_cat(PG_FUNCTION_ARGS);
! extern ArrayType *create_singleton_array(Oid element_type,
Datum element,
int ndims);
--- 183,193 ----
/*
* prototypes for functions defined in array_userfuncs.c
*/
extern Datum array_push(PG_FUNCTION_ARGS);
extern Datum array_cat(PG_FUNCTION_ARGS);
! extern ArrayType *create_singleton_array(FunctionCallInfo fcinfo,
! Oid element_type,
Datum element,
int ndims);
Index: src/include/utils/builtins.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/utils/builtins.h,v
retrieving revision 1.219
diff -c -r1.219 builtins.h
*** src/include/utils/builtins.h 26 May 2003 00:11:28 -0000 1.219
--- src/include/utils/builtins.h 9 Jun 2003 01:31:10 -0000
***************
*** 530,535 ****
--- 530,537 ----
List **namelist);
extern Datum replace_text(PG_FUNCTION_ARGS);
extern Datum split_text(PG_FUNCTION_ARGS);
+ extern Datum text_to_array(PG_FUNCTION_ARGS);
+ extern Datum array_to_text(PG_FUNCTION_ARGS);
extern Datum to_hex32(PG_FUNCTION_ARGS);
extern Datum to_hex64(PG_FUNCTION_ARGS);
extern Datum md5_text(PG_FUNCTION_ARGS);
Index: src/include/utils/lsyscache.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/utils/lsyscache.h,v
retrieving revision 1.70
diff -c -r1.70 lsyscache.h
*** src/include/utils/lsyscache.h 26 May 2003 00:11:28 -0000 1.70
--- src/include/utils/lsyscache.h 9 Jun 2003 01:31:10 -0000
***************
*** 15,20 ****
--- 15,29 ----
#include "access/htup.h"
+ /* I/O function selector for system_cache_lookup */
+ typedef enum IOFuncSelector
+ {
+ IOFunc_input,
+ IOFunc_output,
+ IOFunc_receive,
+ IOFunc_send
+ } IOFuncSelector;
+
extern bool op_in_opclass(Oid opno, Oid opclass);
extern bool op_requires_recheck(Oid opno, Oid opclass);
extern Oid get_opclass_member(Oid opclass, int16 strategy);
***************
*** 39,44 ****
--- 48,54 ----
extern RegProcedure get_oprjoin(Oid opno);
extern char *get_func_name(Oid funcid);
extern Oid get_func_rettype(Oid funcid);
+ extern Oid *get_func_argtypes(Oid funcid, int *nargs);
extern bool get_func_retset(Oid funcid);
extern bool func_strict(Oid funcid);
extern char func_volatile(Oid funcid);
***************
*** 54,59 ****
--- 64,77 ----
extern void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval);
extern void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
char *typalign);
+ extern void get_type_metadata(Oid element_type,
+ IOFuncSelector which_func,
+ int *typlen,
+ bool *typbyval,
+ char *typdelim,
+ Oid *typelem,
+ Oid *proc,
+ char *typalign);
extern char get_typstorage(Oid typid);
extern int32 get_typtypmod(Oid typid);
extern Node *get_typdefault(Oid typid);
Index: src/interfaces/ecpg/preproc/preproc.y
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/interfaces/ecpg/preproc/preproc.y,v
retrieving revision 1.227
diff -c -r1.227 preproc.y
*** src/interfaces/ecpg/preproc/preproc.y 30 May 2003 13:22:02 -0000 1.227
--- src/interfaces/ecpg/preproc/preproc.y 9 Jun 2003 01:42:58 -0000
***************
*** 4549,4555 ****
$3.type_enum != ECPGt_char &&
$3.type_enum != ECPGt_unsigned_char &&
atoi(this->type->type_index) >= 0)
! mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types");
types = this;
}
--- 4549,4555 ----
$3.type_enum != ECPGt_char &&
$3.type_enum != ECPGt_unsigned_char &&
atoi(this->type->type_index) >= 0)
! mmerror(PARSE_ERROR, ET_ERROR, "No multidimensional array support for simple data types");
types = this;
}
***************
*** 5372,5378 ****
$5.type_enum != ECPGt_char &&
$5.type_enum != ECPGt_unsigned_char &&
atoi(this->type->type_index) >= 0)
! mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types");
types = this;
}
--- 5372,5378 ----
$5.type_enum != ECPGt_char &&
$5.type_enum != ECPGt_unsigned_char &&
atoi(this->type->type_index) >= 0)
! mmerror(PARSE_ERROR, ET_ERROR, "No multidimensional array support for simple data types");
types = this;
}
***************
*** 5439,5445 ****
default:
if (atoi(length) >= 0)
! mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types");
if (atoi(dimension) < 0)
type = ECPGmake_simple_type($5.type_enum, make_str("1"));
--- 5439,5445 ----
default:
if (atoi(length) >= 0)
! mmerror(PARSE_ERROR, ET_ERROR, "No multidimensional array support for simple data types");
if (atoi(dimension) < 0)
type = ECPGmake_simple_type($5.type_enum, make_str("1"));
Index: src/interfaces/ecpg/preproc/type.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/interfaces/ecpg/preproc/type.c,v
retrieving revision 1.51
diff -c -r1.51 type.c
*** src/interfaces/ecpg/preproc/type.c 29 May 2003 13:59:26 -0000 1.51
--- src/interfaces/ecpg/preproc/type.c 9 Jun 2003 01:42:58 -0000
***************
*** 493,499 ****
switch (type->u.element->type)
{
case ECPGt_array:
! yyerror("internal error, found multi-dimensional array\n");
break;
case ECPGt_struct:
case ECPGt_union:
--- 493,499 ----
switch (type->u.element->type)
{
case ECPGt_array:
! yyerror("internal error, found multidimensional array\n");
break;
case ECPGt_struct:
case ECPGt_union:
Index: src/interfaces/ecpg/preproc/variable.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/interfaces/ecpg/preproc/variable.c,v
retrieving revision 1.20
diff -c -r1.20 variable.c
*** src/interfaces/ecpg/preproc/variable.c 29 May 2003 13:59:26 -0000 1.20
--- src/interfaces/ecpg/preproc/variable.c 9 Jun 2003 01:42:58 -0000
***************
*** 405,411 ****
if (atoi(type_index) >= 0)
{
if (atoi(*length) >= 0)
! mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support");
*length = type_index;
}
--- 405,411 ----
if (atoi(type_index) >= 0)
{
if (atoi(*length) >= 0)
! mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support");
*length = type_index;
}
***************
*** 413,419 ****
if (atoi(type_dimension) >= 0)
{
if (atoi(*dimension) >= 0 && atoi(*length) >= 0)
! mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support");
if (atoi(*dimension) >= 0)
*length = *dimension;
--- 413,419 ----
if (atoi(type_dimension) >= 0)
{
if (atoi(*dimension) >= 0 && atoi(*length) >= 0)
! mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support");
if (atoi(*dimension) >= 0)
*length = *dimension;
***************
*** 432,441 ****
mmerror(PARSE_ERROR, ET_FATAL, "No pointer to pointer supported for this type");
if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
! mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support");
if (atoi(*length) >= 0 && atoi(*dimension) >= 0 && pointer_len)
! mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support");
switch (type_enum)
{
--- 432,441 ----
mmerror(PARSE_ERROR, ET_FATAL, "No pointer to pointer supported for this type");
if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
! mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support");
if (atoi(*length) >= 0 && atoi(*dimension) >= 0 && pointer_len)
! mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support");
switch (type_enum)
{
***************
*** 449,455 ****
}
if (atoi(*length) >= 0)
! mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support for structures");
break;
case ECPGt_varchar:
--- 449,455 ----
}
if (atoi(*length) >= 0)
! mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support for structures");
break;
case ECPGt_varchar:
***************
*** 494,500 ****
}
if (atoi(*length) >= 0)
! mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support for simple data types");
break;
}
--- 494,500 ----
}
if (atoi(*length) >= 0)
! mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support for simple data types");
break;
}
Index: src/test/regress/expected/arrays.out
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/test/regress/expected/arrays.out,v
retrieving revision 1.11
diff -c -r1.11 arrays.out
*** src/test/regress/expected/arrays.out 8 Apr 2003 23:20:04 -0000 1.11
--- src/test/regress/expected/arrays.out 9 Jun 2003 04:43:05 -0000
***************
*** 178,196 ****
(1 row)
-- functions
! SELECT singleton_array(42) AS "{42}";
! {42}
! ------
! {42}
! (1 row)
!
! SELECT array_append(singleton_array(42), 6) AS "{42,6}";
{42,6}
--------
{42,6}
(1 row)
! SELECT array_prepend(6, singleton_array(42)) AS "{6,42}";
{6,42}
--------
{6,42}
--- 178,190 ----
(1 row)
-- functions
! SELECT array_append(array[42], 6) AS "{42,6}";
{42,6}
--------
{42,6}
(1 row)
! SELECT array_prepend(6, array[42]) AS "{6,42}";
{6,42}
--------
{6,42}
***************
*** 212,235 ****
{{3,4},{5,6},{1,2}}
---------------------
{{3,4},{5,6},{1,2}}
- (1 row)
-
- SELECT array_subscript(n, 2) AS "1.2" FROM arrtest2;
- 1.2
- -----
- 1.2
- (1 row)
-
- SELECT array_assign(n, 2, 9.99) AS "{1.1,9.99,1.3}" FROM arrtest2;
- {1.1,9.99,1.3}
- ----------------
- {1.1,9.99,1.3}
- (1 row)
-
- SELECT array_subscript(array_assign(n, 2, 9.99), 2) AS "9.99" FROM arrtest2;
- 9.99
- ------
- 9.99
(1 row)
-- operators
--- 206,211 ----
Index: src/test/regress/sql/arrays.sql
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/test/regress/sql/arrays.sql,v
retrieving revision 1.10
diff -c -r1.10 arrays.sql
*** src/test/regress/sql/arrays.sql 8 Apr 2003 23:20:04 -0000 1.10
--- src/test/regress/sql/arrays.sql 9 Jun 2003 04:42:20 -0000
***************
*** 130,144 ****
SELECT ARRAY(select f2 from arrtest_f order by f2) AS "ARRAY";
-- functions
! SELECT singleton_array(42) AS "{42}";
! SELECT array_append(singleton_array(42), 6) AS "{42,6}";
! SELECT array_prepend(6, singleton_array(42)) AS "{6,42}";
SELECT array_cat(ARRAY[1,2], ARRAY[3,4]) AS "{{1,2},{3,4}}";
SELECT array_cat(ARRAY[1,2], ARRAY[[3,4],[5,6]]) AS "{{1,2},{3,4},{5,6}}";
SELECT array_cat(ARRAY[[3,4],[5,6]], ARRAY[1,2]) AS "{{3,4},{5,6},{1,2}}";
- SELECT array_subscript(n, 2) AS "1.2" FROM arrtest2;
- SELECT array_assign(n, 2, 9.99) AS "{1.1,9.99,1.3}" FROM arrtest2;
- SELECT array_subscript(array_assign(n, 2, 9.99), 2) AS "9.99" FROM arrtest2;
-- operators
SELECT a FROM arrtest WHERE b = ARRAY[[[113,142],[1,147]]];
--- 130,140 ----
SELECT ARRAY(select f2 from arrtest_f order by f2) AS "ARRAY";
-- functions
! SELECT array_append(array[42], 6) AS "{42,6}";
! SELECT array_prepend(6, array[42]) AS "{6,42}";
SELECT array_cat(ARRAY[1,2], ARRAY[3,4]) AS "{{1,2},{3,4}}";
SELECT array_cat(ARRAY[1,2], ARRAY[[3,4],[5,6]]) AS "{{1,2},{3,4},{5,6}}";
SELECT array_cat(ARRAY[[3,4],[5,6]], ARRAY[1,2]) AS "{{3,4},{5,6},{1,2}}";
-- operators
SELECT a FROM arrtest WHERE b = ARRAY[[[113,142],[1,147]]];