1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-12 21:01:52 +03:00

Ye-old pgindent run. Same 4-space tabs.

This commit is contained in:
Bruce Momjian
2000-04-12 17:17:23 +00:00
parent db4518729d
commit 52f77df613
434 changed files with 24799 additions and 21246 deletions

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.81 2000/03/22 22:08:33 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.82 2000/04/12 17:15:19 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -46,62 +46,63 @@
#define is_indexable_operator(clause,opclass,relam,indexkey_on_left) \
(indexable_operator(clause,opclass,relam,indexkey_on_left) != InvalidOid)
typedef enum {
typedef enum
{
Prefix_None, Prefix_Partial, Prefix_Exact
} Prefix_Status;
static void match_index_orclauses(RelOptInfo *rel, IndexOptInfo *index,
List *restrictinfo_list);
List *restrictinfo_list);
static List *match_index_orclause(RelOptInfo *rel, IndexOptInfo *index,
List *or_clauses,
List *other_matching_indices);
List *or_clauses,
List *other_matching_indices);
static bool match_or_subclause_to_indexkey(RelOptInfo *rel,
IndexOptInfo *index,
Expr *clause);
IndexOptInfo *index,
Expr *clause);
static List *group_clauses_by_indexkey(RelOptInfo *rel, IndexOptInfo *index,
int *indexkeys, Oid *classes,
List *restrictinfo_list);
int *indexkeys, Oid *classes,
List *restrictinfo_list);
static List *group_clauses_by_ikey_for_joins(RelOptInfo *rel,
IndexOptInfo *index,
int *indexkeys, Oid *classes,
List *join_cinfo_list,
List *restr_cinfo_list);
IndexOptInfo *index,
int *indexkeys, Oid *classes,
List *join_cinfo_list,
List *restr_cinfo_list);
static bool match_clause_to_indexkey(RelOptInfo *rel, IndexOptInfo *index,
int indexkey, Oid opclass,
Expr *clause, bool join);
int indexkey, Oid opclass,
Expr *clause, bool join);
static bool pred_test(List *predicate_list, List *restrictinfo_list,
List *joininfo_list);
List *joininfo_list);
static bool one_pred_test(Expr *predicate, List *restrictinfo_list);
static bool one_pred_clause_expr_test(Expr *predicate, Node *clause);
static bool one_pred_clause_test(Expr *predicate, Node *clause);
static bool clause_pred_clause_test(Expr *predicate, Node *clause);
static void indexable_joinclauses(RelOptInfo *rel, IndexOptInfo *index,
List *joininfo_list, List *restrictinfo_list,
List **clausegroups, List **outerrelids);
List *joininfo_list, List *restrictinfo_list,
List **clausegroups, List **outerrelids);
static List *index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
List *clausegroup_list, List *outerrelids_list);
List *clausegroup_list, List *outerrelids_list);
static bool useful_for_mergejoin(RelOptInfo *rel, IndexOptInfo *index,
List *joininfo_list);
List *joininfo_list);
static bool useful_for_ordering(Query *root, RelOptInfo *rel,
IndexOptInfo *index,
ScanDirection scandir);
IndexOptInfo *index,
ScanDirection scandir);
static bool match_index_to_operand(int indexkey, Var *operand,
RelOptInfo *rel, IndexOptInfo *index);
RelOptInfo *rel, IndexOptInfo *index);
static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel,
IndexOptInfo *index);
IndexOptInfo *index);
static bool match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
bool indexkey_on_left);
bool indexkey_on_left);
static Prefix_Status like_fixed_prefix(char *patt, char **prefix);
static Prefix_Status regex_fixed_prefix(char *patt, bool case_insensitive,
char **prefix);
char **prefix);
static List *prefix_quals(Var *leftop, Oid expr_op,
char *prefix, Prefix_Status pstatus);
static char *make_greater_string(const char * str, Oid datatype);
static Oid find_operator(const char * opname, Oid datatype);
static Datum string_to_datum(const char * str, Oid datatype);
static Const *string_to_const(const char * str, Oid datatype);
static bool string_lessthan(const char * str1, const char * str2,
Oid datatype);
char *prefix, Prefix_Status pstatus);
static char *make_greater_string(const char *str, Oid datatype);
static Oid find_operator(const char *opname, Oid datatype);
static Datum string_to_datum(const char *str, Oid datatype);
static Const *string_to_const(const char *str, Oid datatype);
static bool string_lessthan(const char *str1, const char *str2,
Oid datatype);
/*
@ -153,34 +154,34 @@ create_index_paths(Query *root,
List *joinouterrelids;
/*
* If this is a partial index, we can only use it if it passes
* the predicate test.
* If this is a partial index, we can only use it if it passes the
* predicate test.
*/
if (index->indpred != NIL)
if (!pred_test(index->indpred, restrictinfo_list, joininfo_list))
continue;
/*
* 1. Try matching the index against subclauses of restriction 'or'
* clauses (ie, 'or' clauses that reference only this relation).
* The restrictinfo nodes for the 'or' clauses are marked with lists
* of the matching indices. No paths are actually created now;
* that will be done in orindxpath.c after all indexes for the rel
* have been examined. (We need to do it that way because we can
* potentially use a different index for each subclause of an 'or',
* so we can't build a path for an 'or' clause until all indexes have
* been matched against it.)
* 1. Try matching the index against subclauses of restriction
* 'or' clauses (ie, 'or' clauses that reference only this
* relation). The restrictinfo nodes for the 'or' clauses are
* marked with lists of the matching indices. No paths are
* actually created now; that will be done in orindxpath.c after
* all indexes for the rel have been examined. (We need to do it
* that way because we can potentially use a different index for
* each subclause of an 'or', so we can't build a path for an 'or'
* clause until all indexes have been matched against it.)
*
* We don't even think about special handling of 'or' clauses that
* involve more than one relation (ie, are join clauses).
* Can we do anything useful with those?
* involve more than one relation (ie, are join clauses). Can we
* do anything useful with those?
*/
match_index_orclauses(rel, index, restrictinfo_list);
/*
* 2. If the keys of this index match any of the available non-'or'
* restriction clauses, then create a path using those clauses
* as indexquals.
* 2. If the keys of this index match any of the available
* non-'or' restriction clauses, then create a path using those
* clauses as indexquals.
*/
restrictclauses = group_clauses_by_indexkey(rel,
index,
@ -191,7 +192,7 @@ create_index_paths(Query *root,
if (restrictclauses != NIL)
add_path(rel, (Path *) create_index_path(root, rel, index,
restrictclauses,
NoMovementScanDirection));
NoMovementScanDirection));
/*
* 3. If this index can be used for a mergejoin, then create an
@ -205,16 +206,17 @@ create_index_paths(Query *root,
if (restrictclauses == NIL)
{
if (useful_for_mergejoin(rel, index, joininfo_list) ||
useful_for_ordering(root, rel, index, ForwardScanDirection))
useful_for_ordering(root, rel, index, ForwardScanDirection))
add_path(rel, (Path *)
create_index_path(root, rel, index,
NIL,
ForwardScanDirection));
}
/*
* Currently, backwards scan is never considered except for the case
* of matching a query result ordering. Possibly should consider
* it in other places?
* Currently, backwards scan is never considered except for the
* case of matching a query result ordering. Possibly should
* consider it in other places?
*/
if (useful_for_ordering(root, rel, index, BackwardScanDirection))
add_path(rel, (Path *)
@ -223,11 +225,11 @@ create_index_paths(Query *root,
BackwardScanDirection));
/*
* 4. Create an innerjoin index path for each combination of
* other rels used in available join clauses. These paths will
* be considered as the inner side of nestloop joins against
* those sets of other rels. indexable_joinclauses() finds sets
* of clauses that can be used with each combination of outer rels,
* 4. Create an innerjoin index path for each combination of other
* rels used in available join clauses. These paths will be
* considered as the inner side of nestloop joins against those
* sets of other rels. indexable_joinclauses() finds sets of
* clauses that can be used with each combination of outer rels,
* and index_innerjoin builds the paths themselves. We add the
* paths to the rel's innerjoin list, NOT to the result list.
*/
@ -247,7 +249,7 @@ create_index_paths(Query *root,
/****************************************************************************
* ---- ROUTINES TO PROCESS 'OR' CLAUSES ----
* ---- ROUTINES TO PROCESS 'OR' CLAUSES ----
****************************************************************************/
@ -280,6 +282,7 @@ match_index_orclauses(RelOptInfo *rel,
if (restriction_is_or_clause(restrictinfo))
{
/*
* Add this index to the subclause index list for each
* subclause that it matches.
@ -309,7 +312,7 @@ match_index_orclauses(RelOptInfo *rel,
* that have already been matched to subclauses within this
* particular 'or' clause (i.e., a list previously generated by
* this routine), or NIL if this routine has not previously been
* run for this 'or' clause.
* run for this 'or' clause.
*
* Returns a list of the form ((a b c) (d e f) nil (g h) ...) where
* a,b,c are nodes of indices that match the first subclause in
@ -326,7 +329,8 @@ match_index_orclause(RelOptInfo *rel,
List *index_list;
List *clist;
/* first time through, we create list of same length as OR clause,
/*
* first time through, we create list of same length as OR clause,
* containing an empty sublist for each subclause.
*/
if (!other_matching_indices)
@ -374,8 +378,8 @@ match_or_subclause_to_indexkey(RelOptInfo *rel,
IndexOptInfo *index,
Expr *clause)
{
int indexkey = index->indexkeys[0];
Oid opclass = index->classlist[0];
int indexkey = index->indexkeys[0];
Oid opclass = index->classlist[0];
if (and_clause((Node *) clause))
{
@ -400,10 +404,10 @@ match_or_subclause_to_indexkey(RelOptInfo *rel,
* used as indexquals.
*
* In the simplest case this just means making a one-element list of the
* given opclause. However, if the OR subclause is an AND, we have to
* given opclause. However, if the OR subclause is an AND, we have to
* scan it to find the opclause(s) that match the index. (There should
* be at least one, if match_or_subclause_to_indexkey succeeded, but there
* could be more.) Also, we apply expand_indexqual_conditions() to convert
* could be more.) Also, we apply expand_indexqual_conditions() to convert
* any special matching opclauses to indexable operators.
*
* The passed-in clause is not changed.
@ -413,9 +417,9 @@ extract_or_indexqual_conditions(RelOptInfo *rel,
IndexOptInfo *index,
Expr *orsubclause)
{
List *quals = NIL;
int indexkey = index->indexkeys[0];
Oid opclass = index->classlist[0];
List *quals = NIL;
int indexkey = index->indexkeys[0];
Oid opclass = index->classlist[0];
if (and_clause((Node *) orsubclause))
{
@ -514,8 +518,9 @@ group_clauses_by_indexkey(RelOptInfo *rel,
clausegroup = lappend(clausegroup, rinfo);
}
/* If no clauses match this key, we're done; we don't want to
* look at keys to its right.
/*
* If no clauses match this key, we're done; we don't want to look
* at keys to its right.
*/
if (clausegroup == NIL)
break;
@ -533,7 +538,7 @@ group_clauses_by_indexkey(RelOptInfo *rel,
/*
* group_clauses_by_ikey_for_joins
* Generates a list of join clauses that can be used with an index
* Generates a list of join clauses that can be used with an index
* to scan the inner side of a nestloop join.
*
* This is much like group_clauses_by_indexkey(), but we consider both
@ -593,8 +598,9 @@ group_clauses_by_ikey_for_joins(RelOptInfo *rel,
clausegroup = lappend(clausegroup, rinfo);
}
/* If no clauses match this key, we're done; we don't want to
* look at keys to its right.
/*
* If no clauses match this key, we're done; we don't want to look
* at keys to its right.
*/
if (clausegroup == NIL)
break;
@ -607,8 +613,8 @@ group_clauses_by_ikey_for_joins(RelOptInfo *rel,
} while (!DoneMatchingIndexKeys(indexkeys, index));
/*
* if no join clause was matched then there ain't clauses for
* joins at all.
* if no join clause was matched then there ain't clauses for joins at
* all.
*/
if (!jfound)
{
@ -623,8 +629,8 @@ group_clauses_by_ikey_for_joins(RelOptInfo *rel,
/*
* match_clause_to_indexkey()
* Determines whether a restriction or join clause matches
* a key of an index.
* Determines whether a restriction or join clause matches
* a key of an index.
*
* To match, the clause:
@ -673,43 +679,46 @@ match_clause_to_indexkey(RelOptInfo *rel,
*rightop;
/* Clause must be a binary opclause. */
if (! is_opclause((Node *) clause))
if (!is_opclause((Node *) clause))
return false;
leftop = get_leftop(clause);
rightop = get_rightop(clause);
if (! leftop || ! rightop)
if (!leftop || !rightop)
return false;
if (!join)
{
/*
* Not considering joins, so check for clauses of the form:
* (indexkey operator constant) or (constant operator indexkey).
* We will accept a Param as being constant.
*/
if ((IsA(rightop, Const) || IsA(rightop, Param)) &&
if ((IsA(rightop, Const) ||IsA(rightop, Param)) &&
match_index_to_operand(indexkey, leftop, rel, index))
{
if (is_indexable_operator(clause, opclass, index->relam, true))
return true;
/*
* If we didn't find a member of the index's opclass,
* see whether it is a "special" indexable operator.
* 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))
return true;
return false;
}
if ((IsA(leftop, Const) || IsA(leftop, Param)) &&
if ((IsA(leftop, Const) ||IsA(leftop, Param)) &&
match_index_to_operand(indexkey, rightop, rel, index))
{
if (is_indexable_operator(clause, opclass, index->relam, false))
return true;
/*
* If we didn't find a member of the index's opclass,
* see whether it is a "special" indexable operator.
* 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))
@ -719,20 +728,21 @@ match_clause_to_indexkey(RelOptInfo *rel,
}
else
{
/*
* Check for an indexqual that could be handled by a nestloop join.
* We need the index key to be compared against an expression
* that uses none of the indexed relation's vars.
* Check for an indexqual that could be handled by a nestloop
* join. We need the index key to be compared against an
* expression that uses none of the indexed relation's vars.
*/
if (match_index_to_operand(indexkey, leftop, rel, index))
{
List *othervarnos = pull_varnos((Node *) rightop);
bool isIndexable;
isIndexable = ! intMember(lfirsti(rel->relids), othervarnos);
isIndexable = !intMember(lfirsti(rel->relids), othervarnos);
freeList(othervarnos);
if (isIndexable &&
is_indexable_operator(clause, opclass, index->relam, true))
is_indexable_operator(clause, opclass, index->relam, true))
return true;
}
else if (match_index_to_operand(indexkey, rightop, rel, index))
@ -740,10 +750,10 @@ match_clause_to_indexkey(RelOptInfo *rel,
List *othervarnos = pull_varnos((Node *) leftop);
bool isIndexable;
isIndexable = ! intMember(lfirsti(rel->relids), othervarnos);
isIndexable = !intMember(lfirsti(rel->relids), othervarnos);
freeList(othervarnos);
if (isIndexable &&
is_indexable_operator(clause, opclass, index->relam, false))
is_indexable_operator(clause, opclass, index->relam, false))
return true;
}
}
@ -768,7 +778,7 @@ match_clause_to_indexkey(RelOptInfo *rel,
*
* Returns the OID of the matching operator, or InvalidOid if no match.
* Note that the returned OID will be different from the one in the given
* expression if we used a binary-compatible substitution. Also note that
* expression if we used a binary-compatible substitution. Also note that
* if indexkey_on_left is FALSE (meaning we need to commute), the returned
* OID is *not* commuted; it can be plugged directly into the given clause.
*/
@ -818,13 +828,14 @@ indexable_operator(Expr *clause, Oid opclass, Oid relam,
if (HeapTupleIsValid(newop))
{
Oid new_expr_op = oprid(newop);
Oid new_expr_op = oprid(newop);
if (new_expr_op != expr_op)
{
/*
* OK, we found a binary-compatible operator of the same name;
* now does it match the index?
* OK, we found a binary-compatible operator of the same
* name; now does it match the index?
*/
if (indexkey_on_left)
commuted_op = new_expr_op;
@ -883,12 +894,12 @@ useful_for_mergejoin(RelOptInfo *rel,
{
if (restrictinfo->left_sortop == ordering[0] &&
match_index_to_operand(indexkeys[0],
get_leftop(restrictinfo->clause),
get_leftop(restrictinfo->clause),
rel, index))
return true;
if (restrictinfo->right_sortop == ordering[0] &&
match_index_to_operand(indexkeys[0],
get_rightop(restrictinfo->clause),
get_rightop(restrictinfo->clause),
rel, index))
return true;
}
@ -1127,7 +1138,7 @@ one_pred_clause_test(Expr *predicate, Node *clause)
*/
static StrategyNumber
BT_implic_table[BTMaxStrategyNumber][BTMaxStrategyNumber] = {
BT_implic_table[BTMaxStrategyNumber][BTMaxStrategyNumber] = {
{2, 2, 0, 0, 0},
{1, 2, 0, 0, 0},
{1, 2, 3, 4, 5},
@ -1346,13 +1357,13 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
* rel's restrictinfo list. Therefore, every clause in the group references
* the current rel plus the same set of other rels (except for the restrict
* clauses, which only reference the current rel). Therefore, this set
* of clauses could be used as an indexqual if the relation is scanned
* of clauses could be used as an indexqual if the relation is scanned
* as the inner side of a nestloop join when the outer side contains
* (at least) all those "other rels".
*
* XXX Actually, given that we are considering a join that requires an
* outer rel set (A,B,C), we should use all qual clauses that reference
* any subset of these rels, not just the full set or none. This is
* any subset of these rels, not just the full set or none. This is
* doable with a doubly nested loop over joininfo_list; is it worth it?
*
* Returns two parallel lists of the same length: the clause groups,
@ -1430,10 +1441,11 @@ index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
pathnode->path.pathtype = T_IndexScan;
pathnode->path.parent = rel;
/*
* There's no point in marking the path with any pathkeys, since
* it will only ever be used as the inner path of a nestloop,
* and so its ordering does not matter.
* it will only ever be used as the inner path of a nestloop, and
* so its ordering does not matter.
*/
pathnode->path.pathkeys = NIL;
@ -1441,7 +1453,8 @@ index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
/* expand special operators to indexquals the executor can handle */
indexquals = expand_indexqual_conditions(indexquals);
/* Note that we are making a pathnode for a single-scan indexscan;
/*
* Note that we are making a pathnode for a single-scan indexscan;
* therefore, both indexid and indexqual should be single-element
* lists.
*/
@ -1456,14 +1469,15 @@ index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
/*
* We must compute the estimated number of output rows for the
* indexscan. This is less than rel->rows because of the additional
* selectivity of the join clauses. Since clausegroup may contain
* both restriction and join clauses, we have to do a set union to
* get the full set of clauses that must be considered to compute
* the correct selectivity. (We can't just nconc the two lists;
* then we might have some restriction clauses appearing twice,
* which'd mislead restrictlist_selectivity into double-counting
* their selectivity.)
* indexscan. This is less than rel->rows because of the
* additional selectivity of the join clauses. Since clausegroup
* may contain both restriction and join clauses, we have to do a
* set union to get the full set of clauses that must be
* considered to compute the correct selectivity. (We can't just
* nconc the two lists; then we might have some restriction
* clauses appearing twice, which'd mislead
* restrictlist_selectivity into double-counting their
* selectivity.)
*/
pathnode->rows = rel->tuples *
restrictlist_selectivity(root,
@ -1490,7 +1504,7 @@ index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
* match_index_to_operand()
* Generalized test for a match between an index's key
* and the operand on one side of a restriction or join clause.
* Now check for functional indices as well.
* Now check for functional indices as well.
*/
static bool
match_index_to_operand(int indexkey,
@ -1500,6 +1514,7 @@ match_index_to_operand(int indexkey,
{
if (index->indproc == InvalidOid)
{
/*
* Normal index.
*/
@ -1530,7 +1545,7 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, IndexOptInfo *index)
/*
* sanity check, make sure we know what we're dealing with here.
*/
if (funcOpnd == NULL || ! IsA(funcOpnd, Expr) ||
if (funcOpnd == NULL || !IsA(funcOpnd, Expr) ||
funcOpnd->opType != FUNC_EXPR ||
funcOpnd->oper == NULL || indexKeys == NULL)
return false;
@ -1550,9 +1565,9 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, IndexOptInfo *index)
i = 0;
foreach(arg, funcargs)
{
Var *var = (Var *) lfirst(arg);
Var *var = (Var *) lfirst(arg);
if (! IsA(var, Var))
if (!IsA(var, Var))
return false;
if (indexKeys[i] == 0)
return false;
@ -1578,10 +1593,10 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, IndexOptInfo *index)
* indexscan machinery. The key idea is that these operators allow us
* to derive approximate indexscan qual clauses, such that any tuples
* that pass the operator clause itself must also satisfy the simpler
* indexscan condition(s). Then we can use the indexscan machinery
* indexscan condition(s). Then we can use the indexscan machinery
* to avoid scanning as much of the table as we'd otherwise have to,
* while applying the original operator as a qpqual condition to ensure
* we deliver only the tuples we want. (In essence, we're using a regular
* we deliver only the tuples we want. (In essence, we're using a regular
* index as if it were a lossy index.)
*
* An example of what we're doing is
@ -1630,11 +1645,12 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
char *patt;
char *prefix;
/* Currently, all known special operators require the indexkey
* on the left, but this test could be pushed into the switch statement
* if some are added that do not...
/*
* Currently, all known special operators require the indexkey on the
* left, but this test could be pushed into the switch statement if
* some are added that do not...
*/
if (! indexkey_on_left)
if (!indexkey_on_left)
return false;
/* we know these will succeed */
@ -1643,7 +1659,7 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
expr_op = ((Oper *) clause->oper)->opno;
/* again, required for all current special ops: */
if (! IsA(rightop, Const) ||
if (!IsA(rightop, Const) ||
((Const *) rightop)->constisnull)
return false;
constvalue = ((Const *) rightop)->constvalue;
@ -1657,7 +1673,8 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
/* the right-hand const is type text for all of these */
patt = textout((text *) DatumGetPointer(constvalue));
isIndexable = like_fixed_prefix(patt, &prefix) != Prefix_None;
if (prefix) pfree(prefix);
if (prefix)
pfree(prefix);
pfree(patt);
break;
@ -1668,7 +1685,8 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
/* the right-hand const is type text for all of these */
patt = textout((text *) DatumGetPointer(constvalue));
isIndexable = regex_fixed_prefix(patt, false, &prefix) != Prefix_None;
if (prefix) pfree(prefix);
if (prefix)
pfree(prefix);
pfree(patt);
break;
@ -1679,13 +1697,14 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
/* the right-hand const is type text for all of these */
patt = textout((text *) DatumGetPointer(constvalue));
isIndexable = regex_fixed_prefix(patt, true, &prefix) != Prefix_None;
if (prefix) pfree(prefix);
if (prefix)
pfree(prefix);
pfree(patt);
break;
}
/* done if the expression doesn't look indexable */
if (! isIndexable)
if (!isIndexable)
return false;
/*
@ -1699,32 +1718,32 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
case OID_TEXT_LIKE_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_class(find_operator(">=", TEXTOID), opclass, relam) ||
!op_class(find_operator("<", TEXTOID), opclass, relam))
isIndexable = false;
break;
case OID_BPCHAR_LIKE_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_class(find_operator(">=", BPCHAROID), opclass, relam) ||
!op_class(find_operator("<", BPCHAROID), opclass, relam))
isIndexable = false;
break;
case OID_VARCHAR_LIKE_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_class(find_operator(">=", VARCHAROID), opclass, relam) ||
!op_class(find_operator("<", VARCHAROID), opclass, relam))
isIndexable = false;
break;
case OID_NAME_LIKE_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_class(find_operator(">=", NAMEOID), opclass, relam) ||
!op_class(find_operator("<", NAMEOID), opclass, relam))
isIndexable = false;
break;
}
@ -1736,7 +1755,7 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
* expand_indexqual_conditions
* Given a list of (implicitly ANDed) indexqual clauses,
* expand any "special" index operators into clauses that the indexscan
* machinery will know what to do with. Clauses that were not
* machinery will know what to do with. Clauses that were not
* recognized by match_special_index_operator() must be passed through
* unchanged.
*/
@ -1749,6 +1768,7 @@ expand_indexqual_conditions(List *indexquals)
foreach(q, indexquals)
{
Expr *clause = (Expr *) lfirst(q);
/* we know these will succeed */
Var *leftop = get_leftop(clause);
Var *rightop = get_rightop(clause);
@ -1760,11 +1780,13 @@ expand_indexqual_conditions(List *indexquals)
switch (expr_op)
{
/*
* LIKE and regex operators are not members of any index opclass,
* so if we find one in an indexqual list we can assume that
* it was accepted by match_special_index_operator().
*/
/*
* LIKE and regex operators are not members of any index
* opclass, so if we find one in an indexqual list we can
* assume that it was accepted by
* match_special_index_operator().
*/
case OID_TEXT_LIKE_OP:
case OID_BPCHAR_LIKE_OP:
case OID_VARCHAR_LIKE_OP:
@ -1776,7 +1798,8 @@ expand_indexqual_conditions(List *indexquals)
resultquals = nconc(resultquals,
prefix_quals(leftop, expr_op,
prefix, pstatus));
if (prefix) pfree(prefix);
if (prefix)
pfree(prefix);
pfree(patt);
break;
@ -1791,7 +1814,8 @@ expand_indexqual_conditions(List *indexquals)
resultquals = nconc(resultquals,
prefix_quals(leftop, expr_op,
prefix, pstatus));
if (prefix) pfree(prefix);
if (prefix)
pfree(prefix);
pfree(patt);
break;
@ -1806,7 +1830,8 @@ expand_indexqual_conditions(List *indexquals)
resultquals = nconc(resultquals,
prefix_quals(leftop, expr_op,
prefix, pstatus));
if (prefix) pfree(prefix);
if (prefix)
pfree(prefix);
pfree(patt);
break;
@ -1833,7 +1858,7 @@ like_fixed_prefix(char *patt, char **prefix)
int pos,
match_pos;
*prefix = match = palloc(strlen(patt)+1);
*prefix = match = palloc(strlen(patt) + 1);
match_pos = 0;
for (pos = 0; patt[pos]; pos++)
@ -1849,14 +1874,15 @@ like_fixed_prefix(char *patt, char **prefix)
if (patt[pos] == '\0')
break;
}
/*
* NOTE: this code used to think that %% meant a literal %,
* but textlike() itself does not think that, and the SQL92
* spec doesn't say any such thing either.
* NOTE: this code used to think that %% meant a literal %, but
* textlike() itself does not think that, and the SQL92 spec
* doesn't say any such thing either.
*/
match[match_pos++] = patt[pos];
}
match[match_pos] = '\0';
/* in LIKE, an empty pattern is an exact match! */
@ -1905,7 +1931,7 @@ regex_fixed_prefix(char *patt, bool case_insensitive,
}
/* OK, allocate space for pattern */
*prefix = match = palloc(strlen(patt)+1);
*prefix = match = palloc(strlen(patt) + 1);
match_pos = 0;
/* note start at pos 1 to skip leading ^ */
@ -1916,9 +1942,11 @@ regex_fixed_prefix(char *patt, bool case_insensitive,
patt[pos] == '*' ||
patt[pos] == '[' ||
patt[pos] == '$' ||
/* XXX I suspect isalpha() is not an adequately locale-sensitive
* test for characters that can vary under case folding?
*/
/*
* XXX I suspect isalpha() is not an adequately locale-sensitive
* test for characters that can vary under case folding?
*/
(case_insensitive && isalpha(patt[pos])))
break;
if (patt[pos] == '\\')
@ -1932,9 +1960,9 @@ regex_fixed_prefix(char *patt, bool case_insensitive,
match[match_pos] = '\0';
if (patt[pos] == '$' && patt[pos+1] == '\0')
if (patt[pos] == '$' && patt[pos + 1] == '\0')
return Prefix_Exact; /* pattern specifies exact match */
if (match_pos > 0)
return Prefix_Partial;
return Prefix_None;
@ -2020,7 +2048,8 @@ prefix_quals(Var *leftop, Oid expr_op,
result = lcons(expr, NIL);
/*
* If we can create a string larger than the prefix, say "x < greaterstr".
* If we can create a string larger than the prefix, say "x <
* greaterstr".
*/
greaterstr = make_greater_string(prefix, datatype);
if (greaterstr)
@ -2058,17 +2087,20 @@ prefix_quals(Var *leftop, Oid expr_op,
* given "foos" and return "foot", will this actually be greater than "fooss"?
*/
static char *
make_greater_string(const char * str, Oid datatype)
make_greater_string(const char *str, Oid datatype)
{
char *workstr;
int len;
/* Make a modifiable copy, which will be our return value if successful */
/*
* Make a modifiable copy, which will be our return value if
* successful
*/
workstr = pstrdup((char *) str);
while ((len = strlen(workstr)) > 0)
{
unsigned char *lastchar = (unsigned char *) (workstr + len - 1);
unsigned char *lastchar = (unsigned char *) (workstr + len - 1);
/*
* Try to generate a larger string by incrementing the last byte.
@ -2077,14 +2109,15 @@ make_greater_string(const char * str, Oid datatype)
{
(*lastchar)++;
if (string_lessthan(str, workstr, datatype))
return workstr; /* Success! */
return workstr; /* Success! */
}
/*
* Truncate off the last character, which might be more than 1 byte
* in MULTIBYTE case.
* Truncate off the last character, which might be more than 1
* byte in MULTIBYTE case.
*/
#ifdef MULTIBYTE
len = pg_mbcliplen((const unsigned char *) workstr, len, len-1);
len = pg_mbcliplen((const unsigned char *) workstr, len, len - 1);
workstr[len] = '\0';
#else
*lastchar = '\0';
@ -2102,7 +2135,7 @@ make_greater_string(const char * str, Oid datatype)
/* See if there is a binary op of the given name for the given datatype */
static Oid
find_operator(const char * opname, Oid datatype)
find_operator(const char *opname, Oid datatype)
{
HeapTuple optup;
@ -2122,10 +2155,12 @@ find_operator(const char * opname, Oid datatype)
* returned value should be pfree'd if no longer needed.
*/
static Datum
string_to_datum(const char * str, Oid datatype)
string_to_datum(const char *str, Oid datatype)
{
/* We cheat a little by assuming that textin() will do for
* bpchar and varchar constants too...
/*
* We cheat a little by assuming that textin() will do for bpchar and
* varchar constants too...
*/
if (datatype == NAMEOID)
return PointerGetDatum(namein((char *) str));
@ -2137,7 +2172,7 @@ string_to_datum(const char * str, Oid datatype)
* Generate a Const node of the appropriate type from a C string.
*/
static Const *
string_to_const(const char * str, Oid datatype)
string_to_const(const char *str, Oid datatype)
{
Datum conval = string_to_datum(str, datatype);
@ -2151,7 +2186,7 @@ string_to_const(const char * str, Oid datatype)
* "<" operator function, to ensure we get the right result...
*/
static bool
string_lessthan(const char * str1, const char * str2, Oid datatype)
string_lessthan(const char *str1, const char *str2, Oid datatype)
{
Datum datum1 = string_to_datum(str1, datatype);
Datum datum2 = string_to_datum(str2, datatype);