From: Bruce Momjian Date: Wed, 25 Jun 2003 21:30:34 +0000 (+0000) Subject: Back out array mega-patch. X-Git-Tag: REL7_4_BETA1~301 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=111d8e522b61169393e2698924db07586fdd847f;p=postgresql Back out array mega-patch. Joe Conway --- diff --git a/doc/src/sgml/array.sgml b/doc/src/sgml/array.sgml index a7a05762de..985a92f7fa 100644 --- a/doc/src/sgml/array.sgml +++ b/doc/src/sgml/array.sgml @@ -1,4 +1,4 @@ - + Arrays @@ -60,74 +60,14 @@ INSERT INTO sal_emp - - 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. + 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. - - - 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. - - - @@ -192,30 +132,11 @@ SELECT schedule[1:2][1] FROM sal_emp WHERE name = 'Bill'; 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 + 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) - + is specified. @@ -226,23 +147,7 @@ UPDATE sal_emp SET pay_by_quarter = '{25000,25000,27000,27000}' 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: + or updated at a single element: UPDATE sal_emp SET pay_by_quarter[4] = 15000 @@ -255,14 +160,6 @@ UPDATE sal_emp SET pay_by_quarter[4] = 15000 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'; - @@ -281,88 +178,6 @@ UPDATE sal_emp SET pay_by_quarter = array_assign(pay_by_quarter, 4, 15000) create an array with subscript values running from -2 to 7. - - 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: @@ -378,16 +193,6 @@ CREATE TABLE tictactoe ( length. - - 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 @@ -495,72 +300,6 @@ SELECT * FROM sal_emp WHERE pay_by_quarter **= 10000; 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) - - - - @@ -578,14 +317,6 @@ SELECT CAST(ARRAY[1,2,3] AS float8[]); 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 if they are empty strings or contain curly braces, delimiter characters, diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index d092cafa2d..3db3ab34e8 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -1,5 +1,5 @@ @@ -6962,203 +6962,6 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); - - Array Functions - - - shows the operators - available for the array types. - - - - <type>array</type> 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. - - - - <type>array</type> 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 diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index 9025862be1..a2160fa025 100644 --- a/src/backend/catalog/pg_aggregate.c +++ b/src/backend/catalog/pg_aggregate.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.57 2003/06/24 23:14:42 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.58 2003/06/25 21:30:25 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -50,16 +50,10 @@ AggregateCreate(const char *aggName, Oid finalfn = InvalidOid; /* can be omitted */ Oid finaltype; Oid fnArgs[FUNC_MAX_ARGS]; - int nargs_transfn; - int nargs_finalfn; + int nargs; 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; @@ -74,49 +68,24 @@ AggregateCreate(const char *aggName, MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid)); fnArgs[0] = aggTransType; if (aggBaseType == ANYOID) - nargs_transfn = 1; + nargs = 1; else { fnArgs[1] = aggBaseType; - nargs_transfn = 2; + nargs = 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); - + transfn = LookupFuncName(aggtransfnName, nargs, fnArgs); 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)); - + func_error("AggregateCreate", aggtransfnName, nargs, fnArgs, NULL); tup = SearchSysCache(PROCOID, ObjectIdGetDatum(transfn), 0, 0, 0); if (!HeapTupleIsValid(tup)) - func_error("AggregateCreate", aggtransfnName, - nargs_transfn, fnArgs, NULL); + 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 @@ -136,26 +105,17 @@ AggregateCreate(const char *aggName, { 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); - + finalfn = LookupFuncName(aggfinalfnName, 1, fnArgs); 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); + 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 { @@ -166,27 +126,6 @@ AggregateCreate(const char *aggName, } 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 * aggregate. (This could fail if there's already a conflicting diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c index 07b9862e41..bee50e686f 100644 --- a/src/backend/commands/aggregatecmds.c +++ b/src/backend/commands/aggregatecmds.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.6 2003/06/24 23:14:43 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.7 2003/06/25 21:30:26 momjian Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -119,9 +119,7 @@ DefineAggregate(List *names, List *parameters) baseTypeId = typenameTypeId(baseType); transTypeId = typenameTypeId(transType); - if (get_typtype(transTypeId) == 'p' && - transTypeId != ANYARRAYOID && - transTypeId != ANYELEMENTOID) + if (get_typtype(transTypeId) == 'p') elog(ERROR, "Aggregate transition datatype cannot be %s", format_type_be(transTypeId)); diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index e729344060..6e0a46e0e7 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.131 2003/06/24 23:14:43 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.132 2003/06/25 21:30:28 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1528,17 +1528,17 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext, { /* Check other sub-arrays are compatible */ if (elem_ndims != ARR_NDIM(array)) - elog(ERROR, "Multidimensional arrays must have 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, "Multidimensional arrays must have array " + 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, "Multidimensional arrays must have array " + elog(ERROR, "Multiple dimension arrays must have array " "expressions with matching dimensions"); } diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index dc8c1554bb..04d656f05a 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -45,7 +45,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.108 2003/06/24 23:14:43 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.109 2003/06/25 21:30:28 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -58,7 +58,6 @@ #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" @@ -213,7 +212,7 @@ static TupleTableSlot *agg_retrieve_direct(AggState *aggstate); 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. @@ -352,12 +351,14 @@ advance_transition_function(AggState *aggstate, 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); /* @@ -1186,21 +1187,7 @@ ExecInitAgg(Agg *node, EState *estate) 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; /* Planner should have assigned aggregate to correct level */ @@ -1251,166 +1238,6 @@ ExecInitAgg(Agg *node, EState *estate) &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. @@ -1423,7 +1250,14 @@ ExecInitAgg(Agg *node, EState *estate) peraggstate->initValue = (Datum) 0; else peraggstate->initValue = GetAggInitVal(textInitVal, - transfn_arg_types[0]); + 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 @@ -1635,36 +1469,3 @@ aggregate_dummy(PG_FUNCTION_ARGS) 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; -} diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index 62aaa7e8d4..6456737768 100644 --- a/src/backend/executor/nodeSubplan.c +++ b/src/backend/executor/nodeSubplan.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.48 2003/06/24 23:14:43 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.49 2003/06/25 21:30:29 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -28,6 +28,23 @@ #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); @@ -37,6 +54,13 @@ static Datum ExecScanSubPlan(SubPlanState *node, 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 @@ -200,7 +224,6 @@ ExecScanSubPlan(SubPlanState *node, PlanState *planstate = node->planstate; SubLinkType subLinkType = subplan->subLinkType; bool useOr = subplan->useOr; - bool isExpr = subplan->isExpr; MemoryContext oldcontext; TupleTableSlot *slot; Datum result; @@ -271,11 +294,6 @@ ExecScanSubPlan(SubPlanState *node, bool rownull = false; int col = 1; List *plst; - int numelems; - int elemnum; - Datum dvalue; - Datum *dvalues = NULL; - bool disnull; if (subLinkType == EXISTS_SUBLINK) { @@ -313,6 +331,9 @@ ExecScanSubPlan(SubPlanState *node, if (subLinkType == ARRAY_SUBLINK) { + Datum dvalue; + bool disnull; + found = true; /* stash away current value */ dvalue = heap_getattr(tup, 1, tdesc, &disnull); @@ -330,164 +351,99 @@ ExecScanSubPlan(SubPlanState *node, 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. + * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining + * operators for columns of tuple. */ - if (!isExpr) - numelems = 1; - else + plst = subplan->paramIds; + foreach(lst, node->exprs) { - Oid expr_typeid = tdesc->attrs[0]->atttypid; + ExprState *exprstate = (ExprState *) lfirst(lst); + int paramid = lfirsti(plst); + ParamExecData *prmdata; + Datum expresult; + bool expnull; - 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); - } + /* + * 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)); - /* get current value */ - dvalue = heap_getattr(tup, 1, tdesc, &disnull); + /* + * Now we can eval the combining operator for this column. + */ + expresult = ExecEvalExprSwitchContext(exprstate, econtext, + &expnull, NULL); - /* XXX this will need work if/when arrays support NULL elements */ - if (!disnull) + /* + * Combine the result into the row result as appropriate. + */ + if (col == 1) { - if (subplan->elemtype != InvalidOid) - { - ArrayType *v = DatumGetArrayTypeP(dvalue); - - deconstruct_array(v, subplan->elemtype, subplan->elmlen, - subplan->elmbyval, subplan->elmalign, - &dvalues, &numelems); - } - else + rowresult = expresult; + rownull = expnull; + } + else if (useOr) + { + /* combine within row per OR semantics */ + if (expnull) + rownull = true; + else if (DatumGetBool(expresult)) { - numelems = 1; - dvalues = (Datum *) palloc(numelems * sizeof(Datum)); - dvalues[0] = dvalue; + rowresult = BoolGetDatum(true); + rownull = false; + break; /* needn't look at any more columns */ } } else { - numelems = 1; - dvalues = (Datum *) palloc(numelems * sizeof(Datum)); - dvalues[0] = (Datum) 0; + /* 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++; } - for (elemnum = 0; elemnum < numelems; elemnum++) + if (subLinkType == ANY_SUBLINK) { - /* - * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining - * operators for columns of tuple. - */ - col = 1; - plst = subplan->paramIds; - foreach(lst, node->exprs) + /* combine across rows per OR semantics */ + if (rownull) + *isNull = true; + else if (DatumGetBool(rowresult)) { - 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 */ - } + result = BoolGetDatum(true); + *isNull = false; + break; /* needn't look at any more rows */ } - else + } + else if (subLinkType == ALL_SUBLINK) + { + /* combine across rows per AND semantics */ + if (rownull) + *isNull = true; + else if (!DatumGetBool(rowresult)) { - /* must be MULTIEXPR_SUBLINK */ - result = rowresult; - *isNull = rownull; + result = BoolGetDatum(false); + *isNull = false; + break; /* needn't look at any more rows */ } } + else + { + /* must be MULTIEXPR_SUBLINK */ + result = rowresult; + *isNull = rownull; + } } if (!found) @@ -524,7 +480,6 @@ static void 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; @@ -532,7 +487,6 @@ buildSubPlanHash(SubPlanState *node) MemoryContext oldcontext; int nbuckets; TupleTableSlot *slot; - TupleTableSlot *arrslot = NULL; Assert(subplan->subLinkType == ANY_SUBLINK); Assert(!subplan->useOr); @@ -612,139 +566,43 @@ buildSubPlanHash(SubPlanState *node) { HeapTuple tup = slot->val; TupleDesc tdesc = slot->ttc_tupleDescriptor; - TupleDesc arrtdesc = NULL; + int col = 1; 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. + * Load up the Params representing the raw sub-select outputs, + * then form the projection tuple to store in the hashtable. */ - if (!isExpr) - numelems = 1; - else + foreach(plst, subplan->paramIds) { - 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; - } - + 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; - for (elemnum = 0; elemnum < numelems; elemnum++) + /* + * 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)) { - 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; - } + (void) LookupTupleHashEntry(node->hashtable, slot, &isnew); + node->havehashrows = true; + } + else if (node->hashnulls) + { + (void) LookupTupleHashEntry(node->hashnulls, slot, &isnew); + node->havenullrows = true; } /* @@ -761,8 +619,6 @@ buildSubPlanHash(SubPlanState *node) * have the potential for a double free attempt. */ ExecClearTuple(node->projRight->pi_slot); - if (arrslot) - ExecClearTuple(arrslot); MemoryContextSwitchTo(oldcontext); } @@ -1243,3 +1099,101 @@ ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent) 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); +} diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 0cd199656c..8f81f1953c 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.255 2003/06/25 04:19:24 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.256 2003/06/25 21:30:29 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -728,7 +728,6 @@ _copyAggref(Aggref *from) COPY_SCALAR_FIELD(agglevelsup); COPY_SCALAR_FIELD(aggstar); COPY_SCALAR_FIELD(aggdistinct); - COPY_NODE_FIELD(args); return newnode; } @@ -827,7 +826,6 @@ _copySubLink(SubLink *from) COPY_SCALAR_FIELD(subLinkType); COPY_SCALAR_FIELD(useOr); - COPY_SCALAR_FIELD(isExpr); COPY_NODE_FIELD(lefthand); COPY_NODE_FIELD(operName); COPY_OIDLIST_FIELD(operOids); @@ -846,12 +844,6 @@ _copySubPlan(SubPlan *from) 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); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 93f63c586c..a56b01429e 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -18,7 +18,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.198 2003/06/25 04:19:24 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.199 2003/06/25 21:30:29 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -205,7 +205,6 @@ _equalAggref(Aggref *a, Aggref *b) COMPARE_SCALAR_FIELD(agglevelsup); COMPARE_SCALAR_FIELD(aggstar); COMPARE_SCALAR_FIELD(aggdistinct); - COMPARE_NODE_FIELD(args); return true; } @@ -302,7 +301,6 @@ _equalSubLink(SubLink *a, SubLink *b) { COMPARE_SCALAR_FIELD(subLinkType); COMPARE_SCALAR_FIELD(useOr); - COMPARE_SCALAR_FIELD(isExpr); COMPARE_NODE_FIELD(lefthand); COMPARE_NODE_FIELD(operName); COMPARE_OIDLIST_FIELD(operOids); @@ -316,12 +314,6 @@ _equalSubPlan(SubPlan *a, SubPlan *b) { 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 */ diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index cbd5784f56..e2b8cb789d 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.209 2003/06/24 23:14:43 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.210 2003/06/25 21:30:29 momjian Exp $ * * NOTES * Every node type that can appear in stored rules' parsetrees *must* @@ -616,7 +616,6 @@ _outAggref(StringInfo str, Aggref *node) WRITE_UINT_FIELD(agglevelsup); WRITE_BOOL_FIELD(aggstar); WRITE_BOOL_FIELD(aggdistinct); - WRITE_NODE_FIELD(args); } static void @@ -702,7 +701,6 @@ _outSubLink(StringInfo str, SubLink *node) 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); @@ -716,12 +714,6 @@ _outSubPlan(StringInfo str, SubPlan *node) 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); diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index a661f9e8ad..1d2db3b37a 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.155 2003/06/24 23:14:43 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.156 2003/06/25 21:30:30 momjian Exp $ * * NOTES * Path and Plan nodes do not have any readfuncs support, because we @@ -416,7 +416,6 @@ _readAggref(void) READ_UINT_FIELD(agglevelsup); READ_BOOL_FIELD(aggstar); READ_BOOL_FIELD(aggdistinct); - READ_NODE_FIELD(args); READ_DONE(); } @@ -546,7 +545,6 @@ _readSubLink(void) 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); diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 138e7d8063..aee5f4a1a1 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.77 2003/06/24 23:14:43 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.78 2003/06/25 21:30:30 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -83,7 +83,7 @@ typedef struct finalize_primnode_context static List *convert_sublink_opers(List *lefthand, List *operOids, List *targetlist, int rtindex, - bool isExpr, List **righthandIds); + 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); @@ -299,12 +299,6 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual) */ 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; @@ -380,7 +374,7 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual) exprs = convert_sublink_opers(lefthand, slink->operOids, plan->targetlist, - 0, node->isExpr, + 0, &node->paramIds); node->setParam = listCopy(node->paramIds); PlannerInitPlan = lappend(PlannerInitPlan, node); @@ -463,7 +457,7 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual) node->exprs = convert_sublink_opers(lefthand, slink->operOids, plan->targetlist, - 0, node->isExpr, + 0, &node->paramIds); /* @@ -505,7 +499,7 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual) static List * convert_sublink_opers(List *lefthand, List *operOids, List *targetlist, int rtindex, - bool isExpr, List **righthandIds) + List **righthandIds) { List *result = NIL; List *lst; @@ -560,38 +554,13 @@ convert_sublink_opers(List *lefthand, List *operOids, * 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)); - } + result = lappend(result, + make_op_expr(NULL, + tup, + leftop, + rightop, + exprType(leftop), + te->resdom->restype)); ReleaseSysCache(tup); @@ -702,17 +671,13 @@ convert_IN_to_join(Query *parse, SubLink *sublink) /* * 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. + * 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; - 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.) @@ -765,7 +730,7 @@ convert_IN_to_join(Query *parse, SubLink *sublink) exprs = convert_sublink_opers(sublink->lefthand, sublink->operOids, subselect->targetList, - rtindex, sublink->isExpr, + rtindex, &ininfo->sub_targetlist); return (Node *) make_ands_explicit(exprs); } diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 6b5014f90e..8b04066133 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.140 2003/06/24 23:14:43 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.141 2003/06/25 21:30:30 momjian Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -132,28 +132,6 @@ get_rightop(Expr *clause) return NULL; } -/***************************************************************************** - * 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 *****************************************************************************/ diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index ed409c9171..b24e00b9a5 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.420 2003/06/25 04:19:24 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.421 2003/06/25 21:30:30 momjian Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -5505,7 +5505,6 @@ r_expr: row IN_P select_with_parens { SubLink *n = makeNode(SubLink); n->subLinkType = ANY_SUBLINK; - n->isExpr = false; n->lefthand = $1; n->operName = makeList1(makeString("=")); n->subselect = $3; @@ -5516,7 +5515,6 @@ r_expr: row IN_P select_with_parens /* 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; @@ -5528,7 +5526,6 @@ r_expr: row IN_P select_with_parens { SubLink *n = makeNode(SubLink); n->subLinkType = $3; - n->isExpr = false; n->lefthand = $1; n->operName = $2; n->subselect = $4; @@ -5539,7 +5536,6 @@ r_expr: row IN_P select_with_parens { SubLink *n = makeNode(SubLink); n->subLinkType = MULTIEXPR_SUBLINK; - n->isExpr = false; n->lefthand = $1; n->operName = $2; n->subselect = $3; @@ -5923,7 +5919,6 @@ a_expr: c_expr { $$ = $1; } { SubLink *n = (SubLink *)$3; n->subLinkType = ANY_SUBLINK; - n->isExpr = false; n->lefthand = makeList1($1); n->operName = makeList1(makeString("=")); $$ = (Node *)n; @@ -5951,7 +5946,6 @@ a_expr: c_expr { $$ = $1; } { /* Make an IN node */ SubLink *n = (SubLink *)$4; - n->isExpr = false; n->subLinkType = ANY_SUBLINK; n->lefthand = makeList1($1); n->operName = makeList1(makeString("=")); @@ -5978,38 +5972,11 @@ a_expr: c_expr { $$ = $1; } { 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 @@ -6586,7 +6553,6 @@ c_expr: columnref { $$ = (Node *) $1; } { SubLink *n = makeNode(SubLink); n->subLinkType = EXPR_SUBLINK; - n->isExpr = false; n->lefthand = NIL; n->operName = NIL; n->subselect = $1; @@ -6596,7 +6562,6 @@ c_expr: columnref { $$ = (Node *) $1; } { SubLink *n = makeNode(SubLink); n->subLinkType = EXISTS_SUBLINK; - n->isExpr = false; n->lefthand = NIL; n->operName = NIL; n->subselect = $2; @@ -6606,7 +6571,6 @@ c_expr: columnref { $$ = (Node *) $1; } { SubLink *n = makeNode(SubLink); n->subLinkType = ARRAY_SUBLINK; - n->isExpr = false; n->lefthand = NIL; n->operName = NIL; n->subselect = $2; @@ -6781,7 +6745,6 @@ trim_list: a_expr FROM expr_list { $$ = lappend($3, $1); } in_expr: select_with_parens { SubLink *n = makeNode(SubLink); - n->isExpr = false; n->subselect = $1; /* other fields will be filled later */ $$ = (Node *)n; diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 7fd831ca91..987d129027 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.99 2003/06/25 04:32:03 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.100 2003/06/25 21:30:31 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -859,11 +859,7 @@ enforce_generic_type_consistency(Oid *actual_arg_types, /* 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; - + 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)); @@ -923,11 +919,7 @@ enforce_generic_type_consistency(Oid *actual_arg_types, { if (!OidIsValid(array_typeid)) { - if (elem_typeid != ANYELEMENTOID) - array_typeid = get_array_type(elem_typeid); - else - array_typeid = ANYARRAYOID; - + 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)); @@ -1178,11 +1170,6 @@ IsBinaryCoercible(Oid srctype, Oid targettype) 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, ObjectIdGetDatum(srctype), diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 5234c22e4f..1e65521710 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.149 2003/06/24 23:14:45 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.150 2003/06/25 21:30:31 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -436,7 +436,6 @@ transformExpr(ParseState *pstate, Node *expr) sublink->operName = NIL; sublink->operOids = NIL; sublink->useOr = FALSE; - sublink->isExpr = FALSE; } else if (sublink->subLinkType == EXPR_SUBLINK || sublink->subLinkType == ARRAY_SUBLINK) @@ -464,7 +463,6 @@ transformExpr(ParseState *pstate, Node *expr) sublink->operName = NIL; sublink->operOids = NIL; sublink->useOr = FALSE; - sublink->isExpr = FALSE; } else { @@ -540,30 +538,10 @@ transformExpr(ParseState *pstate, Node *expr) * 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); - } - + optup = oper(op, + exprType(lexpr), + exprType((Node *) tent->expr), + false); opform = (Form_pg_operator) GETSTRUCT(optup); if (opform->oprresult != BOOLOID) @@ -765,7 +743,7 @@ transformExpr(ParseState *pstate, Node *expr) ArrayExpr *e = (ArrayExpr *) lfirst(element); if (!IsA(e, ArrayExpr)) - elog(ERROR, "Multidimensional ARRAY[] must be built from nested array expressions"); + elog(ERROR, "Multi-dimensional ARRAY[] must be built from nested array expressions"); if (ndims == 0) ndims = e->ndims; else if (e->ndims != ndims) diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 2b0e10e4ca..806138a25a 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.151 2003/06/25 20:07:39 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.152 2003/06/25 21:30:31 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -336,7 +336,6 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, aggref->target = lfirst(fargs); aggref->aggstar = agg_star; aggref->aggdistinct = agg_distinct; - aggref->args = fargs; /* parse_agg.c does additional aggregate-specific processing */ transformAggregateCall(pstate, aggref); diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index a6b66625be..69edb4b85b 100644 --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.65 2003/06/24 23:14:45 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.66 2003/06/25 21:30:32 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -137,33 +137,6 @@ Operator 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 @@ -202,33 +175,6 @@ Operator 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* @@ -274,21 +220,6 @@ equality_oper_funcid(Oid argtype) 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; -} - /* * ordering_oper_opid - convenience routine for oprid(ordering_oper()) * diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index cfef2db349..415a086b7d 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.89 2003/06/24 23:14:45 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.90 2003/06/25 21:30:32 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -427,15 +427,6 @@ aclitemeq(const AclItem *a1, const AclItem *a2) a1->ai_grantor == a2->ai_grantor; } -/* - * 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))); -} /* * acldefault() --- create an ACL describing default access permissions diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c index f5e50771b1..519ac8d188 100644 --- a/src/backend/utils/adt/array_userfuncs.c +++ b/src/backend/utils/adt/array_userfuncs.c @@ -6,7 +6,7 @@ * Copyright (c) 2003, PostgreSQL Global Development Group * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/array_userfuncs.c,v 1.2 2003/06/24 23:14:45 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/array_userfuncs.c,v 1.3 2003/06/25 21:30:32 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -18,6 +18,35 @@ #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 @@ -41,7 +70,6 @@ array_push(PG_FUNCTION_ARGS) 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"); @@ -67,61 +95,28 @@ array_push(PG_FUNCTION_ARGS) 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; - } + /* Sanity check: do we have a one-dimensional array */ + if (ARR_NDIM(v) != 1) + elog(ERROR, "Arrays greater than one-dimension are not supported"); - if (my_extra->element_type != element_type) + lb = ARR_LBOUND(v); + dimv = ARR_DIMS(v); + if (arg0_elemid != InvalidOid) { - /* 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; + /* append newelem */ + int ub = dimv[0] + lb[0] - 1; + indx = ub + 1; } else { - typlen = my_extra->typlen; - typbyval = my_extra->typbyval; - typalign = my_extra->typalign; + /* prepend newelem */ + indx = lb[0] - 1; } - result = array_set(v, 1, &indx, newelem, -1, typlen, typbyval, - typalign, &isNull); + get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign); + + result = array_set(v, 1, &indx, newelem, -1, + typlen, typbyval, typalign, &isNull); PG_RETURN_ARRAYTYPE_P(result); } @@ -150,28 +145,13 @@ array_cat(PG_FUNCTION_ARGS) /* * 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 + * 1) two arrays with ndims1 == ndims2 + * 2) ndims1 == ndims2 - 1 + * 3) 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); @@ -286,15 +266,147 @@ array_cat(PG_FUNCTION_ARGS) 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); +} /* - * used by text_to_array() in varlena.c + * actually does the work for singleton_array(), and array_accum() if it is + * given a null input array. */ ArrayType * -create_singleton_array(FunctionCallInfo fcinfo, - Oid element_type, - Datum element, - int ndims) +create_singleton_array(Oid element_type, Datum element, int ndims) { Datum dvalues[1]; int16 typlen; @@ -303,7 +415,6 @@ create_singleton_array(FunctionCallInfo fcinfo, int dims[MAXDIM]; int lbs[MAXDIM]; int i; - ArrayMetaState *my_extra; if (element_type == 0) elog(ERROR, "Invalid array element type: %u", element_type); @@ -318,35 +429,7 @@ create_singleton_array(FunctionCallInfo fcinfo, 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; - } + get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign); return construct_md_array(dvalues, ndims, dims, lbs, element_type, typlen, typbyval, typalign); diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 27a805d9b2..c03d8c861d 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.90 2003/06/24 23:14:45 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.91 2003/06/25 21:30:32 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -21,10 +21,8 @@ #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" @@ -72,6 +70,16 @@ #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, @@ -85,6 +93,10 @@ static Datum *ReadArrayBinary(StringInfo buf, int nitems, 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, @@ -107,7 +119,7 @@ static void array_insert_slice(int ndim, int *dim, int *lb, char *destPtr, int *st, int *endp, char *srcPtr, int typlen, bool typbyval, char typalign); -static int array_cmp(FunctionCallInfo fcinfo); + /*--------------------------------------------------------------------- * array_in : @@ -142,49 +154,12 @@ array_in(PG_FUNCTION_ARGS) 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; - } + /* 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? */ @@ -661,51 +636,12 @@ array_out(PG_FUNCTION_ARGS) 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; - } + 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); @@ -864,7 +800,6 @@ array_recv(PG_FUNCTION_ARGS) dim[MAXDIM], lBound[MAXDIM]; char typalign; - ArrayMetaState *my_extra; /* Get the array header information */ ndim = pq_getmsgint(buf, 4); @@ -896,50 +831,14 @@ array_recv(PG_FUNCTION_ARGS) 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; - } + /* 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, @@ -1077,54 +976,15 @@ array_send(PG_FUNCTION_ARGS) 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; - } + 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); @@ -1616,26 +1476,6 @@ array_set(ArrayType *array, 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"); @@ -1792,31 +1632,6 @@ array_set_slice(ArrayType *array, /* 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"); @@ -1996,13 +1811,6 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType) 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) @@ -2021,81 +1829,11 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType) 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; - } + /* 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)); @@ -2311,6 +2049,8 @@ deconstruct_array(ArrayType *array, * compares two arrays for equality * result : * returns true if the arrays are equal, false otherwise. + * + * XXX bitwise equality is pretty bogus ... *----------------------------------------------------------------------------- */ Datum @@ -2318,118 +2058,12 @@ array_eq(PG_FUNCTION_ARGS) { 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) + if (ARR_SIZE(array1) != ARR_SIZE(array2)) + result = false; + else if (memcmp(array1, array2, ARR_SIZE(array1)) != 0) 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); @@ -2439,190 +2073,53 @@ array_eq(PG_FUNCTION_ARGS) } -/*----------------------------------------------------------------------------- - * 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 |*****************/ /***************************************************************************/ +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 */ @@ -2926,18 +2423,6 @@ array_type_coerce(PG_FUNCTION_ARGS) 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)) { @@ -2954,16 +2439,10 @@ array_type_coerce(PG_FUNCTION_ARGS) } /* - * If it's binary-compatible, modify the element type in the array header, - * but otherwise leave the array as we received it. + * If it's binary-compatible, return the array unmodified. */ 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); - } + PG_RETURN_ARRAYTYPE_P(src); /* * Use array_map to apply the function to each array element. @@ -2975,118 +2454,3 @@ array_type_coerce(PG_FUNCTION_ARGS) 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); -} diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index aca19d17e8..ce6443647e 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.99 2003/06/24 23:14:46 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.100 2003/06/25 21:30:32 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -19,14 +19,11 @@ #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; @@ -1986,7 +1983,8 @@ split_text(PG_FUNCTION_ARGS) if (fldnum == 1) /* first field - just return the input * string */ PG_RETURN_TEXT_P(inputstring); - else /* otherwise return an empty string */ + else +/* otherwise return an empty string */ PG_RETURN_TEXT_P(PG_STR_GET_TEXT("")); } @@ -2006,7 +2004,8 @@ split_text(PG_FUNCTION_ARGS) if (fldnum == 1) /* first field - just return the input * string */ PG_RETURN_TEXT_P(inputstring); - else /* otherwise return an empty string */ + else +/* otherwise return an empty string */ PG_RETURN_TEXT_P(PG_STR_GET_TEXT("")); } else if ((start_posn != 0) && (end_posn == 0)) @@ -2029,191 +2028,6 @@ split_text(PG_FUNCTION_ARGS) } } -/* - * 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 /* * Convert a int32 to a string containing a base 16 (hex) representation of diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 2c0c645791..479f23090f 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.98 2003/06/25 03:56:31 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.99 2003/06/25 21:30:32 momjian Exp $ * * NOTES * Eventually, the index information should go through here, too. @@ -718,40 +718,6 @@ get_func_rettype(Oid funcid) return result; } -/* - * 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. @@ -1124,56 +1090,6 @@ get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, 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 char get_typalign(Oid typid) diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index d772a0a06c..e161bd1e59 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.69 2003/06/24 23:14:46 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.70 2003/06/25 21:30:32 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1673,29 +1673,3 @@ get_fn_expr_argtype(FunctionCallInfo fcinfo, int argnum) 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; -} diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h index 43672f716f..4b6107ce53 100644 --- a/src/include/catalog/pg_amop.h +++ b/src/include/catalog/pg_amop.h @@ -16,7 +16,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_amop.h,v 1.51 2003/06/24 23:14:46 momjian Exp $ + * $Id: pg_amop.h,v 1.52 2003/06/25 21:30:32 momjian Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -418,15 +418,6 @@ DATA(insert ( 2098 3 f 2334 )); 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 diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h index 87553a4980..6febdecffc 100644 --- a/src/include/catalog/pg_amproc.h +++ b/src/include/catalog/pg_amproc.h @@ -14,7 +14,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_amproc.h,v 1.39 2003/06/24 23:14:46 momjian Exp $ + * $Id: pg_amproc.h,v 1.40 2003/06/25 21:30:32 momjian Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -78,7 +78,6 @@ DATA(insert ( 1993 3 199 )); /* btree */ -DATA(insert ( 397 1 382 )); DATA(insert ( 421 1 357 )); DATA(insert ( 423 1 1596 )); DATA(insert ( 424 1 1693 )); diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h index 828afe5aa8..88d2aac1a7 100644 --- a/src/include/catalog/pg_opclass.h +++ b/src/include/catalog/pg_opclass.h @@ -26,7 +26,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_opclass.h,v 1.52 2003/06/24 23:14:46 momjian Exp $ + * $Id: pg_opclass.h,v 1.53 2003/06/25 21:30:32 momjian Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -87,8 +87,6 @@ typedef FormData_pg_opclass *Form_pg_opclass; */ 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 )); diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index 3a7b143c9f..2bbef276c0 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_operator.h,v 1.116 2003/06/24 23:14:46 momjian Exp $ + * $Id: pg_operator.h,v 1.117 2003/06/25 21:30:32 momjian Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -116,15 +116,10 @@ DATA(insert OID = 96 ( "=" PGNSP PGUID b t 23 23 16 96 518 97 97 97 521 int 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 = 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 f 28 23 16 0 0 0 0 0 0 xideqint4 eqsel eqjoinsel )); @@ -430,7 +425,6 @@ DATA(insert OID = 965 ( "^" PGNSP PGUID b f 701 701 701 0 0 0 0 0 0 dpow - 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 - - )); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index d4c2f64cb7..bae6f644fc 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_proc.h,v 1.306 2003/06/24 23:14:47 momjian Exp $ + * $Id: pg_proc.h,v 1.307 2003/06/25 21:30:32 momjian Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -758,8 +758,6 @@ DATA(insert OID = 359 ( btnamecmp PGNSP PGUID 12 f f t f i 2 23 "19 19" btn 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 = 382 ( 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"); @@ -990,23 +988,14 @@ DESCR("greater-than"); 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 = 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_ )); @@ -1017,18 +1006,22 @@ DATA(insert OID = 2091 ( array_lower PGNSP PGUID 12 f f t f i 2 23 "2277 23" 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 = 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"); @@ -1329,8 +1322,6 @@ DATA(insert OID = 1036 ( aclremove PGNSP PGUID 12 f f t f s 2 1034 "1034 10 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 = 1365 ( makeaclitem PGNSP PGUID 12 f f t f s 5 1033 "23 23 23 25 16" makeaclitem - _null_ )); DESCR("make ACL item"); DATA(insert OID = 1038 ( seteval PGNSP PGUID 12 f f t t v 1 23 "26" seteval - _null_ )); diff --git a/src/include/fmgr.h b/src/include/fmgr.h index 784b50885e..51844eac38 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -11,14 +11,13 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: fmgr.h,v 1.28 2003/06/24 23:14:46 momjian Exp $ + * $Id: fmgr.h,v 1.29 2003/06/25 21:30:32 momjian Exp $ * *------------------------------------------------------------------------- */ #ifndef FMGR_H #define FMGR_H -#include "nodes/nodes.h" /* * All functions that can be called directly by fmgr must have this signature. @@ -373,14 +372,14 @@ extern Datum OidFunctionCall9(Oid functionId, Datum arg1, Datum arg2, 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); +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 diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 3756e443ff..23dff8ed62 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -10,7 +10,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: primnodes.h,v 1.84 2003/06/24 23:14:48 momjian Exp $ + * $Id: primnodes.h,v 1.85 2003/06/25 21:30:33 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -226,7 +226,6 @@ typedef struct Aggref Index agglevelsup; /* > 0 if agg belongs to outer query */ bool aggstar; /* TRUE if argument was really '*' */ bool aggdistinct; /* TRUE if it's agg(DISTINCT ...) */ - List *args; /* arguments to the aggregate */ } Aggref; /* ---------------- @@ -359,19 +358,15 @@ typedef struct BoolExpr /* ---------------- * 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: + * 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 ...) - * 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 @@ -420,8 +415,6 @@ typedef struct SubLink 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 */ @@ -463,15 +456,6 @@ typedef struct SubPlan 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 */ diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h index 946fc68c46..04add3c6f6 100644 --- a/src/include/optimizer/clauses.h +++ b/src/include/optimizer/clauses.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: clauses.h,v 1.64 2003/06/24 23:14:49 momjian Exp $ + * $Id: clauses.h,v 1.65 2003/06/25 21:30:33 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -28,9 +28,6 @@ extern Expr *make_opclause(Oid opno, Oid opresulttype, bool opretset, 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); diff --git a/src/include/parser/parse_oper.h b/src/include/parser/parse_oper.h index e7c8bdb56c..13642f5a34 100644 --- a/src/include/parser/parse_oper.h +++ b/src/include/parser/parse_oper.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: parse_oper.h,v 1.26 2003/06/24 23:14:49 momjian Exp $ + * $Id: parse_oper.h,v 1.27 2003/06/25 21:30:33 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -44,7 +44,6 @@ extern Operator ordering_oper(Oid argtype, bool noError); /* 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 */ diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index 0d77611901..9cf35618ad 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: acl.h,v 1.53 2003/06/24 23:14:49 momjian Exp $ + * $Id: acl.h,v 1.54 2003/06/25 21:30:33 momjian Exp $ * * NOTES * For backward-compatibility purposes we have to allow there @@ -192,7 +192,6 @@ extern Datum aclinsert(PG_FUNCTION_ARGS); extern Datum aclremove(PG_FUNCTION_ARGS); extern Datum aclcontains(PG_FUNCTION_ARGS); extern Datum makeaclitem(PG_FUNCTION_ARGS); -extern Datum aclitem_eq(PG_FUNCTION_ARGS); /* * prototypes for functions in aclchk.c diff --git a/src/include/utils/array.h b/src/include/utils/array.h index 5df86b1827..23a32d3459 100644 --- a/src/include/utils/array.h +++ b/src/include/utils/array.h @@ -10,7 +10,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: array.h,v 1.39 2003/06/24 23:14:49 momjian Exp $ + * $Id: array.h,v 1.40 2003/06/25 21:30:33 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -32,37 +32,6 @@ typedef struct 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 */ @@ -117,15 +86,11 @@ extern Datum array_recv(PG_FUNCTION_ARGS); 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_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, @@ -159,14 +124,7 @@ extern void deconstruct_array(ArrayType *array, 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 @@ -183,11 +141,12 @@ extern int mda_next_tuple(int n, int *curr, int *span); /* * 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(FunctionCallInfo fcinfo, - Oid element_type, +extern ArrayType *create_singleton_array(Oid element_type, Datum element, int ndims); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 43e174722b..958021eb1f 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: builtins.h,v 1.221 2003/06/24 23:14:49 momjian Exp $ + * $Id: builtins.h,v 1.222 2003/06/25 21:30:33 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -530,8 +530,6 @@ extern bool SplitIdentifierString(char *rawstring, char separator, 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); diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index e9de9f02c3..d7d3bba9d9 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: lsyscache.h,v 1.73 2003/06/25 03:56:31 momjian Exp $ + * $Id: lsyscache.h,v 1.74 2003/06/25 21:30:33 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -15,15 +15,6 @@ #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); @@ -50,7 +41,6 @@ extern RegProcedure get_oprrest(Oid opno); 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); @@ -66,14 +56,6 @@ extern bool get_typbyval(Oid typid); 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); diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y index ff175700cf..ffa849045a 100644 --- a/src/interfaces/ecpg/preproc/preproc.y +++ b/src/interfaces/ecpg/preproc/preproc.y @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/Attic/preproc.y,v 1.238 2003/06/25 10:44:21 meskes Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/Attic/preproc.y,v 1.239 2003/06/25 21:30:33 momjian Exp $ */ /* Copyright comment */ %{ @@ -4599,7 +4599,7 @@ type_declaration: S_TYPEDEF $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"); + mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types"); types = this; } @@ -5419,7 +5419,7 @@ ECPGTypedef: TYPE_P $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"); + mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types"); types = this; } @@ -5486,7 +5486,7 @@ ECPGVar: SQL_VAR default: if (atoi(length) >= 0) - mmerror(PARSE_ERROR, ET_ERROR, "No multidimensional array support for simple data types"); + 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")); diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c index 80406bbccc..5f2dd86bb5 100644 --- a/src/interfaces/ecpg/preproc/type.c +++ b/src/interfaces/ecpg/preproc/type.c @@ -504,7 +504,7 @@ ECPGfree_type(struct ECPGtype * type) switch (type->u.element->type) { case ECPGt_array: - yyerror("internal error, found multidimensional array\n"); + yyerror("internal error, found multi-dimensional array\n"); break; case ECPGt_struct: case ECPGt_union: diff --git a/src/interfaces/ecpg/preproc/variable.c b/src/interfaces/ecpg/preproc/variable.c index 9fa2ec8a6c..be96e18c0c 100644 --- a/src/interfaces/ecpg/preproc/variable.c +++ b/src/interfaces/ecpg/preproc/variable.c @@ -436,7 +436,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty if (atoi(type_index) >= 0) { if (atoi(*length) >= 0) - mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support"); + mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support"); *length = type_index; } @@ -444,7 +444,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty if (atoi(type_dimension) >= 0) { if (atoi(*dimension) >= 0 && atoi(*length) >= 0) - mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support"); + mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support"); if (atoi(*dimension) >= 0) *length = *dimension; @@ -463,10 +463,10 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty 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"); + 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 multidimensional array support"); + mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support"); switch (type_enum) { @@ -480,7 +480,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty } if (atoi(*length) >= 0) - mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support for structures"); + mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support for structures"); break; case ECPGt_varchar: @@ -525,7 +525,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty } if (atoi(*length) >= 0) - mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support for simple data types"); + mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support for simple data types"); break; } diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out index c5f638bd46..617cf09a9a 100644 --- a/src/test/regress/expected/arrays.out +++ b/src/test/regress/expected/arrays.out @@ -178,13 +178,19 @@ SELECT ARRAY(select f2 from arrtest_f order by f2) AS "ARRAY"; (1 row) -- functions -SELECT array_append(array[42], 6) AS "{42,6}"; +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, array[42]) AS "{6,42}"; +SELECT array_prepend(6, singleton_array(42)) AS "{6,42}"; {6,42} -------- {6,42} @@ -208,6 +214,24 @@ SELECT array_cat(ARRAY[[3,4],[5,6]], ARRAY[1,2]) AS "{{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 SELECT a FROM arrtest WHERE b = ARRAY[[[113,142],[1,147]]]; a diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql index e39044e40a..82eff24125 100644 --- a/src/test/regress/sql/arrays.sql +++ b/src/test/regress/sql/arrays.sql @@ -130,11 +130,15 @@ SELECT ARRAY[ARRAY['hello'],ARRAY['world']]; 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 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]]];