Commit 1c9ac7df authored by Tom Lane's avatar Tom Lane

Change pg_amop's index on (amopclaid,amopopr) to index (amopopr,amopclaid).

This makes no difference for existing uses, but allows SelectSortFunction()
and pred_test_simple_clause() to use indexscans instead of seqscans to
locate entries for a particular operator in pg_amop.  Better yet, they can
use the SearchSysCacheList() API to cache the search results.
parent 30f60948
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.136 2003/03/23 01:49:02 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.137 2003/05/13 04:38:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,27 +17,22 @@ ...@@ -17,27 +17,22 @@
#include <math.h> #include <math.h>
#include "access/heapam.h"
#include "access/nbtree.h" #include "access/nbtree.h"
#include "catalog/catname.h"
#include "catalog/pg_amop.h" #include "catalog/pg_amop.h"
#include "catalog/pg_namespace.h" #include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
#include "executor/executor.h" #include "executor/executor.h"
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/cost.h" #include "optimizer/cost.h"
#include "optimizer/pathnode.h" #include "optimizer/pathnode.h"
#include "optimizer/paths.h" #include "optimizer/paths.h"
#include "optimizer/restrictinfo.h" #include "optimizer/restrictinfo.h"
#include "optimizer/var.h" #include "optimizer/var.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "parser/parse_oper.h"
#include "rewrite/rewriteManip.h" #include "rewrite/rewriteManip.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h" #include "utils/catcache.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/selfuncs.h" #include "utils/selfuncs.h"
#include "utils/syscache.h" #include "utils/syscache.h"
...@@ -1120,18 +1115,18 @@ pred_test_simple_clause(Expr *predicate, Node *clause) ...@@ -1120,18 +1115,18 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
clause_op, clause_op,
test_op; test_op;
Oid opclass_id = InvalidOid; Oid opclass_id = InvalidOid;
bool found = false;
StrategyNumber pred_strategy = 0, StrategyNumber pred_strategy = 0,
clause_strategy, clause_strategy = 0,
test_strategy; test_strategy;
Expr *test_expr; Expr *test_expr;
ExprState *test_exprstate; ExprState *test_exprstate;
Datum test_result; Datum test_result;
bool isNull; bool isNull;
Relation relation; HeapTuple test_tuple;
HeapScanDesc scan; Form_pg_amop test_form;
HeapTuple tuple; CatCList *catlist;
ScanKeyData entry[1]; int i;
Form_pg_amop aform;
EState *estate; EState *estate;
MemoryContext oldcontext; MemoryContext oldcontext;
...@@ -1141,7 +1136,8 @@ pred_test_simple_clause(Expr *predicate, Node *clause) ...@@ -1141,7 +1136,8 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
/* /*
* Can't do anything more unless they are both binary opclauses with a * Can't do anything more unless they are both binary opclauses with a
* Var on the left and a Const on the right. * Var on the left and a Const on the right. (XXX someday try to
* commute Const/Var cases?)
*/ */
if (!is_opclause(predicate)) if (!is_opclause(predicate))
return false; return false;
...@@ -1174,101 +1170,95 @@ pred_test_simple_clause(Expr *predicate, Node *clause) ...@@ -1174,101 +1170,95 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
clause_op = ((OpExpr *) clause)->opno; clause_op = ((OpExpr *) clause)->opno;
/* /*
* 1. Find a "btree" strategy number for the pred_op * 1. Find "btree" strategy numbers for the pred_op and clause_op.
* *
* The following assumes that any given operator will only be in a single * We must find a btree opclass that contains both operators, else the
* btree operator class. This is true at least for all the * implication can't be determined. If there are multiple such opclasses,
* pre-defined operator classes. If it isn't true, then whichever * assume we can use any one to determine the logical relationship of the
* operator class happens to be returned first for the given operator * two operators and the correct corresponding test operator. This should
* will be used to find the associated strategy numbers for the test. * work for any logically consistent opclasses.
* --Nels, Jan '93
*/ */
ScanKeyEntryInitialize(&entry[0], 0x0, catlist = SearchSysCacheList(AMOPOPID, 1,
Anum_pg_amop_amopopr, ObjectIdGetDatum(pred_op),
F_OIDEQ, 0, 0, 0);
ObjectIdGetDatum(pred_op));
relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
scan = heap_beginscan(relation, SnapshotNow, 1, entry);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) for (i = 0; i < catlist->n_members; i++)
{ {
aform = (Form_pg_amop) GETSTRUCT(tuple); HeapTuple pred_tuple = &catlist->members[i]->tuple;
if (opclass_is_btree(aform->amopclaid)) Form_pg_amop pred_form = (Form_pg_amop) GETSTRUCT(pred_tuple);
HeapTuple clause_tuple;
if (!opclass_is_btree(pred_form->amopclaid))
continue;
/* Get the predicate operator's btree strategy number */
pred_strategy = (StrategyNumber) pred_form->amopstrategy;
Assert(pred_strategy >= 1 && pred_strategy <= 5);
/*
* Remember which operator class this strategy number came from
*/
opclass_id = pred_form->amopclaid;
/*
* From the same opclass, find a strategy num for the clause_op,
* if possible
*/
clause_tuple = SearchSysCache(AMOPOPID,
ObjectIdGetDatum(clause_op),
ObjectIdGetDatum(opclass_id),
0, 0);
if (HeapTupleIsValid(clause_tuple))
{ {
/* Get the predicate operator's btree strategy number (1 to 5) */ Form_pg_amop clause_form = (Form_pg_amop) GETSTRUCT(clause_tuple);
pred_strategy = (StrategyNumber) aform->amopstrategy;
Assert(pred_strategy >= 1 && pred_strategy <= 5);
/* /* Get the restriction clause operator's strategy number */
* Remember which operator class this strategy number came clause_strategy = (StrategyNumber) clause_form->amopstrategy;
* from Assert(clause_strategy >= 1 && clause_strategy <= 5);
*/
opclass_id = aform->amopclaid; ReleaseSysCache(clause_tuple);
found = true;
break; break;
} }
} }
heap_endscan(scan); ReleaseSysCacheList(catlist);
heap_close(relation, AccessShareLock);
if (!OidIsValid(opclass_id))
{
/* predicate operator isn't btree-indexable */
return false;
}
/* if (!found)
* 2. From the same opclass, find a strategy num for the clause_op
*/
tuple = SearchSysCache(AMOPOPID,
ObjectIdGetDatum(opclass_id),
ObjectIdGetDatum(clause_op),
0, 0);
if (!HeapTupleIsValid(tuple))
{ {
/* clause operator isn't btree-indexable, or isn't in this opclass */ /* couldn't find a btree opclass to interpret the operators */
return false; return false;
} }
aform = (Form_pg_amop) GETSTRUCT(tuple);
/* Get the restriction clause operator's strategy number (1 to 5) */
clause_strategy = (StrategyNumber) aform->amopstrategy;
Assert(clause_strategy >= 1 && clause_strategy <= 5);
ReleaseSysCache(tuple);
/* /*
* 3. Look up the "test" strategy number in the implication table * 2. Look up the "test" strategy number in the implication table
*/ */
test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1]; test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1];
if (test_strategy == 0) if (test_strategy == 0)
{
return false; /* the implication cannot be determined */ return false; /* the implication cannot be determined */
}
/* /*
* 4. From the same opclass, find the operator for the test strategy * 3. From the same opclass, find the operator for the test strategy
*/ */
tuple = SearchSysCache(AMOPSTRATEGY, test_tuple = SearchSysCache(AMOPSTRATEGY,
ObjectIdGetDatum(opclass_id), ObjectIdGetDatum(opclass_id),
Int16GetDatum(test_strategy), Int16GetDatum(test_strategy),
0, 0); 0, 0);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(test_tuple))
{ {
/* this probably shouldn't fail? */ /* This should not fail, else pg_amop entry is missing */
elog(DEBUG1, "pred_test_simple_clause: unknown test_op"); elog(ERROR, "Missing pg_amop entry for opclass %u strategy %d",
return false; opclass_id, test_strategy);
} }
aform = (Form_pg_amop) GETSTRUCT(tuple); test_form = (Form_pg_amop) GETSTRUCT(test_tuple);
/* Get the test operator */ /* Get the test operator */
test_op = aform->amopopr; test_op = test_form->amopopr;
ReleaseSysCache(tuple); ReleaseSysCache(test_tuple);
/* /*
* 5. Evaluate the test. For this we need an EState. * 4. Evaluate the test. For this we need an EState.
*/ */
estate = CreateExecutorState(); estate = CreateExecutorState();
...@@ -1298,6 +1288,7 @@ pred_test_simple_clause(Expr *predicate, Node *clause) ...@@ -1298,6 +1288,7 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
if (isNull) if (isNull)
{ {
/* Treat a null result as false ... but it's a tad fishy ... */
elog(DEBUG1, "pred_test_simple_clause: null test result"); elog(DEBUG1, "pred_test_simple_clause: null test result");
return false; return false;
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.93 2003/05/09 18:08:48 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.94 2003/05/13 04:38:58 tgl Exp $
* *
* NOTES * NOTES
* Eventually, the index information should go through here, too. * Eventually, the index information should go through here, too.
...@@ -44,8 +44,8 @@ bool ...@@ -44,8 +44,8 @@ bool
op_in_opclass(Oid opno, Oid opclass) op_in_opclass(Oid opno, Oid opclass)
{ {
return SearchSysCacheExists(AMOPOPID, return SearchSysCacheExists(AMOPOPID,
ObjectIdGetDatum(opclass),
ObjectIdGetDatum(opno), ObjectIdGetDatum(opno),
ObjectIdGetDatum(opclass),
0, 0); 0, 0);
} }
...@@ -67,8 +67,8 @@ op_requires_recheck(Oid opno, Oid opclass) ...@@ -67,8 +67,8 @@ op_requires_recheck(Oid opno, Oid opclass)
bool result; bool result;
tp = SearchSysCache(AMOPOPID, tp = SearchSysCache(AMOPOPID,
ObjectIdGetDatum(opclass),
ObjectIdGetDatum(opno), ObjectIdGetDatum(opno),
ObjectIdGetDatum(opclass),
0, 0); 0, 0);
if (!HeapTupleIsValid(tp)) if (!HeapTupleIsValid(tp))
elog(ERROR, "op_requires_recheck: op %u is not a member of opclass %u", elog(ERROR, "op_requires_recheck: op %u is not a member of opclass %u",
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.87 2002/09/04 20:31:30 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.88 2003/05/13 04:38:58 tgl Exp $
* *
* NOTES * NOTES
* These routines allow the parser/planner/executor to perform * These routines allow the parser/planner/executor to perform
...@@ -128,8 +128,8 @@ static const struct cachedesc cacheinfo[] = { ...@@ -128,8 +128,8 @@ static const struct cachedesc cacheinfo[] = {
0, 0,
2, 2,
{ {
Anum_pg_amop_amopclaid,
Anum_pg_amop_amopopr, Anum_pg_amop_amopopr,
Anum_pg_amop_amopclaid,
0, 0,
0 0
}}, }},
......
...@@ -78,7 +78,7 @@ ...@@ -78,7 +78,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.32 2002/11/13 00:39:48 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.33 2003/05/13 04:38:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -87,18 +87,18 @@ ...@@ -87,18 +87,18 @@
#include "access/heapam.h" #include "access/heapam.h"
#include "access/nbtree.h" #include "access/nbtree.h"
#include "catalog/catname.h"
#include "catalog/pg_amop.h" #include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h" #include "catalog/pg_amproc.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "utils/catcache.h"
#include "utils/datum.h" #include "utils/datum.h"
#include "utils/fmgroids.h"
#include "utils/logtape.h" #include "utils/logtape.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "utils/tuplesort.h" #include "utils/tuplesort.h"
/* /*
* Possible states of a Tuplesort object. These denote the states that * Possible states of a Tuplesort object. These denote the states that
* persist between calls of Tuplesort routines. * persist between calls of Tuplesort routines.
...@@ -1708,32 +1708,30 @@ SelectSortFunction(Oid sortOperator, ...@@ -1708,32 +1708,30 @@ SelectSortFunction(Oid sortOperator,
RegProcedure *sortFunction, RegProcedure *sortFunction,
SortFunctionKind *kind) SortFunctionKind *kind)
{ {
Relation relation; CatCList *catlist;
HeapScanDesc scan; int i;
ScanKeyData skey[1];
HeapTuple tuple; HeapTuple tuple;
Form_pg_operator optup; Form_pg_operator optup;
Oid opclass = InvalidOid; Oid opclass = InvalidOid;
/* /*
* Scan pg_amop to see if the target operator is registered as the "<" * Search pg_amop to see if the target operator is registered as the "<"
* or ">" operator of any btree opclass. It's possible that it might * or ">" operator of any btree opclass. It's possible that it might
* be registered both ways (eg, if someone were to build a "reverse * be registered both ways (eg, if someone were to build a "reverse
* sort" opclass for some reason); prefer the "<" case if so. If the * sort" opclass for some reason); prefer the "<" case if so. If the
* operator is registered the same way in multiple opclasses, assume * operator is registered the same way in multiple opclasses, assume
* we can use the associated comparator function from any one. * we can use the associated comparator function from any one.
*/ */
ScanKeyEntryInitialize(&skey[0], 0x0, catlist = SearchSysCacheList(AMOPOPID, 1,
Anum_pg_amop_amopopr, ObjectIdGetDatum(sortOperator),
F_OIDEQ, 0, 0, 0);
ObjectIdGetDatum(sortOperator));
relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock); for (i = 0; i < catlist->n_members; i++)
scan = heap_beginscan(relation, SnapshotNow, 1, skey);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{ {
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple); Form_pg_amop aform;
tuple = &catlist->members[i]->tuple;
aform = (Form_pg_amop) GETSTRUCT(tuple);
if (!opclass_is_btree(aform->amopclaid)) if (!opclass_is_btree(aform->amopclaid))
continue; continue;
...@@ -1751,8 +1749,7 @@ SelectSortFunction(Oid sortOperator, ...@@ -1751,8 +1749,7 @@ SelectSortFunction(Oid sortOperator,
} }
} }
heap_endscan(scan); ReleaseSysCacheList(catlist);
heap_close(relation, AccessShareLock);
if (OidIsValid(opclass)) if (OidIsValid(opclass))
{ {
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: catversion.h,v 1.191 2003/05/12 23:08:50 tgl Exp $ * $Id: catversion.h,v 1.192 2003/05/13 04:38:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200305121 #define CATALOG_VERSION_NO 200305122
#endif #endif
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: indexing.h,v 1.77 2002/11/15 02:50:10 momjian Exp $ * $Id: indexing.h,v 1.78 2003/05/13 04:38:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
* References to specific system indexes in the C code should use these * References to specific system indexes in the C code should use these
* macros rather than hardwiring the actual index name. * macros rather than hardwiring the actual index name.
*/ */
#define AccessMethodOperatorIndex "pg_amop_opc_opr_index" #define AccessMethodOperatorIndex "pg_amop_opr_opc_index"
#define AccessMethodStrategyIndex "pg_amop_opc_strategy_index" #define AccessMethodStrategyIndex "pg_amop_opc_strategy_index"
#define AccessMethodProcedureIndex "pg_amproc_opc_procnum_index" #define AccessMethodProcedureIndex "pg_amproc_opc_procnum_index"
#define AggregateFnoidIndex "pg_aggregate_fnoid_index" #define AggregateFnoidIndex "pg_aggregate_fnoid_index"
...@@ -115,7 +115,7 @@ extern void CatalogUpdateIndexes(Relation heapRel, HeapTuple heapTuple); ...@@ -115,7 +115,7 @@ extern void CatalogUpdateIndexes(Relation heapRel, HeapTuple heapTuple);
DECLARE_UNIQUE_INDEX(pg_aggregate_fnoid_index on pg_aggregate using btree(aggfnoid oid_ops)); DECLARE_UNIQUE_INDEX(pg_aggregate_fnoid_index on pg_aggregate using btree(aggfnoid oid_ops));
DECLARE_UNIQUE_INDEX(pg_am_name_index on pg_am using btree(amname name_ops)); DECLARE_UNIQUE_INDEX(pg_am_name_index on pg_am using btree(amname name_ops));
DECLARE_UNIQUE_INDEX(pg_am_oid_index on pg_am using btree(oid oid_ops)); DECLARE_UNIQUE_INDEX(pg_am_oid_index on pg_am using btree(oid oid_ops));
DECLARE_UNIQUE_INDEX(pg_amop_opc_opr_index on pg_amop using btree(amopclaid oid_ops, amopopr oid_ops)); DECLARE_UNIQUE_INDEX(pg_amop_opr_opc_index on pg_amop using btree(amopopr oid_ops, amopclaid oid_ops));
DECLARE_UNIQUE_INDEX(pg_amop_opc_strategy_index on pg_amop using btree(amopclaid oid_ops, amopstrategy int2_ops)); DECLARE_UNIQUE_INDEX(pg_amop_opc_strategy_index on pg_amop using btree(amopclaid oid_ops, amopstrategy int2_ops));
DECLARE_UNIQUE_INDEX(pg_amproc_opc_procnum_index on pg_amproc using btree(amopclaid oid_ops, amprocnum int2_ops)); DECLARE_UNIQUE_INDEX(pg_amproc_opc_procnum_index on pg_amproc using btree(amopclaid oid_ops, amprocnum int2_ops));
DECLARE_UNIQUE_INDEX(pg_attrdef_adrelid_adnum_index on pg_attrdef using btree(adrelid oid_ops, adnum int2_ops)); DECLARE_UNIQUE_INDEX(pg_attrdef_adrelid_adnum_index on pg_attrdef using btree(adrelid oid_ops, adnum int2_ops));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment