Commit ec646dbc authored by Tom Lane's avatar Tom Lane

Create a 'type cache' that keeps track of the data needed for any particular

datatype by array_eq and array_cmp; use this to solve problems with memory
leaks in array indexing support.  The parser's equality_oper and ordering_oper
routines also use the cache.  Change the operator search algorithms to look
for appropriate btree or hash index opclasses, instead of assuming operators
named '<' or '=' have the right semantics.  (ORDER BY ASC/DESC now also look
at opclasses, instead of assuming '<' and '>' are the right things.)  Add
several more index opclasses so that there is no regression in functionality
for base datatypes.  initdb forced due to catalog additions.
parent d89578cc
......@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -390,7 +390,6 @@ examine_attribute(Relation onerel, int attnum)
{
Form_pg_attribute attr = onerel->rd_att->attrs[attnum - 1];
Operator func_operator;
Oid oprrest;
HeapTuple typtuple;
Oid eqopr = InvalidOid;
Oid eqfunc = InvalidOid;
......@@ -409,12 +408,8 @@ examine_attribute(Relation onerel, int attnum)
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))
......@@ -447,9 +442,7 @@ examine_attribute(Relation onerel, int attnum)
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;
......
......@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -529,7 +529,8 @@ GetDefaultOpClass(Oid attrType, Oid accessMethodId)
* 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;
......
......@@ -9,7 +9,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -261,7 +261,9 @@ DefineOpClass(CreateOpClassStmt *stmt)
/*
* 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)
{
......
......@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.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 $
*
*-------------------------------------------------------------------------
*/
......@@ -1402,11 +1402,12 @@ _copyTypeName(TypeName *from)
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);
......@@ -2924,8 +2925,8 @@ copyObject(void *from)
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);
......
......@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.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 $
*
*-------------------------------------------------------------------------
*/
......@@ -1480,8 +1480,9 @@ _equalTypeCast(TypeCast *a, TypeCast *b)
}
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);
......@@ -2045,8 +2046,8 @@ equal(void *a, void *b)
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);
......
......@@ -10,7 +10,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -629,8 +629,9 @@ create_unique_plan(Query *root, UniquePath *best_path)
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);
......
......@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -1327,7 +1327,9 @@ hash_safe_grouping(Query *parse)
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)
......
......@@ -11,7 +11,7 @@
*
*
* 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
......@@ -115,7 +115,7 @@ static void doNegateFloat(Value *v);
TypeName *typnam;
DefElem *defelt;
SortGroupBy *sortgroupby;
SortBy *sortby;
JoinExpr *jexpr;
IndexElem *ielem;
Alias *alias;
......@@ -189,7 +189,7 @@ static void doNegateFloat(Value *v);
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
......@@ -278,7 +278,7 @@ static void doNegateFloat(Value *v);
%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
......@@ -4577,21 +4577,34 @@ sortby_list:
| 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*/ }
;
......
......@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -1295,7 +1295,7 @@ transformSortClause(ParseState *pstate,
foreach(olitem, orderlist)
{
SortGroupBy *sortby = lfirst(olitem);
SortBy *sortby = lfirst(olitem);
TargetEntry *tle;
tle = findTargetlistEntry(pstate, sortby->node,
......@@ -1303,7 +1303,9 @@ transformSortClause(ParseState *pstate,
sortlist = addTargetToSortList(pstate, tle,
sortlist, targetlist,
sortby->useOp, resolveUnknown);
sortby->sortby_kind,
sortby->useOp,
resolveUnknown);
}
return sortlist;
......@@ -1409,7 +1411,7 @@ transformDistinctClause(ParseState *pstate, List *distinctlist,
{
*sortClause = addTargetToSortList(pstate, tle,
*sortClause, targetlist,
NIL, true);
SORTBY_ASC, NIL, true);
/*
* Probably, the tle should always have been added at the
......@@ -1457,7 +1459,8 @@ addAllTargetsToSortList(ParseState *pstate, List *sortlist,
if (!tle->resdom->resjunk)
sortlist = addTargetToSortList(pstate, tle,
sortlist, targetlist,
NIL, resolveUnknown);
SORTBY_ASC, NIL,
resolveUnknown);
}
return sortlist;
}
......@@ -1478,7 +1481,8 @@ addAllTargetsToSortList(ParseState *pstate, List *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))
......@@ -1499,13 +1503,25 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
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);
}
......
......@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -26,6 +26,7 @@
#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,
......@@ -135,52 +136,49 @@ LookupOperNameTypeNames(List *opername, TypeName *oprleft,
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),
......@@ -197,53 +195,119 @@ equality_oper(Oid argtype, bool noError)
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),
......@@ -286,16 +350,16 @@ ordering_oper_opid(Oid argtype)
}
/*
* 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;
}
......
......@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -480,6 +480,23 @@ aclitem_eq(PG_FUNCTION_ARGS)
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
*
......
......@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -28,6 +28,7 @@
#include "utils/memutils.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
/*----------
......@@ -2341,6 +2342,9 @@ deconstruct_array(ArrayType *array,
* 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
......@@ -2357,13 +2361,12 @@ array_eq(PG_FUNCTION_ARGS)
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))
......@@ -2379,38 +2382,31 @@ array_eq(PG_FUNCTION_ARGS)
/*
* 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 */
......@@ -2519,23 +2515,14 @@ array_cmp(FunctionCallInfo fcinfo)
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,
......@@ -2543,37 +2530,34 @@ array_cmp(FunctionCallInfo fcinfo)
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);
......@@ -2581,7 +2565,7 @@ array_cmp(FunctionCallInfo fcinfo)
{
Datum elt1;
Datum elt2;
Datum opresult;
int32 cmpresult;
/* Get element pair */
elt1 = fetch_att(p1, typbyval, typlen);
......@@ -2594,15 +2578,17 @@ array_cmp(FunctionCallInfo fcinfo)
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;
......
......@@ -9,7 +9,7 @@
* 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"
......@@ -342,6 +342,9 @@ cash_send(PG_FUNCTION_ARGS)
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
/*
* Comparison functions
*/
Datum
cash_eq(PG_FUNCTION_ARGS)
......@@ -397,6 +400,20 @@ cash_ge(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.
......
This diff is collapsed.
......@@ -17,7 +17,7 @@
*
* 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 $
*
* ----------
*/
......@@ -39,6 +39,7 @@
#include "parser/parse_oper.h"
#include "rewrite/rewriteHandler.h"
#include "utils/lsyscache.h"
#include "utils/typcache.h"
#include "miscadmin.h"
......@@ -48,7 +49,6 @@
*/
#define RI_INIT_QUERYHASHSIZE 128
#define RI_INIT_OPREQHASHSIZE 128
#define RI_MATCH_TYPE_UNSPECIFIED 0
#define RI_MATCH_TYPE_FULL 1
......@@ -109,20 +109,11 @@ typedef struct RI_QueryHashEntry
} 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;
/* ----------
......@@ -3197,8 +3188,8 @@ ri_NullCheck(Relation rel, HeapTuple tup, RI_QueryKey *key, int pairidx)
/* ----------
* 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
......@@ -3212,12 +3203,6 @@ ri_InitHashTables(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);
}
......@@ -3438,57 +3423,22 @@ ri_OneKeyEqual(Relation rel, int column, HeapTuple oldtup, HeapTuple newtup,
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));
}
......@@ -3,7 +3,7 @@
* 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.
*
......@@ -69,6 +69,7 @@
#include "utils/array.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/typcache.h"
/* ----------
......@@ -1815,21 +1816,24 @@ get_select_query_def(Query *query, deparse_context *context,
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 = ", ";
}
}
......@@ -4032,6 +4036,15 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
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? */
......
......@@ -4,7 +4,7 @@
# 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 $
#
#-------------------------------------------------------------------------
......@@ -12,7 +12,7 @@ subdir = src/backend/utils/cache
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
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.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.
......@@ -122,7 +122,6 @@ get_op_hash_function(Oid opno)
{
CatCList *catlist;
int i;
HeapTuple tuple;
Oid opclass = InvalidOid;
/*
......@@ -137,10 +136,8 @@ get_op_hash_function(Oid opno)
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))
......@@ -155,20 +152,7 @@ get_op_hash_function(Oid opno)
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... */
......@@ -176,6 +160,35 @@ get_op_hash_function(Oid opno)
}
/* ---------- 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 ---------- */
/*
......
/*-------------------------------------------------------------------------
*
* 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;
}
......@@ -78,7 +78,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -88,7 +88,6 @@
#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"
......@@ -1754,26 +1753,17 @@ SelectSortFunction(Oid sortOperator,
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),
......
......@@ -37,7 +37,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200307301
#define CATALOG_VERSION_NO 200308171
#endif
......@@ -16,7 +16,7 @@
* 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
......@@ -418,6 +418,36 @@ DATA(insert ( 2098 3 f 2334 ));
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
*/
......@@ -496,5 +526,7 @@ DATA(insert ( 2230 1 f 2316 ));
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 */
......@@ -14,7 +14,7 @@
* 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
......@@ -110,6 +110,9 @@ DATA(insert ( 2095 1 2166 ));
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 */
......@@ -145,5 +148,6 @@ DATA(insert ( 2229 1 456 ));
DATA(insert ( 2230 1 456 ));
DATA(insert ( 2231 1 456 ));
DATA(insert ( 2232 1 455 ));
DATA(insert ( 2235 1 329 ));
#endif /* PG_AMPROC_H */
......@@ -26,7 +26,7 @@
* 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
......@@ -157,6 +157,7 @@ DATA(insert OID = 2097 ( 403 bpchar_pattern_ops PGNSP PGUID 1042 f 0 ));
#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 ));
......@@ -168,5 +169,8 @@ DATA(insert OID = 2229 ( 405 text_pattern_ops PGNSP PGUID 25 f 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 */
......@@ -8,7 +8,7 @@
* 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
......@@ -424,7 +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 = 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 - - ));
......@@ -448,6 +448,7 @@ DATA(insert OID = 1071 ( "<>" PGNSP PGUID b f 2277 2277 16 1071 1070 0 0 0
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 ));
......
......@@ -7,7 +7,7 @@
* 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
......@@ -758,6 +758,12 @@ DATA(insert OID = 359 ( btnamecmp PGNSP PGUID 12 f f t f i 2 23 "19 19" btn
DESCR("btree less-equal-greater");
DATA(insert OID = 360 ( bttextcmp PGNSP PGUID 12 f f t f i 2 23 "25 25" bttextcmp - _null_ ));
DESCR("btree less-equal-greater");
DATA(insert OID = 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");
......@@ -844,6 +850,8 @@ DATA(insert OID = 456 ( hashvarlena PGNSP PGUID 12 f f t f i 1 23 "2281" has
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_ ));
......
......@@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -265,7 +265,7 @@ typedef enum NodeTag
T_ExprFieldSelect,
T_ResTarget,
T_TypeCast,
T_SortGroupBy,
T_SortBy,
T_RangeSubselect,
T_RangeFunction,
T_TypeName,
......
......@@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -279,14 +279,19 @@ typedef struct ResTarget
} 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
......@@ -614,7 +619,7 @@ typedef struct SelectStmt
* 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 */
......
......@@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -37,7 +37,8 @@ extern List *addAllTargetsToSortList(ParseState *pstate,
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);
......
......@@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -38,15 +38,16 @@ extern Operator compatible_oper(List *op, Oid arg1, Oid arg2, bool noError);
/* 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);
......
......@@ -7,7 +7,7 @@
* 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
......@@ -209,6 +209,7 @@ extern Datum aclremove(PG_FUNCTION_ARGS);
extern Datum aclcontains(PG_FUNCTION_ARGS);
extern Datum makeaclitem(PG_FUNCTION_ARGS);
extern Datum aclitem_eq(PG_FUNCTION_ARGS);
extern Datum hash_aclitem(PG_FUNCTION_ARGS);
/*
* prototypes for functions in aclchk.c
......
......@@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -222,6 +222,8 @@ extern Datum btfloat8cmp(PG_FUNCTION_ARGS);
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);
......
......@@ -23,6 +23,7 @@ extern Datum cash_lt(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);
......
......@@ -6,7 +6,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -28,6 +28,7 @@ extern bool op_in_opclass(Oid opno, Oid opclass);
extern bool op_requires_recheck(Oid opno, Oid opclass);
extern Oid get_opclass_member(Oid opclass, int16 strategy);
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);
......
/*-------------------------------------------------------------------------
*
* 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 */
......@@ -81,7 +81,7 @@ SELECT '' AS four, f1 FROM CIRCLE_TBL WHERE diameter(f1) >= 10;
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
......
......@@ -504,7 +504,7 @@ SELECT '' AS two, circle(f1)
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
......
......@@ -504,7 +504,7 @@ SELECT '' AS two, circle(f1)
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
......
......@@ -42,5 +42,4 @@ SELECT '' AS four, f1 FROM CIRCLE_TBL WHERE diameter(f1) >= 10;
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 < ;
......@@ -152,5 +152,4 @@ SELECT '' AS two, circle(f1)
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 <<;
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