mirror of
https://github.com/postgres/postgres.git
synced 2025-07-11 10:01:57 +03:00
Restructure pg_opclass, pg_amop, and pg_amproc per previous discussions in
pgsql-hackers. pg_opclass now has a row for each opclass supported by each index AM, not a row for each opclass name. This allows pg_opclass to show directly whether an AM supports an opclass, and furthermore makes it possible to store additional information about an opclass that might be AM-dependent. pg_opclass and pg_amop now store "lossy" and "haskeytype" information that we previously expected the user to remember to provide in CREATE INDEX commands. Lossiness is no longer an index-level property, but is associated with the use of a particular operator in a particular index opclass. Along the way, IndexSupportInitialize now uses the syscaches to retrieve pg_amop and pg_amproc entries. I find this reduces backend launch time by about ten percent, at the cost of a couple more special cases in catcache.c's IndexScanOK. Initial work by Oleg Bartunov and Teodor Sigaev, further hacking by Tom Lane. initdb forced.
This commit is contained in:
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.110 2001/08/06 18:09:45 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.111 2001/08/21 16:36:02 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -46,16 +46,16 @@
|
||||
*
|
||||
* Determine whether we should continue matching index keys in a clause.
|
||||
* Depends on if there are more to match or if this is a functional index.
|
||||
* In the latter case we stop after the first match since the there can
|
||||
* be only key (i.e. the function's return value) and the attributes in
|
||||
* In the latter case we stop after the first match since there can
|
||||
* be only 1 key (i.e. the function's return value) and the attributes in
|
||||
* keys list represent the arguments to the function. -mer 3 Oct. 1991
|
||||
*/
|
||||
#define DoneMatchingIndexKeys(indexkeys, index) \
|
||||
(indexkeys[0] == 0 || \
|
||||
(index->indproc != InvalidOid))
|
||||
|
||||
#define is_indexable_operator(clause,opclass,relam,indexkey_on_left) \
|
||||
(indexable_operator(clause,opclass,relam,indexkey_on_left) != InvalidOid)
|
||||
#define is_indexable_operator(clause,opclass,indexkey_on_left) \
|
||||
(indexable_operator(clause,opclass,indexkey_on_left) != InvalidOid)
|
||||
|
||||
|
||||
static void match_index_orclauses(RelOptInfo *rel, IndexOptInfo *index,
|
||||
@ -92,7 +92,7 @@ static bool match_index_to_operand(int indexkey, Var *operand,
|
||||
RelOptInfo *rel, IndexOptInfo *index);
|
||||
static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel,
|
||||
IndexOptInfo *index);
|
||||
static bool match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
|
||||
static bool match_special_index_operator(Expr *clause, Oid opclass,
|
||||
bool indexkey_on_left);
|
||||
static List *prefix_quals(Var *leftop, Oid expr_op,
|
||||
char *prefix, Pattern_Prefix_Status pstatus);
|
||||
@ -754,30 +754,28 @@ match_clause_to_indexkey(RelOptInfo *rel,
|
||||
if (match_index_to_operand(indexkey, leftop, rel, index) &&
|
||||
is_pseudo_constant_clause((Node *) rightop))
|
||||
{
|
||||
if (is_indexable_operator(clause, opclass, index->relam, true))
|
||||
if (is_indexable_operator(clause, opclass, true))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* If we didn't find a member of the index's opclass, see
|
||||
* whether it is a "special" indexable operator.
|
||||
*/
|
||||
if (match_special_index_operator(clause, opclass, index->relam,
|
||||
true))
|
||||
if (match_special_index_operator(clause, opclass, true))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
if (match_index_to_operand(indexkey, rightop, rel, index) &&
|
||||
is_pseudo_constant_clause((Node *) leftop))
|
||||
{
|
||||
if (is_indexable_operator(clause, opclass, index->relam, false))
|
||||
if (is_indexable_operator(clause, opclass, false))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* If we didn't find a member of the index's opclass, see
|
||||
* whether it is a "special" indexable operator.
|
||||
*/
|
||||
if (match_special_index_operator(clause, opclass, index->relam,
|
||||
false))
|
||||
if (match_special_index_operator(clause, opclass, false))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@ -799,7 +797,7 @@ match_clause_to_indexkey(RelOptInfo *rel,
|
||||
isIndexable =
|
||||
!intMember(lfirsti(rel->relids), othervarnos) &&
|
||||
!contain_noncachable_functions((Node *) rightop) &&
|
||||
is_indexable_operator(clause, opclass, index->relam, true);
|
||||
is_indexable_operator(clause, opclass, true);
|
||||
freeList(othervarnos);
|
||||
return isIndexable;
|
||||
}
|
||||
@ -811,7 +809,7 @@ match_clause_to_indexkey(RelOptInfo *rel,
|
||||
isIndexable =
|
||||
!intMember(lfirsti(rel->relids), othervarnos) &&
|
||||
!contain_noncachable_functions((Node *) leftop) &&
|
||||
is_indexable_operator(clause, opclass, index->relam, false);
|
||||
is_indexable_operator(clause, opclass, false);
|
||||
freeList(othervarnos);
|
||||
return isIndexable;
|
||||
}
|
||||
@ -822,12 +820,11 @@ match_clause_to_indexkey(RelOptInfo *rel,
|
||||
|
||||
/*
|
||||
* indexable_operator
|
||||
* Does a binary opclause contain an operator matching the index's
|
||||
* access method?
|
||||
* Does a binary opclause contain an operator matching the index opclass?
|
||||
*
|
||||
* If the indexkey is on the right, what we actually want to know
|
||||
* is whether the operator has a commutator operator that matches
|
||||
* the index's access method.
|
||||
* the index's opclass.
|
||||
*
|
||||
* We try both the straightforward match and matches that rely on
|
||||
* recognizing binary-compatible datatypes. For example, if we have
|
||||
@ -844,8 +841,7 @@ match_clause_to_indexkey(RelOptInfo *rel,
|
||||
* OID is *not* commuted; it can be plugged directly into the given clause.
|
||||
*/
|
||||
Oid
|
||||
indexable_operator(Expr *clause, Oid opclass, Oid relam,
|
||||
bool indexkey_on_left)
|
||||
indexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left)
|
||||
{
|
||||
Oid expr_op = ((Oper *) clause->oper)->opno;
|
||||
Oid commuted_op,
|
||||
@ -865,8 +861,8 @@ indexable_operator(Expr *clause, Oid opclass, Oid relam,
|
||||
if (commuted_op == InvalidOid)
|
||||
return InvalidOid;
|
||||
|
||||
/* Done if the (commuted) operator is a member of the index's AM */
|
||||
if (op_class(commuted_op, opclass, relam))
|
||||
/* Done if the (commuted) operator is a member of the index's opclass */
|
||||
if (op_in_opclass(commuted_op, opclass))
|
||||
return expr_op;
|
||||
|
||||
/*
|
||||
@ -937,7 +933,7 @@ indexable_operator(Expr *clause, Oid opclass, Oid relam,
|
||||
if (commuted_op == InvalidOid)
|
||||
return InvalidOid;
|
||||
|
||||
if (op_class(commuted_op, opclass, relam))
|
||||
if (op_in_opclass(commuted_op, opclass))
|
||||
return new_op;
|
||||
}
|
||||
}
|
||||
@ -1171,8 +1167,8 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
Oid pred_op,
|
||||
clause_op,
|
||||
test_op;
|
||||
Oid opclass_id;
|
||||
StrategyNumber pred_strategy,
|
||||
Oid opclass_id = InvalidOid;
|
||||
StrategyNumber pred_strategy = 0,
|
||||
clause_strategy,
|
||||
test_strategy;
|
||||
Oper *test_oper;
|
||||
@ -1182,7 +1178,7 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
Relation relation;
|
||||
HeapScanDesc scan;
|
||||
HeapTuple tuple;
|
||||
ScanKeyData entry[3];
|
||||
ScanKeyData entry[1];
|
||||
Form_pg_amop aform;
|
||||
ExprContext *econtext;
|
||||
|
||||
@ -1227,23 +1223,6 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
/*
|
||||
* 1. Find a "btree" strategy number for the pred_op
|
||||
*
|
||||
* XXX consider using syscache lookups for these searches. Right
|
||||
* now we don't have caches that match all of the search conditions,
|
||||
* but reconsider it after upcoming restructuring of pg_opclass.
|
||||
*/
|
||||
relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
|
||||
|
||||
ScanKeyEntryInitialize(&entry[0], 0,
|
||||
Anum_pg_amop_amopid,
|
||||
F_OIDEQ,
|
||||
ObjectIdGetDatum(BTREE_AM_OID));
|
||||
|
||||
ScanKeyEntryInitialize(&entry[1], 0,
|
||||
Anum_pg_amop_amopopr,
|
||||
F_OIDEQ,
|
||||
ObjectIdGetDatum(pred_op));
|
||||
|
||||
/*
|
||||
* The following assumes that any given operator will only be in a
|
||||
* single btree operator class. This is true at least for all the
|
||||
* pre-defined operator classes. If it isn't true, then whichever
|
||||
@ -1251,46 +1230,47 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
* will be used to find the associated strategy numbers for the test.
|
||||
* --Nels, Jan '93
|
||||
*/
|
||||
scan = heap_beginscan(relation, false, SnapshotNow, 2, entry);
|
||||
tuple = heap_getnext(scan, 0);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
ScanKeyEntryInitialize(&entry[0], 0x0,
|
||||
Anum_pg_amop_amopopr,
|
||||
F_OIDEQ,
|
||||
ObjectIdGetDatum(pred_op));
|
||||
|
||||
relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
|
||||
scan = heap_beginscan(relation, false, SnapshotNow, 1, entry);
|
||||
|
||||
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
|
||||
{
|
||||
/* predicate operator isn't btree-indexable */
|
||||
heap_endscan(scan);
|
||||
heap_close(relation, AccessShareLock);
|
||||
return false;
|
||||
aform = (Form_pg_amop) GETSTRUCT(tuple);
|
||||
if (opclass_is_btree(aform->amopclaid))
|
||||
{
|
||||
/* Get the predicate operator's btree strategy number (1 to 5) */
|
||||
pred_strategy = (StrategyNumber) aform->amopstrategy;
|
||||
Assert(pred_strategy >= 1 && pred_strategy <= 5);
|
||||
/* Remember which operator class this strategy number came from */
|
||||
opclass_id = aform->amopclaid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
aform = (Form_pg_amop) GETSTRUCT(tuple);
|
||||
|
||||
/* Get the predicate operator's btree strategy number (1 to 5) */
|
||||
pred_strategy = (StrategyNumber) aform->amopstrategy;
|
||||
Assert(pred_strategy >= 1 && pred_strategy <= 5);
|
||||
|
||||
/* Remember which operator class this strategy number came from */
|
||||
opclass_id = aform->amopclaid;
|
||||
|
||||
heap_endscan(scan);
|
||||
heap_close(relation, AccessShareLock);
|
||||
|
||||
if (!OidIsValid(opclass_id))
|
||||
{
|
||||
/* predicate operator isn't btree-indexable */
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* 2. From the same opclass, find a strategy num for the clause_op
|
||||
*/
|
||||
ScanKeyEntryInitialize(&entry[1], 0,
|
||||
Anum_pg_amop_amopclaid,
|
||||
F_OIDEQ,
|
||||
ObjectIdGetDatum(opclass_id));
|
||||
|
||||
ScanKeyEntryInitialize(&entry[2], 0,
|
||||
Anum_pg_amop_amopopr,
|
||||
F_OIDEQ,
|
||||
ObjectIdGetDatum(clause_op));
|
||||
|
||||
scan = heap_beginscan(relation, false, SnapshotNow, 3, entry);
|
||||
tuple = heap_getnext(scan, 0);
|
||||
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 */
|
||||
heap_endscan(scan);
|
||||
heap_close(relation, AccessShareLock);
|
||||
return false;
|
||||
}
|
||||
aform = (Form_pg_amop) GETSTRUCT(tuple);
|
||||
@ -1299,7 +1279,7 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
clause_strategy = (StrategyNumber) aform->amopstrategy;
|
||||
Assert(clause_strategy >= 1 && clause_strategy <= 5);
|
||||
|
||||
heap_endscan(scan);
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
/*
|
||||
* 3. Look up the "test" strategy number in the implication table
|
||||
@ -1307,26 +1287,20 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1];
|
||||
if (test_strategy == 0)
|
||||
{
|
||||
heap_close(relation, AccessShareLock);
|
||||
return false; /* the implication cannot be determined */
|
||||
}
|
||||
|
||||
/*
|
||||
* 4. From the same opclass, find the operator for the test strategy
|
||||
*/
|
||||
ScanKeyEntryInitialize(&entry[2], 0,
|
||||
Anum_pg_amop_amopstrategy,
|
||||
F_INT2EQ,
|
||||
Int16GetDatum(test_strategy));
|
||||
|
||||
scan = heap_beginscan(relation, false, SnapshotNow, 3, entry);
|
||||
tuple = heap_getnext(scan, 0);
|
||||
tuple = SearchSysCache(AMOPSTRATEGY,
|
||||
ObjectIdGetDatum(opclass_id),
|
||||
Int16GetDatum(test_strategy),
|
||||
0, 0);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
{
|
||||
/* this probably shouldn't fail? */
|
||||
elog(DEBUG, "pred_test_simple_clause: unknown test_op");
|
||||
heap_endscan(scan);
|
||||
heap_close(relation, AccessShareLock);
|
||||
return false;
|
||||
}
|
||||
aform = (Form_pg_amop) GETSTRUCT(tuple);
|
||||
@ -1334,9 +1308,7 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
/* Get the test operator */
|
||||
test_op = aform->amopopr;
|
||||
|
||||
heap_endscan(scan);
|
||||
|
||||
heap_close(relation, AccessShareLock);
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
/*
|
||||
* 5. Evaluate the test
|
||||
@ -1681,7 +1653,7 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, IndexOptInfo *index)
|
||||
* Return 'true' if we can do something with it anyway.
|
||||
*/
|
||||
static bool
|
||||
match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
|
||||
match_special_index_operator(Expr *clause, Oid opclass,
|
||||
bool indexkey_on_left)
|
||||
{
|
||||
bool isIndexable = false;
|
||||
@ -1806,8 +1778,8 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
|
||||
case OID_TEXT_ICLIKE_OP:
|
||||
case OID_TEXT_REGEXEQ_OP:
|
||||
case OID_TEXT_ICREGEXEQ_OP:
|
||||
if (!op_class(find_operator(">=", TEXTOID), opclass, relam) ||
|
||||
!op_class(find_operator("<", TEXTOID), opclass, relam))
|
||||
if (!op_in_opclass(find_operator(">=", TEXTOID), opclass) ||
|
||||
!op_in_opclass(find_operator("<", TEXTOID), opclass))
|
||||
isIndexable = false;
|
||||
break;
|
||||
|
||||
@ -1815,8 +1787,8 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
|
||||
case OID_BPCHAR_ICLIKE_OP:
|
||||
case OID_BPCHAR_REGEXEQ_OP:
|
||||
case OID_BPCHAR_ICREGEXEQ_OP:
|
||||
if (!op_class(find_operator(">=", BPCHAROID), opclass, relam) ||
|
||||
!op_class(find_operator("<", BPCHAROID), opclass, relam))
|
||||
if (!op_in_opclass(find_operator(">=", BPCHAROID), opclass) ||
|
||||
!op_in_opclass(find_operator("<", BPCHAROID), opclass))
|
||||
isIndexable = false;
|
||||
break;
|
||||
|
||||
@ -1824,8 +1796,8 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
|
||||
case OID_VARCHAR_ICLIKE_OP:
|
||||
case OID_VARCHAR_REGEXEQ_OP:
|
||||
case OID_VARCHAR_ICREGEXEQ_OP:
|
||||
if (!op_class(find_operator(">=", VARCHAROID), opclass, relam) ||
|
||||
!op_class(find_operator("<", VARCHAROID), opclass, relam))
|
||||
if (!op_in_opclass(find_operator(">=", VARCHAROID), opclass) ||
|
||||
!op_in_opclass(find_operator("<", VARCHAROID), opclass))
|
||||
isIndexable = false;
|
||||
break;
|
||||
|
||||
@ -1833,24 +1805,24 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
|
||||
case OID_NAME_ICLIKE_OP:
|
||||
case OID_NAME_REGEXEQ_OP:
|
||||
case OID_NAME_ICREGEXEQ_OP:
|
||||
if (!op_class(find_operator(">=", NAMEOID), opclass, relam) ||
|
||||
!op_class(find_operator("<", NAMEOID), opclass, relam))
|
||||
if (!op_in_opclass(find_operator(">=", NAMEOID), opclass) ||
|
||||
!op_in_opclass(find_operator("<", NAMEOID), opclass))
|
||||
isIndexable = false;
|
||||
break;
|
||||
|
||||
case OID_INET_SUB_OP:
|
||||
case OID_INET_SUBEQ_OP:
|
||||
/* for SUB we actually need ">" not ">=", but this should do */
|
||||
if (!op_class(find_operator(">=", INETOID), opclass, relam) ||
|
||||
!op_class(find_operator("<=", INETOID), opclass, relam))
|
||||
if (!op_in_opclass(find_operator(">=", INETOID), opclass) ||
|
||||
!op_in_opclass(find_operator("<=", INETOID), opclass))
|
||||
isIndexable = false;
|
||||
break;
|
||||
|
||||
case OID_CIDR_SUB_OP:
|
||||
case OID_CIDR_SUBEQ_OP:
|
||||
/* for SUB we actually need ">" not ">=", but this should do */
|
||||
if (!op_class(find_operator(">=", CIDROID), opclass, relam) ||
|
||||
!op_class(find_operator("<=", CIDROID), opclass, relam))
|
||||
if (!op_in_opclass(find_operator(">=", CIDROID), opclass) ||
|
||||
!op_in_opclass(find_operator("<=", CIDROID), opclass))
|
||||
isIndexable = false;
|
||||
break;
|
||||
}
|
||||
|
Reference in New Issue
Block a user