Index: doc/src/sgml/array.sgml
===================================================================
RCS file: /opt/src/cvs/pgsql-server/doc/src/sgml/array.sgml,v
retrieving revision 1.25
diff -c -r1.25 array.sgml
*** doc/src/sgml/array.sgml 13 Mar 2003 01:30:26 -0000 1.25
--- doc/src/sgml/array.sgml 22 May 2003 23:42:01 -0000
***************
*** 9,15 ****
PostgreSQL allows columns of a table to be
! defined as variable-length multidimensional arrays. Arrays of any
built-in type or user-defined type can be created.
--- 9,15 ----
PostgreSQL allows columns of a table to be
! defined as variable-length multi-dimensional arrays. Arrays of any
built-in type or user-defined type can be created.
***************
*** 60,73 ****
! A limitation of the present array implementation is that individual
! elements of an array cannot be SQL null values. The entire array can be set
! to null, but you can't have an array with some elements null and some
! not. Fixing this is on the to-do list.
--- 60,133 ----
+
+ A limitation of the present array implementation is that individual
+ elements of an array cannot be SQL null values. The entire array can be set
+ to null, but you can't have an array with some elements null and some
+ not.
+
+
+ This can lead to surprising results. For example, the result of the
+ previous two inserts looks like this:
+
+ SELECT * FROM sal_emp;
+ name | pay_by_quarter | schedule
+ -------+---------------------------+--------------------
+ Bill | {10000,10000,10000,10000} | {{meeting},{""}}
+ Carol | {20000,25000,25000,25000} | {{talk},{meeting}}
+ (2 rows)
+
+ Because the [2][2] element of
+ schedule is missing in each of the
+ INSERT statements, the [1][2]
+ element is discarded.
+
+
+
+
+ Fixing this is on the to-do list.
+
+
+
+
+ The ARRAY expression syntax may also be used:
+
+ INSERT INTO sal_emp
+ VALUES ('Bill',
+ ARRAY[10000, 10000, 10000, 10000],
+ ARRAY[['meeting', 'lunch'], ['','']]);
+
+ INSERT INTO sal_emp
+ VALUES ('Carol',
+ ARRAY[20000, 25000, 25000, 25000],
+ ARRAY[['talk', 'consult'], ['meeting', '']]);
+ SELECT * FROM sal_emp;
+ name | pay_by_quarter | schedule
+ -------+---------------------------+-------------------------------
+ Bill | {10000,10000,10000,10000} | {{meeting,lunch},{"",""}}
+ Carol | {20000,25000,25000,25000} | {{talk,consult},{meeting,""}}
+ (2 rows)
+
+ Note that with this syntax, multi-dimesion 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: Multiple dimension arrays must have array expressions with matching dimensions
+
+ Also notice that string literals are single quoted instead of double quoted.
+
+
! The examples in the rest of this section are based on the
! ARRAY expression syntax INSERTs.
+
***************
*** 132,142 ****
with the same result. An array subscripting operation is always taken to
! represent an array slice if any of the subscripts are written in the
! form
lower:upper.
A lower bound of 1 is assumed for any subscript where only one value
! is specified.
--- 192,221 ----
with the same result. An array subscripting operation is always taken to
! represent an array slice if any of the subscripts are written in the form
lower:upper.
A lower bound of 1 is assumed for any subscript where only one value
! is specified; another example follows:
!
! SELECT schedule[1:2][2] FROM sal_emp WHERE name = 'Bill';
! schedule
! ---------------------------
! {{meeting,lunch},{"",""}}
! (1 row)
!
!
!
!
! Additionally, we can also access a single arbitrary array element of
! a one-dimensional array with the array_subscript
! function:
!
! SELECT array_subscript(pay_by_quarter, 2) FROM sal_emp WHERE name = 'Bill';
! array_subscript
! -----------------
! 10000
! (1 row)
!
***************
*** 147,153 ****
WHERE name = 'Carol';
! or updated at a single element:
UPDATE sal_emp SET pay_by_quarter[4] = 15000
--- 226,248 ----
WHERE name = 'Carol';
! or using the ARRAY expression syntax:
!
!
! UPDATE sal_emp SET pay_by_quarter = ARRAY[25000,25000,27000,27000]
! WHERE name = 'Carol';
!
!
!
!
! Anywhere you can use the curly braces
array syntax,
! you can also use the ARRAY expression syntax. The
! remainder of this section will illustrate only one or the other, but
! not both.
!
!
!
! An array may also be updated at a single element:
UPDATE sal_emp SET pay_by_quarter[4] = 15000
***************
*** 160,165 ****
--- 255,268 ----
UPDATE sal_emp SET pay_by_quarter[1:2] = '{27000,27000}'
WHERE name = 'Carol';
+
+ A one-dimensional array may also be updated with the
+ array_assign function:
+
+
+ UPDATE sal_emp SET pay_by_quarter = array_assign(pay_by_quarter, 4, 15000)
+ WHERE name = 'Bill';
+
***************
*** 169,175 ****
value currently has 4 elements, it will have five elements after an
update that assigns to array[5]>. Currently, enlargement in
this fashion is only allowed for one-dimensional arrays, not
! multidimensional arrays.
--- 272,278 ----
value currently has 4 elements, it will have five elements after an
update that assigns to array[5]>. Currently, enlargement in
this fashion is only allowed for one-dimensional arrays, not
! multi-dimensional arrays.
***************
*** 179,184 ****
--- 282,367 ----
+ 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 multi-dimensional arrays.
+ 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}}
+
+
+ array_prepend and array_append
+ work with a one-dimensional array and a single element to be pushed on
+ to the beginning or end of the array, respectively. 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 array_prepend(1, ARRAY[2,3]) AS f) AS t;
+ array_dims
+ ------------
+ [0:2]
+ (1 row)
+
+
+ array_cat works with either two
+ n>-dimension arrays, or an n>-dimension
+ and an n+1> dimension array. In the former case, the two
+ n>-dimension arrays become outer elements of an
+ n+1> dimension array. In the latter, the
+ n>-dimension array is added as either the first or last
+ outer element of the n+1> dimension array.
+
+
+
+ A final method of enlarging arrays is through the concatenation operator,
+ ||, which works exactly as array_cat
+ does.
+
+ 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 syntax for CREATE TABLE allows fixed-length
arrays to be defined:
***************
*** 194,199 ****
--- 377,392 ----
+ An alternative syntax for one-dimensional arrays may be used.
+ pay_by_quarter could have been defined as:
+
+ pay_by_quarter integer ARRAY[4],
+
+ This syntax may only be used with the integer
+ constant to denote the array size.
+
+
+
Actually, the current implementation does not enforce the declared
number of dimensions either. Arrays of a particular element type are
all considered to be of the same type, regardless of size or number
***************
*** 292,298 ****
for the array's element type. (Among the standard data types provided
in the PostgreSQL distribution, type
box> uses a semicolon (;>) but all the others
! use comma.) In a multidimensional array, each dimension (row, plane,
cube, etc.) gets its own level of curly braces, and delimiters
must be written between adjacent curly-braced entities of the same level.
You may write whitespace before a left brace, after a right
--- 485,491 ----
for the array's element type. (Among the standard data types provided
in the PostgreSQL distribution, type
box> uses a semicolon (;>) but all the others
! use comma.) In a multi-dimensional array, each dimension (row, plane,
cube, etc.) gets its own level of curly braces, and delimiters
must be written between adjacent curly-braced entities of the same level.
You may write whitespace before a left brace, after a right
***************
*** 300,305 ****
--- 493,564 ----
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 multi-dimensional arrays, the keyword
+ ARRAY is only necessary for the outer level. For example,
+ '{{"hello world", "happy birthday"}}' could be written as:
+
+ SELECT ARRAY[['hello world', 'happy birthday']];
+ array
+ ------------------------------------
+ {{"hello world","happy birthday"}}
+ (1 row)
+
+ or it also could be written as:
+
+ SELECT ARRAY[ARRAY['hello world', 'happy birthday']];
+ array
+ ------------------------------------
+ {{"hello world","happy birthday"}}
+ (1 row)
+
+
+
+
+ A final method to represent an array, is through an
+ ARRAY sub-select expression. For example:
+
+ SELECT ARRAY(SELECT oid FROM pg_proc WHERE proname LIKE 'bytea%');
+ ?column?
+ -------------------------------------------------------------
+ {2011,1954,1948,1952,1951,1244,1950,2005,1949,1953,2006,31}
+ (1 row)
+
+ The sub-select may only return a single column. The
+ resulting one-dimensional array will have an element for each row in the
+ sub-select result, with an element type matching that of the sub-select's
+ target column.
+
+
+
+ Arrays may be cast from one type to another in similar fashion to other
+ data types:
+
+
+ SELECT ARRAY[1,2,3]::oid[];
+ array
+ ---------
+ {1,2,3}
+ (1 row)
+
+ SELECT CAST(ARRAY[1,2,3] AS float8[]);
+ array
+ ---------
+ {1,2,3}
+ (1 row)
+
+
+
+
***************
*** 316,321 ****
--- 575,588 ----
Alternatively, you can use backslash-escaping to protect all data characters
that would otherwise be taken as array syntax or ignorable white space.
+
+
+
+ The discussion in the preceding paragraph with respect to double quoting does
+ not pertain to the ARRAY expression syntax. In that case,
+ each element is quoted exactly as any other literal value of the element type.
+
+
The array output routine will put double quotes around element values
Index: doc/src/sgml/func.sgml
===================================================================
RCS file: /opt/src/cvs/pgsql-server/doc/src/sgml/func.sgml,v
retrieving revision 1.154
diff -c -r1.154 func.sgml
*** doc/src/sgml/func.sgml 5 May 2003 15:08:49 -0000 1.154
--- doc/src/sgml/func.sgml 22 May 2003 23:42:01 -0000
***************
*** 6962,6967 ****
--- 6962,7224 ----
+
+ Array Functions
+
+
+ shows the operators
+ available for the array types.
+
+
+
+ array Operators
+
+
+
+ Operator
+ Description
+ Example
+ Result
+
+
+
+
+ =
+ equals
+ ARRAY[1.1,2.1,3.1]::int[] = ARRAY[1,2,3]
+ t
+
+
+ ||
+ array-to-array concatenation
+ ARRAY[1,2,3] || ARRAY[4,5,6]
+ {{1,2,3},{4,5,6}}
+
+
+ ||
+ array-to-array concatenation
+ ARRAY[1,2,3] || ARRAY[[4,5,6],[7,8,9]]
+ {{1,2,3},{4,5,6},{7,8,9}}
+
+
+ ||
+ element-to-array concatenation
+ 3 || ARRAY[4,5,6]
+ {3,4,5,6}
+
+
+ ||
+ array-to-element concatenation
+ ARRAY[4,5,6] || 7
+ {4,5,6,7}
+
+
+
+
+
+
+ shows the functions
+ available for use with array types. See
+ for more discussion and examples for the use of these functions.
+
+
+
+ array Functions
+
+
+
+ Function
+ Return Type
+ Description
+ Example
+ Result
+
+
+
+
+
+
+ array_accum
+ (anyarray, anyelement)
+
+
+ anyarray
+
+ append an element to the end of an array, ignoring
+ NULL elements, and creating an array if needed
+
+ array_accum(null, 1)
+ {1}
+
+
+
+
+ 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_assign
+ (anyarray, integer, anyelement)
+
+
+ anyarray
+
+ assign a value to a specific array element, returning
+ NULL for NULL inputs
+
+ array_assign(ARRAY[1,2,3], 2, 99)
+ {1,99,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_subscript
+ (anyarray, integer)
+
+
+ anyelement
+
+ returns requested array element, returning
+ NULL for NULL inputs
+
+ array_subscript(ARRAY[1,2,3], 3)
+ 3
+
+
+
+
+ array_to_str
+ (anyarray, text)
+
+
+ text
+
+ concatenates array elements using provided delimiter, returning
+ NULL for NULL inputs
+
+ array_to_str(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
+
+
+
+
+ singleton_array
+ (anyelement)
+
+
+ anyarray
+
+ create an array from the provided element, returning
+ NULL for NULL inputs
+
+ singleton_array(1)
+ {1}
+
+
+
+
+ str_to_array
+ (text, text)
+
+
+ text[]
+
+ splits string into array elements using provided delimiter, returning
+ NULL for NULL inputs
+
+ str_to_array('1.10~^~2.20~^~3.30','~^~')::float8[]
+ {1.1,2.2,3.3}
+
+
+
+
+
Aggregate Functions
Index: src/backend/executor/nodeSubplan.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/executor/nodeSubplan.c,v
retrieving revision 1.45
diff -c -r1.45 nodeSubplan.c
*** src/backend/executor/nodeSubplan.c 8 Apr 2003 23:20:01 -0000 1.45
--- src/backend/executor/nodeSubplan.c 22 May 2003 23:42:01 -0000
***************
*** 28,50 ****
#include "utils/datum.h"
#include "utils/lsyscache.h"
-
- typedef struct ArrayBuildState
- {
- MemoryContext mcontext; /* where all the temp stuff is kept */
- Datum *dvalues; /* array of accumulated Datums */
- /*
- * The allocated size of dvalues[] is always a multiple of
- * ARRAY_ELEMS_CHUNKSIZE
- */
- #define ARRAY_ELEMS_CHUNKSIZE 64
- int nelems; /* number of valid Datums in dvalues[] */
- Oid element_type; /* data type of the Datums */
- int16 typlen; /* needed info about datatype */
- bool typbyval;
- char typalign;
- } ArrayBuildState;
-
static Datum ExecHashSubPlan(SubPlanState *node,
ExprContext *econtext,
bool *isNull);
--- 28,33 ----
***************
*** 54,66 ****
static void buildSubPlanHash(SubPlanState *node);
static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot);
static bool tupleAllNulls(HeapTuple tuple);
- static ArrayBuildState *accumArrayResult(ArrayBuildState *astate,
- Datum dvalue, bool disnull,
- Oid element_type,
- MemoryContext rcontext);
- static Datum makeArrayResult(ArrayBuildState *astate,
- MemoryContext rcontext);
-
/* ----------------------------------------------------------------
* ExecSubPlan
--- 37,42 ----
***************
*** 1084,1185 ****
prm->execPlan = node;
parent->chgParam = bms_add_member(parent->chgParam, paramid);
}
- }
-
- /*
- * accumArrayResult - accumulate one (more) Datum for an ARRAY_SUBLINK
- *
- * astate is working state (NULL on first call)
- * rcontext is where to keep working state
- */
- static ArrayBuildState *
- accumArrayResult(ArrayBuildState *astate,
- Datum dvalue, bool disnull,
- Oid element_type,
- MemoryContext rcontext)
- {
- MemoryContext arr_context,
- oldcontext;
-
- if (astate == NULL)
- {
- /* First time through --- initialize */
-
- /* Make a temporary context to hold all the junk */
- arr_context = AllocSetContextCreate(rcontext,
- "ARRAY_SUBLINK Result",
- ALLOCSET_DEFAULT_MINSIZE,
- ALLOCSET_DEFAULT_INITSIZE,
- ALLOCSET_DEFAULT_MAXSIZE);
- oldcontext = MemoryContextSwitchTo(arr_context);
- astate = (ArrayBuildState *) palloc(sizeof(ArrayBuildState));
- astate->mcontext = arr_context;
- astate->dvalues = (Datum *)
- palloc(ARRAY_ELEMS_CHUNKSIZE * sizeof(Datum));
- astate->nelems = 0;
- astate->element_type = element_type;
- get_typlenbyvalalign(element_type,
- &astate->typlen,
- &astate->typbyval,
- &astate->typalign);
- }
- else
- {
- oldcontext = MemoryContextSwitchTo(astate->mcontext);
- Assert(astate->element_type == element_type);
- /* enlarge dvalues[] if needed */
- if ((astate->nelems % ARRAY_ELEMS_CHUNKSIZE) == 0)
- astate->dvalues = (Datum *)
- repalloc(astate->dvalues,
- (astate->nelems + ARRAY_ELEMS_CHUNKSIZE) * sizeof(Datum));
- }
-
- if (disnull)
- elog(ERROR, "NULL elements not allowed in Arrays");
-
- /* Use datumCopy to ensure pass-by-ref stuff is copied into mcontext */
- astate->dvalues[astate->nelems++] =
- datumCopy(dvalue, astate->typbyval, astate->typlen);
-
- MemoryContextSwitchTo(oldcontext);
-
- return astate;
- }
-
- /*
- * makeArrayResult - produce final result of ARRAY_SUBLINK
- *
- * astate is working state (not NULL)
- * rcontext is where to construct result
- */
- static Datum
- makeArrayResult(ArrayBuildState *astate,
- MemoryContext rcontext)
- {
- ArrayType *result;
- int dims[1];
- int lbs[1];
- MemoryContext oldcontext;
-
- /* Build the final array result in rcontext */
- oldcontext = MemoryContextSwitchTo(rcontext);
-
- dims[0] = astate->nelems;
- lbs[0] = 1;
-
- result = construct_md_array(astate->dvalues,
- 1,
- dims,
- lbs,
- astate->element_type,
- astate->typlen,
- astate->typbyval,
- astate->typalign);
-
- MemoryContextSwitchTo(oldcontext);
-
- /* Clean up all the junk */
- MemoryContextDelete(astate->mcontext);
-
- return PointerGetDatum(result);
}
--- 1060,1063 ----
Index: src/backend/utils/adt/array_userfuncs.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/adt/array_userfuncs.c,v
retrieving revision 1.1
diff -c -r1.1 array_userfuncs.c
*** src/backend/utils/adt/array_userfuncs.c 8 Apr 2003 23:20:02 -0000 1.1
--- src/backend/utils/adt/array_userfuncs.c 23 May 2003 00:05:38 -0000
***************
*** 42,48 ****
else
ndims = 1;
! PG_RETURN_ARRAYTYPE_P(create_singleton_array(elem_type,
PG_GETARG_DATUM(0),
ndims));
}
--- 42,48 ----
else
ndims = 1;
! PG_RETURN_ARRAYTYPE_P(create_singleton_array(fcinfo, elem_type,
PG_GETARG_DATUM(0),
ndims));
}
***************
*** 70,75 ****
--- 70,76 ----
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");
***************
*** 113,119 ****
indx = lb[0] - 1;
}
! get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
result = array_set(v, 1, &indx, newelem, -1,
typlen, typbyval, typalign, &isNull);
--- 114,148 ----
indx = lb[0] - 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;
! }
result = array_set(v, 1, &indx, newelem, -1,
typlen, typbyval, typalign, &isNull);
***************
*** 293,299 ****
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));
}
--- 322,328 ----
if (tgt_elem_type == InvalidOid)
elog(ERROR, "Target type is not an array");
! PG_RETURN_ARRAYTYPE_P(create_singleton_array(fcinfo, tgt_elem_type,
PG_GETARG_DATUM(1),
1));
}
***************
*** 329,334 ****
--- 358,364 ----
int16 typlen;
bool typbyval;
char typalign;
+ ArrayMetaState *my_extra;
v = PG_GETARG_ARRAYTYPE_P(0);
idx_to_chg = PG_GETARG_INT32(1);
***************
*** 349,355 ****
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);
--- 379,413 ----
if (element_type == 0)
elog(ERROR, "Invalid array element type: %u", element_type);
! /*
! * We arrange to look up info about element type only once per series
! * of calls, assuming the element type doesn't change underneath us.
! */
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! if (my_extra == NULL)
! {
! fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(ArrayMetaState));
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! my_extra->element_type = InvalidOid;
! }
!
! if (my_extra->element_type != element_type)
! {
! /* Get info about element type */
! get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
!
! my_extra->element_type = element_type;
! my_extra->typlen = typlen;
! my_extra->typbyval = typbyval;
! my_extra->typalign = typalign;
! }
! else
! {
! typlen = my_extra->typlen;
! typbyval = my_extra->typbyval;
! typalign = my_extra->typalign;
! }
result = array_set(v, 1, &idx_to_chg, newelem, -1,
typlen, typbyval, typalign, &isNull);
***************
*** 375,380 ****
--- 433,439 ----
int16 typlen;
bool typbyval;
char typalign;
+ ArrayMetaState *my_extra;
v = PG_GETARG_ARRAYTYPE_P(0);
idx = PG_GETARG_INT32(1);
***************
*** 394,400 ****
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);
--- 453,487 ----
if (element_type == 0)
elog(ERROR, "Invalid array element type: %u", element_type);
! /*
! * We arrange to look up info about element type only once per series
! * of calls, assuming the element type doesn't change underneath us.
! */
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! if (my_extra == NULL)
! {
! fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(ArrayMetaState));
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! my_extra->element_type = InvalidOid;
! }
!
! if (my_extra->element_type != element_type)
! {
! /* Get info about element type */
! get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
!
! my_extra->element_type = element_type;
! my_extra->typlen = typlen;
! my_extra->typbyval = typbyval;
! my_extra->typalign = typalign;
! }
! else
! {
! typlen = my_extra->typlen;
! typbyval = my_extra->typbyval;
! typalign = my_extra->typalign;
! }
result = array_ref(v, 1, &idx, -1, typlen, typbyval, typalign, &isNull);
***************
*** 406,412 ****
* given a null input array.
*/
ArrayType *
! create_singleton_array(Oid element_type, Datum element, int ndims)
{
Datum dvalues[1];
int16 typlen;
--- 493,502 ----
* given a null input array.
*/
ArrayType *
! create_singleton_array(FunctionCallInfo fcinfo,
! Oid element_type,
! Datum element,
! int ndims)
{
Datum dvalues[1];
int16 typlen;
***************
*** 415,420 ****
--- 505,511 ----
int dims[MAXDIM];
int lbs[MAXDIM];
int i;
+ ArrayMetaState *my_extra;
if (element_type == 0)
elog(ERROR, "Invalid array element type: %u", element_type);
***************
*** 429,435 ****
lbs[i] = 1;
}
! get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
return construct_md_array(dvalues, ndims, dims, lbs, element_type,
typlen, typbyval, typalign);
--- 520,554 ----
lbs[i] = 1;
}
! /*
! * We arrange to look up info about element type only once per series
! * of calls, assuming the element type doesn't change underneath us.
! */
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! if (my_extra == NULL)
! {
! fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(ArrayMetaState));
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! my_extra->element_type = InvalidOid;
! }
!
! if (my_extra->element_type != element_type)
! {
! /* Get info about element type */
! get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
!
! my_extra->element_type = element_type;
! my_extra->typlen = typlen;
! my_extra->typbyval = typbyval;
! my_extra->typalign = typalign;
! }
! else
! {
! typlen = my_extra->typlen;
! typbyval = my_extra->typbyval;
! typalign = my_extra->typalign;
! }
return construct_md_array(dvalues, ndims, dims, lbs, element_type,
typlen, typbyval, typalign);
Index: src/backend/utils/adt/arrayfuncs.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/adt/arrayfuncs.c,v
retrieving revision 1.89
diff -c -r1.89 arrayfuncs.c
*** src/backend/utils/adt/arrayfuncs.c 9 May 2003 23:01:45 -0000 1.89
--- src/backend/utils/adt/arrayfuncs.c 22 May 2003 23:42:01 -0000
***************
*** 21,28 ****
--- 21,30 ----
#include "catalog/pg_type.h"
#include "libpq/pqformat.h"
#include "parser/parse_coerce.h"
+ #include "parser/parse_oper.h"
#include "utils/array.h"
#include "utils/builtins.h"
+ #include "utils/datum.h"
#include "utils/memutils.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
***************
*** 70,85 ****
#define RETURN_NULL(type) do { *isNull = true; return (type) 0; } while (0)
- /* I/O function selector for system_cache_lookup */
- typedef enum IOFuncSelector
- {
- IOFunc_input,
- IOFunc_output,
- IOFunc_receive,
- IOFunc_send
- } IOFuncSelector;
-
-
static int ArrayCount(char *str, int *dim, char typdelim);
static Datum *ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim,
FmgrInfo *inputproc, Oid typelem, int32 typmod,
--- 72,77 ----
***************
*** 93,102 ****
static void CopyArrayEls(char *p, Datum *values, int nitems,
int typlen, bool typbyval, char typalign,
bool freedata);
- static void system_cache_lookup(Oid element_type, IOFuncSelector which_func,
- int *typlen, bool *typbyval,
- char *typdelim, Oid *typelem,
- Oid *proc, char *typalign);
static Datum ArrayCast(char *value, bool byval, int len);
static int ArrayCastAndSet(Datum src,
int typlen, bool typbyval, char typalign,
--- 85,90 ----
***************
*** 154,165 ****
dim[MAXDIM],
lBound[MAXDIM];
char typalign;
! /* Get info about element type, including its input conversion proc */
! system_cache_lookup(element_type, IOFunc_input,
! &typlen, &typbyval, &typdelim,
! &typelem, &typinput, &typalign);
! fmgr_info(typinput, &inputproc);
/* Make a modifiable copy of the input */
/* XXX why are we allocating an extra 2 bytes here? */
--- 142,190 ----
dim[MAXDIM],
lBound[MAXDIM];
char typalign;
+ ArrayMetaState *my_extra;
! /*
! * We arrange to look up info about element type, including its input
! * conversion proc only once per series of calls, assuming the element
! * type doesn't change underneath us.
! */
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! if (my_extra == NULL)
! {
! fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(ArrayMetaState));
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! my_extra->element_type = InvalidOid;
! }
!
! if (my_extra->element_type != element_type)
! {
! /* Get info about element type, including its input conversion proc */
! get_type_metadata(element_type, IOFunc_input,
! &typlen, &typbyval, &typdelim,
! &typelem, &typinput, &typalign);
! fmgr_info(typinput, &inputproc);
!
! my_extra->element_type = element_type;
! my_extra->typlen = typlen;
! my_extra->typbyval = typbyval;
! my_extra->typdelim = typdelim;
! my_extra->typelem = typelem;
! my_extra->typiofunc = typinput;
! my_extra->typalign = typalign;
! my_extra->proc = inputproc;
! }
! else
! {
! typlen = my_extra->typlen;
! typbyval = my_extra->typbyval;
! typdelim = my_extra->typdelim;
! typelem = my_extra->typelem;
! typinput = my_extra->typiofunc;
! typalign = my_extra->typalign;
! inputproc = my_extra->proc;
! }
/* Make a modifiable copy of the input */
/* XXX why are we allocating an extra 2 bytes here? */
***************
*** 636,647 ****
indx[MAXDIM];
int ndim,
*dim;
element_type = ARR_ELEMTYPE(v);
! system_cache_lookup(element_type, IOFunc_output,
! &typlen, &typbyval, &typdelim,
! &typelem, &typoutput, &typalign);
! fmgr_info(typoutput, &outputproc);
ndim = ARR_NDIM(v);
dim = ARR_DIMS(v);
--- 661,711 ----
indx[MAXDIM];
int ndim,
*dim;
+ ArrayMetaState *my_extra;
element_type = ARR_ELEMTYPE(v);
!
! /*
! * We arrange to look up info about element type, including its input
! * conversion proc only once per series of calls, assuming the element
! * type doesn't change underneath us.
! */
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! if (my_extra == NULL)
! {
! fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(ArrayMetaState));
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! my_extra->element_type = InvalidOid;
! }
!
! if (my_extra->element_type != element_type)
! {
! /* Get info about element type, including its output conversion proc */
! get_type_metadata(element_type, IOFunc_output,
! &typlen, &typbyval, &typdelim,
! &typelem, &typoutput, &typalign);
! fmgr_info(typoutput, &outputproc);
!
! my_extra->element_type = element_type;
! my_extra->typlen = typlen;
! my_extra->typbyval = typbyval;
! my_extra->typdelim = typdelim;
! my_extra->typelem = typelem;
! my_extra->typiofunc = typoutput;
! my_extra->typalign = typalign;
! my_extra->proc = outputproc;
! }
! else
! {
! typlen = my_extra->typlen;
! typbyval = my_extra->typbyval;
! typdelim = my_extra->typdelim;
! typelem = my_extra->typelem;
! typoutput = my_extra->typiofunc;
! typalign = my_extra->typalign;
! outputproc = my_extra->proc;
! }
ndim = ARR_NDIM(v);
dim = ARR_DIMS(v);
***************
*** 800,805 ****
--- 864,870 ----
dim[MAXDIM],
lBound[MAXDIM];
char typalign;
+ ArrayMetaState *my_extra;
/* Get the array header information */
ndim = pq_getmsgint(buf, 4);
***************
*** 831,844 ****
PG_RETURN_ARRAYTYPE_P(retval);
}
! /* Get info about element type, including its receive conversion proc */
! system_cache_lookup(element_type, IOFunc_receive,
! &typlen, &typbyval, &typdelim,
! &typelem, &typreceive, &typalign);
! if (!OidIsValid(typreceive))
! elog(ERROR, "No binary input function available for type %s",
! format_type_be(element_type));
! fmgr_info(typreceive, &receiveproc);
dataPtr = ReadArrayBinary(buf, nitems, &receiveproc, typelem,
typlen, typbyval, typalign,
--- 896,945 ----
PG_RETURN_ARRAYTYPE_P(retval);
}
! /*
! * We arrange to look up info about element type, including its receive
! * conversion proc only once per series of calls, assuming the element
! * type doesn't change underneath us.
! */
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! if (my_extra == NULL)
! {
! fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(ArrayMetaState));
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! my_extra->element_type = InvalidOid;
! }
!
! if (my_extra->element_type != element_type)
! {
! /* Get info about element type, including its receive conversion proc */
! get_type_metadata(element_type, IOFunc_receive,
! &typlen, &typbyval, &typdelim,
! &typelem, &typreceive, &typalign);
! if (!OidIsValid(typreceive))
! elog(ERROR, "No binary input function available for type %s",
! format_type_be(element_type));
! fmgr_info(typreceive, &receiveproc);
!
! my_extra->element_type = element_type;
! my_extra->typlen = typlen;
! my_extra->typbyval = typbyval;
! my_extra->typdelim = typdelim;
! my_extra->typelem = typelem;
! my_extra->typiofunc = typreceive;
! my_extra->typalign = typalign;
! my_extra->proc = receiveproc;
! }
! else
! {
! typlen = my_extra->typlen;
! typbyval = my_extra->typbyval;
! typdelim = my_extra->typdelim;
! typelem = my_extra->typelem;
! typreceive = my_extra->typiofunc;
! typalign = my_extra->typalign;
! receiveproc = my_extra->proc;
! }
dataPtr = ReadArrayBinary(buf, nitems, &receiveproc, typelem,
typlen, typbyval, typalign,
***************
*** 976,990 ****
int ndim,
*dim;
StringInfoData buf;
/* Get information about the element type and the array dimensions */
element_type = ARR_ELEMTYPE(v);
! system_cache_lookup(element_type, IOFunc_send, &typlen, &typbyval,
! &typdelim, &typelem, &typsend, &typalign);
! if (!OidIsValid(typsend))
! elog(ERROR, "No binary output function available for type %s",
! format_type_be(element_type));
! fmgr_info(typsend, &sendproc);
ndim = ARR_NDIM(v);
dim = ARR_DIMS(v);
--- 1077,1130 ----
int ndim,
*dim;
StringInfoData buf;
+ ArrayMetaState *my_extra;
/* Get information about the element type and the array dimensions */
element_type = ARR_ELEMTYPE(v);
!
! /*
! * We arrange to look up info about element type, including its send
! * proc only once per series of calls, assuming the element
! * type doesn't change underneath us.
! */
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! if (my_extra == NULL)
! {
! fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(ArrayMetaState));
! my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
! my_extra->element_type = InvalidOid;
! }
!
! if (my_extra->element_type != element_type)
! {
! /* Get info about element type, including its send proc */
! get_type_metadata(element_type, IOFunc_send, &typlen, &typbyval,
! &typdelim, &typelem, &typsend, &typalign);
! if (!OidIsValid(typsend))
! elog(ERROR, "No binary output function available for type %s",
! format_type_be(element_type));
! fmgr_info(typsend, &sendproc);
!
! my_extra->element_type = element_type;
! my_extra->typlen = typlen;
! my_extra->typbyval = typbyval;
! my_extra->typdelim = typdelim;
! my_extra->typelem = typelem;
! my_extra->typiofunc = typsend;
! my_extra->typalign = typalign;
! my_extra->proc = sendproc;
! }
! else
! {
! typlen = my_extra->typlen;
! typbyval = my_extra->typbyval;
! typdelim = my_extra->typdelim;
! typelem = my_extra->typelem;
! typsend = my_extra->typiofunc;
! typalign = my_extra->typalign;
! sendproc = my_extra->proc;
! }
ndim = ARR_NDIM(v);
dim = ARR_DIMS(v);
***************
*** 1811,1816 ****
--- 1951,1963 ----
Oid typelem;
Oid proc;
char *s;
+ typedef struct {
+ ArrayMetaState *inp_extra;
+ ArrayMetaState *ret_extra;
+ } am_extra;
+ am_extra *my_extra;
+ ArrayMetaState *inp_extra;
+ ArrayMetaState *ret_extra;
/* Get input array */
if (fcinfo->nargs < 1)
***************
*** 1829,1839 ****
if (nitems <= 0)
PG_RETURN_ARRAYTYPE_P(v);
! /* Lookup source and result types. Unneeded variables are reused. */
! system_cache_lookup(inpType, IOFunc_input, &inp_typlen, &inp_typbyval,
! &typdelim, &typelem, &proc, &inp_typalign);
! system_cache_lookup(retType, IOFunc_input, &typlen, &typbyval,
! &typdelim, &typelem, &proc, &typalign);
/* Allocate temporary array for new values */
values = (Datum *) palloc(nitems * sizeof(Datum));
--- 1976,2056 ----
if (nitems <= 0)
PG_RETURN_ARRAYTYPE_P(v);
! /*
! * We arrange to look up info about input and return element types only
! * once per series of calls, assuming the element type doesn't change
! * underneath us.
! */
! my_extra = (am_extra *) fcinfo->flinfo->fn_extra;
! if (my_extra == NULL)
! {
! fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(am_extra));
! my_extra = (am_extra *) fcinfo->flinfo->fn_extra;
!
! my_extra->inp_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(ArrayMetaState));
! inp_extra = my_extra->inp_extra;
! inp_extra->element_type = InvalidOid;
!
! my_extra->ret_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
! sizeof(ArrayMetaState));
! ret_extra = my_extra->ret_extra;
! ret_extra->element_type = InvalidOid;
! }
! else
! {
! inp_extra = my_extra->inp_extra;
! ret_extra = my_extra->ret_extra;
! }
!
! if (inp_extra->element_type != inpType)
! {
! /* Lookup source and result types. Unneeded variables are reused. */
! get_type_metadata(inpType, IOFunc_input, &inp_typlen, &inp_typbyval,
! &typdelim, &typelem, &proc, &inp_typalign);
!
! inp_extra->element_type = inpType;
! inp_extra->typlen = inp_typlen;
! inp_extra->typbyval = inp_typbyval;
! inp_extra->typdelim = typdelim;
! inp_extra->typelem = typelem;
! inp_extra->typiofunc = proc;
! inp_extra->typalign = inp_typalign;
! }
! else
! {
! inp_typlen = inp_extra->typlen;
! inp_typbyval = inp_extra->typbyval;
! typdelim = inp_extra->typdelim;
! typelem = inp_extra->typelem;
! proc = inp_extra->typiofunc;
! inp_typalign = inp_extra->typalign;
! }
!
! if (ret_extra->element_type != retType)
! {
! /* Lookup source and result types. Unneeded variables are reused. */
! get_type_metadata(retType, IOFunc_input, &typlen, &typbyval,
! &typdelim, &typelem, &proc, &typalign);
!
! ret_extra->element_type = retType;
! ret_extra->typlen = typlen;
! ret_extra->typbyval = typbyval;
! ret_extra->typdelim = typdelim;
! ret_extra->typelem = typelem;
! ret_extra->typiofunc = proc;
! ret_extra->typalign = typalign;
! }
! else
! {
! typlen = ret_extra->typlen;
! typbyval = ret_extra->typbyval;
! typdelim = ret_extra->typdelim;
! typelem = ret_extra->typelem;
! proc = ret_extra->typiofunc;
! typalign = ret_extra->typalign;
! }
/* Allocate temporary array for new values */
values = (Datum *) palloc(nitems * sizeof(Datum));
***************
*** 2049,2056 ****
* compares two arrays for equality
* result :
* returns true if the arrays are equal, false otherwise.
- *
- * XXX bitwise equality is pretty bogus ...
*-----------------------------------------------------------------------------
*/
Datum
--- 2266,2271 ----
***************
*** 2058,2069 ****
{
ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
bool result = true;
! if (ARR_SIZE(array1) != ARR_SIZE(array2))
! result = false;
! else if (memcmp(array1, array2, ARR_SIZE(array1)) != 0)
result = false;
/* Avoid leaking memory when handed toasted input. */
PG_FREE_IF_COPY(array1, 0);
--- 2273,2390 ----
{
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 *fmgr_info = fcinfo->flinfo;
bool result = true;
+ int typlen;
+ bool typbyval;
+ char typdelim;
+ Oid typelem;
+ char typalign;
+ Oid typiofunc;
+ int i;
+ ArrayMetaState *my_extra;
+ FunctionCallInfoData locfcinfo;
! /* fast path if the arrays do not have the same number of elements */
! if (nitems1 != nitems2)
result = false;
+ else
+ {
+ /*
+ * We arrange to look up the equality function only once per series of
+ * calls, assuming the element type doesn't change underneath us.
+ */
+ my_extra = (ArrayMetaState *) fmgr_info->fn_extra;
+ if (my_extra == NULL)
+ {
+ fmgr_info->fn_extra = MemoryContextAlloc(fmgr_info->fn_mcxt,
+ sizeof(ArrayMetaState));
+ my_extra = (ArrayMetaState *) 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, 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);
***************
*** 2077,2125 ****
/******************| Support Routines |*****************/
/***************************************************************************/
- static void
- system_cache_lookup(Oid element_type,
- IOFuncSelector which_func,
- int *typlen,
- bool *typbyval,
- char *typdelim,
- Oid *typelem,
- Oid *proc,
- char *typalign)
- {
- HeapTuple typeTuple;
- Form_pg_type typeStruct;
-
- typeTuple = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(element_type),
- 0, 0, 0);
- if (!HeapTupleIsValid(typeTuple))
- elog(ERROR, "cache lookup failed for type %u", element_type);
- typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
-
- *typlen = typeStruct->typlen;
- *typbyval = typeStruct->typbyval;
- *typdelim = typeStruct->typdelim;
- *typelem = typeStruct->typelem;
- *typalign = typeStruct->typalign;
- switch (which_func)
- {
- case IOFunc_input:
- *proc = typeStruct->typinput;
- break;
- case IOFunc_output:
- *proc = typeStruct->typoutput;
- break;
- case IOFunc_receive:
- *proc = typeStruct->typreceive;
- break;
- case IOFunc_send:
- *proc = typeStruct->typsend;
- break;
- }
- ReleaseSysCache(typeTuple);
- }
-
/*
* Fetch array element at pointer, converted correctly to a Datum
*/
--- 2398,2403 ----
***************
*** 2453,2456 ****
--- 2731,2849 ----
locfcinfo.arg[0] = PointerGetDatum(src);
return array_map(&locfcinfo, my_extra->srctype, my_extra->desttype);
+ }
+
+ /*
+ * accumArrayResult - accumulate one (more) Datum for an ARRAY_SUBLINK
+ *
+ * astate is working state (NULL on first call)
+ * rcontext is where to keep working state
+ */
+ ArrayBuildState *
+ accumArrayResult(ArrayBuildState *astate,
+ Datum dvalue, bool disnull,
+ Oid element_type,
+ MemoryContext rcontext)
+ {
+ MemoryContext arr_context,
+ oldcontext;
+
+ if (astate == NULL)
+ {
+ /* First time through --- initialize */
+
+ /* Make a temporary context to hold all the junk */
+ arr_context = AllocSetContextCreate(rcontext,
+ "accumArrayResult",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+ oldcontext = MemoryContextSwitchTo(arr_context);
+ astate = (ArrayBuildState *) palloc(sizeof(ArrayBuildState));
+ astate->mcontext = arr_context;
+ astate->dvalues = (Datum *)
+ palloc(ARRAY_ELEMS_CHUNKSIZE * sizeof(Datum));
+ astate->nelems = 0;
+ astate->element_type = element_type;
+ get_typlenbyvalalign(element_type,
+ &astate->typlen,
+ &astate->typbyval,
+ &astate->typalign);
+ }
+ else
+ {
+ oldcontext = MemoryContextSwitchTo(astate->mcontext);
+ Assert(astate->element_type == element_type);
+ /* enlarge dvalues[] if needed */
+ if ((astate->nelems % ARRAY_ELEMS_CHUNKSIZE) == 0)
+ astate->dvalues = (Datum *)
+ repalloc(astate->dvalues,
+ (astate->nelems + ARRAY_ELEMS_CHUNKSIZE) * sizeof(Datum));
+ }
+
+ if (disnull)
+ elog(ERROR, "NULL elements not allowed in Arrays");
+
+ /* Use datumCopy to ensure pass-by-ref stuff is copied into mcontext */
+ astate->dvalues[astate->nelems++] =
+ datumCopy(dvalue, astate->typbyval, astate->typlen);
+
+ MemoryContextSwitchTo(oldcontext);
+
+ return astate;
+ }
+
+ /*
+ * makeArrayResult - produce final result of accumArrayResult
+ *
+ * astate is working state (not NULL)
+ * rcontext is where to construct result
+ */
+ Datum
+ makeArrayResult(ArrayBuildState *astate,
+ MemoryContext rcontext)
+ {
+ int dims[1];
+ int lbs[1];
+
+ dims[0] = astate->nelems;
+ lbs[0] = 1;
+
+ return makeMdArrayResult(astate, 1, dims, lbs, rcontext);
+ }
+
+ /*
+ * makeMdArrayResult - produce md final result of accumArrayResult
+ *
+ * astate is working state (not NULL)
+ * rcontext is where to construct result
+ */
+ Datum
+ makeMdArrayResult(ArrayBuildState *astate,
+ int ndims,
+ int *dims,
+ int *lbs,
+ MemoryContext rcontext)
+ {
+ ArrayType *result;
+ MemoryContext oldcontext;
+
+ /* Build the final array result in rcontext */
+ oldcontext = MemoryContextSwitchTo(rcontext);
+
+ result = construct_md_array(astate->dvalues,
+ ndims,
+ dims,
+ lbs,
+ astate->element_type,
+ astate->typlen,
+ astate->typbyval,
+ astate->typalign);
+
+ MemoryContextSwitchTo(oldcontext);
+
+ /* Clean up all the junk */
+ MemoryContextDelete(astate->mcontext);
+
+ return PointerGetDatum(result);
}
Index: src/backend/utils/adt/varlena.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/adt/varlena.c,v
retrieving revision 1.98
diff -c -r1.98 varlena.c
*** src/backend/utils/adt/varlena.c 15 May 2003 15:50:19 -0000 1.98
--- src/backend/utils/adt/varlena.c 23 May 2003 00:11:27 -0000
***************
*** 19,29 ****
--- 19,32 ----
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "access/tuptoaster.h"
+ #include "catalog/pg_type.h"
#include "lib/stringinfo.h"
#include "libpq/crypt.h"
#include "libpq/pqformat.h"
+ #include "utils/array.h"
#include "utils/builtins.h"
#include "utils/pg_locale.h"
+ #include "utils/lsyscache.h"
typedef struct varlena unknown;
***************
*** 1983,1990 ****
if (fldnum == 1) /* first field - just return the input
* string */
PG_RETURN_TEXT_P(inputstring);
! else
! /* otherwise return an empty string */
PG_RETURN_TEXT_P(PG_STR_GET_TEXT(""));
}
--- 1986,1992 ----
if (fldnum == 1) /* first field - just return the input
* string */
PG_RETURN_TEXT_P(inputstring);
! else /* otherwise return an empty string */
PG_RETURN_TEXT_P(PG_STR_GET_TEXT(""));
}
***************
*** 2004,2011 ****
if (fldnum == 1) /* first field - just return the input
* string */
PG_RETURN_TEXT_P(inputstring);
! else
! /* otherwise return an empty string */
PG_RETURN_TEXT_P(PG_STR_GET_TEXT(""));
}
else if ((start_posn != 0) && (end_posn == 0))
--- 2006,2012 ----
if (fldnum == 1) /* first field - just return the input
* string */
PG_RETURN_TEXT_P(inputstring);
! else /* otherwise return an empty string */
PG_RETURN_TEXT_P(PG_STR_GET_TEXT(""));
}
else if ((start_posn != 0) && (end_posn == 0))
***************
*** 2026,2031 ****
--- 2027,2217 ----
result_text = text_substring(PointerGetDatum(inputstring), start_posn + fldsep_len, end_posn - start_posn - fldsep_len, false);
PG_RETURN_TEXT_P(result_text);
}
+ }
+
+ /*
+ * text_to_array
+ * parse input string
+ * return text array of elements
+ * based on provided field separator
+ */
+ Datum
+ text_to_array(PG_FUNCTION_ARGS)
+ {
+ text *inputstring = PG_GETARG_TEXT_P(0);
+ int inputstring_len = TEXTLEN(inputstring);
+ text *fldsep = PG_GETARG_TEXT_P(1);
+ int fldsep_len = TEXTLEN(fldsep);
+ int fldnum;
+ int start_posn = 0;
+ int end_posn = 0;
+ text *result_text = NULL;
+ ArrayBuildState *astate = NULL;
+ MemoryContext oldcontext = CurrentMemoryContext;
+
+ /* return NULL for empty input string */
+ if (inputstring_len < 1)
+ PG_RETURN_NULL();
+
+ /* empty field separator
+ * return one element, 1D, array using the input string */
+ if (fldsep_len < 1)
+ PG_RETURN_ARRAYTYPE_P(create_singleton_array(fcinfo, TEXTOID,
+ CStringGetDatum(inputstring), 1));
+
+ /* start with end position holding the initial start position */
+ end_posn = 0;
+ for (fldnum=1;;fldnum++) /* field number is 1 based */
+ {
+ Datum dvalue;
+ bool disnull = false;
+
+ start_posn = end_posn;
+ end_posn = text_position(PointerGetDatum(inputstring),
+ PointerGetDatum(fldsep),
+ fldnum);
+
+ if ((start_posn == 0) && (end_posn == 0)) /* fldsep not found */
+ {
+ if (fldnum == 1)
+ {
+ /* first element
+ * return one element, 1D, array using the input string */
+ PG_RETURN_ARRAYTYPE_P(create_singleton_array(fcinfo, TEXTOID,
+ CStringGetDatum(inputstring), 1));
+ }
+ else
+ {
+ /* otherwise create array and exit */
+ PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate, oldcontext));
+ }
+ }
+ else if ((start_posn != 0) && (end_posn == 0))
+ {
+ /* last field requested */
+ result_text = text_substring(PointerGetDatum(inputstring), start_posn + fldsep_len, -1, true);
+ }
+ else if ((start_posn == 0) && (end_posn != 0))
+ {
+ /* first field requested */
+ result_text = LEFT(inputstring, fldsep);
+ }
+ else
+ {
+ /* prior to last field requested */
+ result_text = text_substring(PointerGetDatum(inputstring), start_posn + fldsep_len, end_posn - start_posn - fldsep_len, false);
+ }
+
+ /* stash away current value */
+ dvalue = PointerGetDatum(result_text);
+ astate = accumArrayResult(astate, dvalue,
+ disnull, TEXTOID, oldcontext);
+
+ }
+
+ /* never reached -- keep compiler quiet */
+ PG_RETURN_NULL();
+ }
+
+ /*
+ * array_to_text
+ * concatenate Cstring representation of input array elements
+ * using provided field separator
+ */
+ Datum
+ array_to_text(PG_FUNCTION_ARGS)
+ {
+ ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
+ char *fldsep = PG_TEXTARG_GET_STR(1);
+ int nitems, *dims, ndims;
+ char *p;
+ Oid element_type;
+ int typlen;
+ bool typbyval;
+ char typdelim;
+ Oid typoutput,
+ typelem;
+ FmgrInfo outputproc;
+ char typalign;
+ StringInfo result_str = makeStringInfo();
+ int i;
+ ArrayMetaState *my_extra;
+
+ p = ARR_DATA_PTR(v);
+ ndims = ARR_NDIM(v);
+ dims = ARR_DIMS(v);
+ nitems = ArrayGetNItems(ndims, dims);
+
+ /* if there are no elements, return an empty string */
+ if (nitems == 0)
+ PG_RETURN_TEXT_P(PG_STR_GET_TEXT(""));
+
+ element_type = ARR_ELEMTYPE(v);
+
+ /*
+ * We arrange to look up info about element type, including its output
+ * conversion proc only once per series of calls, assuming the element
+ * type doesn't change underneath us.
+ */
+ my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
+ if (my_extra == NULL)
+ {
+ fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
+ sizeof(ArrayMetaState));
+ my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
+ my_extra->element_type = InvalidOid;
+ }
+
+ if (my_extra->element_type != element_type)
+ {
+ /* Get info about element type, including its output conversion proc */
+ get_type_metadata(element_type, IOFunc_output,
+ &typlen, &typbyval, &typdelim,
+ &typelem, &typoutput, &typalign);
+ fmgr_info(typoutput, &outputproc);
+
+ my_extra->element_type = element_type;
+ my_extra->typlen = typlen;
+ my_extra->typbyval = typbyval;
+ my_extra->typdelim = typdelim;
+ my_extra->typelem = typelem;
+ my_extra->typiofunc = typoutput;
+ my_extra->typalign = typalign;
+ my_extra->proc = outputproc;
+ }
+ else
+ {
+ typlen = my_extra->typlen;
+ typbyval = my_extra->typbyval;
+ typdelim = my_extra->typdelim;
+ typelem = my_extra->typelem;
+ typoutput = my_extra->typiofunc;
+ typalign = my_extra->typalign;
+ outputproc = my_extra->proc;
+ }
+
+ for (i = 0; i < nitems; i++)
+ {
+ Datum itemvalue;
+ char *value;
+
+ itemvalue = fetch_att(p, typbyval, typlen);
+
+ value = DatumGetCString(FunctionCall3(&outputproc,
+ itemvalue,
+ ObjectIdGetDatum(typelem),
+ Int32GetDatum(-1)));
+
+ if (i > 0)
+ appendStringInfo(result_str, "%s%s", fldsep, value);
+ else
+ appendStringInfo(result_str, "%s", value);
+
+ p = att_addlength(p, typlen, PointerGetDatum(p));
+ p = (char *) att_align(p, typalign);
+ }
+
+ PG_RETURN_TEXT_P(PG_STR_GET_TEXT(result_str->data));
}
#define HEXBASE 16
Index: src/backend/utils/cache/lsyscache.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/cache/lsyscache.c,v
retrieving revision 1.94
diff -c -r1.94 lsyscache.c
*** src/backend/utils/cache/lsyscache.c 13 May 2003 04:38:58 -0000 1.94
--- src/backend/utils/cache/lsyscache.c 22 May 2003 23:42:01 -0000
***************
*** 969,974 ****
--- 969,1024 ----
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)
Index: src/backend/utils/fmgr/fmgr.c
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/fmgr/fmgr.c,v
retrieving revision 1.68
diff -c -r1.68 fmgr.c
*** src/backend/utils/fmgr/fmgr.c 8 Apr 2003 23:20:02 -0000 1.68
--- src/backend/utils/fmgr/fmgr.c 22 May 2003 23:42:01 -0000
***************
*** 1673,1675 ****
--- 1673,1701 ----
return exprType((Node *) nth(argnum, args));
}
+
+ /*
+ * Get the OID of the function or operator
+ *
+ * Returns InvalidOid if information is not available
+ */
+ Oid
+ get_fn_expr_functype(FunctionCallInfo fcinfo)
+ {
+ Node *expr;
+
+ /*
+ * can't return anything useful if we have no FmgrInfo or if
+ * its fn_expr node has not been initialized
+ */
+ if (!fcinfo || !fcinfo->flinfo || !fcinfo->flinfo->fn_expr)
+ return InvalidOid;
+
+ expr = fcinfo->flinfo->fn_expr;
+ if (IsA(expr, FuncExpr))
+ return ((FuncExpr *) expr)->funcid;
+ else if (IsA(expr, OpExpr))
+ return ((OpExpr *) expr)->opno;
+ else
+ return InvalidOid;
+ }
Index: src/include/fmgr.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/fmgr.h,v
retrieving revision 1.27
diff -c -r1.27 fmgr.h
*** src/include/fmgr.h 8 Apr 2003 23:20:04 -0000 1.27
--- src/include/fmgr.h 22 May 2003 23:42:01 -0000
***************
*** 377,385 ****
* Routines in fmgr.c
*/
extern Pg_finfo_record *fetch_finfo_record(void *filehandle, char *funcname);
! extern Oid fmgr_internal_function(const char *proname);
! extern Oid get_fn_expr_rettype(FunctionCallInfo fcinfo);
! extern Oid get_fn_expr_argtype(FunctionCallInfo fcinfo, int argnum);
/*
* Routines in dfmgr.c
--- 377,386 ----
* Routines in fmgr.c
*/
extern Pg_finfo_record *fetch_finfo_record(void *filehandle, char *funcname);
! extern Oid fmgr_internal_function(const char *proname);
! extern Oid get_fn_expr_rettype(FunctionCallInfo fcinfo);
! extern Oid get_fn_expr_argtype(FunctionCallInfo fcinfo, int argnum);
! extern Oid get_fn_expr_functype(FunctionCallInfo fcinfo);
/*
* Routines in dfmgr.c
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/catalog/pg_proc.h,v
retrieving revision 1.300
diff -c -r1.300 pg_proc.h
*** src/include/catalog/pg_proc.h 15 May 2003 15:50:19 -0000 1.300
--- src/include/catalog/pg_proc.h 22 May 2003 23:42:01 -0000
***************
*** 1016,1021 ****
--- 1016,1025 ----
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 = 385 ( str_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 = 386 ( array_to_str 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");
Index: src/include/utils/array.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/utils/array.h,v
retrieving revision 1.38
diff -c -r1.38 array.h
*** src/include/utils/array.h 8 May 2003 22:19:57 -0000 1.38
--- src/include/utils/array.h 23 May 2003 00:06:49 -0000
***************
*** 32,37 ****
--- 32,68 ----
Oid elemtype; /* element type OID */
} ArrayType;
+ typedef struct ArrayBuildState
+ {
+ MemoryContext mcontext; /* where all the temp stuff is kept */
+ Datum *dvalues; /* array of accumulated Datums */
+ /*
+ * The allocated size of dvalues[] is always a multiple of
+ * ARRAY_ELEMS_CHUNKSIZE
+ */
+ #define ARRAY_ELEMS_CHUNKSIZE 64
+ int nelems; /* number of valid Datums in dvalues[] */
+ Oid element_type; /* data type of the Datums */
+ int16 typlen; /* needed info about datatype */
+ bool typbyval;
+ char typalign;
+ } ArrayBuildState;
+
+ /*
+ * structure to cache type metadata needed for array manipulation
+ */
+ typedef struct ArrayMetaState
+ {
+ Oid element_type;
+ int typlen;
+ bool typbyval;
+ char typdelim;
+ Oid typelem;
+ Oid typiofunc;
+ char typalign;
+ FmgrInfo proc;
+ } ArrayMetaState;
+
/*
* fmgr macros for array objects
*/
***************
*** 124,130 ****
Oid elmtype,
int elmlen, bool elmbyval, char elmalign,
Datum **elemsp, int *nelemsp);
!
/*
* prototypes for functions defined in arrayutils.c
--- 155,168 ----
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
***************
*** 146,152 ****
extern Datum array_accum(PG_FUNCTION_ARGS);
extern Datum array_cat(PG_FUNCTION_ARGS);
! extern ArrayType *create_singleton_array(Oid element_type,
Datum element,
int ndims);
--- 184,191 ----
extern Datum array_accum(PG_FUNCTION_ARGS);
extern Datum array_cat(PG_FUNCTION_ARGS);
! extern ArrayType *create_singleton_array(FunctionCallInfo fcinfo,
! Oid element_type,
Datum element,
int ndims);
Index: src/include/utils/builtins.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/utils/builtins.h,v
retrieving revision 1.217
diff -c -r1.217 builtins.h
*** src/include/utils/builtins.h 15 May 2003 15:50:20 -0000 1.217
--- src/include/utils/builtins.h 22 May 2003 23:42:01 -0000
***************
*** 539,544 ****
--- 539,546 ----
List **namelist);
extern Datum replace_text(PG_FUNCTION_ARGS);
extern Datum split_text(PG_FUNCTION_ARGS);
+ extern Datum text_to_array(PG_FUNCTION_ARGS);
+ extern Datum array_to_text(PG_FUNCTION_ARGS);
extern Datum to_hex32(PG_FUNCTION_ARGS);
extern Datum to_hex64(PG_FUNCTION_ARGS);
extern Datum md5_text(PG_FUNCTION_ARGS);
Index: src/include/utils/lsyscache.h
===================================================================
RCS file: /opt/src/cvs/pgsql-server/src/include/utils/lsyscache.h,v
retrieving revision 1.69
diff -c -r1.69 lsyscache.h
*** src/include/utils/lsyscache.h 9 May 2003 18:08:48 -0000 1.69
--- src/include/utils/lsyscache.h 22 May 2003 23:42:01 -0000
***************
*** 15,20 ****
--- 15,29 ----
#include "access/htup.h"
+ /* I/O function selector for system_cache_lookup */
+ typedef enum IOFuncSelector
+ {
+ IOFunc_input,
+ IOFunc_output,
+ IOFunc_receive,
+ IOFunc_send
+ } IOFuncSelector;
+
extern bool op_in_opclass(Oid opno, Oid opclass);
extern bool op_requires_recheck(Oid opno, Oid opclass);
extern char *get_attname(Oid relid, AttrNumber attnum);
***************
*** 53,58 ****
--- 62,75 ----
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);