Commit b3c0551e authored by Tom Lane's avatar Tom Lane

Create real array comparison functions (that use the element datatype's

comparison functions), replacing the highly bogus bitwise array_eq.  Create
a btree index opclass for ANYARRAY --- it is now possible to create indexes
on array columns.
Arrange to cache the results of catalog lookups across multiple array
operations, instead of repeating the lookups on every call.
Add string_to_array and array_to_string functions.
Remove singleton_array, array_accum, array_assign, and array_subscript
functions, since these were for proof-of-concept and not intended to become
supported functions.
Minor adjustments to behavior in some corner cases with empty or
zero-dimensional arrays.

Joe Conway (with some editorializing by Tom Lane).
parent 0c985ab5
This diff is collapsed.
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.156 2003/06/25 21:30:25 momjian Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.157 2003/06/27 00:33:25 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -6962,6 +6962,203 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); ...@@ -6962,6 +6962,203 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
</sect1> </sect1>
<sect1 id="functions-array">
<title>Array Functions</title>
<para>
<xref linkend="array-operators-table"> shows the operators
available for the <type>array</type> types.
</para>
<table id="array-operators-table">
<title><type>array</type> Operators</title>
<tgroup cols="4">
<thead>
<row>
<entry>Operator</entry>
<entry>Description</entry>
<entry>Example</entry>
<entry>Result</entry>
</row>
</thead>
<tbody>
<row>
<entry> <literal>=</literal> </entry>
<entry>equals</entry>
<entry><literal>ARRAY[1.1,2.1,3.1]::int[] = ARRAY[1,2,3]</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>||</literal> </entry>
<entry>array-to-array concatenation</entry>
<entry><literal>ARRAY[1,2,3] || ARRAY[4,5,6]</literal></entry>
<entry><literal>{{1,2,3},{4,5,6}}</literal></entry>
</row>
<row>
<entry> <literal>||</literal> </entry>
<entry>array-to-array concatenation</entry>
<entry><literal>ARRAY[1,2,3] || ARRAY[[4,5,6],[7,8,9]]</literal></entry>
<entry><literal>{{1,2,3},{4,5,6},{7,8,9}}</literal></entry>
</row>
<row>
<entry> <literal>||</literal> </entry>
<entry>element-to-array concatenation</entry>
<entry><literal>3 || ARRAY[4,5,6]</literal></entry>
<entry><literal>{3,4,5,6}</literal></entry>
</row>
<row>
<entry> <literal>||</literal> </entry>
<entry>array-to-element concatenation</entry>
<entry><literal>ARRAY[4,5,6] || 7</literal></entry>
<entry><literal>{4,5,6,7}</literal></entry>
</row>
</tbody>
</tgroup>
</table>
<para>
<xref linkend="array-functions-table"> shows the functions
available for use with array types. See <xref linkend="arrays">
for more discussion and examples for the use of these functions.
</para>
<table id="array-functions-table">
<title><type>array</type> Functions</title>
<tgroup cols="5">
<thead>
<row>
<entry>Function</entry>
<entry>Return Type</entry>
<entry>Description</entry>
<entry>Example</entry>
<entry>Result</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<literal>
<function>array_append</function>
(<type>anyarray</type>, <type>anyelement</type>)
</literal>
</entry>
<entry><type>anyarray</type></entry>
<entry>
append an element to the end of an array, returning
<literal>NULL</literal> for <literal>NULL</literal> inputs
</entry>
<entry><literal>array_append(ARRAY[1,2], 3)</literal></entry>
<entry><literal>{1,2,3}</literal></entry>
</row>
<row>
<entry>
<literal>
<function>array_cat</function>
(<type>anyarray</type>, <type>anyarray</type>)
</literal>
</entry>
<entry><type>anyarray</type></entry>
<entry>
concatenate two arrays, returning <literal>NULL</literal>
for <literal>NULL</literal> inputs
</entry>
<entry><literal>array_cat(ARRAY[1,2,3], ARRAY[4,5,6])</literal></entry>
<entry><literal>{{1,2,3},{4,5,6}}</literal></entry>
</row>
<row>
<entry>
<literal>
<function>array_dims</function>
(<type>anyarray</type>)
</literal>
</entry>
<entry><type>text</type></entry>
<entry>
returns a text representation of array dimension lower and upper bounds,
generating an ERROR for <literal>NULL</literal> inputs
</entry>
<entry><literal>array_dims(array[[1,2,3],[4,5,6]])</literal></entry>
<entry><literal>[1:2][1:3]</literal></entry>
</row>
<row>
<entry>
<literal>
<function>array_lower</function>
(<type>anyarray</type>, <type>integer</type>)
</literal>
</entry>
<entry><type>integer</type></entry>
<entry>
returns lower bound of the requested array dimension, returning
<literal>NULL</literal> for <literal>NULL</literal> inputs
</entry>
<entry><literal>array_lower(array_prepend(0, ARRAY[1,2,3]), 1)</literal></entry>
<entry><literal>0</literal></entry>
</row>
<row>
<entry>
<literal>
<function>array_prepend</function>
(<type>anyelement</type>, <type>anyarray</type>)
</literal>
</entry>
<entry><type>anyarray</type></entry>
<entry>
append an element to the beginning of an array, returning
<literal>NULL</literal> for <literal>NULL</literal> inputs
</entry>
<entry><literal>array_prepend(1, ARRAY[2,3])</literal></entry>
<entry><literal>{1,2,3}</literal></entry>
</row>
<row>
<entry>
<literal>
<function>array_to_string</function>
(<type>anyarray</type>, <type>text</type>)
</literal>
</entry>
<entry><type>text</type></entry>
<entry>
concatenates array elements using provided delimiter, returning
<literal>NULL</literal> for <literal>NULL</literal> inputs
</entry>
<entry><literal>array_to_string(array[1.1,2.2,3.3]::numeric(4,2)[],'~^~')</literal></entry>
<entry><literal>1.10~^~2.20~^~3.30</literal></entry>
</row>
<row>
<entry>
<literal>
<function>array_upper</function>
(<type>anyarray</type>, <type>integer</type>)
</literal>
</entry>
<entry><type>integer</type></entry>
<entry>
returns upper bound of the requested array dimension, returning
<literal>NULL</literal> for <literal>NULL</literal> inputs
</entry>
<entry><literal>array_upper(array_append(ARRAY[1,2,3], 4), 1)</literal></entry>
<entry><literal>4</literal></entry>
</row>
<row>
<entry>
<literal>
<function>string_to_array</function>
(<type>text</type>, <type>text</type>)
</literal>
</entry>
<entry><type>text[]</type></entry>
<entry>
splits string into array elements using provided delimiter, returning
<literal>NULL</literal> for <literal>NULL</literal> inputs
</entry>
<entry><literal>string_to_array('1.10~^~2.20~^~3.30','~^~')::float8[]</literal></entry>
<entry><literal>{1.1,2.2,3.3}</literal></entry>
</row>
</tbody>
</tgroup>
</table>
</sect1>
<sect1 id="functions-aggregate"> <sect1 id="functions-aggregate">
<title>Aggregate Functions</title> <title>Aggregate Functions</title>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.132 2003/06/25 21:30:28 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.133 2003/06/27 00:33:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1528,17 +1528,17 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext, ...@@ -1528,17 +1528,17 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
{ {
/* Check other sub-arrays are compatible */ /* Check other sub-arrays are compatible */
if (elem_ndims != ARR_NDIM(array)) if (elem_ndims != ARR_NDIM(array))
elog(ERROR, "Multiple dimension arrays must have array " elog(ERROR, "Multidimensional arrays must have array "
"expressions with matching number of dimensions"); "expressions with matching number of dimensions");
if (memcmp(elem_dims, ARR_DIMS(array), if (memcmp(elem_dims, ARR_DIMS(array),
elem_ndims * sizeof(int)) != 0) elem_ndims * sizeof(int)) != 0)
elog(ERROR, "Multiple dimension arrays must have array " elog(ERROR, "Multidimensional arrays must have array "
"expressions with matching dimensions"); "expressions with matching dimensions");
if (memcmp(elem_lbs, ARR_LBOUND(array), if (memcmp(elem_lbs, ARR_LBOUND(array),
elem_ndims * sizeof(int)) != 0) elem_ndims * sizeof(int)) != 0)
elog(ERROR, "Multiple dimension arrays must have array " elog(ERROR, "Multidimensional arrays must have array "
"expressions with matching dimensions"); "expressions with matching dimensions");
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.49 2003/06/25 21:30:29 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.50 2003/06/27 00:33:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -29,22 +29,6 @@ ...@@ -29,22 +29,6 @@
#include "utils/lsyscache.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, static Datum ExecHashSubPlan(SubPlanState *node,
ExprContext *econtext, ExprContext *econtext,
bool *isNull); bool *isNull);
...@@ -54,12 +38,6 @@ static Datum ExecScanSubPlan(SubPlanState *node, ...@@ -54,12 +38,6 @@ static Datum ExecScanSubPlan(SubPlanState *node,
static void buildSubPlanHash(SubPlanState *node); static void buildSubPlanHash(SubPlanState *node);
static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot); static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot);
static bool tupleAllNulls(HeapTuple tuple); 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);
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -1099,101 +1077,3 @@ ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent) ...@@ -1099,101 +1077,3 @@ ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
parent->chgParam = bms_add_member(parent->chgParam, paramid); 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);
}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.100 2003/06/25 21:30:31 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.101 2003/06/27 00:33:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1145,7 +1145,8 @@ IsPreferredType(CATEGORY category, Oid type) ...@@ -1145,7 +1145,8 @@ IsPreferredType(CATEGORY category, Oid type)
* invokable, no-function-needed pg_cast entry. Also, a domain is always * invokable, no-function-needed pg_cast entry. Also, a domain is always
* binary-coercible to its base type, though *not* vice versa (in the other * binary-coercible to its base type, though *not* vice versa (in the other
* direction, one must apply domain constraint checks before accepting the * direction, one must apply domain constraint checks before accepting the
* value as legitimate). * value as legitimate). We also need to special-case the polymorphic
* ANYARRAY type.
* *
* This function replaces IsBinaryCompatible(), which was an inherently * This function replaces IsBinaryCompatible(), which was an inherently
* symmetric test. Since the pg_cast entries aren't necessarily symmetric, * symmetric test. Since the pg_cast entries aren't necessarily symmetric,
...@@ -1170,6 +1171,11 @@ IsBinaryCoercible(Oid srctype, Oid targettype) ...@@ -1170,6 +1171,11 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
if (srctype == targettype) if (srctype == targettype)
return true; return true;
/* Also accept any array type as coercible to ANYARRAY */
if (targettype == ANYARRAYOID)
if (get_element_type(srctype) != InvalidOid)
return true;
/* Else look in pg_cast */ /* Else look in pg_cast */
tuple = SearchSysCache(CASTSOURCETARGET, tuple = SearchSysCache(CASTSOURCETARGET,
ObjectIdGetDatum(srctype), ObjectIdGetDatum(srctype),
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.150 2003/06/25 21:30:31 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.151 2003/06/27 00:33:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -743,7 +743,7 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -743,7 +743,7 @@ transformExpr(ParseState *pstate, Node *expr)
ArrayExpr *e = (ArrayExpr *) lfirst(element); ArrayExpr *e = (ArrayExpr *) lfirst(element);
if (!IsA(e, ArrayExpr)) if (!IsA(e, ArrayExpr))
elog(ERROR, "Multi-dimensional ARRAY[] must be built from nested array expressions"); elog(ERROR, "Multidimensional ARRAY[] must be built from nested array expressions");
if (ndims == 0) if (ndims == 0)
ndims = e->ndims; ndims = e->ndims;
else if (e->ndims != ndims) else if (e->ndims != ndims)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.66 2003/06/25 21:30:32 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.67 2003/06/27 00:33:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -137,28 +137,50 @@ Operator ...@@ -137,28 +137,50 @@ Operator
equality_oper(Oid argtype, bool noError) equality_oper(Oid argtype, bool noError)
{ {
Operator optup; Operator optup;
Oid elem_type;
/* /*
* Look for an "=" operator for the datatype. We require it to be * If the datatype is an array, then we can use array_eq ... but only
* an exact or binary-compatible match, since most callers are not * if there is a suitable equality operator for the element type.
* prepared to cope with adding any run-time type coercion steps. * (We must run this test first, since compatible_oper will find
* array_eq, but would not notice the lack of an element operator.)
*/ */
optup = compatible_oper(makeList1(makeString("=")), elem_type = get_element_type(argtype);
argtype, argtype, true); if (OidIsValid(elem_type))
if (optup != NULL) {
optup = equality_oper(elem_type, true);
if (optup != NULL)
{
ReleaseSysCache(optup);
return SearchSysCache(OPEROID,
ObjectIdGetDatum(ARRAY_EQ_OP),
0, 0, 0);
}
}
else
{ {
/* /*
* Only believe that it's equality if it's mergejoinable, * Look for an "=" operator for the datatype. We require it to be
* hashjoinable, or uses eqsel() as oprrest. * an exact or binary-compatible match, since most callers are not
* prepared to cope with adding any run-time type coercion steps.
*/ */
Form_pg_operator pgopform = (Form_pg_operator) GETSTRUCT(optup); optup = compatible_oper(makeList1(makeString("=")),
argtype, argtype, true);
if (optup != NULL)
{
/*
* Only believe that it's equality if it's mergejoinable,
* hashjoinable, or uses eqsel() as oprrest.
*/
Form_pg_operator pgopform = (Form_pg_operator) GETSTRUCT(optup);
if (OidIsValid(pgopform->oprlsortop) || if (OidIsValid(pgopform->oprlsortop) ||
pgopform->oprcanhash || pgopform->oprcanhash ||
pgopform->oprrest == F_EQSEL) pgopform->oprrest == F_EQSEL)
return optup; return optup;
ReleaseSysCache(optup); ReleaseSysCache(optup);
}
} }
if (!noError) if (!noError)
elog(ERROR, "Unable to identify an equality operator for type %s", elog(ERROR, "Unable to identify an equality operator for type %s",
...@@ -175,27 +197,50 @@ Operator ...@@ -175,27 +197,50 @@ Operator
ordering_oper(Oid argtype, bool noError) ordering_oper(Oid argtype, bool noError)
{ {
Operator optup; Operator optup;
Oid elem_type;
/* /*
* Find the type's equality operator, and use its lsortop (it *must* * If the datatype is an array, then we can use array_lt ... but only
* be mergejoinable). We use this definition because for sorting and * if there is a suitable ordering operator for the element type.
* grouping purposes, it's important that the equality and ordering * (We must run this test first, since the code below would find
* operators are consistent. * array_lt if there's an element = operator, but would not notice the
* lack of an element < operator.)
*/ */
optup = equality_oper(argtype, noError); elem_type = get_element_type(argtype);
if (optup != NULL) if (OidIsValid(elem_type))
{ {
Oid lsortop = ((Form_pg_operator) GETSTRUCT(optup))->oprlsortop; optup = ordering_oper(elem_type, true);
if (optup != NULL)
ReleaseSysCache(optup);
if (OidIsValid(lsortop))
{ {
optup = SearchSysCache(OPEROID, ReleaseSysCache(optup);
ObjectIdGetDatum(lsortop), return SearchSysCache(OPEROID,
0, 0, 0); ObjectIdGetDatum(ARRAY_LT_OP),
if (optup != NULL) 0, 0, 0);
return optup; }
}
else
{
/*
* Find the 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 = equality_oper(argtype, noError);
if (optup != NULL)
{
Oid lsortop;
lsortop = ((Form_pg_operator) GETSTRUCT(optup))->oprlsortop;
ReleaseSysCache(optup);
if (OidIsValid(lsortop))
{
optup = SearchSysCache(OPEROID,
ObjectIdGetDatum(lsortop),
0, 0, 0);
if (optup != NULL)
return optup;
}
} }
} }
if (!noError) if (!noError)
...@@ -237,6 +282,21 @@ ordering_oper_opid(Oid argtype) ...@@ -237,6 +282,21 @@ ordering_oper_opid(Oid argtype)
return result; 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;
}
/* given operator tuple, return the operator OID */ /* given operator tuple, return the operator OID */
Oid Oid
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.90 2003/06/25 21:30:32 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.91 2003/06/27 00:33:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -34,7 +34,7 @@ static const char *getid(const char *s, char *n); ...@@ -34,7 +34,7 @@ static const char *getid(const char *s, char *n);
static void putid(char *p, const char *s); static void putid(char *p, const char *s);
static Acl *allocacl(int n); static Acl *allocacl(int n);
static const char *aclparse(const char *s, AclItem *aip); static const char *aclparse(const char *s, AclItem *aip);
static bool aclitemeq(const AclItem *a1, const AclItem *a2); static bool aclitem_match(const AclItem *a1, const AclItem *a2);
static Acl *recursive_revoke(Acl *acl, AclId grantee, static Acl *recursive_revoke(Acl *acl, AclId grantee,
AclMode revoke_privs, DropBehavior behavior); AclMode revoke_privs, DropBehavior behavior);
...@@ -415,18 +415,33 @@ aclitemout(PG_FUNCTION_ARGS) ...@@ -415,18 +415,33 @@ aclitemout(PG_FUNCTION_ARGS)
} }
/* /*
* aclitemeq * aclitem_match
* Two AclItems are considered equal iff they have the same * Two AclItems are considered to match iff they have the same
* grantee and grantor; the privileges are ignored. * grantee and grantor; the privileges are ignored.
*/ */
static bool static bool
aclitemeq(const AclItem *a1, const AclItem *a2) aclitem_match(const AclItem *a1, const AclItem *a2)
{ {
return ACLITEM_GET_IDTYPE(*a1) == ACLITEM_GET_IDTYPE(*a2) && return ACLITEM_GET_IDTYPE(*a1) == ACLITEM_GET_IDTYPE(*a2) &&
a1->ai_grantee == a2->ai_grantee && a1->ai_grantee == a2->ai_grantee &&
a1->ai_grantor == a2->ai_grantor; a1->ai_grantor == a2->ai_grantor;
} }
/*
* aclitem equality operator
*/
Datum
aclitem_eq(PG_FUNCTION_ARGS)
{
AclItem *a1 = PG_GETARG_ACLITEM_P(0);
AclItem *a2 = PG_GETARG_ACLITEM_P(1);
bool result;
result = a1->ai_privs == a2->ai_privs &&
a1->ai_grantee == a2->ai_grantee &&
a1->ai_grantor == a2->ai_grantor;
PG_RETURN_BOOL(result);
}
/* /*
* acldefault() --- create an ACL describing default access permissions * acldefault() --- create an ACL describing default access permissions
...@@ -535,7 +550,7 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBeh ...@@ -535,7 +550,7 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBeh
for (dst = 0; dst < num; ++dst) for (dst = 0; dst < num; ++dst)
{ {
if (aclitemeq(mod_aip, old_aip + dst)) if (aclitem_match(mod_aip, old_aip + dst))
{ {
/* found a match, so modify existing item */ /* found a match, so modify existing item */
new_acl = allocacl(num); new_acl = allocacl(num);
...@@ -685,8 +700,10 @@ aclremove(PG_FUNCTION_ARGS) ...@@ -685,8 +700,10 @@ aclremove(PG_FUNCTION_ARGS)
old_aip = ACL_DAT(old_acl); old_aip = ACL_DAT(old_acl);
/* Search for the matching entry */ /* Search for the matching entry */
for (dst = 0; dst < old_num && !aclitemeq(mod_aip, old_aip + dst); ++dst) for (dst = 0;
; dst < old_num && !aclitem_match(mod_aip, old_aip + dst);
++dst)
/* continue */ ;
if (dst >= old_num) if (dst >= old_num)
{ {
......
This diff is collapsed.
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.100 2003/06/25 21:30:32 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.101 2003/06/27 00:33:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -19,11 +19,14 @@ ...@@ -19,11 +19,14 @@
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "access/tuptoaster.h" #include "access/tuptoaster.h"
#include "catalog/pg_type.h"
#include "lib/stringinfo.h" #include "lib/stringinfo.h"
#include "libpq/crypt.h" #include "libpq/crypt.h"
#include "libpq/pqformat.h" #include "libpq/pqformat.h"
#include "utils/array.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/pg_locale.h" #include "utils/pg_locale.h"
#include "utils/lsyscache.h"
typedef struct varlena unknown; typedef struct varlena unknown;
...@@ -1983,8 +1986,7 @@ split_text(PG_FUNCTION_ARGS) ...@@ -1983,8 +1986,7 @@ split_text(PG_FUNCTION_ARGS)
if (fldnum == 1) /* first field - just return the input if (fldnum == 1) /* first field - just return the input
* string */ * string */
PG_RETURN_TEXT_P(inputstring); PG_RETURN_TEXT_P(inputstring);
else else /* otherwise return an empty string */
/* otherwise return an empty string */
PG_RETURN_TEXT_P(PG_STR_GET_TEXT("")); PG_RETURN_TEXT_P(PG_STR_GET_TEXT(""));
} }
...@@ -2004,8 +2006,7 @@ split_text(PG_FUNCTION_ARGS) ...@@ -2004,8 +2006,7 @@ split_text(PG_FUNCTION_ARGS)
if (fldnum == 1) /* first field - just return the input if (fldnum == 1) /* first field - just return the input
* string */ * string */
PG_RETURN_TEXT_P(inputstring); PG_RETURN_TEXT_P(inputstring);
else else /* otherwise return an empty string */
/* otherwise return an empty string */
PG_RETURN_TEXT_P(PG_STR_GET_TEXT("")); PG_RETURN_TEXT_P(PG_STR_GET_TEXT(""));
} }
else if ((start_posn != 0) && (end_posn == 0)) else if ((start_posn != 0) && (end_posn == 0))
...@@ -2028,6 +2029,176 @@ split_text(PG_FUNCTION_ARGS) ...@@ -2028,6 +2029,176 @@ 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 typalign;
Oid typelem;
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_io_data(element_type, IOFunc_output,
&my_extra->typlen, &my_extra->typbyval,
&my_extra->typalign, &my_extra->typdelim,
&my_extra->typelem, &my_extra->typiofunc);
fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
fcinfo->flinfo->fn_mcxt);
my_extra->element_type = element_type;
}
typlen = my_extra->typlen;
typbyval = my_extra->typbyval;
typalign = my_extra->typalign;
typelem = my_extra->typelem;
for (i = 0; i < nitems; i++)
{
Datum itemvalue;
char *value;
itemvalue = fetch_att(p, typbyval, typlen);
value = DatumGetCString(FunctionCall3(&my_extra->proc,
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 #define HEXBASE 16
/* /*
* Convert a int32 to a string containing a base 16 (hex) representation of * Convert a int32 to a string containing a base 16 (hex) representation of
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.99 2003/06/25 21:30:32 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.100 2003/06/27 00:33:25 tgl Exp $
* *
* NOTES * NOTES
* Eventually, the index information should go through here, too. * Eventually, the index information should go through here, too.
...@@ -1090,6 +1090,56 @@ get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, ...@@ -1090,6 +1090,56 @@ get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
ReleaseSysCache(tp); ReleaseSysCache(tp);
} }
/*
* get_type_io_data
*
* A six-fer: given the type OID, return typlen, typbyval, typalign,
* typdelim, typelem, and IO function OID. The IO function
* returned is controlled by IOFuncSelector
*/
void
get_type_io_data(Oid typid,
IOFuncSelector which_func,
int16 *typlen,
bool *typbyval,
char *typalign,
char *typdelim,
Oid *typelem,
Oid *func)
{
HeapTuple typeTuple;
Form_pg_type typeStruct;
typeTuple = SearchSysCache(TYPEOID,
ObjectIdGetDatum(typid),
0, 0, 0);
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "cache lookup failed for type %u", typid);
typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
*typlen = typeStruct->typlen;
*typbyval = typeStruct->typbyval;
*typalign = typeStruct->typalign;
*typdelim = typeStruct->typdelim;
*typelem = typeStruct->typelem;
switch (which_func)
{
case IOFunc_input:
*func = typeStruct->typinput;
break;
case IOFunc_output:
*func = typeStruct->typoutput;
break;
case IOFunc_receive:
*func = typeStruct->typreceive;
break;
case IOFunc_send:
*func = typeStruct->typsend;
break;
}
ReleaseSysCache(typeTuple);
}
#ifdef NOT_USED #ifdef NOT_USED
char char
get_typalign(Oid typid) get_typalign(Oid typid)
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: catversion.h,v 1.200 2003/06/25 01:26:16 momjian Exp $ * $Id: catversion.h,v 1.201 2003/06/27 00:33:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200306241 #define CATALOG_VERSION_NO 200306261
#endif #endif
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_amop.h,v 1.52 2003/06/25 21:30:32 momjian Exp $ * $Id: pg_amop.h,v 1.53 2003/06/27 00:33:25 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
...@@ -418,6 +418,15 @@ DATA(insert ( 2098 3 f 2334 )); ...@@ -418,6 +418,15 @@ DATA(insert ( 2098 3 f 2334 ));
DATA(insert ( 2098 4 f 2335 )); DATA(insert ( 2098 4 f 2335 ));
DATA(insert ( 2098 5 f 2336 )); 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 * hash index _ops
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_amproc.h,v 1.40 2003/06/25 21:30:32 momjian Exp $ * $Id: pg_amproc.h,v 1.41 2003/06/27 00:33:25 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
...@@ -78,6 +78,7 @@ DATA(insert ( 1993 3 199 )); ...@@ -78,6 +78,7 @@ DATA(insert ( 1993 3 199 ));
/* btree */ /* btree */
DATA(insert ( 397 1 382 ));
DATA(insert ( 421 1 357 )); DATA(insert ( 421 1 357 ));
DATA(insert ( 423 1 1596 )); DATA(insert ( 423 1 1596 ));
DATA(insert ( 424 1 1693 )); DATA(insert ( 424 1 1693 ));
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_opclass.h,v 1.53 2003/06/25 21:30:32 momjian Exp $ * $Id: pg_opclass.h,v 1.54 2003/06/27 00:33:25 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
...@@ -87,6 +87,8 @@ typedef FormData_pg_opclass *Form_pg_opclass; ...@@ -87,6 +87,8 @@ typedef FormData_pg_opclass *Form_pg_opclass;
*/ */
DATA(insert OID = 421 ( 403 abstime_ops PGNSP PGUID 702 t 0 )); 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 = 422 ( 402 bigbox_ops PGNSP PGUID 603 f 0 ));
DATA(insert OID = 423 ( 403 bit_ops PGNSP PGUID 1560 t 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 )); DATA(insert OID = 424 ( 403 bool_ops PGNSP PGUID 16 t 0 ));
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_operator.h,v 1.117 2003/06/25 21:30:32 momjian Exp $ * $Id: pg_operator.h,v 1.118 2003/06/27 00:33:25 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
...@@ -116,7 +116,6 @@ DATA(insert OID = 96 ( "=" PGNSP PGUID b t 23 23 16 96 518 97 97 97 521 int ...@@ -116,7 +116,6 @@ 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 = 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 = 98 ( "=" PGNSP PGUID b t 25 25 16 98 531 664 664 664 666 texteq eqsel eqjoinsel ));
DATA(insert OID = 329 ( "=" PGNSP PGUID b f 2277 2277 16 329 0 0 0 0 0 array_eq eqsel eqjoinsel ));
DATA(insert OID = 349 ( "||" PGNSP PGUID b f 2277 2283 2277 0 0 0 0 0 0 array_append - - )); DATA(insert OID = 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 = 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 = 375 ( "||" PGNSP PGUID b f 2277 2277 2277 0 0 0 0 0 0 array_cat - - ));
...@@ -425,6 +424,7 @@ DATA(insert OID = 965 ( "^" PGNSP PGUID b f 701 701 701 0 0 0 0 0 0 dpow - ...@@ -425,6 +424,7 @@ 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 = 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 = 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 = 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 974 0 0 0 0 0 aclitemeq eqsel eqjoinsel ));
/* additional geometric operators - thomas 1997-07-09 */ /* 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 - - )); DATA(insert OID = 969 ( "@@" PGNSP PGUID l f 0 601 600 0 0 0 0 0 0 lseg_center - - ));
...@@ -441,6 +441,16 @@ DATA(insert OID = 1059 ( "<=" PGNSP PGUID b f 1042 1042 16 1061 1060 0 0 0 ...@@ -441,6 +441,16 @@ DATA(insert OID = 1059 ( "<=" PGNSP PGUID b f 1042 1042 16 1061 1060 0 0 0
DATA(insert OID = 1060 ( ">" PGNSP PGUID b f 1042 1042 16 1058 1059 0 0 0 0 bpchargt scalargtsel scalargtjoinsel )); DATA(insert OID = 1060 ( ">" PGNSP PGUID b f 1042 1042 16 1058 1059 0 0 0 0 bpchargt scalargtsel scalargtjoinsel ));
DATA(insert OID = 1061 ( ">=" PGNSP PGUID b f 1042 1042 16 1059 1058 0 0 0 0 bpcharge scalargtsel scalargtjoinsel )); DATA(insert OID = 1061 ( ">=" PGNSP PGUID b f 1042 1042 16 1059 1058 0 0 0 0 bpcharge scalargtsel scalargtjoinsel ));
/* generic array comparison operators */
DATA(insert OID = 1070 ( "=" PGNSP PGUID b f 2277 2277 16 1070 1071 1072 1072 1072 1073 array_eq eqsel eqjoinsel ));
#define ARRAY_EQ_OP 1070
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 ));
#define ARRAY_LT_OP 1072
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 ));
/* date operators */ /* date operators */
DATA(insert OID = 1076 ( "+" PGNSP PGUID b f 1082 1186 1114 0 0 0 0 0 0 date_pl_interval - - )); DATA(insert OID = 1076 ( "+" PGNSP PGUID b f 1082 1186 1114 0 0 0 0 0 0 date_pl_interval - - ));
DATA(insert OID = 1077 ( "-" PGNSP PGUID b f 1082 1186 1114 0 0 0 0 0 0 date_mi_interval - - )); DATA(insert OID = 1077 ( "-" PGNSP PGUID b f 1082 1186 1114 0 0 0 0 0 0 date_mi_interval - - ));
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_proc.h,v 1.307 2003/06/25 21:30:32 momjian Exp $ * $Id: pg_proc.h,v 1.308 2003/06/27 00:33:25 tgl Exp $
* *
* NOTES * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * The script catalog/genbki.sh reads this file and generates .bki
...@@ -758,6 +758,8 @@ DATA(insert OID = 359 ( btnamecmp PGNSP PGUID 12 f f t f i 2 23 "19 19" btn ...@@ -758,6 +758,8 @@ DATA(insert OID = 359 ( btnamecmp PGNSP PGUID 12 f f t f i 2 23 "19 19" btn
DESCR("btree less-equal-greater"); DESCR("btree less-equal-greater");
DATA(insert OID = 360 ( bttextcmp PGNSP PGUID 12 f f t f i 2 23 "25 25" bttextcmp - _null_ )); DATA(insert OID = 360 ( bttextcmp PGNSP PGUID 12 f f t f i 2 23 "25 25" bttextcmp - _null_ ));
DESCR("btree less-equal-greater"); 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_ )); DATA(insert OID = 361 ( lseg_distance PGNSP PGUID 12 f f t f i 2 701 "601 601" lseg_distance - _null_ ));
DESCR("distance between"); DESCR("distance between");
...@@ -988,14 +990,23 @@ DESCR("greater-than"); ...@@ -988,14 +990,23 @@ DESCR("greater-than");
DATA(insert OID = 743 ( text_ge PGNSP PGUID 12 f f t f i 2 16 "25 25" text_ge - _null_ )); 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"); 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_ )); DATA(insert OID = 745 ( current_user PGNSP PGUID 12 f f t f s 0 19 "" current_user - _null_ ));
DESCR("current user name"); DESCR("current user name");
DATA(insert OID = 746 ( session_user PGNSP PGUID 12 f f t f s 0 19 "" session_user - _null_ )); DATA(insert OID = 746 ( session_user PGNSP PGUID 12 f f t f s 0 19 "" session_user - _null_ ));
DESCR("session user name"); 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_ )); DATA(insert OID = 747 ( array_dims PGNSP PGUID 12 f f t f i 1 25 "2277" array_dims - _null_ ));
DESCR("array dimensions"); 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_ )); DATA(insert OID = 750 ( array_in PGNSP PGUID 12 f f t f s 3 2277 "2275 26 23" array_in - _null_ ));
...@@ -1006,22 +1017,18 @@ DATA(insert OID = 2091 ( array_lower PGNSP PGUID 12 f f t f i 2 23 "2277 23" ...@@ -1006,22 +1017,18 @@ DATA(insert OID = 2091 ( array_lower PGNSP PGUID 12 f f t f i 2 23 "2277 23"
DESCR("array lower dimension"); 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_ )); 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"); 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_ )); 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"); 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_ )); 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"); 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_ )); 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"); 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_ )); 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"); 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_ )); DATA(insert OID = 760 ( smgrin PGNSP PGUID 12 f f t f s 1 210 "2275" smgrin - _null_ ));
DESCR("I/O"); DESCR("I/O");
...@@ -1322,6 +1329,8 @@ DATA(insert OID = 1036 ( aclremove PGNSP PGUID 12 f f t f s 2 1034 "1034 10 ...@@ -1322,6 +1329,8 @@ DATA(insert OID = 1036 ( aclremove PGNSP PGUID 12 f f t f s 2 1034 "1034 10
DESCR("remove ACL item"); DESCR("remove ACL item");
DATA(insert OID = 1037 ( aclcontains PGNSP PGUID 12 f f t f s 2 16 "1034 1033" aclcontains - _null_ )); DATA(insert OID = 1037 ( aclcontains PGNSP PGUID 12 f f t f s 2 16 "1034 1033" aclcontains - _null_ ));
DESCR("does ACL contain item?"); 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_ )); 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"); DESCR("make ACL item");
DATA(insert OID = 1038 ( seteval PGNSP PGUID 12 f f t t v 1 23 "26" seteval - _null_ )); DATA(insert OID = 1038 ( seteval PGNSP PGUID 12 f f t t v 1 23 "26" seteval - _null_ ));
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: parse_oper.h,v 1.27 2003/06/25 21:30:33 momjian Exp $ * $Id: parse_oper.h,v 1.28 2003/06/27 00:33:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -45,6 +45,7 @@ extern Operator ordering_oper(Oid argtype, bool noError); ...@@ -45,6 +45,7 @@ extern Operator ordering_oper(Oid argtype, bool noError);
extern Oid compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError); extern Oid compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError);
extern Oid equality_oper_funcid(Oid argtype); extern Oid equality_oper_funcid(Oid argtype);
extern Oid ordering_oper_opid(Oid argtype); extern Oid ordering_oper_opid(Oid argtype);
extern Oid ordering_oper_funcid(Oid argtype);
/* Extract operator OID or underlying-function OID from an Operator tuple */ /* Extract operator OID or underlying-function OID from an Operator tuple */
extern Oid oprid(Operator op); extern Oid oprid(Operator op);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: acl.h,v 1.54 2003/06/25 21:30:33 momjian Exp $ * $Id: acl.h,v 1.55 2003/06/27 00:33:26 tgl Exp $
* *
* NOTES * NOTES
* For backward-compatibility purposes we have to allow there * For backward-compatibility purposes we have to allow there
...@@ -192,6 +192,7 @@ extern Datum aclinsert(PG_FUNCTION_ARGS); ...@@ -192,6 +192,7 @@ extern Datum aclinsert(PG_FUNCTION_ARGS);
extern Datum aclremove(PG_FUNCTION_ARGS); extern Datum aclremove(PG_FUNCTION_ARGS);
extern Datum aclcontains(PG_FUNCTION_ARGS); extern Datum aclcontains(PG_FUNCTION_ARGS);
extern Datum makeaclitem(PG_FUNCTION_ARGS); extern Datum makeaclitem(PG_FUNCTION_ARGS);
extern Datum aclitem_eq(PG_FUNCTION_ARGS);
/* /*
* prototypes for functions in aclchk.c * prototypes for functions in aclchk.c
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: array.h,v 1.40 2003/06/25 21:30:33 momjian Exp $ * $Id: array.h,v 1.41 2003/06/27 00:33:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -32,6 +32,37 @@ typedef struct ...@@ -32,6 +32,37 @@ typedef struct
Oid elemtype; /* element type OID */ Oid elemtype; /* element type OID */
} ArrayType; } 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;
int16 typlen;
bool typbyval;
char typalign;
char typdelim;
Oid typelem;
Oid typiofunc;
FmgrInfo proc;
} ArrayMetaState;
/* /*
* fmgr macros for array objects * fmgr macros for array objects
*/ */
...@@ -86,11 +117,15 @@ extern Datum array_recv(PG_FUNCTION_ARGS); ...@@ -86,11 +117,15 @@ extern Datum array_recv(PG_FUNCTION_ARGS);
extern Datum array_send(PG_FUNCTION_ARGS); extern Datum array_send(PG_FUNCTION_ARGS);
extern Datum array_length_coerce(PG_FUNCTION_ARGS); extern Datum array_length_coerce(PG_FUNCTION_ARGS);
extern Datum array_eq(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_dims(PG_FUNCTION_ARGS);
extern Datum array_lower(PG_FUNCTION_ARGS); extern Datum array_lower(PG_FUNCTION_ARGS);
extern Datum array_upper(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_type_coerce(PG_FUNCTION_ARGS);
extern Datum array_ref(ArrayType *array, int nSubscripts, int *indx, extern Datum array_ref(ArrayType *array, int nSubscripts, int *indx,
...@@ -124,7 +159,14 @@ extern void deconstruct_array(ArrayType *array, ...@@ -124,7 +159,14 @@ extern void deconstruct_array(ArrayType *array,
Oid elmtype, Oid elmtype,
int elmlen, bool elmbyval, char elmalign, int elmlen, bool elmbyval, char elmalign,
Datum **elemsp, int *nelemsp); 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 * prototypes for functions defined in arrayutils.c
...@@ -141,12 +183,11 @@ extern int mda_next_tuple(int n, int *curr, int *span); ...@@ -141,12 +183,11 @@ extern int mda_next_tuple(int n, int *curr, int *span);
/* /*
* prototypes for functions defined in array_userfuncs.c * 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_push(PG_FUNCTION_ARGS);
extern Datum array_accum(PG_FUNCTION_ARGS);
extern Datum array_cat(PG_FUNCTION_ARGS); extern Datum array_cat(PG_FUNCTION_ARGS);
extern ArrayType *create_singleton_array(Oid element_type, extern ArrayType *create_singleton_array(FunctionCallInfo fcinfo,
Oid element_type,
Datum element, Datum element,
int ndims); int ndims);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: builtins.h,v 1.222 2003/06/25 21:30:33 momjian Exp $ * $Id: builtins.h,v 1.223 2003/06/27 00:33:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -530,6 +530,8 @@ extern bool SplitIdentifierString(char *rawstring, char separator, ...@@ -530,6 +530,8 @@ extern bool SplitIdentifierString(char *rawstring, char separator,
List **namelist); List **namelist);
extern Datum replace_text(PG_FUNCTION_ARGS); extern Datum replace_text(PG_FUNCTION_ARGS);
extern Datum split_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_hex32(PG_FUNCTION_ARGS);
extern Datum to_hex64(PG_FUNCTION_ARGS); extern Datum to_hex64(PG_FUNCTION_ARGS);
extern Datum md5_text(PG_FUNCTION_ARGS); extern Datum md5_text(PG_FUNCTION_ARGS);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: lsyscache.h,v 1.74 2003/06/25 21:30:33 momjian Exp $ * $Id: lsyscache.h,v 1.75 2003/06/27 00:33:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -15,6 +15,15 @@ ...@@ -15,6 +15,15 @@
#include "access/htup.h" #include "access/htup.h"
/* I/O function selector for get_type_io_data */
typedef enum IOFuncSelector
{
IOFunc_input,
IOFunc_output,
IOFunc_receive,
IOFunc_send
} IOFuncSelector;
extern bool op_in_opclass(Oid opno, Oid opclass); extern bool op_in_opclass(Oid opno, Oid opclass);
extern bool op_requires_recheck(Oid opno, Oid opclass); extern bool op_requires_recheck(Oid opno, Oid opclass);
extern Oid get_opclass_member(Oid opclass, int16 strategy); extern Oid get_opclass_member(Oid opclass, int16 strategy);
...@@ -56,6 +65,14 @@ extern bool get_typbyval(Oid typid); ...@@ -56,6 +65,14 @@ extern bool get_typbyval(Oid typid);
extern void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval); extern void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval);
extern void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, extern void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
char *typalign); char *typalign);
extern void get_type_io_data(Oid typid,
IOFuncSelector which_func,
int16 *typlen,
bool *typbyval,
char *typalign,
char *typdelim,
Oid *typelem,
Oid *func);
extern char get_typstorage(Oid typid); extern char get_typstorage(Oid typid);
extern int32 get_typtypmod(Oid typid); extern int32 get_typtypmod(Oid typid);
extern Node *get_typdefault(Oid typid); extern Node *get_typdefault(Oid typid);
......
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/Attic/preproc.y,v 1.240 2003/06/26 11:37:05 meskes Exp $ */ /* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/Attic/preproc.y,v 1.241 2003/06/27 00:33:26 tgl Exp $ */
/* Copyright comment */ /* Copyright comment */
%{ %{
...@@ -4597,7 +4597,7 @@ type_declaration: S_TYPEDEF ...@@ -4597,7 +4597,7 @@ type_declaration: S_TYPEDEF
$3.type_enum != ECPGt_char && $3.type_enum != ECPGt_char &&
$3.type_enum != ECPGt_unsigned_char && $3.type_enum != ECPGt_unsigned_char &&
atoi(this->type->type_index) >= 0) atoi(this->type->type_index) >= 0)
mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types"); mmerror(PARSE_ERROR, ET_ERROR, "No multidimensional array support for simple data types");
types = this; types = this;
} }
...@@ -5417,7 +5417,7 @@ ECPGTypedef: TYPE_P ...@@ -5417,7 +5417,7 @@ ECPGTypedef: TYPE_P
$5.type_enum != ECPGt_char && $5.type_enum != ECPGt_char &&
$5.type_enum != ECPGt_unsigned_char && $5.type_enum != ECPGt_unsigned_char &&
atoi(this->type->type_index) >= 0) atoi(this->type->type_index) >= 0)
mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types"); mmerror(PARSE_ERROR, ET_ERROR, "No multidimensional array support for simple data types");
types = this; types = this;
} }
...@@ -5484,7 +5484,7 @@ ECPGVar: SQL_VAR ...@@ -5484,7 +5484,7 @@ ECPGVar: SQL_VAR
default: default:
if (atoi(length) >= 0) if (atoi(length) >= 0)
mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types"); mmerror(PARSE_ERROR, ET_ERROR, "No multidimensional array support for simple data types");
if (atoi(dimension) < 0) if (atoi(dimension) < 0)
type = ECPGmake_simple_type($5.type_enum, make_str("1")); type = ECPGmake_simple_type($5.type_enum, make_str("1"));
......
...@@ -504,7 +504,7 @@ ECPGfree_type(struct ECPGtype * type) ...@@ -504,7 +504,7 @@ ECPGfree_type(struct ECPGtype * type)
switch (type->u.element->type) switch (type->u.element->type)
{ {
case ECPGt_array: case ECPGt_array:
yyerror("internal error, found multi-dimensional array\n"); yyerror("internal error, found multidimensional array\n");
break; break;
case ECPGt_struct: case ECPGt_struct:
case ECPGt_union: case ECPGt_union:
......
...@@ -436,7 +436,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty ...@@ -436,7 +436,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty
if (atoi(type_index) >= 0) if (atoi(type_index) >= 0)
{ {
if (atoi(*length) >= 0) if (atoi(*length) >= 0)
mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support"); mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support");
*length = type_index; *length = type_index;
} }
...@@ -444,7 +444,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty ...@@ -444,7 +444,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty
if (atoi(type_dimension) >= 0) if (atoi(type_dimension) >= 0)
{ {
if (atoi(*dimension) >= 0 && atoi(*length) >= 0) if (atoi(*dimension) >= 0 && atoi(*length) >= 0)
mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support"); mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support");
if (atoi(*dimension) >= 0) if (atoi(*dimension) >= 0)
*length = *dimension; *length = *dimension;
...@@ -463,10 +463,10 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty ...@@ -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"); mmerror(PARSE_ERROR, ET_FATAL, "No pointer to pointer supported for this type");
if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0)) if (pointer_len > 1 && (atoi(*length) >= 0 || atoi(*dimension) >= 0))
mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support"); mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support");
if (atoi(*length) >= 0 && atoi(*dimension) >= 0 && pointer_len) if (atoi(*length) >= 0 && atoi(*dimension) >= 0 && pointer_len)
mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support"); mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support");
switch (type_enum) switch (type_enum)
{ {
...@@ -480,7 +480,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty ...@@ -480,7 +480,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty
} }
if (atoi(*length) >= 0) if (atoi(*length) >= 0)
mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support for structures"); mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support for structures");
break; break;
case ECPGt_varchar: case ECPGt_varchar:
...@@ -525,7 +525,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty ...@@ -525,7 +525,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty
} }
if (atoi(*length) >= 0) if (atoi(*length) >= 0)
mmerror(PARSE_ERROR, ET_FATAL, "No multi-dimensional array support for simple data types"); mmerror(PARSE_ERROR, ET_FATAL, "No multidimensional array support for simple data types");
break; break;
} }
......
...@@ -178,19 +178,13 @@ SELECT ARRAY(select f2 from arrtest_f order by f2) AS "ARRAY"; ...@@ -178,19 +178,13 @@ SELECT ARRAY(select f2 from arrtest_f order by f2) AS "ARRAY";
(1 row) (1 row)
-- functions -- functions
SELECT singleton_array(42) AS "{42}"; SELECT array_append(array[42], 6) AS "{42,6}";
{42}
------
{42}
(1 row)
SELECT array_append(singleton_array(42), 6) AS "{42,6}";
{42,6} {42,6}
-------- --------
{42,6} {42,6}
(1 row) (1 row)
SELECT array_prepend(6, singleton_array(42)) AS "{6,42}"; SELECT array_prepend(6, array[42]) AS "{6,42}";
{6,42} {6,42}
-------- --------
{6,42} {6,42}
...@@ -214,24 +208,6 @@ SELECT array_cat(ARRAY[[3,4],[5,6]], ARRAY[1,2]) AS "{{3,4},{5,6},{1,2}}"; ...@@ -214,24 +208,6 @@ SELECT array_cat(ARRAY[[3,4],[5,6]], ARRAY[1,2]) AS "{{3,4},{5,6},{1,2}}";
{{3,4},{5,6},{1,2}} {{3,4},{5,6},{1,2}}
(1 row) (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 -- operators
SELECT a FROM arrtest WHERE b = ARRAY[[[113,142],[1,147]]]; SELECT a FROM arrtest WHERE b = ARRAY[[[113,142],[1,147]]];
a a
...@@ -318,3 +294,24 @@ SELECT CAST(ARRAY[[[[[['a','bb','ccc']]]]]] as text[]) as "{{{{{{a,bb,ccc}}}}}}" ...@@ -318,3 +294,24 @@ SELECT CAST(ARRAY[[[[[['a','bb','ccc']]]]]] as text[]) as "{{{{{{a,bb,ccc}}}}}}"
{{{{{{a,bb,ccc}}}}}} {{{{{{a,bb,ccc}}}}}}
(1 row) (1 row)
-- test indexes on arrays
create temp table arr_tbl (f1 int[] unique);
NOTICE: CREATE TABLE / UNIQUE will create implicit index 'arr_tbl_f1_key' for table 'arr_tbl'
insert into arr_tbl values ('{1,2,3}');
insert into arr_tbl values ('{1,2}');
-- failure expected:
insert into arr_tbl values ('{1,2,3}');
ERROR: Cannot insert a duplicate key into unique index arr_tbl_f1_key
insert into arr_tbl values ('{2,3,4}');
insert into arr_tbl values ('{1,5,3}');
insert into arr_tbl values ('{1,2,10}');
set enable_seqscan to off;
select * from arr_tbl where f1 > '{1,2,3}' and f1 <= '{1,5,3}';
f1
----------
{1,2,10}
{1,5,3}
(2 rows)
-- note: if above select doesn't produce the expected tuple order,
-- then you didn't get an indexscan plan, and something is busted.
...@@ -130,15 +130,11 @@ SELECT ARRAY[ARRAY['hello'],ARRAY['world']]; ...@@ -130,15 +130,11 @@ SELECT ARRAY[ARRAY['hello'],ARRAY['world']];
SELECT ARRAY(select f2 from arrtest_f order by f2) AS "ARRAY"; SELECT ARRAY(select f2 from arrtest_f order by f2) AS "ARRAY";
-- functions -- functions
SELECT singleton_array(42) AS "{42}"; SELECT array_append(array[42], 6) AS "{42,6}";
SELECT array_append(singleton_array(42), 6) AS "{42,6}"; SELECT array_prepend(6, array[42]) AS "{6,42}";
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]) 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[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_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 -- operators
SELECT a FROM arrtest WHERE b = ARRAY[[[113,142],[1,147]]]; SELECT a FROM arrtest WHERE b = ARRAY[[[113,142],[1,147]]];
...@@ -157,3 +153,17 @@ SELECT ARRAY[1,2,3]::text[]::int[]::float8[] is of (float8[]) as "TRUE"; ...@@ -157,3 +153,17 @@ SELECT ARRAY[1,2,3]::text[]::int[]::float8[] is of (float8[]) as "TRUE";
SELECT ARRAY[['a','bc'],['def','hijk']]::text[]::varchar[] AS "{{a,bc},{def,hijk}}"; SELECT ARRAY[['a','bc'],['def','hijk']]::text[]::varchar[] AS "{{a,bc},{def,hijk}}";
SELECT ARRAY[['a','bc'],['def','hijk']]::text[]::varchar[] is of (varchar[]) as "TRUE"; SELECT ARRAY[['a','bc'],['def','hijk']]::text[]::varchar[] is of (varchar[]) as "TRUE";
SELECT CAST(ARRAY[[[[[['a','bb','ccc']]]]]] as text[]) as "{{{{{{a,bb,ccc}}}}}}"; SELECT CAST(ARRAY[[[[[['a','bb','ccc']]]]]] as text[]) as "{{{{{{a,bb,ccc}}}}}}";
-- test indexes on arrays
create temp table arr_tbl (f1 int[] unique);
insert into arr_tbl values ('{1,2,3}');
insert into arr_tbl values ('{1,2}');
-- failure expected:
insert into arr_tbl values ('{1,2,3}');
insert into arr_tbl values ('{2,3,4}');
insert into arr_tbl values ('{1,5,3}');
insert into arr_tbl values ('{1,2,10}');
set enable_seqscan to off;
select * from arr_tbl where f1 > '{1,2,3}' and f1 <= '{1,5,3}';
-- note: if above select doesn't produce the expected tuple order,
-- then you didn't get an indexscan plan, and something is busted.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment