1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Cross-data-type comparisons are now indexable by btrees, pursuant to my

pghackers proposal of 8-Nov.  All the existing cross-type comparison
operators (int2/int4/int8 and float4/float8) have appropriate support.
The original proposal of storing the right-hand-side datatype as part of
the primary key for pg_amop and pg_amproc got modified a bit in the event;
it is easier to store zero as the 'default' case and only store a nonzero
when the operator is actually cross-type.  Along the way, remove the
long-since-defunct bigbox_ops operator class.
This commit is contained in:
Tom Lane
2003-11-12 21:15:59 +00:00
parent 49f98fa833
commit fa5c8a055a
76 changed files with 2237 additions and 1492 deletions

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.147 2003/08/04 02:40:00 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.148 2003/11/12 21:15:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1072,7 +1072,7 @@ pred_test_recurse_pred(Expr *predicate, Node *clause)
*
* If you know, for some ATTR, that "ATTR given_op CONST1" is true, and you
* want to determine whether "ATTR target_op CONST2" must also be true, then
* you can use "CONST1 test_op CONST2" as a test. If this test returns true,
* you can use "CONST2 test_op CONST1" as a test. If this test returns true,
* then the target expression must be true; if the test returns false, then
* the target expression may be false.
*
@ -1082,11 +1082,11 @@ pred_test_recurse_pred(Expr *predicate, Node *clause)
static const StrategyNumber
BT_implic_table[BTMaxStrategyNumber][BTMaxStrategyNumber] = {
{2, 2, 0, 0, 0},
{1, 2, 0, 0, 0},
{1, 2, 3, 4, 5},
{0, 0, 0, 4, 5},
{0, 0, 0, 4, 4}
{4, 4, 0, 0, 0},
{5, 4, 0, 0, 0},
{5, 4, 3, 2, 1},
{0, 0, 0, 2, 1},
{0, 0, 0, 2, 2}
};
@ -1118,12 +1118,13 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
*clause_const;
Oid pred_op,
clause_op,
test_op;
Oid opclass_id = InvalidOid;
test_op = InvalidOid;
Oid opclass_id;
bool found = false;
StrategyNumber pred_strategy = 0,
clause_strategy = 0,
StrategyNumber pred_strategy,
clause_strategy,
test_strategy;
Oid clause_subtype;
Expr *test_expr;
ExprState *test_exprstate;
Datum test_result;
@ -1140,7 +1141,9 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
/*
* Can't do anything more unless they are both binary opclauses with a
* Var on the left and a Const on the right. (XXX someday try to
* commute Const/Var cases?)
* commute Const/Var cases?) Note we don't have to think about binary
* relabeling of the Const node, since that would have been folded right
* into the Const.
*/
if (!is_opclause(predicate))
return false;
@ -1173,14 +1176,20 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
clause_op = ((OpExpr *) clause)->opno;
/*
* 1. Find "btree" strategy numbers for the pred_op and clause_op.
* Try to find a btree opclass containing the needed operators.
*
* We must find a btree opclass that contains both operators, else the
* implication can't be determined. If there are multiple such
* opclasses, assume we can use any one to determine the logical
* relationship of the two operators and the correct corresponding
* test operator. This should work for any logically consistent
* opclasses.
* implication can't be determined. Also, the pred_op has to be of
* default subtype (implying left and right input datatypes are the same);
* otherwise it's unsafe to put the pred_const on the left side of the
* test. Also, the opclass must contain a suitable test operator
* matching the clause_const's type (which we take to mean that it has
* the same subtype as the original clause_operator).
*
* If there are multiple matching opclasses, assume we can use any one to
* determine the logical relationship of the two operators and the correct
* corresponding test operator. This should work for any logically
* consistent opclasses.
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(pred_op),
@ -1192,7 +1201,13 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
Form_pg_amop pred_form = (Form_pg_amop) GETSTRUCT(pred_tuple);
HeapTuple clause_tuple;
if (!opclass_is_btree(pred_form->amopclaid))
opclass_id = pred_form->amopclaid;
/* must be btree */
if (!opclass_is_btree(opclass_id))
continue;
/* predicate operator must be default within this opclass */
if (pred_form->amopsubtype != InvalidOid)
continue;
/* Get the predicate operator's btree strategy number */
@ -1200,12 +1215,7 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
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,
* From the same opclass, find a strategy number for the clause_op,
* if possible
*/
clause_tuple = SearchSysCache(AMOPOPID,
@ -1216,13 +1226,35 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
{
Form_pg_amop clause_form = (Form_pg_amop) GETSTRUCT(clause_tuple);
/* Get the restriction clause operator's strategy number */
/* Get the restriction clause operator's strategy/subtype */
clause_strategy = (StrategyNumber) clause_form->amopstrategy;
Assert(clause_strategy >= 1 && clause_strategy <= 5);
clause_subtype = clause_form->amopsubtype;
/* done with clause_tuple */
ReleaseSysCache(clause_tuple);
found = true;
break;
/*
* Look up the "test" strategy number in the implication table
*/
test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1];
if (test_strategy == 0)
{
/* Can't determine implication using this interpretation */
continue;
}
/*
* See if opclass has an operator for the test strategy and the
* clause datatype.
*/
test_op = get_opclass_member(opclass_id, clause_subtype,
test_strategy);
if (OidIsValid(test_op))
{
found = true;
break;
}
}
}
@ -1235,25 +1267,7 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
}
/*
* 2. Look up the "test" strategy number in the implication table
*/
test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1];
if (test_strategy == 0)
return false; /* the implication cannot be determined */
/*
* 3. From the same opclass, find the operator for the test strategy
*/
test_op = get_opclass_member(opclass_id, test_strategy);
if (!OidIsValid(test_op))
{
/* This should not fail, else pg_amop entry is missing */
elog(ERROR, "missing pg_amop entry for opclass %u strategy %d",
opclass_id, test_strategy);
}
/*
* 4. Evaluate the test. For this we need an EState.
* Evaluate the test. For this we need an EState.
*/
estate = CreateExecutorState();
@ -1264,8 +1278,8 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
test_expr = make_opclause(test_op,
BOOLOID,
false,
(Expr *) clause_const,
(Expr *) pred_const);
(Expr *) pred_const,
(Expr *) clause_const);
/* Prepare it for execution */
test_exprstate = ExecPrepareExpr(test_expr, estate);
@ -1907,7 +1921,7 @@ match_special_index_operator(Expr *clause, Oid opclass,
* (The latter is not depended on by any part of the planner, so far as I can
* tell; but some parts of the executor do assume that the indxqual list
* ultimately delivered to the executor is so ordered. One such place is
* _bt_orderkeys() in the btree support. Perhaps that ought to be fixed
* _bt_preprocess_keys() in the btree support. Perhaps that ought to be fixed
* someday --- tgl 7/00)
*/
List *
@ -2103,7 +2117,8 @@ prefix_quals(Node *leftop, Oid opclass,
*/
if (pstatus == Pattern_Prefix_Exact)
{
oproid = get_opclass_member(opclass, BTEqualStrategyNumber);
oproid = get_opclass_member(opclass, InvalidOid,
BTEqualStrategyNumber);
if (oproid == InvalidOid)
elog(ERROR, "no = operator for opclass %u", opclass);
expr = make_opclause(oproid, BOOLOID, false,
@ -2117,7 +2132,8 @@ prefix_quals(Node *leftop, Oid opclass,
*
* We can always say "x >= prefix".
*/
oproid = get_opclass_member(opclass, BTGreaterEqualStrategyNumber);
oproid = get_opclass_member(opclass, InvalidOid,
BTGreaterEqualStrategyNumber);
if (oproid == InvalidOid)
elog(ERROR, "no >= operator for opclass %u", opclass);
expr = make_opclause(oproid, BOOLOID, false,
@ -2132,7 +2148,8 @@ prefix_quals(Node *leftop, Oid opclass,
greaterstr = make_greater_string(prefix_const);
if (greaterstr)
{
oproid = get_opclass_member(opclass, BTLessStrategyNumber);
oproid = get_opclass_member(opclass, InvalidOid,
BTLessStrategyNumber);
if (oproid == InvalidOid)
elog(ERROR, "no < operator for opclass %u", opclass);
expr = make_opclause(oproid, BOOLOID, false,
@ -2189,13 +2206,15 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
*/
if (is_eq)
{
opr1oid = get_opclass_member(opclass, BTGreaterEqualStrategyNumber);
opr1oid = get_opclass_member(opclass, InvalidOid,
BTGreaterEqualStrategyNumber);
if (opr1oid == InvalidOid)
elog(ERROR, "no >= operator for opclass %u", opclass);
}
else
{
opr1oid = get_opclass_member(opclass, BTGreaterStrategyNumber);
opr1oid = get_opclass_member(opclass, InvalidOid,
BTGreaterStrategyNumber);
if (opr1oid == InvalidOid)
elog(ERROR, "no > operator for opclass %u", opclass);
}
@ -2210,7 +2229,8 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
/* create clause "key <= network_scan_last( rightop )" */
opr2oid = get_opclass_member(opclass, BTLessEqualStrategyNumber);
opr2oid = get_opclass_member(opclass, InvalidOid,
BTLessEqualStrategyNumber);
if (opr2oid == InvalidOid)
elog(ERROR, "no <= operator for opclass %u", opclass);

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.158 2003/11/09 21:30:36 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.159 2003/11/12 21:15:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -63,13 +63,15 @@ static HashJoin *create_hashjoin_plan(Query *root, HashPath *best_path,
static void fix_indxqual_references(List *indexquals, IndexPath *index_path,
List **fixed_indexquals,
List **recheck_indexquals,
List **indxstrategy);
List **indxstrategy,
List **indxsubtype);
static void fix_indxqual_sublist(List *indexqual,
Relids baserelids, int baserelid,
IndexOptInfo *index,
List **fixed_quals,
List **recheck_quals,
List **strategy);
List **strategy,
List **subtype);
static Node *fix_indxqual_operand(Node *node, int baserelid,
IndexOptInfo *index,
Oid *opclass);
@ -79,8 +81,8 @@ static void copy_path_costsize(Plan *dest, Path *src);
static void copy_plan_costsize(Plan *dest, Plan *src);
static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid);
static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
List *indxid, List *indxqual,
List *indxqualorig, List *indxstrategy,
List *indxid, List *indxqual, List *indxqualorig,
List *indxstrategy, List *indxsubtype,
ScanDirection indexscandir);
static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid,
List *tideval);
@ -704,6 +706,7 @@ create_indexscan_plan(Query *root,
List *fixed_indxqual;
List *recheck_indxqual;
List *indxstrategy;
List *indxsubtype;
FastList indexids;
List *ixinfo;
IndexScan *scan_plan;
@ -771,7 +774,7 @@ create_indexscan_plan(Query *root,
*/
fix_indxqual_references(indxqual, best_path,
&fixed_indxqual, &recheck_indxqual,
&indxstrategy);
&indxstrategy, &indxsubtype);
/*
* If there were any "lossy" operators, need to add back the
@ -804,6 +807,7 @@ create_indexscan_plan(Query *root,
fixed_indxqual,
indxqual,
indxstrategy,
indxsubtype,
best_path->indexscandir);
copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
@ -1151,8 +1155,8 @@ create_hashjoin_plan(Query *root,
* must add (the original form of) the indexqual clause to the "qpquals"
* of the indexscan node, where the operator will be re-evaluated to
* ensure it passes.
* * We must construct a list of operator strategy numbers corresponding
* to the top-level operators of each index clause.
* * We must construct lists of operator strategy numbers and subtypes for
* the top-level operators of each index clause.
*
* Both the input list and the output lists have the form of lists of sublists
* of qual clauses --- the top-level list has one entry for each indexscan
@ -1167,11 +1171,12 @@ create_hashjoin_plan(Query *root,
* need rechecking.
*
* indxstrategy receives a list of integer sublists of strategy numbers.
* indxsubtype receives a list of OID sublists of strategy subtypes.
*/
static void
fix_indxqual_references(List *indexquals, IndexPath *index_path,
List **fixed_indexquals, List **recheck_indexquals,
List **indxstrategy)
List **indxstrategy, List **indxsubtype)
{
FastList fixed_quals;
FastList recheck_quals;
@ -1183,6 +1188,7 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path,
FastListInit(&fixed_quals);
FastListInit(&recheck_quals);
*indxstrategy = NIL;
*indxsubtype = NIL;
foreach(i, indexquals)
{
List *indexqual = lfirst(i);
@ -1190,13 +1196,16 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path,
List *fixed_qual;
List *recheck_qual;
List *strategy;
List *subtype;
fix_indxqual_sublist(indexqual, baserelids, baserelid, index,
&fixed_qual, &recheck_qual, &strategy);
&fixed_qual, &recheck_qual,
&strategy, &subtype);
FastAppend(&fixed_quals, fixed_qual);
if (recheck_qual != NIL)
FastAppend(&recheck_quals, recheck_qual);
*indxstrategy = lappend(*indxstrategy, strategy);
*indxsubtype = lappend(*indxsubtype, subtype);
ixinfo = lnext(ixinfo);
}
@ -1211,12 +1220,15 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path,
* For each qual clause, commute if needed to put the indexkey operand on the
* left, and then fix its varattno. (We do not need to change the other side
* of the clause.) Also change the operator if necessary, check for
* lossy index behavior, and determine the operator's strategy number.
* lossy index behavior, and determine the operator's strategy number and
* subtype number.
*
* Returns three lists: the list of fixed indexquals, the list (usually
* empty) of original clauses that must be rechecked as qpquals because
* the index is lossy for this operator type, and the integer list of
* strategy numbers.
* Returns four lists:
* the list of fixed indexquals
* the list (usually empty) of original clauses that must be rechecked
* as qpquals because the index is lossy for this operator type
* the integer list of strategy numbers
* the OID list of strategy subtypes
*/
static void
fix_indxqual_sublist(List *indexqual,
@ -1224,7 +1236,8 @@ fix_indxqual_sublist(List *indexqual,
IndexOptInfo *index,
List **fixed_quals,
List **recheck_quals,
List **strategy)
List **strategy,
List **subtype)
{
FastList fixed_qual;
FastList recheck_qual;
@ -1233,6 +1246,7 @@ fix_indxqual_sublist(List *indexqual,
FastListInit(&fixed_qual);
FastListInit(&recheck_qual);
*strategy = NIL;
*subtype = NIL;
foreach(i, indexqual)
{
OpExpr *clause = (OpExpr *) lfirst(i);
@ -1240,6 +1254,7 @@ fix_indxqual_sublist(List *indexqual,
Relids leftvarnos;
Oid opclass;
int stratno;
Oid stratsubtype;
bool recheck;
if (!IsA(clause, OpExpr) ||
@ -1278,13 +1293,14 @@ fix_indxqual_sublist(List *indexqual,
/*
* Look up the operator in the operator class to get its strategy
* number and the recheck indicator. This also double-checks that
* numbers and the recheck indicator. This also double-checks that
* we found an operator matching the index.
*/
get_op_opclass_properties(newclause->opno, opclass,
&stratno, &recheck);
&stratno, &stratsubtype, &recheck);
*strategy = lappendi(*strategy, stratno);
*subtype = lappendo(*subtype, stratsubtype);
/*
* If index is lossy for this operator, add (a copy of) original form
@ -1540,6 +1556,7 @@ make_indexscan(List *qptlist,
List *indxqual,
List *indxqualorig,
List *indxstrategy,
List *indxsubtype,
ScanDirection indexscandir)
{
IndexScan *node = makeNode(IndexScan);
@ -1555,6 +1572,7 @@ make_indexscan(List *qptlist,
node->indxqual = indxqual;
node->indxqualorig = indxqualorig;
node->indxstrategy = indxstrategy;
node->indxsubtype = indxsubtype;
node->indxorderdir = indexscandir;
return node;

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.88 2003/11/09 21:30:37 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.89 2003/11/12 21:15:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -23,7 +23,6 @@
#include "catalog/pg_amop.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_index.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/plancat.h"
@ -329,10 +328,10 @@ find_inheritance_children(Oid inhparent)
if (!has_subclass(inhparent))
return NIL;
ScanKeyEntryInitialize(&key[0], 0,
Anum_pg_inherits_inhparent,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(inhparent), OIDOID);
ScanKeyInit(&key[0],
Anum_pg_inherits_inhparent,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(inhparent));
relation = heap_openr(InheritsRelationName, AccessShareLock);
scan = heap_beginscan(relation, SnapshotNow, 1, key);
while ((inheritsTuple = heap_getnext(scan, ForwardScanDirection)) != NULL)