mirror of
https://github.com/postgres/postgres.git
synced 2025-08-27 07:42:10 +03:00
Restructure operator classes to allow improved handling of cross-data-type
cases. Operator classes now exist within "operator families". While most families are equivalent to a single class, related classes can be grouped into one family to represent the fact that they are semantically compatible. Cross-type operators are now naturally adjunct parts of a family, without having to wedge them into a particular opclass as we had done originally. This commit restructures the catalogs and cleans up enough of the fallout so that everything still works at least as well as before, but most of the work needed to actually improve the planner's behavior will come later. Also, there are not yet CREATE/DROP/ALTER OPERATOR FAMILY commands; the only way to create a new family right now is to allow CREATE OPERATOR CLASS to make one by default. I owe some more documentation work, too. But that can all be done in smaller pieces once this infrastructure is in place.
This commit is contained in:
@@ -54,7 +54,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.170 2006/12/15 18:42:26 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.171 2006/12/23 00:43:10 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1258,6 +1258,8 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
|
||||
Path *outer_path = path->jpath.outerjoinpath;
|
||||
Path *inner_path = path->jpath.innerjoinpath;
|
||||
List *mergeclauses = path->path_mergeclauses;
|
||||
List *mergefamilies = path->path_mergefamilies;
|
||||
List *mergestrategies = path->path_mergestrategies;
|
||||
List *outersortkeys = path->outersortkeys;
|
||||
List *innersortkeys = path->innersortkeys;
|
||||
Cost startup_cost = 0;
|
||||
@@ -1347,13 +1349,16 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
|
||||
*
|
||||
* Since this calculation is somewhat expensive, and will be the same for
|
||||
* all mergejoin paths associated with the merge clause, we cache the
|
||||
* results in the RestrictInfo node.
|
||||
* results in the RestrictInfo node. XXX that won't work anymore once
|
||||
* we support multiple possible orderings!
|
||||
*/
|
||||
if (mergeclauses && path->jpath.jointype != JOIN_FULL)
|
||||
{
|
||||
firstclause = (RestrictInfo *) linitial(mergeclauses);
|
||||
if (firstclause->left_mergescansel < 0) /* not computed yet? */
|
||||
mergejoinscansel(root, (Node *) firstclause->clause,
|
||||
linitial_oid(mergefamilies),
|
||||
linitial_int(mergestrategies),
|
||||
&firstclause->left_mergescansel,
|
||||
&firstclause->right_mergescansel);
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.212 2006/10/04 00:29:54 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.213 2006/12/23 00:43:10 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
#include "access/skey.h"
|
||||
#include "catalog/pg_am.h"
|
||||
#include "catalog/pg_opclass.h"
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_opfamily.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "optimizer/clauses.h"
|
||||
@@ -40,10 +40,10 @@
|
||||
/*
|
||||
* DoneMatchingIndexKeys() - MACRO
|
||||
*/
|
||||
#define DoneMatchingIndexKeys(classes) (classes[0] == InvalidOid)
|
||||
#define DoneMatchingIndexKeys(families) (families[0] == InvalidOid)
|
||||
|
||||
#define IsBooleanOpclass(opclass) \
|
||||
((opclass) == BOOL_BTREE_OPS_OID || (opclass) == BOOL_HASH_OPS_OID)
|
||||
#define IsBooleanOpfamily(opfamily) \
|
||||
((opfamily) == BOOL_BTREE_FAM_OID || (opfamily) == BOOL_HASH_FAM_OID)
|
||||
|
||||
|
||||
static List *find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
|
||||
@@ -61,15 +61,15 @@ static Cost bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel,
|
||||
static List *pull_indexpath_quals(Path *bitmapqual);
|
||||
static bool lists_intersect_ptr(List *list1, List *list2);
|
||||
static bool match_clause_to_indexcol(IndexOptInfo *index,
|
||||
int indexcol, Oid opclass,
|
||||
int indexcol, Oid opfamily,
|
||||
RestrictInfo *rinfo,
|
||||
Relids outer_relids,
|
||||
SaOpControl saop_control);
|
||||
static bool is_indexable_operator(Oid expr_op, Oid opclass,
|
||||
static bool is_indexable_operator(Oid expr_op, Oid opfamily,
|
||||
bool indexkey_on_left);
|
||||
static bool match_rowcompare_to_indexcol(IndexOptInfo *index,
|
||||
int indexcol,
|
||||
Oid opclass,
|
||||
Oid opfamily,
|
||||
RowCompareExpr *clause,
|
||||
Relids outer_relids);
|
||||
static Relids indexable_outerrelids(RelOptInfo *rel);
|
||||
@@ -89,17 +89,17 @@ static bool match_index_to_query_keys(PlannerInfo *root,
|
||||
List *ignorables);
|
||||
static bool match_boolean_index_clause(Node *clause, int indexcol,
|
||||
IndexOptInfo *index);
|
||||
static bool match_special_index_operator(Expr *clause, Oid opclass,
|
||||
static bool match_special_index_operator(Expr *clause, Oid opfamily,
|
||||
bool indexkey_on_left);
|
||||
static Expr *expand_boolean_index_clause(Node *clause, int indexcol,
|
||||
IndexOptInfo *index);
|
||||
static List *expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass);
|
||||
static List *expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily);
|
||||
static RestrictInfo *expand_indexqual_rowcompare(RestrictInfo *rinfo,
|
||||
IndexOptInfo *index,
|
||||
int indexcol);
|
||||
static List *prefix_quals(Node *leftop, Oid opclass,
|
||||
static List *prefix_quals(Node *leftop, Oid opfamily,
|
||||
Const *prefix, Pattern_Prefix_Status pstatus);
|
||||
static List *network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass,
|
||||
static List *network_prefix_quals(Node *leftop, Oid expr_op, Oid opfamily,
|
||||
Datum rightop);
|
||||
static Datum string_to_datum(const char *str, Oid datatype);
|
||||
static Const *string_to_const(const char *str, Oid datatype);
|
||||
@@ -858,7 +858,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
|
||||
List *clausegroup_list = NIL;
|
||||
bool found_outer_clause = false;
|
||||
int indexcol = 0;
|
||||
Oid *classes = index->classlist;
|
||||
Oid *families = index->opfamily;
|
||||
|
||||
*found_clause = false; /* default result */
|
||||
|
||||
@@ -867,7 +867,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
|
||||
|
||||
do
|
||||
{
|
||||
Oid curClass = classes[0];
|
||||
Oid curFamily = families[0];
|
||||
List *clausegroup = NIL;
|
||||
ListCell *l;
|
||||
|
||||
@@ -879,7 +879,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
|
||||
Assert(IsA(rinfo, RestrictInfo));
|
||||
if (match_clause_to_indexcol(index,
|
||||
indexcol,
|
||||
curClass,
|
||||
curFamily,
|
||||
rinfo,
|
||||
outer_relids,
|
||||
saop_control))
|
||||
@@ -899,7 +899,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
|
||||
Assert(IsA(rinfo, RestrictInfo));
|
||||
if (match_clause_to_indexcol(index,
|
||||
indexcol,
|
||||
curClass,
|
||||
curFamily,
|
||||
rinfo,
|
||||
outer_relids,
|
||||
saop_control))
|
||||
@@ -918,9 +918,9 @@ group_clauses_by_indexkey(IndexOptInfo *index,
|
||||
clausegroup_list = lappend(clausegroup_list, clausegroup);
|
||||
|
||||
indexcol++;
|
||||
classes++;
|
||||
families++;
|
||||
|
||||
} while (!DoneMatchingIndexKeys(classes));
|
||||
} while (!DoneMatchingIndexKeys(families));
|
||||
|
||||
if (!*found_clause && !found_outer_clause)
|
||||
return NIL; /* no indexable clauses anywhere */
|
||||
@@ -937,7 +937,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
|
||||
*
|
||||
* (1) must be in the form (indexkey op const) or (const op indexkey);
|
||||
* and
|
||||
* (2) must contain an operator which is in the same class as the index
|
||||
* (2) must contain an operator which is in the same family as the index
|
||||
* operator for this column, or is a "special" operator as recognized
|
||||
* by match_special_index_operator().
|
||||
*
|
||||
@@ -978,7 +978,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
|
||||
*
|
||||
* 'index' is the index of interest.
|
||||
* 'indexcol' is a column number of 'index' (counting from 0).
|
||||
* 'opclass' is the corresponding operator class.
|
||||
* 'opfamily' is the corresponding operator family.
|
||||
* 'rinfo' is the clause to be tested (as a RestrictInfo node).
|
||||
* 'saop_control' indicates whether ScalarArrayOpExpr clauses can be used.
|
||||
*
|
||||
@@ -990,7 +990,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
|
||||
static bool
|
||||
match_clause_to_indexcol(IndexOptInfo *index,
|
||||
int indexcol,
|
||||
Oid opclass,
|
||||
Oid opfamily,
|
||||
RestrictInfo *rinfo,
|
||||
Relids outer_relids,
|
||||
SaOpControl saop_control)
|
||||
@@ -1013,7 +1013,7 @@ match_clause_to_indexcol(IndexOptInfo *index,
|
||||
return false;
|
||||
|
||||
/* First check for boolean-index cases. */
|
||||
if (IsBooleanOpclass(opclass))
|
||||
if (IsBooleanOpfamily(opfamily))
|
||||
{
|
||||
if (match_boolean_index_clause((Node *) clause, indexcol, index))
|
||||
return true;
|
||||
@@ -1052,7 +1052,7 @@ match_clause_to_indexcol(IndexOptInfo *index,
|
||||
}
|
||||
else if (clause && IsA(clause, RowCompareExpr))
|
||||
{
|
||||
return match_rowcompare_to_indexcol(index, indexcol, opclass,
|
||||
return match_rowcompare_to_indexcol(index, indexcol, opfamily,
|
||||
(RowCompareExpr *) clause,
|
||||
outer_relids);
|
||||
}
|
||||
@@ -1067,15 +1067,15 @@ match_clause_to_indexcol(IndexOptInfo *index,
|
||||
bms_is_subset(right_relids, outer_relids) &&
|
||||
!contain_volatile_functions(rightop))
|
||||
{
|
||||
if (is_indexable_operator(expr_op, opclass, true))
|
||||
if (is_indexable_operator(expr_op, opfamily, true))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* If we didn't find a member of the index's opclass, see whether it
|
||||
* If we didn't find a member of the index's opfamily, see whether it
|
||||
* is a "special" indexable operator.
|
||||
*/
|
||||
if (plain_op &&
|
||||
match_special_index_operator(clause, opclass, true))
|
||||
match_special_index_operator(clause, opfamily, true))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -1085,14 +1085,14 @@ match_clause_to_indexcol(IndexOptInfo *index,
|
||||
bms_is_subset(left_relids, outer_relids) &&
|
||||
!contain_volatile_functions(leftop))
|
||||
{
|
||||
if (is_indexable_operator(expr_op, opclass, false))
|
||||
if (is_indexable_operator(expr_op, opfamily, false))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* If we didn't find a member of the index's opclass, see whether it
|
||||
* If we didn't find a member of the index's opfamily, see whether it
|
||||
* is a "special" indexable operator.
|
||||
*/
|
||||
if (match_special_index_operator(clause, opclass, false))
|
||||
if (match_special_index_operator(clause, opfamily, false))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -1102,14 +1102,14 @@ match_clause_to_indexcol(IndexOptInfo *index,
|
||||
|
||||
/*
|
||||
* is_indexable_operator
|
||||
* Does the operator match the specified index opclass?
|
||||
* Does the operator match the specified index opfamily?
|
||||
*
|
||||
* If the indexkey is on the right, what we actually want to know
|
||||
* is whether the operator has a commutator operator that matches
|
||||
* the opclass.
|
||||
* the opfamily.
|
||||
*/
|
||||
static bool
|
||||
is_indexable_operator(Oid expr_op, Oid opclass, bool indexkey_on_left)
|
||||
is_indexable_operator(Oid expr_op, Oid opfamily, bool indexkey_on_left)
|
||||
{
|
||||
/* Get the commuted operator if necessary */
|
||||
if (!indexkey_on_left)
|
||||
@@ -1119,8 +1119,8 @@ is_indexable_operator(Oid expr_op, Oid opclass, bool indexkey_on_left)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* OK if the (commuted) operator is a member of the index's opclass */
|
||||
return op_in_opclass(expr_op, opclass);
|
||||
/* OK if the (commuted) operator is a member of the index's opfamily */
|
||||
return op_in_opfamily(expr_op, opfamily);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1131,7 +1131,7 @@ is_indexable_operator(Oid expr_op, Oid opclass, bool indexkey_on_left)
|
||||
static bool
|
||||
match_rowcompare_to_indexcol(IndexOptInfo *index,
|
||||
int indexcol,
|
||||
Oid opclass,
|
||||
Oid opfamily,
|
||||
RowCompareExpr *clause,
|
||||
Relids outer_relids)
|
||||
{
|
||||
@@ -1144,13 +1144,14 @@ match_rowcompare_to_indexcol(IndexOptInfo *index,
|
||||
return false;
|
||||
|
||||
/*
|
||||
* We could do the matching on the basis of insisting that the opclass
|
||||
* shown in the RowCompareExpr be the same as the index column's opclass,
|
||||
* but that does not work well for cross-type comparisons (the opclass
|
||||
* could be for the other datatype). Also it would fail to handle indexes
|
||||
* using reverse-sort opclasses. Instead, match if the operator listed in
|
||||
* the RowCompareExpr is the < <= > or >= member of the index opclass
|
||||
* (after commutation, if the indexkey is on the right).
|
||||
* We could do the matching on the basis of insisting that the opfamily
|
||||
* shown in the RowCompareExpr be the same as the index column's opfamily,
|
||||
* but that could fail in the presence of reverse-sort opfamilies: it'd
|
||||
* be a matter of chance whether RowCompareExpr had picked the forward
|
||||
* or reverse-sort family. So look only at the operator, and match
|
||||
* if it is a member of the index's opfamily (after commutation, if the
|
||||
* indexkey is on the right). We'll worry later about whether any
|
||||
* additional operators are matchable to the index.
|
||||
*/
|
||||
leftop = (Node *) linitial(clause->largs);
|
||||
rightop = (Node *) linitial(clause->rargs);
|
||||
@@ -1177,8 +1178,8 @@ match_rowcompare_to_indexcol(IndexOptInfo *index,
|
||||
else
|
||||
return false;
|
||||
|
||||
/* We're good if the operator is the right type of opclass member */
|
||||
switch (get_op_opclass_strategy(expr_op, opclass))
|
||||
/* We're good if the operator is the right type of opfamily member */
|
||||
switch (get_op_opfamily_strategy(expr_op, opfamily))
|
||||
{
|
||||
case BTLessStrategyNumber:
|
||||
case BTLessEqualStrategyNumber:
|
||||
@@ -1316,23 +1317,23 @@ matches_any_index(RestrictInfo *rinfo, RelOptInfo *rel, Relids outer_relids)
|
||||
{
|
||||
IndexOptInfo *index = (IndexOptInfo *) lfirst(l);
|
||||
int indexcol = 0;
|
||||
Oid *classes = index->classlist;
|
||||
Oid *families = index->opfamily;
|
||||
|
||||
do
|
||||
{
|
||||
Oid curClass = classes[0];
|
||||
Oid curFamily = families[0];
|
||||
|
||||
if (match_clause_to_indexcol(index,
|
||||
indexcol,
|
||||
curClass,
|
||||
curFamily,
|
||||
rinfo,
|
||||
outer_relids,
|
||||
SAOP_ALLOW))
|
||||
return true;
|
||||
|
||||
indexcol++;
|
||||
classes++;
|
||||
} while (!DoneMatchingIndexKeys(classes));
|
||||
families++;
|
||||
} while (!DoneMatchingIndexKeys(families));
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -1601,11 +1602,11 @@ find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel,
|
||||
* Note: it would be possible to similarly ignore useless ORDER BY items;
|
||||
* that is, an index on just y could be considered to match the ordering of
|
||||
* ... WHERE x = 42 ORDER BY x, y;
|
||||
* But proving that this is safe would require finding a btree opclass
|
||||
* But proving that this is safe would require finding a btree opfamily
|
||||
* containing both the = operator and the < or > operator in the ORDER BY
|
||||
* item. That's significantly more expensive than what we do here, since
|
||||
* we'd have to look at restriction clauses unrelated to the current index
|
||||
* and search for opclasses without any hint from the index. The practical
|
||||
* and search for opfamilies without any hint from the index. The practical
|
||||
* use-cases seem to be mostly covered by ignoring index columns, so that's
|
||||
* all we do for now.
|
||||
*
|
||||
@@ -1627,7 +1628,7 @@ match_variant_ordering(PlannerInfo *root,
|
||||
|
||||
/*
|
||||
* Forget the whole thing if not a btree index; our check for ignorable
|
||||
* columns assumes we are dealing with btree opclasses. (It'd be possible
|
||||
* columns assumes we are dealing with btree opfamilies. (It'd be possible
|
||||
* to factor out just the try for backwards indexscan, but considering
|
||||
* that we presently have no orderable indexes except btrees anyway, it's
|
||||
* hardly worth contorting this code for that case.)
|
||||
@@ -1685,7 +1686,7 @@ identify_ignorable_ordering_cols(PlannerInfo *root,
|
||||
foreach(l, restrictclauses)
|
||||
{
|
||||
List *sublist = (List *) lfirst(l);
|
||||
Oid opclass = index->classlist[indexcol];
|
||||
Oid opfamily = index->opfamily[indexcol];
|
||||
ListCell *l2;
|
||||
|
||||
foreach(l2, sublist)
|
||||
@@ -1698,7 +1699,7 @@ identify_ignorable_ordering_cols(PlannerInfo *root,
|
||||
bool ispc;
|
||||
|
||||
/* First check for boolean-index cases. */
|
||||
if (IsBooleanOpclass(opclass))
|
||||
if (IsBooleanOpfamily(opfamily))
|
||||
{
|
||||
if (match_boolean_index_clause((Node *) clause, indexcol,
|
||||
index))
|
||||
@@ -1729,18 +1730,18 @@ identify_ignorable_ordering_cols(PlannerInfo *root,
|
||||
{
|
||||
Assert(match_index_to_operand(lsecond(clause->args), indexcol,
|
||||
index));
|
||||
/* Must flip operator to get the opclass member */
|
||||
/* Must flip operator to get the opfamily member */
|
||||
clause_op = get_commutator(clause_op);
|
||||
varonleft = false;
|
||||
}
|
||||
if (!OidIsValid(clause_op))
|
||||
continue; /* ignore non match, per next comment */
|
||||
op_strategy = get_op_opclass_strategy(clause_op, opclass);
|
||||
op_strategy = get_op_opfamily_strategy(clause_op, opfamily);
|
||||
|
||||
/*
|
||||
* You might expect to see Assert(op_strategy != 0) here, but you
|
||||
* won't: the clause might contain a special indexable operator
|
||||
* rather than an ordinary opclass member. Currently none of the
|
||||
* rather than an ordinary opfamily member. Currently none of the
|
||||
* special operators are very likely to expand to an equality
|
||||
* operator; we do not bother to check, but just assume no match.
|
||||
*/
|
||||
@@ -1968,7 +1969,7 @@ match_index_to_operand(Node *operand,
|
||||
*
|
||||
* match_special_index_operator() is just an auxiliary function for
|
||||
* match_clause_to_indexcol(); after the latter fails to recognize a
|
||||
* restriction opclause's operator as a member of an index's opclass,
|
||||
* restriction opclause's operator as a member of an index's opfamily,
|
||||
* it asks match_special_index_operator() whether the clause should be
|
||||
* considered an indexqual anyway.
|
||||
*
|
||||
@@ -1978,7 +1979,7 @@ match_index_to_operand(Node *operand,
|
||||
* expand_indexqual_conditions() converts a list of lists of RestrictInfo
|
||||
* nodes (with implicit AND semantics across list elements) into
|
||||
* a list of clauses that the executor can actually handle. For operators
|
||||
* that are members of the index's opclass this transformation is a no-op,
|
||||
* that are members of the index's opfamily this transformation is a no-op,
|
||||
* but clauses recognized by match_special_index_operator() or
|
||||
* match_boolean_index_clause() must be converted into one or more "regular"
|
||||
* indexqual conditions.
|
||||
@@ -1989,8 +1990,8 @@ match_index_to_operand(Node *operand,
|
||||
* match_boolean_index_clause
|
||||
* Recognize restriction clauses that can be matched to a boolean index.
|
||||
*
|
||||
* This should be called only when IsBooleanOpclass() recognizes the
|
||||
* index's operator class. We check to see if the clause matches the
|
||||
* This should be called only when IsBooleanOpfamily() recognizes the
|
||||
* index's operator family. We check to see if the clause matches the
|
||||
* index's key.
|
||||
*/
|
||||
static bool
|
||||
@@ -2034,11 +2035,11 @@ match_boolean_index_clause(Node *clause,
|
||||
*
|
||||
* The given clause is already known to be a binary opclause having
|
||||
* the form (indexkey OP pseudoconst) or (pseudoconst OP indexkey),
|
||||
* but the OP proved not to be one of the index's opclass operators.
|
||||
* but the OP proved not to be one of the index's opfamily operators.
|
||||
* Return 'true' if we can do something with it anyway.
|
||||
*/
|
||||
static bool
|
||||
match_special_index_operator(Expr *clause, Oid opclass,
|
||||
match_special_index_operator(Expr *clause, Oid opfamily,
|
||||
bool indexkey_on_left)
|
||||
{
|
||||
bool isIndexable = false;
|
||||
@@ -2122,12 +2123,12 @@ match_special_index_operator(Expr *clause, Oid opclass,
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Must also check that index's opclass supports the operators we will
|
||||
* Must also check that index's opfamily supports the operators we will
|
||||
* want to apply. (A hash index, for example, will not support ">=".)
|
||||
* Currently, only btree supports the operators we need.
|
||||
*
|
||||
* We insist on the opclass being the specific one we expect, else we'd do
|
||||
* the wrong thing if someone were to make a reverse-sort opclass with the
|
||||
* We insist on the opfamily being the specific one we expect, else we'd do
|
||||
* the wrong thing if someone were to make a reverse-sort opfamily with the
|
||||
* same operators.
|
||||
*/
|
||||
switch (expr_op)
|
||||
@@ -2136,12 +2137,9 @@ match_special_index_operator(Expr *clause, Oid opclass,
|
||||
case OID_TEXT_ICLIKE_OP:
|
||||
case OID_TEXT_REGEXEQ_OP:
|
||||
case OID_TEXT_ICREGEXEQ_OP:
|
||||
/* text operators will be used for varchar inputs, too */
|
||||
isIndexable =
|
||||
(opclass == TEXT_PATTERN_BTREE_OPS_OID) ||
|
||||
(opclass == TEXT_BTREE_OPS_OID && lc_collate_is_c()) ||
|
||||
(opclass == VARCHAR_PATTERN_BTREE_OPS_OID) ||
|
||||
(opclass == VARCHAR_BTREE_OPS_OID && lc_collate_is_c());
|
||||
(opfamily == TEXT_PATTERN_BTREE_FAM_OID) ||
|
||||
(opfamily == TEXT_BTREE_FAM_OID && lc_collate_is_c());
|
||||
break;
|
||||
|
||||
case OID_BPCHAR_LIKE_OP:
|
||||
@@ -2149,8 +2147,8 @@ match_special_index_operator(Expr *clause, Oid opclass,
|
||||
case OID_BPCHAR_REGEXEQ_OP:
|
||||
case OID_BPCHAR_ICREGEXEQ_OP:
|
||||
isIndexable =
|
||||
(opclass == BPCHAR_PATTERN_BTREE_OPS_OID) ||
|
||||
(opclass == BPCHAR_BTREE_OPS_OID && lc_collate_is_c());
|
||||
(opfamily == BPCHAR_PATTERN_BTREE_FAM_OID) ||
|
||||
(opfamily == BPCHAR_BTREE_FAM_OID && lc_collate_is_c());
|
||||
break;
|
||||
|
||||
case OID_NAME_LIKE_OP:
|
||||
@@ -2158,18 +2156,17 @@ match_special_index_operator(Expr *clause, Oid opclass,
|
||||
case OID_NAME_REGEXEQ_OP:
|
||||
case OID_NAME_ICREGEXEQ_OP:
|
||||
isIndexable =
|
||||
(opclass == NAME_PATTERN_BTREE_OPS_OID) ||
|
||||
(opclass == NAME_BTREE_OPS_OID && lc_collate_is_c());
|
||||
(opfamily == NAME_PATTERN_BTREE_FAM_OID) ||
|
||||
(opfamily == NAME_BTREE_FAM_OID && lc_collate_is_c());
|
||||
break;
|
||||
|
||||
case OID_BYTEA_LIKE_OP:
|
||||
isIndexable = (opclass == BYTEA_BTREE_OPS_OID);
|
||||
isIndexable = (opfamily == BYTEA_BTREE_FAM_OID);
|
||||
break;
|
||||
|
||||
case OID_INET_SUB_OP:
|
||||
case OID_INET_SUBEQ_OP:
|
||||
isIndexable = (opclass == INET_BTREE_OPS_OID ||
|
||||
opclass == CIDR_BTREE_OPS_OID);
|
||||
isIndexable = (opfamily == NETWORK_BTREE_FAM_OID);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2180,7 +2177,7 @@ match_special_index_operator(Expr *clause, Oid opclass,
|
||||
* expand_indexqual_conditions
|
||||
* Given a list of sublists of RestrictInfo nodes, produce a flat list
|
||||
* of index qual clauses. Standard qual clauses (those in the index's
|
||||
* opclass) are passed through unchanged. Boolean clauses and "special"
|
||||
* opfamily) are passed through unchanged. Boolean clauses and "special"
|
||||
* index operators are expanded into clauses that the indexscan machinery
|
||||
* will know what to do with. RowCompare clauses are simplified if
|
||||
* necessary to create a clause that is fully checkable by the index.
|
||||
@@ -2196,7 +2193,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
|
||||
List *resultquals = NIL;
|
||||
ListCell *clausegroup_item;
|
||||
int indexcol = 0;
|
||||
Oid *classes = index->classlist;
|
||||
Oid *families = index->opfamily;
|
||||
|
||||
if (clausegroups == NIL)
|
||||
return NIL;
|
||||
@@ -2204,7 +2201,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
|
||||
clausegroup_item = list_head(clausegroups);
|
||||
do
|
||||
{
|
||||
Oid curClass = classes[0];
|
||||
Oid curFamily = families[0];
|
||||
ListCell *l;
|
||||
|
||||
foreach(l, (List *) lfirst(clausegroup_item))
|
||||
@@ -2213,7 +2210,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
|
||||
Expr *clause = rinfo->clause;
|
||||
|
||||
/* First check for boolean cases */
|
||||
if (IsBooleanOpclass(curClass))
|
||||
if (IsBooleanOpfamily(curFamily))
|
||||
{
|
||||
Expr *boolqual;
|
||||
|
||||
@@ -2240,7 +2237,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
|
||||
{
|
||||
resultquals = list_concat(resultquals,
|
||||
expand_indexqual_opclause(rinfo,
|
||||
curClass));
|
||||
curFamily));
|
||||
}
|
||||
else if (IsA(clause, ScalarArrayOpExpr))
|
||||
{
|
||||
@@ -2262,8 +2259,8 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
|
||||
clausegroup_item = lnext(clausegroup_item);
|
||||
|
||||
indexcol++;
|
||||
classes++;
|
||||
} while (clausegroup_item != NULL && !DoneMatchingIndexKeys(classes));
|
||||
families++;
|
||||
} while (clausegroup_item != NULL && !DoneMatchingIndexKeys(families));
|
||||
|
||||
Assert(clausegroup_item == NULL); /* else more groups than indexkeys */
|
||||
|
||||
@@ -2337,7 +2334,7 @@ expand_boolean_index_clause(Node *clause,
|
||||
* The input is a single RestrictInfo, the output a list of RestrictInfos
|
||||
*/
|
||||
static List *
|
||||
expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
|
||||
expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily)
|
||||
{
|
||||
Expr *clause = rinfo->clause;
|
||||
|
||||
@@ -2354,7 +2351,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
|
||||
switch (expr_op)
|
||||
{
|
||||
/*
|
||||
* LIKE and regex operators are not members of any index opclass,
|
||||
* LIKE and regex operators are not members of any index opfamily,
|
||||
* so if we find one in an indexqual list we can assume that it
|
||||
* was accepted by match_special_index_operator().
|
||||
*/
|
||||
@@ -2364,7 +2361,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
|
||||
case OID_BYTEA_LIKE_OP:
|
||||
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like,
|
||||
&prefix, &rest);
|
||||
result = prefix_quals(leftop, opclass, prefix, pstatus);
|
||||
result = prefix_quals(leftop, opfamily, prefix, pstatus);
|
||||
break;
|
||||
|
||||
case OID_TEXT_ICLIKE_OP:
|
||||
@@ -2373,7 +2370,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
|
||||
/* the right-hand const is type text for all of these */
|
||||
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like_IC,
|
||||
&prefix, &rest);
|
||||
result = prefix_quals(leftop, opclass, prefix, pstatus);
|
||||
result = prefix_quals(leftop, opfamily, prefix, pstatus);
|
||||
break;
|
||||
|
||||
case OID_TEXT_REGEXEQ_OP:
|
||||
@@ -2382,7 +2379,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
|
||||
/* the right-hand const is type text for all of these */
|
||||
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex,
|
||||
&prefix, &rest);
|
||||
result = prefix_quals(leftop, opclass, prefix, pstatus);
|
||||
result = prefix_quals(leftop, opfamily, prefix, pstatus);
|
||||
break;
|
||||
|
||||
case OID_TEXT_ICREGEXEQ_OP:
|
||||
@@ -2391,12 +2388,12 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
|
||||
/* the right-hand const is type text for all of these */
|
||||
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC,
|
||||
&prefix, &rest);
|
||||
result = prefix_quals(leftop, opclass, prefix, pstatus);
|
||||
result = prefix_quals(leftop, opfamily, prefix, pstatus);
|
||||
break;
|
||||
|
||||
case OID_INET_SUB_OP:
|
||||
case OID_INET_SUBEQ_OP:
|
||||
result = network_prefix_quals(leftop, expr_op, opclass,
|
||||
result = network_prefix_quals(leftop, expr_op, opfamily,
|
||||
patt->constvalue);
|
||||
break;
|
||||
|
||||
@@ -2416,7 +2413,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
|
||||
* the specified column of the index. We can use additional columns of the
|
||||
* row comparison as index qualifications, so long as they match the index
|
||||
* in the "same direction", ie, the indexkeys are all on the same side of the
|
||||
* clause and the operators are all the same-type members of the opclasses.
|
||||
* clause and the operators are all the same-type members of the opfamilies.
|
||||
* If all the columns of the RowCompareExpr match in this way, we just use it
|
||||
* as-is. Otherwise, we build a shortened RowCompareExpr (if more than one
|
||||
* column matches) or a simple OpExpr (if the first-column match is all
|
||||
@@ -2433,12 +2430,14 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
|
||||
RowCompareExpr *clause = (RowCompareExpr *) rinfo->clause;
|
||||
bool var_on_left;
|
||||
int op_strategy;
|
||||
Oid op_subtype;
|
||||
Oid op_lefttype;
|
||||
Oid op_righttype;
|
||||
bool op_recheck;
|
||||
int matching_cols;
|
||||
Oid expr_op;
|
||||
List *opclasses;
|
||||
List *subtypes;
|
||||
List *opfamilies;
|
||||
List *lefttypes;
|
||||
List *righttypes;
|
||||
List *new_ops;
|
||||
ListCell *largs_cell;
|
||||
ListCell *rargs_cell;
|
||||
@@ -2453,11 +2452,15 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
|
||||
expr_op = linitial_oid(clause->opnos);
|
||||
if (!var_on_left)
|
||||
expr_op = get_commutator(expr_op);
|
||||
get_op_opclass_properties(expr_op, index->classlist[indexcol],
|
||||
&op_strategy, &op_subtype, &op_recheck);
|
||||
/* Build lists of the opclasses and operator subtypes in case needed */
|
||||
opclasses = list_make1_oid(index->classlist[indexcol]);
|
||||
subtypes = list_make1_oid(op_subtype);
|
||||
get_op_opfamily_properties(expr_op, index->opfamily[indexcol],
|
||||
&op_strategy,
|
||||
&op_lefttype,
|
||||
&op_righttype,
|
||||
&op_recheck);
|
||||
/* Build lists of the opfamilies and operator datatypes in case needed */
|
||||
opfamilies = list_make1_oid(index->opfamily[indexcol]);
|
||||
lefttypes = list_make1_oid(op_lefttype);
|
||||
righttypes = list_make1_oid(op_righttype);
|
||||
|
||||
/*
|
||||
* See how many of the remaining columns match some index column in the
|
||||
@@ -2513,15 +2516,19 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
|
||||
break; /* no match found */
|
||||
|
||||
/* Now, do we have the right operator for this column? */
|
||||
if (get_op_opclass_strategy(expr_op, index->classlist[i])
|
||||
if (get_op_opfamily_strategy(expr_op, index->opfamily[i])
|
||||
!= op_strategy)
|
||||
break;
|
||||
|
||||
/* Add opclass and subtype to lists */
|
||||
get_op_opclass_properties(expr_op, index->classlist[i],
|
||||
&op_strategy, &op_subtype, &op_recheck);
|
||||
opclasses = lappend_oid(opclasses, index->classlist[i]);
|
||||
subtypes = lappend_oid(subtypes, op_subtype);
|
||||
/* Add opfamily and datatypes to lists */
|
||||
get_op_opfamily_properties(expr_op, index->opfamily[i],
|
||||
&op_strategy,
|
||||
&op_lefttype,
|
||||
&op_righttype,
|
||||
&op_recheck);
|
||||
opfamilies = lappend_oid(opfamilies, index->opfamily[i]);
|
||||
lefttypes = lappend_oid(lefttypes, op_lefttype);
|
||||
righttypes = lappend_oid(righttypes, op_righttype);
|
||||
|
||||
/* This column matches, keep scanning */
|
||||
matching_cols++;
|
||||
@@ -2547,8 +2554,9 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
|
||||
}
|
||||
else
|
||||
{
|
||||
ListCell *opclasses_cell;
|
||||
ListCell *subtypes_cell;
|
||||
ListCell *opfamilies_cell;
|
||||
ListCell *lefttypes_cell;
|
||||
ListCell *righttypes_cell;
|
||||
|
||||
if (op_strategy == BTLessStrategyNumber)
|
||||
op_strategy = BTLessEqualStrategyNumber;
|
||||
@@ -2557,23 +2565,30 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
|
||||
else
|
||||
elog(ERROR, "unexpected strategy number %d", op_strategy);
|
||||
new_ops = NIL;
|
||||
forboth(opclasses_cell, opclasses, subtypes_cell, subtypes)
|
||||
lefttypes_cell = list_head(lefttypes);
|
||||
righttypes_cell = list_head(righttypes);
|
||||
foreach(opfamilies_cell, opfamilies)
|
||||
{
|
||||
expr_op = get_opclass_member(lfirst_oid(opclasses_cell),
|
||||
lfirst_oid(subtypes_cell),
|
||||
op_strategy);
|
||||
Oid opfam = lfirst_oid(opfamilies_cell);
|
||||
Oid lefttype = lfirst_oid(lefttypes_cell);
|
||||
Oid righttype = lfirst_oid(righttypes_cell);
|
||||
|
||||
expr_op = get_opfamily_member(opfam, lefttype, righttype,
|
||||
op_strategy);
|
||||
if (!OidIsValid(expr_op)) /* should not happen */
|
||||
elog(ERROR, "could not find member %d of opclass %u",
|
||||
op_strategy, lfirst_oid(opclasses_cell));
|
||||
elog(ERROR, "could not find member %d(%u,%u) of opfamily %u",
|
||||
op_strategy, lefttype, righttype, opfam);
|
||||
if (!var_on_left)
|
||||
{
|
||||
expr_op = get_commutator(expr_op);
|
||||
if (!OidIsValid(expr_op)) /* should not happen */
|
||||
elog(ERROR, "could not find commutator of member %d of opclass %u",
|
||||
op_strategy, lfirst_oid(opclasses_cell));
|
||||
elog(ERROR, "could not find commutator of member %d(%u,%u) of opfamily %u",
|
||||
op_strategy, lefttype, righttype, opfam);
|
||||
}
|
||||
new_ops = lappend_oid(new_ops, expr_op);
|
||||
}
|
||||
lefttypes_cell = lnext(lefttypes_cell);
|
||||
righttypes_cell = lnext(righttypes_cell);
|
||||
}
|
||||
|
||||
/* If we have more than one matching col, create a subset rowcompare */
|
||||
@@ -2587,8 +2602,8 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
|
||||
rc->rctype = (op_strategy == BTLessEqualStrategyNumber) ?
|
||||
ROWCOMPARE_GE : ROWCOMPARE_LE;
|
||||
rc->opnos = new_ops;
|
||||
rc->opclasses = list_truncate(list_copy(clause->opclasses),
|
||||
matching_cols);
|
||||
rc->opfamilies = list_truncate(list_copy(clause->opfamilies),
|
||||
matching_cols);
|
||||
rc->largs = list_truncate((List *) copyObject(clause->largs),
|
||||
matching_cols);
|
||||
rc->rargs = list_truncate((List *) copyObject(clause->rargs),
|
||||
@@ -2608,12 +2623,12 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
|
||||
|
||||
/*
|
||||
* Given a fixed prefix that all the "leftop" values must have,
|
||||
* generate suitable indexqual condition(s). opclass is the index
|
||||
* operator class; we use it to deduce the appropriate comparison
|
||||
* generate suitable indexqual condition(s). opfamily is the index
|
||||
* operator family; we use it to deduce the appropriate comparison
|
||||
* operators and operand datatypes.
|
||||
*/
|
||||
static List *
|
||||
prefix_quals(Node *leftop, Oid opclass,
|
||||
prefix_quals(Node *leftop, Oid opfamily,
|
||||
Const *prefix_const, Pattern_Prefix_Status pstatus)
|
||||
{
|
||||
List *result;
|
||||
@@ -2624,35 +2639,30 @@ prefix_quals(Node *leftop, Oid opclass,
|
||||
|
||||
Assert(pstatus != Pattern_Prefix_None);
|
||||
|
||||
switch (opclass)
|
||||
switch (opfamily)
|
||||
{
|
||||
case TEXT_BTREE_OPS_OID:
|
||||
case TEXT_PATTERN_BTREE_OPS_OID:
|
||||
case TEXT_BTREE_FAM_OID:
|
||||
case TEXT_PATTERN_BTREE_FAM_OID:
|
||||
datatype = TEXTOID;
|
||||
break;
|
||||
|
||||
case VARCHAR_BTREE_OPS_OID:
|
||||
case VARCHAR_PATTERN_BTREE_OPS_OID:
|
||||
datatype = VARCHAROID;
|
||||
break;
|
||||
|
||||
case BPCHAR_BTREE_OPS_OID:
|
||||
case BPCHAR_PATTERN_BTREE_OPS_OID:
|
||||
case BPCHAR_BTREE_FAM_OID:
|
||||
case BPCHAR_PATTERN_BTREE_FAM_OID:
|
||||
datatype = BPCHAROID;
|
||||
break;
|
||||
|
||||
case NAME_BTREE_OPS_OID:
|
||||
case NAME_PATTERN_BTREE_OPS_OID:
|
||||
case NAME_BTREE_FAM_OID:
|
||||
case NAME_PATTERN_BTREE_FAM_OID:
|
||||
datatype = NAMEOID;
|
||||
break;
|
||||
|
||||
case BYTEA_BTREE_OPS_OID:
|
||||
case BYTEA_BTREE_FAM_OID:
|
||||
datatype = BYTEAOID;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* shouldn't get here */
|
||||
elog(ERROR, "unexpected opclass: %u", opclass);
|
||||
elog(ERROR, "unexpected opfamily: %u", opfamily);
|
||||
return NIL;
|
||||
}
|
||||
|
||||
@@ -2688,10 +2698,10 @@ prefix_quals(Node *leftop, Oid opclass,
|
||||
*/
|
||||
if (pstatus == Pattern_Prefix_Exact)
|
||||
{
|
||||
oproid = get_opclass_member(opclass, InvalidOid,
|
||||
BTEqualStrategyNumber);
|
||||
oproid = get_opfamily_member(opfamily, datatype, datatype,
|
||||
BTEqualStrategyNumber);
|
||||
if (oproid == InvalidOid)
|
||||
elog(ERROR, "no = operator for opclass %u", opclass);
|
||||
elog(ERROR, "no = operator for opfamily %u", opfamily);
|
||||
expr = make_opclause(oproid, BOOLOID, false,
|
||||
(Expr *) leftop, (Expr *) prefix_const);
|
||||
result = list_make1(make_restrictinfo(expr, true, false, false, NULL));
|
||||
@@ -2703,10 +2713,10 @@ prefix_quals(Node *leftop, Oid opclass,
|
||||
*
|
||||
* We can always say "x >= prefix".
|
||||
*/
|
||||
oproid = get_opclass_member(opclass, InvalidOid,
|
||||
BTGreaterEqualStrategyNumber);
|
||||
oproid = get_opfamily_member(opfamily, datatype, datatype,
|
||||
BTGreaterEqualStrategyNumber);
|
||||
if (oproid == InvalidOid)
|
||||
elog(ERROR, "no >= operator for opclass %u", opclass);
|
||||
elog(ERROR, "no >= operator for opfamily %u", opfamily);
|
||||
expr = make_opclause(oproid, BOOLOID, false,
|
||||
(Expr *) leftop, (Expr *) prefix_const);
|
||||
result = list_make1(make_restrictinfo(expr, true, false, false, NULL));
|
||||
@@ -2719,10 +2729,10 @@ prefix_quals(Node *leftop, Oid opclass,
|
||||
greaterstr = make_greater_string(prefix_const);
|
||||
if (greaterstr)
|
||||
{
|
||||
oproid = get_opclass_member(opclass, InvalidOid,
|
||||
BTLessStrategyNumber);
|
||||
oproid = get_opfamily_member(opfamily, datatype, datatype,
|
||||
BTLessStrategyNumber);
|
||||
if (oproid == InvalidOid)
|
||||
elog(ERROR, "no < operator for opclass %u", opclass);
|
||||
elog(ERROR, "no < operator for opfamily %u", opfamily);
|
||||
expr = make_opclause(oproid, BOOLOID, false,
|
||||
(Expr *) leftop, (Expr *) greaterstr);
|
||||
result = lappend(result,
|
||||
@@ -2733,12 +2743,12 @@ prefix_quals(Node *leftop, Oid opclass,
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a leftop and a rightop, and a inet-class sup/sub operator,
|
||||
* Given a leftop and a rightop, and a inet-family sup/sub operator,
|
||||
* generate suitable indexqual condition(s). expr_op is the original
|
||||
* operator, and opclass is the index opclass.
|
||||
* operator, and opfamily is the index opfamily.
|
||||
*/
|
||||
static List *
|
||||
network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
|
||||
network_prefix_quals(Node *leftop, Oid expr_op, Oid opfamily, Datum rightop)
|
||||
{
|
||||
bool is_eq;
|
||||
Oid datatype;
|
||||
@@ -2770,17 +2780,17 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
|
||||
*/
|
||||
if (is_eq)
|
||||
{
|
||||
opr1oid = get_opclass_member(opclass, InvalidOid,
|
||||
BTGreaterEqualStrategyNumber);
|
||||
opr1oid = get_opfamily_member(opfamily, datatype, datatype,
|
||||
BTGreaterEqualStrategyNumber);
|
||||
if (opr1oid == InvalidOid)
|
||||
elog(ERROR, "no >= operator for opclass %u", opclass);
|
||||
elog(ERROR, "no >= operator for opfamily %u", opfamily);
|
||||
}
|
||||
else
|
||||
{
|
||||
opr1oid = get_opclass_member(opclass, InvalidOid,
|
||||
BTGreaterStrategyNumber);
|
||||
opr1oid = get_opfamily_member(opfamily, datatype, datatype,
|
||||
BTGreaterStrategyNumber);
|
||||
if (opr1oid == InvalidOid)
|
||||
elog(ERROR, "no > operator for opclass %u", opclass);
|
||||
elog(ERROR, "no > operator for opfamily %u", opfamily);
|
||||
}
|
||||
|
||||
opr1right = network_scan_first(rightop);
|
||||
@@ -2793,10 +2803,10 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
|
||||
|
||||
/* create clause "key <= network_scan_last( rightop )" */
|
||||
|
||||
opr2oid = get_opclass_member(opclass, InvalidOid,
|
||||
BTLessEqualStrategyNumber);
|
||||
opr2oid = get_opfamily_member(opfamily, datatype, datatype,
|
||||
BTLessEqualStrategyNumber);
|
||||
if (opr2oid == InvalidOid)
|
||||
elog(ERROR, "no <= operator for opclass %u", opclass);
|
||||
elog(ERROR, "no <= operator for opfamily %u", opfamily);
|
||||
|
||||
opr2right = network_scan_last(rightop);
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.107 2006/10/04 00:29:54 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.108 2006/12/23 00:43:10 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "access/skey.h"
|
||||
#include "optimizer/cost.h"
|
||||
#include "optimizer/pathnode.h"
|
||||
#include "optimizer/paths.h"
|
||||
@@ -39,6 +40,8 @@ static List *select_mergejoin_clauses(RelOptInfo *joinrel,
|
||||
RelOptInfo *innerrel,
|
||||
List *restrictlist,
|
||||
JoinType jointype);
|
||||
static void build_mergejoin_strat_lists(List *mergeclauses,
|
||||
List **mergefamilies, List **mergestrategies);
|
||||
|
||||
|
||||
/*
|
||||
@@ -225,6 +228,8 @@ sort_inner_and_outer(PlannerInfo *root,
|
||||
List *front_pathkey = (List *) lfirst(l);
|
||||
List *cur_pathkeys;
|
||||
List *cur_mergeclauses;
|
||||
List *mergefamilies;
|
||||
List *mergestrategies;
|
||||
List *outerkeys;
|
||||
List *innerkeys;
|
||||
List *merge_pathkeys;
|
||||
@@ -269,6 +274,10 @@ sort_inner_and_outer(PlannerInfo *root,
|
||||
merge_pathkeys = build_join_pathkeys(root, joinrel, jointype,
|
||||
outerkeys);
|
||||
|
||||
/* Build opfamily info for execution */
|
||||
build_mergejoin_strat_lists(cur_mergeclauses,
|
||||
&mergefamilies, &mergestrategies);
|
||||
|
||||
/*
|
||||
* And now we can make the path.
|
||||
*/
|
||||
@@ -281,6 +290,8 @@ sort_inner_and_outer(PlannerInfo *root,
|
||||
restrictlist,
|
||||
merge_pathkeys,
|
||||
cur_mergeclauses,
|
||||
mergefamilies,
|
||||
mergestrategies,
|
||||
outerkeys,
|
||||
innerkeys));
|
||||
}
|
||||
@@ -410,6 +421,8 @@ match_unsorted_outer(PlannerInfo *root,
|
||||
Path *outerpath = (Path *) lfirst(l);
|
||||
List *merge_pathkeys;
|
||||
List *mergeclauses;
|
||||
List *mergefamilies;
|
||||
List *mergestrategies;
|
||||
List *innersortkeys;
|
||||
List *trialsortkeys;
|
||||
Path *cheapest_startup_inner;
|
||||
@@ -516,6 +529,10 @@ match_unsorted_outer(PlannerInfo *root,
|
||||
mergeclauses,
|
||||
innerrel);
|
||||
|
||||
/* Build opfamily info for execution */
|
||||
build_mergejoin_strat_lists(mergeclauses,
|
||||
&mergefamilies, &mergestrategies);
|
||||
|
||||
/*
|
||||
* Generate a mergejoin on the basis of sorting the cheapest inner.
|
||||
* Since a sort will be needed, only cheapest total cost matters. (But
|
||||
@@ -531,6 +548,8 @@ match_unsorted_outer(PlannerInfo *root,
|
||||
restrictlist,
|
||||
merge_pathkeys,
|
||||
mergeclauses,
|
||||
mergefamilies,
|
||||
mergestrategies,
|
||||
NIL,
|
||||
innersortkeys));
|
||||
|
||||
@@ -589,6 +608,11 @@ match_unsorted_outer(PlannerInfo *root,
|
||||
}
|
||||
else
|
||||
newclauses = mergeclauses;
|
||||
|
||||
/* Build opfamily info for execution */
|
||||
build_mergejoin_strat_lists(newclauses,
|
||||
&mergefamilies, &mergestrategies);
|
||||
|
||||
add_path(joinrel, (Path *)
|
||||
create_mergejoin_path(root,
|
||||
joinrel,
|
||||
@@ -598,6 +622,8 @@ match_unsorted_outer(PlannerInfo *root,
|
||||
restrictlist,
|
||||
merge_pathkeys,
|
||||
newclauses,
|
||||
mergefamilies,
|
||||
mergestrategies,
|
||||
NIL,
|
||||
NIL));
|
||||
cheapest_total_inner = innerpath;
|
||||
@@ -633,6 +659,11 @@ match_unsorted_outer(PlannerInfo *root,
|
||||
else
|
||||
newclauses = mergeclauses;
|
||||
}
|
||||
|
||||
/* Build opfamily info for execution */
|
||||
build_mergejoin_strat_lists(newclauses,
|
||||
&mergefamilies, &mergestrategies);
|
||||
|
||||
add_path(joinrel, (Path *)
|
||||
create_mergejoin_path(root,
|
||||
joinrel,
|
||||
@@ -642,6 +673,8 @@ match_unsorted_outer(PlannerInfo *root,
|
||||
restrictlist,
|
||||
merge_pathkeys,
|
||||
newclauses,
|
||||
mergefamilies,
|
||||
mergestrategies,
|
||||
NIL,
|
||||
NIL));
|
||||
}
|
||||
@@ -946,3 +979,35 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
|
||||
|
||||
return result_list;
|
||||
}
|
||||
|
||||
/*
|
||||
* Temporary hack to build opfamily and strategy lists needed for mergejoin
|
||||
* by the executor. We need to rethink the planner's handling of merge
|
||||
* planning so that it can deal with multiple possible merge orders, but
|
||||
* that's not done yet.
|
||||
*/
|
||||
static void
|
||||
build_mergejoin_strat_lists(List *mergeclauses,
|
||||
List **mergefamilies, List **mergestrategies)
|
||||
{
|
||||
ListCell *l;
|
||||
|
||||
*mergefamilies = NIL;
|
||||
*mergestrategies = NIL;
|
||||
|
||||
foreach(l, mergeclauses)
|
||||
{
|
||||
RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l);
|
||||
|
||||
/*
|
||||
* We do not need to worry about whether the mergeclause will be
|
||||
* commuted at runtime --- it's the same opfamily either way.
|
||||
*/
|
||||
*mergefamilies = lappend_oid(*mergefamilies, restrictinfo->mergeopfamily);
|
||||
/*
|
||||
* For the moment, strategy must always be LessThan --- see
|
||||
* hack version of get_op_mergejoin_info
|
||||
*/
|
||||
*mergestrategies = lappend_int(*mergestrategies, BTLessStrategyNumber);
|
||||
}
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.217 2006/10/04 00:29:54 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.218 2006/12/23 00:43:10 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -73,7 +73,7 @@ static void fix_indexqual_references(List *indexquals, IndexPath *index_path,
|
||||
List **indexstrategy,
|
||||
List **indexsubtype);
|
||||
static Node *fix_indexqual_operand(Node *node, IndexOptInfo *index,
|
||||
Oid *opclass);
|
||||
Oid *opfamily);
|
||||
static List *get_switched_clauses(List *clauses, Relids outerrelids);
|
||||
static List *order_qual_clauses(PlannerInfo *root, List *clauses);
|
||||
static void copy_path_costsize(Plan *dest, Path *src);
|
||||
@@ -113,7 +113,7 @@ static HashJoin *make_hashjoin(List *tlist,
|
||||
static Hash *make_hash(Plan *lefttree);
|
||||
static MergeJoin *make_mergejoin(List *tlist,
|
||||
List *joinclauses, List *otherclauses,
|
||||
List *mergeclauses,
|
||||
List *mergeclauses, List *mergefamilies, List *mergestrategies,
|
||||
Plan *lefttree, Plan *righttree,
|
||||
JoinType jointype);
|
||||
static Sort *make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
|
||||
@@ -1540,6 +1540,8 @@ create_mergejoin_plan(PlannerInfo *root,
|
||||
joinclauses,
|
||||
otherclauses,
|
||||
mergeclauses,
|
||||
best_path->path_mergefamilies,
|
||||
best_path->path_mergestrategies,
|
||||
outer_plan,
|
||||
inner_plan,
|
||||
best_path->jpath.jointype);
|
||||
@@ -1676,9 +1678,10 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
|
||||
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
|
||||
Expr *clause;
|
||||
Oid clause_op;
|
||||
Oid opclass;
|
||||
Oid opfamily;
|
||||
int stratno;
|
||||
Oid stratsubtype;
|
||||
Oid stratlefttype;
|
||||
Oid stratrighttype;
|
||||
bool recheck;
|
||||
|
||||
Assert(IsA(rinfo, RestrictInfo));
|
||||
@@ -1709,11 +1712,11 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
|
||||
|
||||
/*
|
||||
* Now, determine which index attribute this is, change the
|
||||
* indexkey operand as needed, and get the index opclass.
|
||||
* indexkey operand as needed, and get the index opfamily.
|
||||
*/
|
||||
linitial(op->args) = fix_indexqual_operand(linitial(op->args),
|
||||
index,
|
||||
&opclass);
|
||||
&opfamily);
|
||||
clause_op = op->opno;
|
||||
}
|
||||
else if (IsA(clause, RowCompareExpr))
|
||||
@@ -1734,20 +1737,20 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
|
||||
* For each column in the row comparison, determine which index
|
||||
* attribute this is and change the indexkey operand as needed.
|
||||
*
|
||||
* Save the index opclass for only the first column. We will
|
||||
* return the operator and opclass info for just the first column
|
||||
* Save the index opfamily for only the first column. We will
|
||||
* return the operator and opfamily info for just the first column
|
||||
* of the row comparison; the executor will have to look up the
|
||||
* rest if it needs them.
|
||||
*/
|
||||
foreach(lc, rc->largs)
|
||||
{
|
||||
Oid tmp_opclass;
|
||||
Oid tmp_opfamily;
|
||||
|
||||
lfirst(lc) = fix_indexqual_operand(lfirst(lc),
|
||||
index,
|
||||
&tmp_opclass);
|
||||
&tmp_opfamily);
|
||||
if (lc == list_head(rc->largs))
|
||||
opclass = tmp_opclass;
|
||||
opfamily = tmp_opfamily;
|
||||
}
|
||||
clause_op = linitial_oid(rc->opnos);
|
||||
}
|
||||
@@ -1759,11 +1762,11 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
|
||||
|
||||
/*
|
||||
* Now, determine which index attribute this is, change the
|
||||
* indexkey operand as needed, and get the index opclass.
|
||||
* indexkey operand as needed, and get the index opfamily.
|
||||
*/
|
||||
linitial(saop->args) = fix_indexqual_operand(linitial(saop->args),
|
||||
index,
|
||||
&opclass);
|
||||
&opfamily);
|
||||
clause_op = saop->opno;
|
||||
}
|
||||
else
|
||||
@@ -1776,15 +1779,18 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
|
||||
*fixed_indexquals = lappend(*fixed_indexquals, clause);
|
||||
|
||||
/*
|
||||
* Look up the (possibly commuted) operator in the operator class to
|
||||
* get its strategy numbers and the recheck indicator. This also
|
||||
* Look up the (possibly commuted) operator in the operator family to
|
||||
* get its strategy number and the recheck indicator. This also
|
||||
* double-checks that we found an operator matching the index.
|
||||
*/
|
||||
get_op_opclass_properties(clause_op, opclass,
|
||||
&stratno, &stratsubtype, &recheck);
|
||||
get_op_opfamily_properties(clause_op, opfamily,
|
||||
&stratno,
|
||||
&stratlefttype,
|
||||
&stratrighttype,
|
||||
&recheck);
|
||||
|
||||
*indexstrategy = lappend_int(*indexstrategy, stratno);
|
||||
*indexsubtype = lappend_oid(*indexsubtype, stratsubtype);
|
||||
*indexsubtype = lappend_oid(*indexsubtype, stratrighttype);
|
||||
|
||||
/* If it's not lossy, add to nonlossy_indexquals */
|
||||
if (!recheck)
|
||||
@@ -1793,7 +1799,7 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path,
|
||||
}
|
||||
|
||||
static Node *
|
||||
fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass)
|
||||
fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opfamily)
|
||||
{
|
||||
/*
|
||||
* We represent index keys by Var nodes having the varno of the base table
|
||||
@@ -1826,8 +1832,8 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass)
|
||||
{
|
||||
result = (Var *) copyObject(node);
|
||||
result->varattno = pos + 1;
|
||||
/* return the correct opclass, too */
|
||||
*opclass = index->classlist[pos];
|
||||
/* return the correct opfamily, too */
|
||||
*opfamily = index->opfamily[pos];
|
||||
return (Node *) result;
|
||||
}
|
||||
}
|
||||
@@ -1853,8 +1859,8 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass)
|
||||
result = makeVar(index->rel->relid, pos + 1,
|
||||
exprType(lfirst(indexpr_item)), -1,
|
||||
0);
|
||||
/* return the correct opclass, too */
|
||||
*opclass = index->classlist[pos];
|
||||
/* return the correct opfamily, too */
|
||||
*opfamily = index->opfamily[pos];
|
||||
return (Node *) result;
|
||||
}
|
||||
indexpr_item = lnext(indexpr_item);
|
||||
@@ -1863,7 +1869,7 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index, Oid *opclass)
|
||||
|
||||
/* Ooops... */
|
||||
elog(ERROR, "node is not an index attribute");
|
||||
*opclass = InvalidOid; /* keep compiler quiet */
|
||||
*opfamily = InvalidOid; /* keep compiler quiet */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2327,6 +2333,8 @@ make_mergejoin(List *tlist,
|
||||
List *joinclauses,
|
||||
List *otherclauses,
|
||||
List *mergeclauses,
|
||||
List *mergefamilies,
|
||||
List *mergestrategies,
|
||||
Plan *lefttree,
|
||||
Plan *righttree,
|
||||
JoinType jointype)
|
||||
@@ -2340,6 +2348,8 @@ make_mergejoin(List *tlist,
|
||||
plan->lefttree = lefttree;
|
||||
plan->righttree = righttree;
|
||||
node->mergeclauses = mergeclauses;
|
||||
node->mergefamilies = mergefamilies;
|
||||
node->mergestrategies = mergestrategies;
|
||||
node->join.jointype = jointype;
|
||||
node->join.joinqual = joinclauses;
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.124 2006/12/07 19:33:40 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.125 2006/12/23 00:43:10 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1109,10 +1109,10 @@ process_implied_equality(PlannerInfo *root,
|
||||
|
||||
/*
|
||||
* Let's just make sure this appears to be a compatible operator.
|
||||
*
|
||||
* XXX needs work
|
||||
*/
|
||||
if (pgopform->oprlsortop != sortop1 ||
|
||||
pgopform->oprrsortop != sortop2 ||
|
||||
pgopform->oprresult != BOOLOID)
|
||||
if (pgopform->oprresult != BOOLOID)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||
errmsg("equality operator for types %s and %s should be merge-joinable, but isn't",
|
||||
@@ -1276,6 +1276,7 @@ check_mergejoinable(RestrictInfo *restrictinfo)
|
||||
Oid opno,
|
||||
leftOp,
|
||||
rightOp;
|
||||
Oid opfamily;
|
||||
|
||||
if (restrictinfo->pseudoconstant)
|
||||
return;
|
||||
@@ -1286,14 +1287,17 @@ check_mergejoinable(RestrictInfo *restrictinfo)
|
||||
|
||||
opno = ((OpExpr *) clause)->opno;
|
||||
|
||||
if (op_mergejoinable(opno,
|
||||
&leftOp,
|
||||
&rightOp) &&
|
||||
if (op_mergejoinable(opno) &&
|
||||
!contain_volatile_functions((Node *) clause))
|
||||
{
|
||||
restrictinfo->mergejoinoperator = opno;
|
||||
restrictinfo->left_sortop = leftOp;
|
||||
restrictinfo->right_sortop = rightOp;
|
||||
/* XXX for the moment, continue to force use of particular sortops */
|
||||
if (get_op_mergejoin_info(opno, &leftOp, &rightOp, &opfamily))
|
||||
{
|
||||
restrictinfo->mergejoinoperator = opno;
|
||||
restrictinfo->left_sortop = leftOp;
|
||||
restrictinfo->right_sortop = rightOp;
|
||||
restrictinfo->mergeopfamily = opfamily;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.22 2006/10/04 00:29:54 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.23 2006/12/23 00:43:10 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -340,8 +340,8 @@ build_minmax_path(PlannerInfo *root, RelOptInfo *rel, MinMaxAggInfo *info)
|
||||
|
||||
Assert(is_opclause(rinfo->clause));
|
||||
strategy =
|
||||
get_op_opclass_strategy(((OpExpr *) rinfo->clause)->opno,
|
||||
index->classlist[prevcol]);
|
||||
get_op_opfamily_strategy(((OpExpr *) rinfo->clause)->opno,
|
||||
index->opfamily[prevcol]);
|
||||
if (strategy == BTEqualStrategyNumber)
|
||||
break;
|
||||
}
|
||||
@@ -390,10 +390,10 @@ build_minmax_path(PlannerInfo *root, RelOptInfo *rel, MinMaxAggInfo *info)
|
||||
* Does an aggregate match an index column?
|
||||
*
|
||||
* It matches if its argument is equal to the index column's data and its
|
||||
* sortop is either the LessThan or GreaterThan member of the column's opclass.
|
||||
* sortop is either a LessThan or GreaterThan member of the column's opfamily.
|
||||
*
|
||||
* We return ForwardScanDirection if match the LessThan member,
|
||||
* BackwardScanDirection if match the GreaterThan member,
|
||||
* We return ForwardScanDirection if match a LessThan member,
|
||||
* BackwardScanDirection if match a GreaterThan member,
|
||||
* and NoMovementScanDirection if there's no match.
|
||||
*/
|
||||
static ScanDirection
|
||||
@@ -405,9 +405,9 @@ match_agg_to_index_col(MinMaxAggInfo *info, IndexOptInfo *index, int indexcol)
|
||||
if (!match_index_to_operand((Node *) info->target, indexcol, index))
|
||||
return NoMovementScanDirection;
|
||||
|
||||
/* Look up the operator in the opclass */
|
||||
strategy = get_op_opclass_strategy(info->aggsortop,
|
||||
index->classlist[indexcol]);
|
||||
/* Look up the operator in the opfamily */
|
||||
strategy = get_op_opfamily_strategy(info->aggsortop,
|
||||
index->opfamily[indexcol]);
|
||||
if (strategy == BTLessStrategyNumber)
|
||||
return ForwardScanDirection;
|
||||
if (strategy == BTGreaterStrategyNumber)
|
||||
|
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.114 2006/12/10 22:13:26 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.115 2006/12/23 00:43:10 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -689,11 +689,11 @@ convert_IN_to_join(PlannerInfo *root, SubLink *sublink)
|
||||
return NULL;
|
||||
if (sublink->testexpr && IsA(sublink->testexpr, OpExpr))
|
||||
{
|
||||
List *opclasses;
|
||||
List *opfamilies;
|
||||
List *opstrats;
|
||||
|
||||
get_op_btree_interpretation(((OpExpr *) sublink->testexpr)->opno,
|
||||
&opclasses, &opstrats);
|
||||
&opfamilies, &opstrats);
|
||||
if (!list_member_int(opstrats, ROWCOMPARE_EQ))
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.224 2006/12/21 16:05:13 petere Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.225 2006/12/23 00:43:10 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -1294,13 +1294,9 @@ CommuteRowCompareExpr(RowCompareExpr *clause)
|
||||
clause->opnos = newops;
|
||||
|
||||
/*
|
||||
* Note: we don't bother to update the opclasses list, but just set it to
|
||||
* empty. This is OK since this routine is currently only used for index
|
||||
* quals, and the index machinery won't use the opclass information. The
|
||||
* original opclass list is NOT valid if we have commuted any cross-type
|
||||
* comparisons, so don't leave it in place.
|
||||
* Note: we need not change the opfamilies list; we assume any btree
|
||||
* opfamily containing an operator will also contain its commutator.
|
||||
*/
|
||||
clause->opclasses = NIL; /* XXX */
|
||||
|
||||
temp = clause->largs;
|
||||
clause->largs = clause->rargs;
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.133 2006/10/04 00:29:55 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.134 2006/12/23 00:43:11 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1152,6 +1152,10 @@ create_nestloop_path(PlannerInfo *root,
|
||||
* 'pathkeys' are the path keys of the new join path
|
||||
* 'mergeclauses' are the RestrictInfo nodes to use as merge clauses
|
||||
* (this should be a subset of the restrict_clauses list)
|
||||
* 'mergefamilies' are the btree opfamily OIDs identifying the merge
|
||||
* ordering for each merge clause
|
||||
* 'mergestrategies' are the btree operator strategies identifying the merge
|
||||
* ordering for each merge clause
|
||||
* 'outersortkeys' are the sort varkeys for the outer relation
|
||||
* 'innersortkeys' are the sort varkeys for the inner relation
|
||||
*/
|
||||
@@ -1164,6 +1168,8 @@ create_mergejoin_path(PlannerInfo *root,
|
||||
List *restrict_clauses,
|
||||
List *pathkeys,
|
||||
List *mergeclauses,
|
||||
List *mergefamilies,
|
||||
List *mergestrategies,
|
||||
List *outersortkeys,
|
||||
List *innersortkeys)
|
||||
{
|
||||
@@ -1204,6 +1210,8 @@ create_mergejoin_path(PlannerInfo *root,
|
||||
pathnode->jpath.joinrestrictinfo = restrict_clauses;
|
||||
pathnode->jpath.path.pathkeys = pathkeys;
|
||||
pathnode->path_mergeclauses = mergeclauses;
|
||||
pathnode->path_mergefamilies = mergefamilies;
|
||||
pathnode->path_mergestrategies = mergestrategies;
|
||||
pathnode->outersortkeys = outersortkeys;
|
||||
pathnode->innersortkeys = innersortkeys;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.128 2006/12/18 18:56:28 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.129 2006/12/23 00:43:11 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -169,16 +169,16 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
|
||||
info->ncolumns = ncolumns = index->indnatts;
|
||||
|
||||
/*
|
||||
* Need to make classlist and ordering arrays large enough to put
|
||||
* Need to make opfamily and ordering arrays large enough to put
|
||||
* a terminating 0 at the end of each one.
|
||||
*/
|
||||
info->indexkeys = (int *) palloc(sizeof(int) * ncolumns);
|
||||
info->classlist = (Oid *) palloc0(sizeof(Oid) * (ncolumns + 1));
|
||||
info->opfamily = (Oid *) palloc0(sizeof(Oid) * (ncolumns + 1));
|
||||
info->ordering = (Oid *) palloc0(sizeof(Oid) * (ncolumns + 1));
|
||||
|
||||
for (i = 0; i < ncolumns; i++)
|
||||
{
|
||||
info->classlist[i] = indexRelation->rd_indclass->values[i];
|
||||
info->opfamily[i] = indexRelation->rd_opfamily[i];
|
||||
info->indexkeys[i] = index->indkey.values[i];
|
||||
}
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.10 2006/10/04 00:29:55 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.11 2006/12/23 00:43:11 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -939,7 +939,7 @@ arrayexpr_cleanup_fn(PredIterInfo info)
|
||||
* already known immutable, so the clause will certainly always fail.)
|
||||
*
|
||||
* Finally, we may be able to deduce something using knowledge about btree
|
||||
* operator classes; this is encapsulated in btree_predicate_proof().
|
||||
* operator families; this is encapsulated in btree_predicate_proof().
|
||||
*----------
|
||||
*/
|
||||
static bool
|
||||
@@ -989,7 +989,7 @@ predicate_implied_by_simple_clause(Expr *predicate, Node *clause)
|
||||
* that has "foo" as an input. See notes for implication case.
|
||||
*
|
||||
* Finally, we may be able to deduce something using knowledge about btree
|
||||
* operator classes; this is encapsulated in btree_predicate_proof().
|
||||
* operator families; this is encapsulated in btree_predicate_proof().
|
||||
*----------
|
||||
*/
|
||||
static bool
|
||||
@@ -1062,8 +1062,8 @@ extract_not_arg(Node *clause)
|
||||
* The strategy numbers defined by btree indexes (see access/skey.h) are:
|
||||
* (1) < (2) <= (3) = (4) >= (5) >
|
||||
* and in addition we use (6) to represent <>. <> is not a btree-indexable
|
||||
* operator, but we assume here that if the equality operator of a btree
|
||||
* opclass has a negator operator, the negator behaves as <> for the opclass.
|
||||
* operator, but we assume here that if an equality operator of a btree
|
||||
* opfamily has a negator operator, the negator behaves as <> for the opfamily.
|
||||
*
|
||||
* The interpretation of:
|
||||
*
|
||||
@@ -1146,10 +1146,10 @@ static const StrategyNumber BT_refute_table[6][6] = {
|
||||
* What we look for here is binary boolean opclauses of the form
|
||||
* "foo op constant", where "foo" is the same in both clauses. The operators
|
||||
* and constants can be different but the operators must be in the same btree
|
||||
* operator class. We use the above operator implication tables to
|
||||
* operator family. We use the above operator implication tables to
|
||||
* derive implications between nonidentical clauses. (Note: "foo" is known
|
||||
* immutable, and constants are surely immutable, but we have to check that
|
||||
* the operators are too. As of 8.0 it's possible for opclasses to contain
|
||||
* the operators are too. As of 8.0 it's possible for opfamilies to contain
|
||||
* operators that are merely stable, and we dare not make deductions with
|
||||
* these.)
|
||||
*----------
|
||||
@@ -1171,12 +1171,12 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
|
||||
pred_op_negator,
|
||||
clause_op_negator,
|
||||
test_op = InvalidOid;
|
||||
Oid opclass_id;
|
||||
Oid opfamily_id;
|
||||
bool found = false;
|
||||
StrategyNumber pred_strategy,
|
||||
clause_strategy,
|
||||
test_strategy;
|
||||
Oid clause_subtype;
|
||||
Oid clause_righttype;
|
||||
Expr *test_expr;
|
||||
ExprState *test_exprstate;
|
||||
Datum test_result;
|
||||
@@ -1272,28 +1272,30 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to find a btree opclass containing the needed operators.
|
||||
* Try to find a btree opfamily containing the needed operators.
|
||||
*
|
||||
* We must find a btree opclass that contains both operators, else the
|
||||
* XXX this needs work!!!!!!!!!!!!!!!!!!!!!!!
|
||||
*
|
||||
* We must find a btree opfamily that contains both operators, else the
|
||||
* 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
|
||||
* test. Also, the opfamily 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
|
||||
* If there are multiple matching opfamilies, 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.
|
||||
* consistent opfamilies.
|
||||
*/
|
||||
catlist = SearchSysCacheList(AMOPOPID, 1,
|
||||
ObjectIdGetDatum(pred_op),
|
||||
0, 0, 0);
|
||||
|
||||
/*
|
||||
* If we couldn't find any opclass containing the pred_op, perhaps it is a
|
||||
* <> operator. See if it has a negator that is in an opclass.
|
||||
* If we couldn't find any opfamily containing the pred_op, perhaps it is a
|
||||
* <> operator. See if it has a negator that is in an opfamily.
|
||||
*/
|
||||
pred_op_negated = false;
|
||||
if (catlist->n_members == 0)
|
||||
@@ -1312,23 +1314,22 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
|
||||
/* Also may need the clause_op's negator */
|
||||
clause_op_negator = get_negator(clause_op);
|
||||
|
||||
/* Now search the opclasses */
|
||||
/* Now search the opfamilies */
|
||||
for (i = 0; i < catlist->n_members; i++)
|
||||
{
|
||||
HeapTuple pred_tuple = &catlist->members[i]->tuple;
|
||||
Form_pg_amop pred_form = (Form_pg_amop) GETSTRUCT(pred_tuple);
|
||||
HeapTuple clause_tuple;
|
||||
|
||||
opclass_id = pred_form->amopclaid;
|
||||
|
||||
/* must be btree */
|
||||
if (!opclass_is_btree(opclass_id))
|
||||
if (pred_form->amopmethod != BTREE_AM_OID)
|
||||
continue;
|
||||
/* predicate operator must be default within this opclass */
|
||||
if (pred_form->amopsubtype != InvalidOid)
|
||||
/* predicate operator must be default within this opfamily */
|
||||
if (pred_form->amoplefttype != pred_form->amoprighttype)
|
||||
continue;
|
||||
|
||||
/* Get the predicate operator's btree strategy number */
|
||||
opfamily_id = pred_form->amopfamily;
|
||||
pred_strategy = (StrategyNumber) pred_form->amopstrategy;
|
||||
Assert(pred_strategy >= 1 && pred_strategy <= 5);
|
||||
|
||||
@@ -1341,37 +1342,39 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
|
||||
}
|
||||
|
||||
/*
|
||||
* From the same opclass, find a strategy number for the clause_op, if
|
||||
* possible
|
||||
* From the same opfamily, find a strategy number for the clause_op,
|
||||
* if possible
|
||||
*/
|
||||
clause_tuple = SearchSysCache(AMOPOPID,
|
||||
ObjectIdGetDatum(clause_op),
|
||||
ObjectIdGetDatum(opclass_id),
|
||||
ObjectIdGetDatum(opfamily_id),
|
||||
0, 0);
|
||||
if (HeapTupleIsValid(clause_tuple))
|
||||
{
|
||||
Form_pg_amop clause_form = (Form_pg_amop) GETSTRUCT(clause_tuple);
|
||||
|
||||
/* Get the restriction clause operator's strategy/subtype */
|
||||
/* Get the restriction clause operator's strategy/datatype */
|
||||
clause_strategy = (StrategyNumber) clause_form->amopstrategy;
|
||||
Assert(clause_strategy >= 1 && clause_strategy <= 5);
|
||||
clause_subtype = clause_form->amopsubtype;
|
||||
Assert(clause_form->amoplefttype == pred_form->amoplefttype);
|
||||
clause_righttype = clause_form->amoprighttype;
|
||||
ReleaseSysCache(clause_tuple);
|
||||
}
|
||||
else if (OidIsValid(clause_op_negator))
|
||||
{
|
||||
clause_tuple = SearchSysCache(AMOPOPID,
|
||||
ObjectIdGetDatum(clause_op_negator),
|
||||
ObjectIdGetDatum(opclass_id),
|
||||
ObjectIdGetDatum(opfamily_id),
|
||||
0, 0);
|
||||
if (HeapTupleIsValid(clause_tuple))
|
||||
{
|
||||
Form_pg_amop clause_form = (Form_pg_amop) GETSTRUCT(clause_tuple);
|
||||
|
||||
/* Get the restriction clause operator's strategy/subtype */
|
||||
/* Get the restriction clause operator's strategy/datatype */
|
||||
clause_strategy = (StrategyNumber) clause_form->amopstrategy;
|
||||
Assert(clause_strategy >= 1 && clause_strategy <= 5);
|
||||
clause_subtype = clause_form->amopsubtype;
|
||||
Assert(clause_form->amoplefttype == pred_form->amoplefttype);
|
||||
clause_righttype = clause_form->amoprighttype;
|
||||
ReleaseSysCache(clause_tuple);
|
||||
|
||||
/* Only consider negators that are = */
|
||||
@@ -1400,20 +1403,24 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
|
||||
}
|
||||
|
||||
/*
|
||||
* See if opclass has an operator for the test strategy and the clause
|
||||
* datatype.
|
||||
* See if opfamily has an operator for the test strategy and the
|
||||
* datatypes.
|
||||
*/
|
||||
if (test_strategy == BTNE)
|
||||
{
|
||||
test_op = get_opclass_member(opclass_id, clause_subtype,
|
||||
BTEqualStrategyNumber);
|
||||
test_op = get_opfamily_member(opfamily_id,
|
||||
pred_form->amoprighttype,
|
||||
clause_righttype,
|
||||
BTEqualStrategyNumber);
|
||||
if (OidIsValid(test_op))
|
||||
test_op = get_negator(test_op);
|
||||
}
|
||||
else
|
||||
{
|
||||
test_op = get_opclass_member(opclass_id, clause_subtype,
|
||||
test_strategy);
|
||||
test_op = get_opfamily_member(opfamily_id,
|
||||
pred_form->amoprighttype,
|
||||
clause_righttype,
|
||||
test_strategy);
|
||||
}
|
||||
if (OidIsValid(test_op))
|
||||
{
|
||||
@@ -1423,7 +1430,7 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
|
||||
* Note that we require only the test_op to be immutable, not the
|
||||
* original clause_op. (pred_op is assumed to have been checked
|
||||
* immutable by the caller.) Essentially we are assuming that the
|
||||
* opclass is consistent even if it contains operators that are
|
||||
* opfamily is consistent even if it contains operators that are
|
||||
* merely stable.
|
||||
*/
|
||||
if (op_volatile(test_op) == PROVOLATILE_IMMUTABLE)
|
||||
@@ -1438,7 +1445,7 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
|
||||
|
||||
if (!found)
|
||||
{
|
||||
/* couldn't find a btree opclass to interpret the operators */
|
||||
/* couldn't find a btree opfamily to interpret the operators */
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.49 2006/10/04 00:29:55 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.50 2006/12/23 00:43:11 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -342,6 +342,7 @@ make_restrictinfo_internal(Expr *clause,
|
||||
restrictinfo->mergejoinoperator = InvalidOid;
|
||||
restrictinfo->left_sortop = InvalidOid;
|
||||
restrictinfo->right_sortop = InvalidOid;
|
||||
restrictinfo->mergeopfamily = InvalidOid;
|
||||
|
||||
restrictinfo->left_pathkey = NIL;
|
||||
restrictinfo->right_pathkey = NIL;
|
||||
|
Reference in New Issue
Block a user