]> granicus.if.org Git - postgresql/commitdiff
Create a 'type cache' that keeps track of the data needed for any particular
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 17 Aug 2003 19:58:06 +0000 (19:58 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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 <list>   func_name handler_name qual_Op qual_all_Op OptUseOp
+%type <list>   func_name handler_name qual_Op qual_all_Op
                                opt_class opt_validator
 
 %type <range>  qualified_name OptConstrFromTable
@@ -278,7 +278,7 @@ static void doNegateFloat(Value *v);
 %type <value>  NumericOnly FloatOnly IntegerOnly
 %type <columnref>      columnref
 %type <alias>  alias_clause
-%type <sortgroupby>            sortby
+%type <sortby> sortby
 %type <ielem>  index_elem
 %type <node>   table_ref
 %type <jexpr>  joined_table
@@ -4577,21 +4577,34 @@ sortby_list:
                        | sortby_list ',' sortby                                { $$ = lappend($1, $3); }
                ;
 
-sortby:                a_expr OptUseOp
+sortby:                a_expr USING qual_all_Op
                                {
-                                       $$ = makeNode(SortGroupBy);
+                                       $$ = makeNode(SortBy);
                                        $$->node = $1;
-                                       $$->useOp = $2;
+                                       $$->sortby_kind = SORTBY_USING;
+                                       $$->useOp = $3;
+                               }
+                       | a_expr ASC
+                               {
+                                       $$ = makeNode(SortBy);
+                                       $$->node = $1;
+                                       $$->sortby_kind = SORTBY_ASC;
+                                       $$->useOp = NIL;
+                               }
+                       | a_expr DESC
+                               {
+                                       $$ = makeNode(SortBy);
+                                       $$->node = $1;
+                                       $$->sortby_kind = SORTBY_DESC;
+                                       $$->useOp = NIL;
+                               }
+                       | a_expr
+                               {
+                                       $$ = makeNode(SortBy);
+                                       $$->node = $1;
+                                       $$->sortby_kind = SORTBY_ASC;   /* default */
+                                       $$->useOp = NIL;
                                }
-               ;
-
-OptUseOp:      USING qual_all_Op                                               { $$ = $2; }
-                       | ASC
-                                                       { $$ = makeList1(makeString("<")); }
-                       | DESC
-                                                       { $$ = makeList1(makeString(">")); }
-                       | /*EMPTY*/
-                                                       { $$ = makeList1(makeString("<"));      /*default*/ }
                ;
 
 
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 <<;