Create a 'type cache' that keeps track of the data needed for any particular
authorTom Lane
Sun, 17 Aug 2003 19:58:06 +0000 (19:58 +0000)
committerTom Lane
Sun, 17 Aug 2003 19:58:06 +0000 (19:58 +0000)
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.

40 files changed:
src/backend/commands/analyze.c
src/backend/commands/indexcmds.c
src/backend/commands/opclasscmds.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/planner.c
src/backend/parser/gram.y
src/backend/parser/parse_clause.c
src/backend/parser/parse_oper.c
src/backend/utils/adt/acl.c
src/backend/utils/adt/arrayfuncs.c
src/backend/utils/adt/cash.c
src/backend/utils/adt/nabstime.c
src/backend/utils/adt/ri_triggers.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/cache/Makefile
src/backend/utils/cache/lsyscache.c
src/backend/utils/cache/typcache.c [new file with mode: 0644]
src/backend/utils/sort/tuplesort.c
src/include/catalog/catversion.h
src/include/catalog/pg_amop.h
src/include/catalog/pg_amproc.h
src/include/catalog/pg_opclass.h
src/include/catalog/pg_operator.h
src/include/catalog/pg_proc.h
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h
src/include/parser/parse_clause.h
src/include/parser/parse_oper.h
src/include/utils/acl.h
src/include/utils/builtins.h
src/include/utils/cash.h
src/include/utils/lsyscache.h
src/include/utils/typcache.h [new file with mode: 0644]
src/test/regress/expected/circle.out
src/test/regress/expected/geometry.out
src/test/regress/expected/geometry_1.out
src/test/regress/sql/circle.sql
src/test/regress/sql/geometry.sql

index 2272d7bf3fb625c48a557d944aeb242c23b2cc73..aea5e45b231eb1d7f86ecccefb9be8234cea5bae 100644 (file)
@@ -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;
index 36baf4690e3ce8e8194d677b2a90440242a5592e..45f4c3b4f7d82db8bd35c813bf8dd6fd5e0cda3d 100644 (file)
@@ -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;
index 0677751ead4c2bb89f90e382e0cdda6011957c2c..a93af3e6046ed8c5bcabbf3177c141de2b1e30bd 100644 (file)
@@ -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)
    {
index fa1c567df0d022812ba638446392f98e037197b5..55076ec48d34550b31e86b6ada8f98acf7f5cf4f 100644 (file)
@@ -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);
index 5ad5dab1d3ca653662515ee37005a3abda255945..e3a59f4739a674a4b23ee072dba33b85caed2283 100644 (file)
@@ -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);
index 2f7fd02fb4b4f2e23fbfa3406f578a7355cc1a7a..634cfb3a57c4f5709f4ed6bb220ce009b49a04cb 100644 (file)
@@ -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);
index 9eea1c8d20ea797ca9a0339c853d69da3e3b8fb0..c29d127acf474280c4979bd2191bb72d8611d52c 100644 (file)
@@ -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)
index d3060b76c7a739159c0e642cd7014d95095f7de9..ef6f8a80c5cb0d98ba2898ef3dd1f7387d9f5a39 100644 (file)
@@ -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    func_name handler_name qual_Op qual_all_Op OptUseOp
+%type    func_name handler_name qual_Op qual_all_Op
                opt_class opt_validator
 
 %type   qualified_name OptConstrFromTable
@@ -278,7 +278,7 @@ static void doNegateFloat(Value *v);
 %type   NumericOnly FloatOnly IntegerOnly
 %type   columnref
 %type   alias_clause
-%type groupby>        sortby
+%type by> sortby
 %type   index_elem
 %type    table_ref
 %type   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*/ }
        ;
 
 
index ebc3ed23eecf5d8dcbe5223a9c7fa5b2cf0d1bbd..b31e70205dd890cf0bfea0d130b3b6aa2b728d53 100644 (file)
@@ -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);
    }
index e5d2ab2d05f54b0a41841d4e7e12c48ed62b066c..244cd769646200f102d8c982db8993533e0d3707 100644 (file)
@@ -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;
 }
index 504e8f5565234c2540a67c68bd146ccf397d2a05..8d5a675006bbfc2fa60f42253e6984e74cd880e8 100644 (file)
@@ -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
  *
index 37504718ad5e234f6b20a886836ec358238b13b4..46f7881d64801e689ea21429cc0f7a3062db181d 100644 (file)
@@ -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;
index e33aad28d6400f1aef49526828eeb8ff9c821b19..c4fc14134f0ce71f09156d468e072d64892140f7 100644 (file)
@@ -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.
index a4f3b061e6fedaa99f860530224836e9d2ecf664..f694349db7abe9db81b493deb55cff32b592bf71 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -505,11 +505,11 @@ abstime_finite(PG_FUNCTION_ARGS)
 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)
@@ -904,7 +904,7 @@ tintervalout(PG_FUNCTION_ARGS)
    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);
@@ -920,7 +920,7 @@ tintervalout(PG_FUNCTION_ARGS)
        strcat(i_str, p);
        pfree(p);
    }
-   strcat(i_str, "\"]\0");
+   strcat(i_str, "\"]");
    PG_RETURN_CSTRING(i_str);
 }
 
@@ -1190,22 +1190,42 @@ timenow(PG_FUNCTION_ARGS)
 }
 
 /*
- *     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
@@ -1214,9 +1234,7 @@ reltimene(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
@@ -1225,9 +1243,7 @@ reltimelt(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
@@ -1236,9 +1252,7 @@ reltimegt(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
@@ -1247,9 +1261,7 @@ reltimele(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
@@ -1258,9 +1270,16 @@ reltimege(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
+btreltimecmp(PG_FUNCTION_ARGS)
+{
+   RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
+   RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
+
+   PG_RETURN_INT32(reltime_cmp_internal(t1, t2));
 }
 
 
@@ -1287,59 +1306,71 @@ tintervalsame(PG_FUNCTION_ARGS)
    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
@@ -1347,24 +1378,8 @@ tintervallt(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];
-
-   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
@@ -1372,24 +1387,8 @@ tintervalle(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];
-
-   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
@@ -1397,24 +1396,8 @@ tintervalgt(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];
-
-   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
@@ -1422,24 +1405,17 @@ tintervalge(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
+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));
 }
 
 
@@ -1652,7 +1628,7 @@ istinterval(char *i_string,
            break;
    }
    p++;
-   /* skip leading blanks up to "'" */
+   /* skip leading blanks up to '"' */
    while ((c = *p) != '\0')
    {
        if (IsSpace(c))
@@ -1680,10 +1656,10 @@ istinterval(char *i_string,
    /* 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))
@@ -1708,7 +1684,7 @@ istinterval(char *i_string,
    /* 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 ']' */
index 7476204d89f6fa832bf878ab476b3b158f17bee1..55a6944971e2bc1d5b30705e91a91ee12f9e481e 100644 (file)
@@ -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));
 }
index 83989292d6ae21ad8bd1268eb1caa20e45a96288..5504251bc471d9157cf43e8c3b0d6f7dfd73079a 100644 (file)
@@ -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? */
index b13ecc38ddcc18c2ea88a4480e8db72ac765a76d..6a1156aca5eb99fa8946da6835bf55ac9af331da 100644 (file)
@@ -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
 
index 0faa097f349f65ed36a45d2e56814ab057552325..3864a2fa52b4f1bdc5bfeeff45cb02169bc9e746 100644 (file)
@@ -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 ----------                   */
 
 /*
diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c
new file mode 100644 (file)
index 0000000..3ae5a1d
--- /dev/null
@@ -0,0 +1,292 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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;
+}
index 255ec71ff16282ccc6e4eab571d1bc3900277979..983296086be64f03ccd3cd50ed35788ef9ac68f8 100644 (file)
@@ -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),
index 48723471a26004ef6a0d6d49a2013d52f3949ed5..9d4f80b727bfe67f8887078e5c4a7e8619241dad 100644 (file)
@@ -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
index fcf162eb98fe505842829c8c963fbb9b04bace38..bff4b21700341afa95aedeb7b11872a72cc1493a 100644 (file)
@@ -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 */
index 24c1fa416fe789faddfdbf93a03bf8fec2c3af14..a2607db5eb8b9f77719789c246d7ced2a6e74ff5 100644 (file)
@@ -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 */
index bbd69dca5b6d1ad27115fa3e3c3174df5eb170c4..af277ad687aec114506435da31a52d136c08e267 100644 (file)
@@ -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 */
index 176cd1eaaf6ff5054fff8d364e3921a0256d63e2..991e9429d37bc0fd710196f6b4e249a0b8953cfd 100644 (file)
@@ -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 ));
 
index 1fe3812d709ae337dcc196b4c68ba8885041da31..59b957ddd0d8c0acc4edefdae0a6d594d53b115a 100644 (file)
@@ -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_ ));
index 9c80a9ebc74fea1eef9c3c8e8dd5aeaea49ef3c3..6e3254dc67a9749a360a173184233c74783b1114 100644 (file)
@@ -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,
index 497ba3b6247294eed7a49c8f8d6b56a79851e60d..cbaaee49cf951520bb1fc3c67f29b258d435efd8 100644 (file)
@@ -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 */
index 670b72cfbac0e0bb108d075cd7f758b13e349886..8439c19804ceeedb5cc3993ed8e68383c287f375 100644 (file)
@@ -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);
 
index 1167997706a9b0c906ac22491970b746a85b0d40..130f125eff1282d3a505ecbfd4b025ea5b65da9a 100644 (file)
@@ -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);
index 59b5d106fa6060c65dd061d446bcf9bcb66e4042..29a807744ca01d7bfcf7a92291e3a7966b46b10b 100644 (file)
@@ -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
index a84f85122566be3aeb416bd8cbf5b9d4b034f57c..71615b6610f001f45b26a4245ec276cfa8de6b25 100644 (file)
@@ -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);
index 305304c20d2a17d12d82b82ddd50e8808186389e..b78da25edd165876277639b4f365c9d9f44c9630 100644 (file)
@@ -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);
index 4c9c073adea28b1af537d04fce18c7ca907d6f75..927190e35d9bc7c5f49ac931f864e881c09a4caf 100644 (file)
@@ -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);
diff --git a/src/include/utils/typcache.h b/src/include/utils/typcache.h
new file mode 100644 (file)
index 0000000..ae080d3
--- /dev/null
@@ -0,0 +1,66 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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 */
index 37a3591a64bbf6ae00464362e17eb2b836422e03..d8713dc53d5323845cafc5cd1670b8171c36ce50 100644 (file)
@@ -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
index 69118725f4a857d55628a91a16eb77fdc2b183b3..0889ea25e640efa7afa7a61d75305bcbfc5de9ed 100644 (file)
@@ -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
index 76b621fede615b6ac817914cd152ac3d1ccdcfaa..5c205d8bcc7e03be5d607d3aa99fcade1349bbbf 100644 (file)
@@ -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
index 9b384554d75926c50c86dd2fb62a3bc11697671a..fe229b3b2c0cd3b33730a8893f37ccdf8eb0dfe8 100644 (file)
@@ -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 < ;
index fab791df0d533c6abc21ad1144be5981e4f608f6..4abb679148f288412c835f30adfa0147954b563d 100644 (file)
@@ -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 <<;