indxpath.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,156 行 · 第 1/5 页
C
2,156 行
* expand_indexqual_conditions(). 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, it asks match_special_index_operator() * whether the clause should be considered an indexqual anyway. * 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, * but operators recognized by match_special_index_operator() must be * converted into one or more "regular" indexqual conditions. *---------- *//* * match_special_index_operator * Recognize restriction clauses that can be used to generate * additional indexscanable qualifications. * * 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. * Return 'true' if we can do something with it anyway. */static boolmatch_special_index_operator(Expr *clause, Oid opclass, bool indexkey_on_left){ bool isIndexable = false; Node *rightop; Oid expr_op; Const *patt; Const *prefix = NULL; Const *rest = NULL; /* * 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) return false; /* we know these will succeed */ rightop = get_rightop(clause); expr_op = ((OpExpr *) clause)->opno; /* again, required for all current special ops: */ if (!IsA(rightop, Const) || ((Const *) rightop)->constisnull) return false; patt = (Const *) rightop; switch (expr_op) { case OID_TEXT_LIKE_OP: case OID_BPCHAR_LIKE_OP: case OID_NAME_LIKE_OP: /* the right-hand const is type text for all of these */ isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like, &prefix, &rest) != Pattern_Prefix_None; break; case OID_BYTEA_LIKE_OP: isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like, &prefix, &rest) != Pattern_Prefix_None; break; case OID_TEXT_ICLIKE_OP: case OID_BPCHAR_ICLIKE_OP: case OID_NAME_ICLIKE_OP: /* the right-hand const is type text for all of these */ isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like_IC, &prefix, &rest) != Pattern_Prefix_None; break; case OID_TEXT_REGEXEQ_OP: case OID_BPCHAR_REGEXEQ_OP: case OID_NAME_REGEXEQ_OP: /* the right-hand const is type text for all of these */ isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Regex, &prefix, &rest) != Pattern_Prefix_None; break; case OID_TEXT_ICREGEXEQ_OP: case OID_BPCHAR_ICREGEXEQ_OP: case OID_NAME_ICREGEXEQ_OP: /* the right-hand const is type text for all of these */ isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC, &prefix, &rest) != Pattern_Prefix_None; break; case OID_INET_SUB_OP: case OID_INET_SUBEQ_OP: case OID_CIDR_SUB_OP: case OID_CIDR_SUBEQ_OP: isIndexable = true; break; } if (prefix) { pfree(DatumGetPointer(prefix->constvalue)); pfree(prefix); } /* done if the expression doesn't look indexable */ if (!isIndexable) return false; /* * Must also check that index's opclass 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 same operators. */ switch (expr_op) { case OID_TEXT_LIKE_OP: 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()); break; case OID_BPCHAR_LIKE_OP: case OID_BPCHAR_ICLIKE_OP: 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()); break; case OID_NAME_LIKE_OP: case OID_NAME_ICLIKE_OP: 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()); break; case OID_BYTEA_LIKE_OP: isIndexable = (opclass == BYTEA_BTREE_OPS_OID); break; case OID_INET_SUB_OP: case OID_INET_SUBEQ_OP: isIndexable = (opclass == INET_BTREE_OPS_OID); break; case OID_CIDR_SUB_OP: case OID_CIDR_SUBEQ_OP: isIndexable = (opclass == CIDR_BTREE_OPS_OID); break; } return isIndexable;}/* * 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. "Special" index operators * are expanded into clauses that the indexscan machinery will know * what to do with. * * The input list is ordered by index key, and so the output list is too. * (The latter is not depended on by any part of the planner, so far as I can * tell; but some parts of the executor do assume that the indxqual list * ultimately delivered to the executor is so ordered. One such place is * _bt_orderkeys() in the btree support. Perhaps that ought to be fixed * someday --- tgl 7/00) */List *expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups){ FastList resultquals; Oid *classes = index->classlist; if (clausegroups == NIL) return NIL; FastListInit(&resultquals); do { Oid curClass = classes[0]; List *i; foreach(i, (List *) lfirst(clausegroups)) { RestrictInfo *rinfo = (RestrictInfo *) lfirst(i); FastConc(&resultquals, expand_indexqual_condition(rinfo->clause, curClass)); } clausegroups = lnext(clausegroups); classes++; } while (clausegroups != NIL && !DoneMatchingIndexKeys(classes)); Assert(clausegroups == NIL); /* else more groups than indexkeys... */ return FastListValue(&resultquals);}/* * expand_indexqual_condition --- expand a single indexqual condition */static List *expand_indexqual_condition(Expr *clause, Oid opclass){ /* we know these will succeed */ Node *leftop = get_leftop(clause); Node *rightop = get_rightop(clause); Oid expr_op = ((OpExpr *) clause)->opno; Const *patt = (Const *) rightop; Const *prefix = NULL; Const *rest = NULL; Pattern_Prefix_Status pstatus; List *result; 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(). */ case OID_TEXT_LIKE_OP: case OID_BPCHAR_LIKE_OP: case OID_NAME_LIKE_OP: case OID_BYTEA_LIKE_OP: pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like, &prefix, &rest); result = prefix_quals(leftop, opclass, prefix, pstatus); break; case OID_TEXT_ICLIKE_OP: case OID_BPCHAR_ICLIKE_OP: case OID_NAME_ICLIKE_OP: /* 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); break; case OID_TEXT_REGEXEQ_OP: case OID_BPCHAR_REGEXEQ_OP: case OID_NAME_REGEXEQ_OP: /* 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); break; case OID_TEXT_ICREGEXEQ_OP: case OID_BPCHAR_ICREGEXEQ_OP: case OID_NAME_ICREGEXEQ_OP: /* 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); break; case OID_INET_SUB_OP: case OID_INET_SUBEQ_OP: case OID_CIDR_SUB_OP: case OID_CIDR_SUBEQ_OP: result = network_prefix_quals(leftop, expr_op, opclass, patt->constvalue); break; default: result = makeList1(clause); break; } return result;}/* * 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 * operators and operand datatypes. */static List *prefix_quals(Node *leftop, Oid opclass, Const *prefix_const, Pattern_Prefix_Status pstatus){ List *result; Oid datatype; Oid oproid; Expr *expr; Const *greaterstr; Assert(pstatus != Pattern_Prefix_None); switch (opclass) { case TEXT_BTREE_OPS_OID: case TEXT_PATTERN_BTREE_OPS_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: datatype = BPCHAROID; break; case NAME_BTREE_OPS_OID: case NAME_PATTERN_BTREE_OPS_OID: datatype = NAMEOID; break; case BYTEA_BTREE_OPS_OID: datatype = BYTEAOID; break; default: /* shouldn't get here */ elog(ERROR, "unexpected opclass: %u", opclass); return NIL; } /* * If necessary, coerce the prefix constant to the right type. The * given prefix constant is either text or bytea type. */ if (prefix_const->consttype != datatype) { char *prefix; switch (prefix_const->consttype) { case TEXTOID: prefix = DatumGetCString(DirectFunctionCall1(textout, prefix_const->constvalue)); break; case BYTEAOID: prefix = DatumGetCString(DirectFunctionCall1(byteaout, prefix_const->constvalue)); break; default: elog(ERROR, "unexpected const type: %u", prefix_const->consttype); return NIL; } prefix_const = string_to_const(prefix, datatype); pfree(prefix); } /* * If we found an exact-match pattern, generate an "=" indexqual. */ if (pstatus == Pattern_Prefix_Exact) { oproid = get_opclass_member(opclass, BTEqualStrategyNumber); if (oproid == InvalidOid) elog(ERROR, "no = operator for opclass %u", opclass); expr = make_opclause(oproid, BOOLOID, false, (Expr *) leftop, (Expr *) prefix_const); result = makeList1(expr); return result; } /* * Otherwise, we have a nonempty required prefix of the values. * * We can always say "x >= prefix". */ oproid = get_opclass_member(opclass, BTGreaterEqualStrategyNumber); if (oproid == InvalidOid) elog(ERROR, "no >= operator for opclass %u", opclass); expr = make_opclause(oproid, BOOLOID, false, (Expr *) leftop, (Expr *) prefix_const); result = makeList1(expr); /*------- * If we can create a string larger than the prefix, we can say * "x < greaterstr". *------- */ greaterstr = make_greater_string(prefix_const); if (greaterstr) { oproid = get_opclass_member(opclass, BTLessStrategyNumber); if (oproid == InvalidOid) elog(ERROR, "no < operator for opclass %u", opclass); expr = make_opclause(oproid, BOOLOID, false, (Expr *) leftop, (Expr *) greaterstr); result = lappend(result, expr); } return result;}/* * Given a leftop and a rightop, and a inet-class sup/sub operator, * generate suitable indexqual condition(s). expr_op is the original * operator, and opclass is the index opclass. */static List *network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop){ bool is_eq; Oid datatype; Oid opr1o
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?