*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.58 2003/08/04 02:39:58 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.59 2003/08/17 19:58:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
{
Form_pg_attribute attr = onerel->rd_att->attrs[attnum - 1];
Operator func_operator;
- Oid oprrest;
HeapTuple typtuple;
Oid eqopr = InvalidOid;
Oid eqfunc = InvalidOid;
func_operator = equality_oper(attr->atttypid, true);
if (func_operator != NULL)
{
- oprrest = ((Form_pg_operator) GETSTRUCT(func_operator))->oprrest;
- if (oprrest == F_EQSEL)
- {
- eqopr = oprid(func_operator);
- eqfunc = oprfuncid(func_operator);
- }
+ eqopr = oprid(func_operator);
+ eqfunc = oprfuncid(func_operator);
ReleaseSysCache(func_operator);
}
if (!OidIsValid(eqfunc))
func_operator = ordering_oper(attr->atttypid, true);
if (func_operator != NULL)
{
- oprrest = ((Form_pg_operator) GETSTRUCT(func_operator))->oprrest;
- if (oprrest == F_SCALARLTSEL)
- ltopr = oprid(func_operator);
+ ltopr = oprid(func_operator);
ReleaseSysCache(func_operator);
}
stats->ltopr = ltopr;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.105 2003/08/04 02:39:58 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.106 2003/08/17 19:58:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* than one exact match, then someone put bogus entries in pg_opclass.
*
* The initial search is done by namespace.c so that we only consider
- * opclasses visible in the current namespace search path.
+ * opclasses visible in the current namespace search path. (See also
+ * typcache.c, which applies the same logic, but over all opclasses.)
*/
for (opclass = OpclassGetCandidates(accessMethodId);
opclass != NULL;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/opclasscmds.c,v 1.17 2003/08/04 02:39:58 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/opclasscmds.c,v 1.18 2003/08/17 19:58:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* If we are creating a default opclass, check there isn't one
- * already. (XXX should we restrict this test to visible opclasses?)
+ * already. (Note we do not restrict this test to visible opclasses;
+ * this ensures that typcache.c can find unique solutions to its
+ * questions.)
*/
if (stmt->isDefault)
{
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.263 2003/08/08 21:41:43 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.264 2003/08/17 19:58:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
return newnode;
}
-static SortGroupBy *
-_copySortGroupBy(SortGroupBy *from)
+static SortBy *
+_copySortBy(SortBy *from)
{
- SortGroupBy *newnode = makeNode(SortGroupBy);
+ SortBy *newnode = makeNode(SortBy);
+ COPY_SCALAR_FIELD(sortby_kind);
COPY_NODE_FIELD(useOp);
COPY_NODE_FIELD(node);
case T_TypeCast:
retval = _copyTypeCast(from);
break;
- case T_SortGroupBy:
- retval = _copySortGroupBy(from);
+ case T_SortBy:
+ retval = _copySortBy(from);
break;
case T_RangeSubselect:
retval = _copyRangeSubselect(from);
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.207 2003/08/08 21:41:43 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.208 2003/08/17 19:58:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
}
static bool
-_equalSortGroupBy(SortGroupBy *a, SortGroupBy *b)
+_equalSortBy(SortBy *a, SortBy *b)
{
+ COMPARE_SCALAR_FIELD(sortby_kind);
COMPARE_NODE_FIELD(useOp);
COMPARE_NODE_FIELD(node);
case T_TypeCast:
retval = _equalTypeCast(a, b);
break;
- case T_SortGroupBy:
- retval = _equalSortGroupBy(a, b);
+ case T_SortBy:
+ retval = _equalSortBy(a, b);
break;
case T_RangeSubselect:
retval = _equalRangeSubselect(a, b);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.154 2003/08/11 20:46:46 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.155 2003/08/17 19:58:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
tle = get_tle_by_resno(my_tlist, groupColIdx[groupColPos]);
Assert(tle != NULL);
- sortList = addTargetToSortList(NULL, tle, sortList,
- my_tlist, NIL, false);
+ sortList = addTargetToSortList(NULL, tle,
+ sortList, my_tlist,
+ SORTBY_ASC, NIL, false);
}
plan = (Plan *) make_sort_from_sortclauses(root, my_tlist,
subplan, sortList);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.159 2003/08/04 02:40:01 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.160 2003/08/17 19:58:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
Operator optup;
bool oprcanhash;
- optup = equality_oper(tle->resdom->restype, false);
+ optup = equality_oper(tle->resdom->restype, true);
+ if (!optup)
+ return false;
oprcanhash = ((Form_pg_operator) GETSTRUCT(optup))->oprcanhash;
ReleaseSysCache(optup);
if (!oprcanhash)
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.428 2003/08/04 02:40:01 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.429 2003/08/17 19:58:05 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
TypeName *typnam;
DefElem *defelt;
- SortGroupBy *sortgroupby;
+ SortBy *sortby;
JoinExpr *jexpr;
IndexElem *ielem;
Alias *alias;
database_name access_method_clause access_method attr_name
index_name name function_name file_name
-%type <list> func_name handler_name qual_Op qual_all_Op OptUseOp
+%type <list> func_name handler_name qual_Op qual_all_Op
opt_class opt_validator
%type <range> qualified_name OptConstrFromTable
%type <value> NumericOnly FloatOnly IntegerOnly
%type <columnref> columnref
%type <alias> alias_clause
-%type <sortgroupby> sortby
+%type <sortby> sortby
%type <ielem> index_elem
%type <node> table_ref
%type <jexpr> joined_table
| sortby_list ',' sortby { $$ = lappend($1, $3); }
;
-sortby: a_expr OptUseOp
+sortby: a_expr USING qual_all_Op
{
- $$ = makeNode(SortGroupBy);
+ $$ = makeNode(SortBy);
$$->node = $1;
- $$->useOp = $2;
+ $$->sortby_kind = SORTBY_USING;
+ $$->useOp = $3;
+ }
+ | a_expr ASC
+ {
+ $$ = makeNode(SortBy);
+ $$->node = $1;
+ $$->sortby_kind = SORTBY_ASC;
+ $$->useOp = NIL;
+ }
+ | a_expr DESC
+ {
+ $$ = makeNode(SortBy);
+ $$->node = $1;
+ $$->sortby_kind = SORTBY_DESC;
+ $$->useOp = NIL;
+ }
+ | a_expr
+ {
+ $$ = makeNode(SortBy);
+ $$->node = $1;
+ $$->sortby_kind = SORTBY_ASC; /* default */
+ $$->useOp = NIL;
}
- ;
-
-OptUseOp: USING qual_all_Op { $$ = $2; }
- | ASC
- { $$ = makeList1(makeString("<")); }
- | DESC
- { $$ = makeList1(makeString(">")); }
- | /*EMPTY*/
- { $$ = makeList1(makeString("<")); /*default*/ }
;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.121 2003/08/07 19:20:22 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.122 2003/08/17 19:58:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
foreach(olitem, orderlist)
{
- SortGroupBy *sortby = lfirst(olitem);
+ SortBy *sortby = lfirst(olitem);
TargetEntry *tle;
tle = findTargetlistEntry(pstate, sortby->node,
sortlist = addTargetToSortList(pstate, tle,
sortlist, targetlist,
- sortby->useOp, resolveUnknown);
+ sortby->sortby_kind,
+ sortby->useOp,
+ resolveUnknown);
}
return sortlist;
{
*sortClause = addTargetToSortList(pstate, tle,
*sortClause, targetlist,
- NIL, true);
+ SORTBY_ASC, NIL, true);
/*
* Probably, the tle should always have been added at the
if (!tle->resdom->resjunk)
sortlist = addTargetToSortList(pstate, tle,
sortlist, targetlist,
- NIL, resolveUnknown);
+ SORTBY_ASC, NIL,
+ resolveUnknown);
}
return sortlist;
}
List *
addTargetToSortList(ParseState *pstate, TargetEntry *tle,
List *sortlist, List *targetlist,
- List *opname, bool resolveUnknown)
+ int sortby_kind, List *sortby_opname,
+ bool resolveUnknown)
{
/* avoid making duplicate sortlist entries */
if (!targetIsInSortList(tle, sortlist))
sortcl->tleSortGroupRef = assignSortGroupRef(tle, targetlist);
- if (opname)
- sortcl->sortop = compatible_oper_opid(opname,
- restype,
- restype,
- false);
- else
- sortcl->sortop = ordering_oper_opid(restype);
+ switch (sortby_kind)
+ {
+ case SORTBY_ASC:
+ sortcl->sortop = ordering_oper_opid(restype);
+ break;
+ case SORTBY_DESC:
+ sortcl->sortop = reverse_ordering_oper_opid(restype);
+ break;
+ case SORTBY_USING:
+ Assert(sortby_opname != NIL);
+ sortcl->sortop = compatible_oper_opid(sortby_opname,
+ restype,
+ restype,
+ false);
+ break;
+ default:
+ elog(ERROR, "unrecognized sortby_kind: %d", sortby_kind);
+ break;
+ }
sortlist = lappend(sortlist, sortcl);
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.73 2003/08/04 02:40:02 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.74 2003/08/17 19:58:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
+#include "utils/typcache.h"
static Oid binary_oper_exact(Oid arg1, Oid arg2,
Operator
equality_oper(Oid argtype, bool noError)
{
+ TypeCacheEntry *typentry;
+ Oid oproid;
Operator optup;
- Oid elem_type;
+
+ /*
+ * Look for an "=" operator for the datatype. We require it to be
+ * an exact or binary-compatible match, since most callers are not
+ * prepared to cope with adding any run-time type coercion steps.
+ */
+ typentry = lookup_type_cache(argtype, TYPECACHE_EQ_OPR);
+ oproid = typentry->eq_opr;
/*
* If the datatype is an array, then we can use array_eq ... but only
- * if there is a suitable equality operator for the element type. (We
- * must run this test first, since compatible_oper will find array_eq,
- * but would not notice the lack of an element operator.)
+ * if there is a suitable equality operator for the element type.
+ * (This check is not in the raw typcache.c code ... should it be?)
*/
- elem_type = get_element_type(argtype);
- if (OidIsValid(elem_type))
+ if (oproid == ARRAY_EQ_OP)
{
- optup = equality_oper(elem_type, true);
- if (optup != NULL)
+ Oid elem_type = get_element_type(argtype);
+
+ if (OidIsValid(elem_type))
{
- ReleaseSysCache(optup);
- return SearchSysCache(OPEROID,
- ObjectIdGetDatum(ARRAY_EQ_OP),
- 0, 0, 0);
+ optup = equality_oper(elem_type, true);
+ if (optup != NULL)
+ ReleaseSysCache(optup);
+ else
+ oproid = InvalidOid; /* element type has no "=" */
}
+ else
+ oproid = InvalidOid; /* bogus array type? */
}
- else
- {
- /*
- * Look for an "=" operator for the datatype. We require it to be
- * an exact or binary-compatible match, since most callers are not
- * prepared to cope with adding any run-time type coercion steps.
- */
- optup = 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) ||
- pgopform->oprcanhash ||
- pgopform->oprrest == F_EQSEL)
- return optup;
- ReleaseSysCache(optup);
- }
+ if (OidIsValid(oproid))
+ {
+ optup = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(oproid),
+ 0, 0, 0);
+ if (optup == NULL) /* should not fail */
+ elog(ERROR, "cache lookup failed for operator %u", oproid);
+ return optup;
}
+
if (!noError)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
Operator
ordering_oper(Oid argtype, bool noError)
{
+ TypeCacheEntry *typentry;
+ Oid oproid;
Operator optup;
- Oid elem_type;
+
+ /*
+ * Look for a "<" operator for the datatype. We require it to be
+ * an exact or binary-compatible match, since most callers are not
+ * prepared to cope with adding any run-time type coercion steps.
+ *
+ * Note: the search algorithm used by typcache.c ensures that if a "<"
+ * operator is returned, it will be consistent with the "=" operator
+ * returned by equality_oper. This is critical for sorting and grouping
+ * purposes.
+ */
+ typentry = lookup_type_cache(argtype, TYPECACHE_LT_OPR);
+ oproid = typentry->lt_opr;
/*
* If the datatype is an array, then we can use array_lt ... but only
- * if there is a suitable ordering operator for the element type. (We
- * must run this test first, since the code below would find array_lt
- * if there's an element = operator, but would not notice the lack of
- * an element < operator.)
+ * if there is a suitable less-than operator for the element type.
+ * (This check is not in the raw typcache.c code ... should it be?)
*/
- elem_type = get_element_type(argtype);
- if (OidIsValid(elem_type))
+ if (oproid == ARRAY_LT_OP)
{
- optup = ordering_oper(elem_type, true);
- if (optup != NULL)
+ Oid elem_type = get_element_type(argtype);
+
+ if (OidIsValid(elem_type))
{
- ReleaseSysCache(optup);
- return SearchSysCache(OPEROID,
- ObjectIdGetDatum(ARRAY_LT_OP),
- 0, 0, 0);
+ optup = ordering_oper(elem_type, true);
+ if (optup != NULL)
+ ReleaseSysCache(optup);
+ else
+ oproid = InvalidOid; /* element type has no "<" */
}
+ else
+ oproid = InvalidOid; /* bogus array type? */
}
- else
+
+ if (OidIsValid(oproid))
{
- /*
- * 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;
+ optup = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(oproid),
+ 0, 0, 0);
+ if (optup == NULL) /* should not fail */
+ elog(ERROR, "cache lookup failed for operator %u", oproid);
+ return optup;
+ }
- 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)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("could not identify an ordering operator for type %s",
+ format_type_be(argtype)),
+ errhint("Use an explicit ordering operator or modify the query.")));
+ return NULL;
+}
+
+/*
+ * reverse_ordering_oper - identify DESC sort operator (">") for a datatype
+ *
+ * On failure, return NULL if noError, else report a standard error
+ */
+Operator
+reverse_ordering_oper(Oid argtype, bool noError)
+{
+ TypeCacheEntry *typentry;
+ Oid oproid;
+ Operator optup;
+
+ /*
+ * Look for a ">" operator for the datatype. We require it to be
+ * an exact or binary-compatible match, since most callers are not
+ * prepared to cope with adding any run-time type coercion steps.
+ *
+ * Note: the search algorithm used by typcache.c ensures that if a ">"
+ * operator is returned, it will be consistent with the "=" operator
+ * returned by equality_oper. This is critical for sorting and grouping
+ * purposes.
+ */
+ typentry = lookup_type_cache(argtype, TYPECACHE_GT_OPR);
+ oproid = typentry->gt_opr;
+
+ /*
+ * If the datatype is an array, then we can use array_gt ... but only
+ * if there is a suitable greater-than operator for the element type.
+ * (This check is not in the raw typcache.c code ... should it be?)
+ */
+ if (oproid == ARRAY_GT_OP)
+ {
+ Oid elem_type = get_element_type(argtype);
+
+ if (OidIsValid(elem_type))
+ {
+ optup = reverse_ordering_oper(elem_type, true);
+ if (optup != NULL)
+ ReleaseSysCache(optup);
+ else
+ oproid = InvalidOid; /* element type has no ">" */
}
+ else
+ oproid = InvalidOid; /* bogus array type? */
}
+
+ if (OidIsValid(oproid))
+ {
+ optup = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(oproid),
+ 0, 0, 0);
+ if (optup == NULL) /* should not fail */
+ elog(ERROR, "cache lookup failed for operator %u", oproid);
+ return optup;
+ }
+
if (!noError)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
}
/*
- * ordering_oper_funcid - convenience routine for oprfuncid(ordering_oper())
+ * reverse_ordering_oper_opid - convenience routine for oprid(reverse_ordering_oper())
*/
Oid
-ordering_oper_funcid(Oid argtype)
+reverse_ordering_oper_opid(Oid argtype)
{
Operator optup;
Oid result;
- optup = ordering_oper(argtype, false);
- result = oprfuncid(optup);
+ optup = reverse_ordering_oper(argtype, false);
+ result = oprid(optup);
ReleaseSysCache(optup);
return result;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.95 2003/08/14 14:19:07 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.96 2003/08/17 19:58:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
PG_RETURN_BOOL(result);
}
+/*
+ * aclitem hash function
+ *
+ * We make aclitems hashable not so much because anyone is likely to hash
+ * them, as because we want array equality to work on aclitem arrays, and
+ * with the typcache mechanism we must have a hash or btree opclass.
+ */
+Datum
+hash_aclitem(PG_FUNCTION_ARGS)
+{
+ AclItem *a = PG_GETARG_ACLITEM_P(0);
+
+ /* not very bright, but avoids any issue of padding in struct */
+ PG_RETURN_UINT32((uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor));
+}
+
+
/*
* acldefault() --- create an ACL describing default access permissions
*
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.98 2003/08/15 00:22:26 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.99 2003/08/17 19:58:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/memutils.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
+#include "utils/typcache.h"
/*----------
* compares two arrays for equality
* result :
* returns true if the arrays are equal, false otherwise.
+ *
+ * Note: we do not use array_cmp here, since equality may be meaningful in
+ * datatypes that don't have a total ordering (and hence no btree support).
*-----------------------------------------------------------------------------
*/
Datum
int nitems1 = ArrayGetNItems(ndims1, dims1);
int nitems2 = ArrayGetNItems(ndims2, dims2);
Oid element_type = ARR_ELEMTYPE(array1);
- FmgrInfo *ae_fmgr_info = fcinfo->flinfo;
bool result = true;
+ TypeCacheEntry *typentry;
int typlen;
bool typbyval;
char typalign;
int i;
- ArrayMetaState *my_extra;
FunctionCallInfoData locfcinfo;
if (element_type != ARR_ELEMTYPE(array2))
/*
* We arrange to look up the equality function only once per
* series of calls, assuming the element type doesn't change
- * underneath us.
+ * underneath us. The typcache is used so that we have no
+ * memory leakage when being used as an index support function.
*/
- my_extra = (ArrayMetaState *) ae_fmgr_info->fn_extra;
- if (my_extra == NULL)
+ typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
+ if (typentry == NULL ||
+ typentry->type_id != element_type)
{
- ae_fmgr_info->fn_extra = MemoryContextAlloc(ae_fmgr_info->fn_mcxt,
- sizeof(ArrayMetaState));
- my_extra = (ArrayMetaState *) ae_fmgr_info->fn_extra;
- my_extra->element_type = InvalidOid;
- }
-
- if (my_extra->element_type != element_type)
- {
- Oid opfuncid = equality_oper_funcid(element_type);
-
- get_typlenbyvalalign(element_type,
- &my_extra->typlen,
- &my_extra->typbyval,
- &my_extra->typalign);
- fmgr_info_cxt(opfuncid, &my_extra->proc,
- ae_fmgr_info->fn_mcxt);
- my_extra->element_type = element_type;
+ typentry = lookup_type_cache(element_type,
+ TYPECACHE_EQ_OPR_FINFO);
+ if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("could not identify an equality operator for type %s",
+ format_type_be(element_type))));
+ fcinfo->flinfo->fn_extra = (void *) typentry;
}
- typlen = my_extra->typlen;
- typbyval = my_extra->typbyval;
- typalign = my_extra->typalign;
+ typlen = typentry->typlen;
+ typbyval = typentry->typbyval;
+ typalign = typentry->typalign;
/*
* apply the operator to each pair of array elements.
*/
MemSet(&locfcinfo, 0, sizeof(locfcinfo));
- locfcinfo.flinfo = &my_extra->proc;
+ locfcinfo.flinfo = &typentry->eq_opr_finfo;
locfcinfo.nargs = 2;
/* Loop over source data */
int nitems1 = ArrayGetNItems(ndims1, dims1);
int nitems2 = ArrayGetNItems(ndims2, dims2);
Oid element_type = ARR_ELEMTYPE(array1);
- FmgrInfo *ac_fmgr_info = fcinfo->flinfo;
int result = 0;
+ TypeCacheEntry *typentry;
int typlen;
bool typbyval;
char typalign;
int min_nitems;
int i;
- typedef struct
- {
- Oid element_type;
- int16 typlen;
- bool typbyval;
- char typalign;
- FmgrInfo eqproc;
- FmgrInfo ordproc;
- } ac_extra;
- ac_extra *my_extra;
+ FunctionCallInfoData locfcinfo;
if (element_type != ARR_ELEMTYPE(array2))
ereport(ERROR,
errmsg("cannot compare arrays of different element types")));
/*
- * We arrange to look up the element type info and related functions
- * only once per series of calls, assuming the element type doesn't
- * change underneath us.
+ * We arrange to look up the comparison function only once per series of
+ * calls, assuming the element type doesn't change underneath us.
+ * The typcache is used so that we have no memory leakage when being used
+ * as an index support function.
*/
- my_extra = (ac_extra *) ac_fmgr_info->fn_extra;
- if (my_extra == NULL)
+ typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
+ if (typentry == NULL ||
+ typentry->type_id != element_type)
{
- ac_fmgr_info->fn_extra = MemoryContextAlloc(ac_fmgr_info->fn_mcxt,
- sizeof(ac_extra));
- my_extra = (ac_extra *) ac_fmgr_info->fn_extra;
- my_extra->element_type = InvalidOid;
+ typentry = lookup_type_cache(element_type,
+ TYPECACHE_CMP_PROC_FINFO);
+ if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("could not identify a comparison function for type %s",
+ format_type_be(element_type))));
+ fcinfo->flinfo->fn_extra = (void *) typentry;
}
+ typlen = typentry->typlen;
+ typbyval = typentry->typbyval;
+ typalign = typentry->typalign;
- if (my_extra->element_type != element_type)
- {
- Oid eqfuncid = equality_oper_funcid(element_type);
- Oid ordfuncid = ordering_oper_funcid(element_type);
-
- get_typlenbyvalalign(element_type,
- &my_extra->typlen,
- &my_extra->typbyval,
- &my_extra->typalign);
- fmgr_info_cxt(eqfuncid, &my_extra->eqproc,
- ac_fmgr_info->fn_mcxt);
- fmgr_info_cxt(ordfuncid, &my_extra->ordproc,
- ac_fmgr_info->fn_mcxt);
- my_extra->element_type = element_type;
- }
- typlen = my_extra->typlen;
- typbyval = my_extra->typbyval;
- typalign = my_extra->typalign;
+ /*
+ * apply the operator to each pair of array elements.
+ */
+ MemSet(&locfcinfo, 0, sizeof(locfcinfo));
+ locfcinfo.flinfo = &typentry->cmp_proc_finfo;
+ locfcinfo.nargs = 2;
/* Loop over source data */
min_nitems = Min(nitems1, nitems2);
{
Datum elt1;
Datum elt2;
- Datum opresult;
+ int32 cmpresult;
/* Get element pair */
elt1 = fetch_att(p1, typbyval, typlen);
p2 = (char *) att_align(p2, typalign);
/* Compare the pair of elements */
+ locfcinfo.arg[0] = elt1;
+ locfcinfo.arg[1] = elt2;
+ locfcinfo.argnull[0] = false;
+ locfcinfo.argnull[1] = false;
+ locfcinfo.isnull = false;
+ cmpresult = DatumGetInt32(FunctionCallInvoke(&locfcinfo));
- /* are they equal */
- opresult = FunctionCall2(&my_extra->eqproc, elt1, elt2);
- if (DatumGetBool(opresult))
- continue;
+ if (cmpresult == 0)
+ continue; /* equal */
- /* nope, see if arg1 is less than arg2 */
- opresult = FunctionCall2(&my_extra->ordproc, elt1, elt2);
- if (DatumGetBool(opresult))
+ if (cmpresult < 0)
{
/* arg1 is less than arg2 */
result = -1;
* workings can be found in the book "Software Solutions in C" by
* Dale Schumacher, Academic Press, ISBN: 0-12-632360-7.
*
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/cash.c,v 1.59 2003/07/27 04:53:03 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/cash.c,v 1.60 2003/08/17 19:58:05 tgl Exp $
*/
#include "postgres.h"
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
+/*
+ * Comparison functions
+ */
Datum
cash_eq(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(c1 >= c2);
}
+Datum
+cash_cmp(PG_FUNCTION_ARGS)
+{
+ Cash c1 = PG_GETARG_CASH(0);
+ Cash c2 = PG_GETARG_CASH(1);
+
+ if (c1 > c2)
+ PG_RETURN_INT32(1);
+ else if (c1 == c2)
+ PG_RETURN_INT32(0);
+ else
+ PG_RETURN_INT32(-1);
+}
+
/* cash_pl()
* Add two cash values.
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.113 2003/08/04 02:40:05 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.114 2003/08/17 19:58:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static int
abstime_cmp_internal(AbsoluteTime a, AbsoluteTime b)
{
-/*
- * We consider all INVALIDs to be equal and larger than any non-INVALID.
- * This is somewhat arbitrary; the important thing is to have a
- * consistent sort order.
- */
+ /*
+ * We consider all INVALIDs to be equal and larger than any non-INVALID.
+ * This is somewhat arbitrary; the important thing is to have a
+ * consistent sort order.
+ */
if (a == INVALID_ABSTIME)
{
if (b == INVALID_ABSTIME)
char *i_str,
*p;
- i_str = (char *) palloc(T_INTERVAL_LEN); /* ['...' '...'] */
+ i_str = (char *) palloc(T_INTERVAL_LEN); /* ["..." "..."] */
strcpy(i_str, "[\"");
if (interval->status == T_INTERVAL_INVAL)
strcat(i_str, INVALID_INTERVAL_STR);
strcat(i_str, p);
pfree(p);
}
- strcat(i_str, "\"]\0");
+ strcat(i_str, "\"]");
PG_RETURN_CSTRING(i_str);
}
}
/*
- * reltimeeq - returns true iff arguments are equal
- * reltimene - returns true iff arguments are not equal
- * reltimelt - returns true iff t1 less than t2
- * reltimegt - returns true iff t1 greater than t2
- * reltimele - returns true iff t1 less than or equal to t2
- * reltimege - returns true iff t1 greater than or equal to t2
+ * reltime comparison routines
*/
+static int
+reltime_cmp_internal(RelativeTime a, RelativeTime b)
+{
+ /*
+ * We consider all INVALIDs to be equal and larger than any non-INVALID.
+ * This is somewhat arbitrary; the important thing is to have a
+ * consistent sort order.
+ */
+ if (a == INVALID_RELTIME)
+ {
+ if (b == INVALID_RELTIME)
+ return 0; /* INVALID = INVALID */
+ else
+ return 1; /* INVALID > non-INVALID */
+ }
+
+ if (b == INVALID_RELTIME)
+ return -1; /* non-INVALID < INVALID */
+
+ if (a > b)
+ return 1;
+ else if (a == b)
+ return 0;
+ else
+ return -1;
+}
+
Datum
reltimeeq(PG_FUNCTION_ARGS)
{
RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
- if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
- PG_RETURN_BOOL(false);
- PG_RETURN_BOOL(t1 == t2);
+ PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) == 0);
}
Datum
RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
- if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
- PG_RETURN_BOOL(false);
- PG_RETURN_BOOL(t1 != t2);
+ PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) != 0);
}
Datum
RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
- if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
- PG_RETURN_BOOL(false);
- PG_RETURN_BOOL(t1 < t2);
+ PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) < 0);
}
Datum
RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
- if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
- PG_RETURN_BOOL(false);
- PG_RETURN_BOOL(t1 > t2);
+ PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) > 0);
}
Datum
RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
- if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
- PG_RETURN_BOOL(false);
- PG_RETURN_BOOL(t1 <= t2);
+ PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) <= 0);
}
Datum
RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
- if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
- PG_RETURN_BOOL(false);
- PG_RETURN_BOOL(t1 >= t2);
+ PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) >= 0);
+}
+
+Datum
+btreltimecmp(PG_FUNCTION_ARGS)
+{
+ RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
+ RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
+
+ PG_RETURN_INT32(reltime_cmp_internal(t1, t2));
}
PG_RETURN_BOOL(false);
}
-
/*
- * tintervaleq - returns true iff interval i1 is equal to interval i2
- * Check length of intervals.
+ * tinterval comparison routines
+ *
+ * Note: comparison is based on the lengths of the intervals, not on
+ * endpoint value. This is pretty bogus, but since it's only a legacy
+ * datatype I'm not going to propose changing it.
*/
-Datum
-tintervaleq(PG_FUNCTION_ARGS)
+static int
+tinterval_cmp_internal(TimeInterval a, TimeInterval b)
{
- TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
- TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
- AbsoluteTime t10,
- t11,
- t20,
- t21;
+ bool a_invalid;
+ bool b_invalid;
+ AbsoluteTime a_len;
+ AbsoluteTime b_len;
- if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
- PG_RETURN_BOOL(false);
+ /*
+ * We consider all INVALIDs to be equal and larger than any non-INVALID.
+ * This is somewhat arbitrary; the important thing is to have a
+ * consistent sort order.
+ */
+ a_invalid = ((a->status == T_INTERVAL_INVAL) ||
+ (a->data[0] == INVALID_ABSTIME) ||
+ (a->data[1] == INVALID_ABSTIME));
+ b_invalid = ((b->status == T_INTERVAL_INVAL) ||
+ (b->data[0] == INVALID_ABSTIME) ||
+ (b->data[1] == INVALID_ABSTIME));
+
+ if (a_invalid)
+ {
+ if (b_invalid)
+ return 0; /* INVALID = INVALID */
+ else
+ return 1; /* INVALID > non-INVALID */
+ }
- t10 = i1->data[0];
- t11 = i1->data[1];
- t20 = i2->data[0];
- t21 = i2->data[1];
+ if (b_invalid)
+ return -1; /* non-INVALID < INVALID */
- if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
- || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
- PG_RETURN_BOOL(false);
+ a_len = a->data[1] - a->data[0];
+ b_len = b->data[1] - b->data[0];
- PG_RETURN_BOOL((t11 - t10) == (t21 - t20));
+ if (a_len > b_len)
+ return 1;
+ else if (a_len == b_len)
+ return 0;
+ else
+ return -1;
}
Datum
-tintervalne(PG_FUNCTION_ARGS)
+tintervaleq(PG_FUNCTION_ARGS)
{
TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
- AbsoluteTime t10,
- t11,
- t20,
- t21;
- if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
- PG_RETURN_BOOL(false);
-
- t10 = i1->data[0];
- t11 = i1->data[1];
- t20 = i2->data[0];
- t21 = i2->data[1];
+ PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) == 0);
+}
- if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
- || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
- PG_RETURN_BOOL(false);
+Datum
+tintervalne(PG_FUNCTION_ARGS)
+{
+ TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
+ TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
- PG_RETURN_BOOL((t11 - t10) != (t21 - t20));
+ PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) != 0);
}
Datum
{
TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
- AbsoluteTime t10,
- t11,
- t20,
- t21;
-
- if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
- PG_RETURN_BOOL(false);
- t10 = i1->data[0];
- t11 = i1->data[1];
- t20 = i2->data[0];
- t21 = i2->data[1];
-
- if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
- || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
- PG_RETURN_BOOL(false);
-
- PG_RETURN_BOOL((t11 - t10) < (t21 - t20));
+ PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) < 0);
}
Datum
{
TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
- AbsoluteTime t10,
- t11,
- t20,
- t21;
-
- if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
- PG_RETURN_BOOL(false);
- t10 = i1->data[0];
- t11 = i1->data[1];
- t20 = i2->data[0];
- t21 = i2->data[1];
-
- if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
- || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
- PG_RETURN_BOOL(false);
-
- PG_RETURN_BOOL((t11 - t10) <= (t21 - t20));
+ PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) <= 0);
}
Datum
{
TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
- AbsoluteTime t10,
- t11,
- t20,
- t21;
-
- if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
- PG_RETURN_BOOL(false);
- t10 = i1->data[0];
- t11 = i1->data[1];
- t20 = i2->data[0];
- t21 = i2->data[1];
-
- if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
- || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
- PG_RETURN_BOOL(false);
-
- PG_RETURN_BOOL((t11 - t10) > (t21 - t20));
+ PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) > 0);
}
Datum
{
TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
- AbsoluteTime t10,
- t11,
- t20,
- t21;
-
- if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
- PG_RETURN_BOOL(false);
- t10 = i1->data[0];
- t11 = i1->data[1];
- t20 = i2->data[0];
- t21 = i2->data[1];
+ PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) >= 0);
+}
- if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
- || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
- PG_RETURN_BOOL(false);
+Datum
+bttintervalcmp(PG_FUNCTION_ARGS)
+{
+ TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
+ TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
- PG_RETURN_BOOL((t11 - t10) >= (t21 - t20));
+ PG_RETURN_INT32(tinterval_cmp_internal(i1, i2));
}
break;
}
p++;
- /* skip leading blanks up to "'" */
+ /* skip leading blanks up to '"' */
while ((c = *p) != '\0')
{
if (IsSpace(c))
/* get the first date */
*i_start = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
CStringGetDatum(p)));
- /* rechange NULL at the end of the first date to a "'" */
+ /* rechange NULL at the end of the first date to a '"' */
*p1 = '"';
p = ++p1;
- /* skip blanks up to "'", beginning of second date */
+ /* skip blanks up to '"', beginning of second date */
while ((c = *p) != '\0')
{
if (IsSpace(c))
/* get the second date */
*i_end = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
CStringGetDatum(p)));
- /* rechange NULL at the end of the first date to a ''' */
+ /* rechange NULL at the end of the first date to a '"' */
*p1 = '"';
p = ++p1;
/* skip blanks up to ']' */
*
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
*
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.54 2003/08/04 02:40:05 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.55 2003/08/17 19:58:05 tgl Exp $
*
* ----------
*/
#include "parser/parse_oper.h"
#include "rewrite/rewriteHandler.h"
#include "utils/lsyscache.h"
+#include "utils/typcache.h"
#include "miscadmin.h"
*/
#define RI_INIT_QUERYHASHSIZE 128
-#define RI_INIT_OPREQHASHSIZE 128
#define RI_MATCH_TYPE_UNSPECIFIED 0
#define RI_MATCH_TYPE_FULL 1
} RI_QueryHashEntry;
-typedef struct RI_OpreqHashEntry
-{
- Oid typeid;
- FmgrInfo oprfmgrinfo;
-} RI_OpreqHashEntry;
-
-
-
/* ----------
* Local data
* ----------
*/
static HTAB *ri_query_cache = (HTAB *) NULL;
-static HTAB *ri_opreq_cache = (HTAB *) NULL;
/* ----------
/* ----------
* ri_InitHashTables -
*
- * Initialize our internal hash tables for prepared
- * query plans and equal operators.
+ * Initialize our internal hash table for prepared
+ * query plans.
* ----------
*/
static void
ctl.hash = tag_hash;
ri_query_cache = hash_create("RI query cache", RI_INIT_QUERYHASHSIZE,
&ctl, HASH_ELEM | HASH_FUNCTION);
-
- ctl.keysize = sizeof(Oid);
- ctl.entrysize = sizeof(RI_OpreqHashEntry);
- ctl.hash = tag_hash;
- ri_opreq_cache = hash_create("RI OpReq cache", RI_INIT_OPREQHASHSIZE,
- &ctl, HASH_ELEM | HASH_FUNCTION);
}
static bool
ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue)
{
- RI_OpreqHashEntry *entry;
- bool found;
+ TypeCacheEntry *typentry;
/*
- * On the first call initialize the hashtable
+ * Find the data type in the typcache, and ask for eq_opr info.
*/
- if (!ri_opreq_cache)
- ri_InitHashTables();
+ typentry = lookup_type_cache(typeid, TYPECACHE_EQ_OPR_FINFO);
- /*
- * Try to find the '=' operator for this type in our cache
- */
- entry = (RI_OpreqHashEntry *) hash_search(ri_opreq_cache,
- (void *) &typeid,
- HASH_FIND, NULL);
-
- /*
- * If not found, lookup the operator, then do the function manager
- * lookup, and remember that info.
- */
- if (!entry)
- {
- Oid opr_proc;
- FmgrInfo finfo;
-
- opr_proc = equality_oper_funcid(typeid);
-
- /*
- * Since fmgr_info could fail, call it *before* creating the
- * hashtable entry --- otherwise we could ereport leaving an
- * incomplete entry in the hashtable. Also, because this will be
- * a permanent table entry, we must make sure any subsidiary
- * structures of the fmgr record are kept in TopMemoryContext.
- */
- fmgr_info_cxt(opr_proc, &finfo, TopMemoryContext);
-
- entry = (RI_OpreqHashEntry *) hash_search(ri_opreq_cache,
- (void *) &typeid,
- HASH_ENTER, &found);
- if (entry == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_OUT_OF_MEMORY),
- errmsg("out of memory")));
-
- entry->typeid = typeid;
- memcpy(&(entry->oprfmgrinfo), &finfo, sizeof(FmgrInfo));
- }
+ if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("could not identify an equality operator for type %s",
+ format_type_be(typeid))));
/*
* Call the type specific '=' function
*/
- return DatumGetBool(FunctionCall2(&(entry->oprfmgrinfo),
+ return DatumGetBool(FunctionCall2(&(typentry->eq_opr_finfo),
oldvalue, newvalue));
}
* back to source text
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.151 2003/08/11 23:04:49 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.152 2003/08/17 19:58:05 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
#include "utils/array.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
+#include "utils/typcache.h"
/* ----------
SortClause *srt = (SortClause *) lfirst(l);
Node *sortexpr;
Oid sortcoltype;
- char *opname;
+ TypeCacheEntry *typentry;
appendStringInfo(buf, sep);
sortexpr = get_rule_sortgroupclause(srt, query->targetList,
force_colno, context);
sortcoltype = exprType(sortexpr);
- opname = generate_operator_name(srt->sortop,
- sortcoltype, sortcoltype);
- if (strcmp(opname, "<") != 0)
- {
- if (strcmp(opname, ">") == 0)
- appendStringInfo(buf, " DESC");
- else
- appendStringInfo(buf, " USING %s", opname);
- }
+ /* See whether operator is default < or > for datatype */
+ typentry = lookup_type_cache(sortcoltype,
+ TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
+ if (srt->sortop == typentry->lt_opr)
+ /* ASC is default, so emit nothing */ ;
+ else if (srt->sortop == typentry->gt_opr)
+ appendStringInfo(buf, " DESC");
+ else
+ appendStringInfo(buf, " USING %s",
+ generate_operator_name(srt->sortop,
+ sortcoltype,
+ sortcoltype));
sep = ", ";
}
}
if (!HeapTupleIsValid(ht_opc))
elog(ERROR, "cache lookup failed for opclass %u", opclass);
opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
+
+ /* Special case for ARRAY_OPS: pretend it is default for any array type */
+ if (OidIsValid(actual_datatype))
+ {
+ if (opcrec->opcintype == ANYARRAYOID &&
+ OidIsValid(get_element_type(actual_datatype)))
+ actual_datatype = opcrec->opcintype;
+ }
+
if (actual_datatype != opcrec->opcintype || !opcrec->opcdefault)
{
/* Okay, we need the opclass name. Do we need to qualify it? */
# Makefile for utils/cache
#
# IDENTIFICATION
-# $Header: /cvsroot/pgsql/src/backend/utils/cache/Makefile,v 1.17 2002/12/13 19:45:56 tgl Exp $
+# $Header: /cvsroot/pgsql/src/backend/utils/cache/Makefile,v 1.18 2003/08/17 19:58:06 tgl Exp $
#
#-------------------------------------------------------------------------
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
-OBJS = catcache.o inval.o relcache.o syscache.o lsyscache.o
+OBJS = catcache.o inval.o relcache.o syscache.o lsyscache.o typcache.o
all: SUBSYS.o
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.106 2003/08/11 23:04:49 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.107 2003/08/17 19:58:06 tgl Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
{
CatCList *catlist;
int i;
- HeapTuple tuple;
Oid opclass = InvalidOid;
/*
for (i = 0; i < catlist->n_members; i++)
{
- Form_pg_amop aform;
-
- tuple = &catlist->members[i]->tuple;
- aform = (Form_pg_amop) GETSTRUCT(tuple);
+ HeapTuple tuple = &catlist->members[i]->tuple;
+ Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
if (aform->amopstrategy == HTEqualStrategyNumber &&
opclass_is_hash(aform->amopclaid))
if (OidIsValid(opclass))
{
/* Found a suitable opclass, get its hash support function */
- tuple = SearchSysCache(AMPROCNUM,
- ObjectIdGetDatum(opclass),
- Int16GetDatum(HASHPROC),
- 0, 0);
- if (HeapTupleIsValid(tuple))
- {
- Form_pg_amproc aform = (Form_pg_amproc) GETSTRUCT(tuple);
- RegProcedure result;
-
- result = aform->amproc;
- ReleaseSysCache(tuple);
- Assert(RegProcedureIsValid(result));
- return result;
- }
+ return get_opclass_proc(opclass, HASHPROC);
}
/* Didn't find a match... */
}
+/* ---------- AMPROC CACHES ---------- */
+
+/*
+ * get_opclass_proc
+ * Get the OID of the specified support function
+ * for the specified opclass.
+ *
+ * Returns InvalidOid if there is no pg_amproc entry for the given keys.
+ */
+Oid
+get_opclass_proc(Oid opclass, int16 procnum)
+{
+ HeapTuple tp;
+ Form_pg_amproc amproc_tup;
+ RegProcedure result;
+
+ tp = SearchSysCache(AMPROCNUM,
+ ObjectIdGetDatum(opclass),
+ Int16GetDatum(procnum),
+ 0, 0);
+ if (!HeapTupleIsValid(tp))
+ return InvalidOid;
+ amproc_tup = (Form_pg_amproc) GETSTRUCT(tp);
+ result = amproc_tup->amproc;
+ ReleaseSysCache(tp);
+ return result;
+}
+
+
/* ---------- ATTRIBUTE CACHES ---------- */
/*
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * typcache.c
+ * POSTGRES type cache code
+ *
+ * The type cache exists to speed lookup of certain information about data
+ * types that is not directly available from a type's pg_type row. In
+ * particular, we use a type's default btree opclass, or the default hash
+ * opclass if no btree opclass exists, to determine which operators should
+ * be used for grouping and sorting the type (GROUP BY, ORDER BY ASC/DESC).
+ *
+ * Several seemingly-odd choices have been made to support use of the type
+ * cache by the generic array comparison routines array_eq() and array_cmp().
+ * Because these routines are used as index support operations, they cannot
+ * leak memory. To allow them to execute efficiently, all information that
+ * either of them would like to re-use across calls is made available in the
+ * type cache.
+ *
+ * Once created, a type cache entry lives as long as the backend does, so
+ * there is no need for a call to release a cache entry. (For present uses,
+ * it would be okay to flush type cache entries at the ends of transactions,
+ * if we needed to reclaim space.)
+ *
+ * There is presently no provision for clearing out a cache entry if the
+ * stored data becomes obsolete. (The code will work if a type acquires
+ * opclasses it didn't have before while a backend runs --- but not if the
+ * definition of an existing opclass is altered.) However, the relcache
+ * doesn't cope with opclasses changing under it, either, so this seems
+ * a low-priority problem.
+ *
+ *
+ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/typcache.c,v 1.1 2003/08/17 19:58:06 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "access/hash.h"
+#include "access/nbtree.h"
+#include "catalog/catname.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_am.h"
+#include "catalog/pg_opclass.h"
+#include "parser/parse_coerce.h"
+#include "utils/builtins.h"
+#include "utils/catcache.h"
+#include "utils/fmgroids.h"
+#include "utils/hsearch.h"
+#include "utils/lsyscache.h"
+#include "utils/typcache.h"
+
+
+static HTAB *TypeCacheHash = NULL;
+
+
+static Oid lookup_default_opclass(Oid type_id, Oid am_id);
+
+
+/*
+ * lookup_type_cache
+ *
+ * Fetch the type cache entry for the specified datatype, and make sure that
+ * all the fields requested by bits in 'flags' are valid.
+ *
+ * The result is never NULL --- we will elog() if the passed type OID is
+ * invalid. Note however that we may fail to find one or more of the
+ * requested opclass-dependent fields; the caller needs to check whether
+ * the fields are InvalidOid or not.
+ */
+TypeCacheEntry *
+lookup_type_cache(Oid type_id, int flags)
+{
+ TypeCacheEntry *typentry;
+ bool found;
+
+ if (TypeCacheHash == NULL)
+ {
+ /* First time through: initialize the hash table */
+ HASHCTL ctl;
+
+ if (!CacheMemoryContext)
+ CreateCacheMemoryContext();
+
+ MemSet(&ctl, 0, sizeof(ctl));
+ ctl.keysize = sizeof(Oid);
+ ctl.entrysize = sizeof(TypeCacheEntry);
+ ctl.hash = tag_hash;
+ TypeCacheHash = hash_create("Type information cache", 64,
+ &ctl, HASH_ELEM | HASH_FUNCTION);
+ }
+
+ /* Try to look up an existing entry */
+ typentry = (TypeCacheEntry *) hash_search(TypeCacheHash,
+ (void *) &type_id,
+ HASH_FIND, NULL);
+ if (typentry == NULL)
+ {
+ /*
+ * If we didn't find one, we want to make one. But first get the
+ * required info from the pg_type row, just to make sure we don't
+ * make a cache entry for an invalid type OID.
+ */
+ int16 typlen;
+ bool typbyval;
+ char typalign;
+
+ get_typlenbyvalalign(type_id, &typlen, &typbyval, &typalign);
+
+ typentry = (TypeCacheEntry *) hash_search(TypeCacheHash,
+ (void *) &type_id,
+ HASH_ENTER, &found);
+ if (typentry == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("out of memory")));
+ Assert(!found); /* it wasn't there a moment ago */
+
+ MemSet(typentry, 0, sizeof(TypeCacheEntry));
+ typentry->type_id = type_id;
+ typentry->typlen = typlen;
+ typentry->typbyval = typbyval;
+ typentry->typalign = typalign;
+ }
+
+ /* If we haven't already found the opclass, try to do so */
+ if (flags != 0 && typentry->btree_opc == InvalidOid)
+ {
+ typentry->btree_opc = lookup_default_opclass(type_id,
+ BTREE_AM_OID);
+ /* Only care about hash opclass if no btree opclass... */
+ if (typentry->btree_opc == InvalidOid)
+ {
+ if (typentry->hash_opc == InvalidOid)
+ typentry->hash_opc = lookup_default_opclass(type_id,
+ HASH_AM_OID);
+ }
+ else
+ {
+ /*
+ * If we find a btree opclass where previously we only found
+ * a hash opclass, forget the hash equality operator so we
+ * can use the btree operator instead.
+ */
+ typentry->eq_opr = InvalidOid;
+ typentry->eq_opr_finfo.fn_oid = InvalidOid;
+ }
+ }
+
+ /* Look for requested operators and functions */
+ if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) &&
+ typentry->eq_opr == InvalidOid)
+ {
+ if (typentry->btree_opc != InvalidOid)
+ typentry->eq_opr = get_opclass_member(typentry->btree_opc,
+ BTEqualStrategyNumber);
+ if (typentry->eq_opr == InvalidOid &&
+ typentry->hash_opc != InvalidOid)
+ typentry->eq_opr = get_opclass_member(typentry->hash_opc,
+ HTEqualStrategyNumber);
+ }
+ if ((flags & TYPECACHE_LT_OPR) && typentry->lt_opr == InvalidOid)
+ {
+ if (typentry->btree_opc != InvalidOid)
+ typentry->lt_opr = get_opclass_member(typentry->btree_opc,
+ BTLessStrategyNumber);
+ }
+ if ((flags & TYPECACHE_GT_OPR) && typentry->gt_opr == InvalidOid)
+ {
+ if (typentry->btree_opc != InvalidOid)
+ typentry->gt_opr = get_opclass_member(typentry->btree_opc,
+ BTGreaterStrategyNumber);
+ }
+ if ((flags & (TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO)) &&
+ typentry->cmp_proc == InvalidOid)
+ {
+ if (typentry->btree_opc != InvalidOid)
+ typentry->cmp_proc = get_opclass_proc(typentry->btree_opc,
+ BTORDER_PROC);
+ }
+
+ /*
+ * Set up fmgr lookup info as requested
+ *
+ * Note: we tell fmgr the finfo structures live in CacheMemoryContext,
+ * which is not quite right (they're really in DynaHashContext) but this
+ * will do for our purposes.
+ */
+ if ((flags & TYPECACHE_EQ_OPR_FINFO) &&
+ typentry->eq_opr_finfo.fn_oid == InvalidOid &&
+ typentry->eq_opr != InvalidOid)
+ {
+ Oid eq_opr_func;
+
+ eq_opr_func = get_opcode(typentry->eq_opr);
+ if (eq_opr_func != InvalidOid)
+ fmgr_info_cxt(eq_opr_func, &typentry->eq_opr_finfo,
+ CacheMemoryContext);
+ }
+ if ((flags & TYPECACHE_CMP_PROC_FINFO) &&
+ typentry->cmp_proc_finfo.fn_oid == InvalidOid &&
+ typentry->cmp_proc != InvalidOid)
+ {
+ fmgr_info_cxt(typentry->cmp_proc, &typentry->cmp_proc_finfo,
+ CacheMemoryContext);
+ }
+
+ return typentry;
+}
+
+/*
+ * lookup_default_opclass
+ *
+ * Given the OIDs of a datatype and an access method, find the default
+ * operator class, if any. Returns InvalidOid if there is none.
+ */
+static Oid
+lookup_default_opclass(Oid type_id, Oid am_id)
+{
+ int nexact = 0;
+ int ncompatible = 0;
+ Oid exactOid = InvalidOid;
+ Oid compatibleOid = InvalidOid;
+ Relation rel;
+ ScanKeyData skey[1];
+ SysScanDesc scan;
+ HeapTuple tup;
+
+ /* If it's a domain, look at the base type instead */
+ type_id = getBaseType(type_id);
+
+ /*
+ * We scan through all the opclasses available for the access method,
+ * looking for one that is marked default and matches the target type
+ * (either exactly or binary-compatibly, but prefer an exact match).
+ *
+ * We could find more than one binary-compatible match, in which case we
+ * require the user to specify which one he wants. If we find more
+ * than one exact match, then someone put bogus entries in pg_opclass.
+ *
+ * This is the same logic as GetDefaultOpClass() in indexcmds.c, except
+ * that we consider all opclasses, regardless of the current search path.
+ */
+ rel = heap_openr(OperatorClassRelationName, AccessShareLock);
+
+ ScanKeyEntryInitialize(&skey[0], 0x0,
+ Anum_pg_opclass_opcamid, F_OIDEQ,
+ ObjectIdGetDatum(am_id));
+
+ scan = systable_beginscan(rel, OpclassAmNameNspIndex, true,
+ SnapshotNow, 1, skey);
+
+ while (HeapTupleIsValid(tup = systable_getnext(scan)))
+ {
+ Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
+
+ if (opclass->opcdefault)
+ {
+ if (opclass->opcintype == type_id)
+ {
+ nexact++;
+ exactOid = HeapTupleGetOid(tup);
+ }
+ else if (IsBinaryCoercible(type_id, opclass->opcintype))
+ {
+ ncompatible++;
+ compatibleOid = HeapTupleGetOid(tup);
+ }
+ }
+ }
+
+ systable_endscan(scan);
+
+ heap_close(rel, AccessShareLock);
+
+ if (nexact == 1)
+ return exactOid;
+ if (nexact != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("there are multiple default operator classes for data type %s",
+ format_type_be(type_id))));
+ if (ncompatible == 1)
+ return compatibleOid;
+
+ return InvalidOid;
+}
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.36 2003/08/04 02:40:09 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.37 2003/08/17 19:58:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/heapam.h"
#include "access/nbtree.h"
#include "catalog/pg_amop.h"
-#include "catalog/pg_amproc.h"
#include "catalog/pg_operator.h"
#include "miscadmin.h"
#include "utils/catcache.h"
if (OidIsValid(opclass))
{
/* Found a suitable opclass, get its comparator support function */
- tuple = SearchSysCache(AMPROCNUM,
- ObjectIdGetDatum(opclass),
- Int16GetDatum(BTORDER_PROC),
- 0, 0);
- if (HeapTupleIsValid(tuple))
- {
- Form_pg_amproc aform = (Form_pg_amproc) GETSTRUCT(tuple);
-
- *sortFunction = aform->amproc;
- ReleaseSysCache(tuple);
- Assert(RegProcedureIsValid(*sortFunction));
- return;
- }
+ *sortFunction = get_opclass_proc(opclass, BTORDER_PROC);
+ Assert(RegProcedureIsValid(*sortFunction));
+ return;
}
/*
* Can't find a comparator, so use the operator as-is. Decide whether
* it is forward or reverse sort by looking at its name (grotty, but
* this only matters for deciding which end NULLs should get sorted
- * to).
+ * to). XXX possibly better idea: see whether its selectivity function
+ * is scalargtcmp?
*/
tuple = SearchSysCache(OPEROID,
ObjectIdGetDatum(sortOperator),
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: catversion.h,v 1.206 2003/08/04 02:40:10 momjian Exp $
+ * $Id: catversion.h,v 1.207 2003/08/17 19:58:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200307301
+#define CATALOG_VERSION_NO 200308171
#endif
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_amop.h,v 1.54 2003/08/04 02:40:10 momjian Exp $
+ * $Id: pg_amop.h,v 1.55 2003/08/17 19:58:06 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
DATA(insert ( 2098 4 f 2335 ));
DATA(insert ( 2098 5 f 2336 ));
+/*
+ * btree money_ops
+ */
+
+DATA(insert ( 2099 1 f 902 ));
+DATA(insert ( 2099 2 f 904 ));
+DATA(insert ( 2099 3 f 900 ));
+DATA(insert ( 2099 4 f 905 ));
+DATA(insert ( 2099 5 f 903 ));
+
+/*
+ * btree reltime_ops
+ */
+
+DATA(insert ( 2233 1 f 568 ));
+DATA(insert ( 2233 2 f 570 ));
+DATA(insert ( 2233 3 f 566 ));
+DATA(insert ( 2233 4 f 569 ));
+DATA(insert ( 2233 5 f 571 ));
+
+/*
+ * btree tinterval_ops
+ */
+
+DATA(insert ( 2234 1 f 813 ));
+DATA(insert ( 2234 2 f 815 ));
+DATA(insert ( 2234 3 f 811 ));
+DATA(insert ( 2234 4 f 814 ));
+DATA(insert ( 2234 5 f 816 ));
+
/*
* btree array_ops
*/
DATA(insert ( 2231 1 f 2328 ));
/* name_pattern_ops */
DATA(insert ( 2232 1 f 2334 ));
+/* aclitem_ops */
+DATA(insert ( 2235 1 f 974 ));
#endif /* PG_AMOP_H */
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_amproc.h,v 1.43 2003/08/04 02:40:11 momjian Exp $
+ * $Id: pg_amproc.h,v 1.44 2003/08/17 19:58:06 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
DATA(insert ( 2096 1 2166 ));
DATA(insert ( 2097 1 2180 ));
DATA(insert ( 2098 1 2187 ));
+DATA(insert ( 2099 1 377 ));
+DATA(insert ( 2233 1 380 ));
+DATA(insert ( 2234 1 381 ));
/* hash */
DATA(insert ( 2230 1 456 ));
DATA(insert ( 2231 1 456 ));
DATA(insert ( 2232 1 455 ));
+DATA(insert ( 2235 1 329 ));
#endif /* PG_AMPROC_H */
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_opclass.h,v 1.56 2003/08/04 02:40:12 momjian Exp $
+ * $Id: pg_opclass.h,v 1.57 2003/08/17 19:58:06 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
#define BPCHAR_PATTERN_BTREE_OPS_OID 2097
DATA(insert OID = 2098 ( 403 name_pattern_ops PGNSP PGUID 19 f 0 ));
#define NAME_PATTERN_BTREE_OPS_OID 2098
+DATA(insert OID = 2099 ( 403 money_ops PGNSP PGUID 790 t 0 ));
DATA(insert OID = 2222 ( 405 bool_ops PGNSP PGUID 16 t 0 ));
DATA(insert OID = 2223 ( 405 bytea_ops PGNSP PGUID 17 t 0 ));
DATA(insert OID = 2224 ( 405 int2vector_ops PGNSP PGUID 22 t 0 ));
DATA(insert OID = 2230 ( 405 varchar_pattern_ops PGNSP PGUID 1043 f 0 ));
DATA(insert OID = 2231 ( 405 bpchar_pattern_ops PGNSP PGUID 1042 f 0 ));
DATA(insert OID = 2232 ( 405 name_pattern_ops PGNSP PGUID 19 f 0 ));
+DATA(insert OID = 2233 ( 403 reltime_ops PGNSP PGUID 703 t 0 ));
+DATA(insert OID = 2234 ( 403 tinterval_ops PGNSP PGUID 704 t 0 ));
+DATA(insert OID = 2235 ( 405 aclitem_ops PGNSP PGUID 1033 t 0 ));
#endif /* PG_OPCLASS_H */
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_operator.h,v 1.120 2003/08/04 02:40:12 momjian Exp $
+ * $Id: pg_operator.h,v 1.121 2003/08/17 19:58:06 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
DATA(insert OID = 966 ( "+" PGNSP PGUID b f 1034 1033 1034 0 0 0 0 0 0 aclinsert - - ));
DATA(insert OID = 967 ( "-" PGNSP PGUID b f 1034 1033 1034 0 0 0 0 0 0 aclremove - - ));
DATA(insert OID = 968 ( "~" PGNSP PGUID b f 1034 1033 16 0 0 0 0 0 0 aclcontains - - ));
-DATA(insert OID = 974 ( "=" PGNSP PGUID b f 1033 1033 16 974 0 0 0 0 0 aclitemeq eqsel eqjoinsel ));
+DATA(insert OID = 974 ( "=" PGNSP PGUID b t 1033 1033 16 974 0 0 0 0 0 aclitemeq eqsel eqjoinsel ));
/* additional geometric operators - thomas 1997-07-09 */
DATA(insert OID = 969 ( "@@" PGNSP PGUID l f 0 601 600 0 0 0 0 0 0 lseg_center - - ));
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 ));
+#define ARRAY_GT_OP 1073
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 ));
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_proc.h,v 1.312 2003/08/04 02:40:12 momjian Exp $
+ * $Id: pg_proc.h,v 1.313 2003/08/17 19:58:06 tgl Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
DESCR("btree less-equal-greater");
DATA(insert OID = 360 ( bttextcmp PGNSP PGUID 12 f f t f i 2 23 "25 25" bttextcmp - _null_ ));
DESCR("btree less-equal-greater");
+DATA(insert OID = 377 ( cash_cmp PGNSP PGUID 12 f f t f i 2 23 "790 790" cash_cmp - _null_ ));
+DESCR("btree less-equal-greater");
+DATA(insert OID = 380 ( btreltimecmp PGNSP PGUID 12 f f t f i 2 23 "703 703" btreltimecmp - _null_ ));
+DESCR("btree less-equal-greater");
+DATA(insert OID = 381 ( bttintervalcmp PGNSP PGUID 12 f f t f i 2 23 "704 704" bttintervalcmp - _null_ ));
+DESCR("btree less-equal-greater");
DATA(insert OID = 382 ( btarraycmp PGNSP PGUID 12 f f t f i 2 23 "2277 2277" btarraycmp - _null_ ));
DESCR("btree less-equal-greater");
DESCR("hash any varlena type");
DATA(insert OID = 457 ( hashoidvector PGNSP PGUID 12 f f t f i 1 23 "30" hashoidvector - _null_ ));
DESCR("hash");
+DATA(insert OID = 329 ( hash_aclitem PGNSP PGUID 12 f f t f i 1 23 "1033" hash_aclitem - _null_ ));
+DESCR("hash");
DATA(insert OID = 398 ( hashint2vector PGNSP PGUID 12 f f t f i 1 23 "22" hashint2vector - _null_ ));
DESCR("hash");
DATA(insert OID = 399 ( hashmacaddr PGNSP PGUID 12 f f t f i 1 23 "829" hashmacaddr - _null_ ));
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: nodes.h,v 1.146 2003/08/04 02:40:13 momjian Exp $
+ * $Id: nodes.h,v 1.147 2003/08/17 19:58:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
T_ExprFieldSelect,
T_ResTarget,
T_TypeCast,
- T_SortGroupBy,
+ T_SortBy,
T_RangeSubselect,
T_RangeFunction,
T_TypeName,
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parsenodes.h,v 1.246 2003/08/08 21:42:48 momjian Exp $
+ * $Id: parsenodes.h,v 1.247 2003/08/17 19:58:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
} ResTarget;
/*
- * SortGroupBy - for ORDER BY clause
+ * SortBy - for ORDER BY clause
*/
-typedef struct SortGroupBy
+#define SORTBY_ASC 1
+#define SORTBY_DESC 2
+#define SORTBY_USING 3
+
+typedef struct SortBy
{
NodeTag type;
- List *useOp; /* operator to use */
- Node *node; /* Expression */
-} SortGroupBy;
+ int sortby_kind; /* see codes above */
+ List *useOp; /* name of op to use, if SORTBY_USING */
+ Node *node; /* expression to sort on */
+} SortBy;
/*
* RangeSubselect - subquery appearing in a FROM clause
* These fields are used in both "leaf" SelectStmts and upper-level
* SelectStmts.
*/
- List *sortClause; /* sort clause (a list of SortGroupBy's) */
+ List *sortClause; /* sort clause (a list of SortBy's) */
Node *limitOffset; /* # of result tuples to skip */
Node *limitCount; /* # of result tuples to return */
List *forUpdate; /* FOR UPDATE clause */
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parse_clause.h,v 1.36 2003/08/07 19:20:23 tgl Exp $
+ * $Id: parse_clause.h,v 1.37 2003/08/17 19:58:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
bool resolveUnknown);
extern List *addTargetToSortList(ParseState *pstate, TargetEntry *tle,
List *sortlist, List *targetlist,
- List *opname, bool resolveUnknown);
+ int sortby_kind, List *sortby_opname,
+ bool resolveUnknown);
extern Index assignSortGroupRef(TargetEntry *tle, List *tlist);
extern bool targetIsInSortList(TargetEntry *tle, List *sortList);
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parse_oper.h,v 1.32 2003/08/04 02:40:14 momjian Exp $
+ * $Id: parse_oper.h,v 1.33 2003/08/17 19:58:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* currently no need for compatible_left_oper/compatible_right_oper */
-/* Routines for identifying "=" and "<" operators for a type */
+/* Routines for identifying "=", "<", ">" operators for a type */
extern Operator equality_oper(Oid argtype, bool noError);
extern Operator ordering_oper(Oid argtype, bool noError);
+extern Operator reverse_ordering_oper(Oid argtype, bool noError);
/* Convenience routines for common calls on the above */
extern Oid compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError);
extern Oid equality_oper_funcid(Oid argtype);
extern Oid ordering_oper_opid(Oid argtype);
-extern Oid ordering_oper_funcid(Oid argtype);
+extern Oid reverse_ordering_oper_opid(Oid argtype);
/* Extract operator OID or underlying-function OID from an Operator tuple */
extern Oid oprid(Operator op);
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: acl.h,v 1.61 2003/08/08 21:42:55 momjian Exp $
+ * $Id: acl.h,v 1.62 2003/08/17 19:58:06 tgl Exp $
*
* NOTES
* For backward-compatibility purposes we have to allow there
extern Datum aclcontains(PG_FUNCTION_ARGS);
extern Datum makeaclitem(PG_FUNCTION_ARGS);
extern Datum aclitem_eq(PG_FUNCTION_ARGS);
+extern Datum hash_aclitem(PG_FUNCTION_ARGS);
/*
* prototypes for functions in aclchk.c
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: builtins.h,v 1.227 2003/08/08 21:42:55 momjian Exp $
+ * $Id: builtins.h,v 1.228 2003/08/17 19:58:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern Datum btoidcmp(PG_FUNCTION_ARGS);
extern Datum btoidvectorcmp(PG_FUNCTION_ARGS);
extern Datum btabstimecmp(PG_FUNCTION_ARGS);
+extern Datum btreltimecmp(PG_FUNCTION_ARGS);
+extern Datum bttintervalcmp(PG_FUNCTION_ARGS);
extern Datum btcharcmp(PG_FUNCTION_ARGS);
extern Datum btnamecmp(PG_FUNCTION_ARGS);
extern Datum bttextcmp(PG_FUNCTION_ARGS);
extern Datum cash_le(PG_FUNCTION_ARGS);
extern Datum cash_gt(PG_FUNCTION_ARGS);
extern Datum cash_ge(PG_FUNCTION_ARGS);
+extern Datum cash_cmp(PG_FUNCTION_ARGS);
extern Datum cash_pl(PG_FUNCTION_ARGS);
extern Datum cash_mi(PG_FUNCTION_ARGS);
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: lsyscache.h,v 1.80 2003/08/11 23:04:50 tgl Exp $
+ * $Id: lsyscache.h,v 1.81 2003/08/17 19:58:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern bool op_requires_recheck(Oid opno, Oid opclass);
extern Oid get_opclass_member(Oid opclass, int16 strategy);
extern Oid get_op_hash_function(Oid opno);
+extern Oid get_opclass_proc(Oid opclass, int16 procnum);
extern char *get_attname(Oid relid, AttrNumber attnum);
extern char *get_relid_attribute_name(Oid relid, AttrNumber attnum);
extern AttrNumber get_attnum(Oid relid, const char *attname);
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * typcache.h
+ * Type cache definitions.
+ *
+ * The type cache exists to speed lookup of certain information about data
+ * types that is not directly available from a type's pg_type row.
+ *
+ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: typcache.h,v 1.1 2003/08/17 19:58:06 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef TYPCACHE_H
+#define TYPCACHE_H
+
+#include "fmgr.h"
+
+
+typedef struct TypeCacheEntry
+{
+ /* typeId is the hash lookup key and MUST BE FIRST */
+ Oid type_id; /* OID of the data type */
+
+ /* some subsidiary information copied from the pg_type row */
+ int16 typlen;
+ bool typbyval;
+ char typalign;
+
+ /*
+ * Information obtained from opclass entries
+ *
+ * These will be InvalidOid if no match could be found, or if the
+ * information hasn't yet been requested.
+ */
+ Oid btree_opc; /* OID of the default btree opclass */
+ Oid hash_opc; /* OID of the default hash opclass */
+ Oid eq_opr; /* OID of the equality operator */
+ Oid lt_opr; /* OID of the less-than operator */
+ Oid gt_opr; /* OID of the greater-than operator */
+ Oid cmp_proc; /* OID of the btree comparison function */
+
+ /*
+ * Pre-set-up fmgr call info for the equality operator and the btree
+ * comparison function. These are kept in the type cache to avoid
+ * problems with memory leaks in repeated calls to array_eq and array_cmp.
+ * There is not currently a need to maintain call info for the lt_opr
+ * or gt_opr.
+ */
+ FmgrInfo eq_opr_finfo;
+ FmgrInfo cmp_proc_finfo;
+} TypeCacheEntry;
+
+/* Bit flags to indicate which fields a given caller needs to have set */
+#define TYPECACHE_EQ_OPR 0x0001
+#define TYPECACHE_LT_OPR 0x0002
+#define TYPECACHE_GT_OPR 0x0004
+#define TYPECACHE_CMP_PROC 0x0008
+#define TYPECACHE_EQ_OPR_FINFO 0x0010
+#define TYPECACHE_CMP_PROC_FINFO 0x0020
+
+extern TypeCacheEntry *lookup_type_cache(Oid type_id, int flags);
+
+#endif /* TYPCACHE_H */
SELECT '' as five, c1.f1 AS one, c2.f1 AS two, (c1.f1 <-> c2.f1) AS distance
FROM CIRCLE_TBL c1, CIRCLE_TBL c2
WHERE (c1.f1 < c2.f1) AND ((c1.f1 <-> c2.f1) > 0)
- ORDER BY distance, one, two;
+ ORDER BY distance, one USING < , two USING < ;
five | one | two | distance
------+----------------+----------------+------------------
| <(100,200),10> | <(100,1),115> | 74
SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
FROM CIRCLE_TBL c1, POINT_TBL p1
WHERE (p1.f1 <-> c1.f1) > 0
- ORDER BY distance, circle, point using <<;
+ ORDER BY distance, circle using <, point using <<;
twentyfour | circle | point | distance
------------+----------------+------------+---------------
| <(1,2),3> | (-3,4) | 1.472135955
SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
FROM CIRCLE_TBL c1, POINT_TBL p1
WHERE (p1.f1 <-> c1.f1) > 0
- ORDER BY distance, circle, point using <<;
+ ORDER BY distance, circle using <, point using <<;
twentyfour | circle | point | distance
------------+----------------+------------+---------------
| <(1,2),3> | (-3,4) | 1.472135955
SELECT '' as five, c1.f1 AS one, c2.f1 AS two, (c1.f1 <-> c2.f1) AS distance
FROM CIRCLE_TBL c1, CIRCLE_TBL c2
WHERE (c1.f1 < c2.f1) AND ((c1.f1 <-> c2.f1) > 0)
- ORDER BY distance, one, two;
-
+ ORDER BY distance, one USING < , two USING < ;
SELECT '' AS twentyfour, c1.f1 AS circle, p1.f1 AS point, (p1.f1 <-> c1.f1) AS distance
FROM CIRCLE_TBL c1, POINT_TBL p1
WHERE (p1.f1 <-> c1.f1) > 0
- ORDER BY distance, circle, point using <<;
-
+ ORDER BY distance, circle using <, point using <<;