📄 tidpath.c
字号:
/*------------------------------------------------------------------------- * * tidpath.c * Routines to determine which TID conditions are usable for scanning * a given relation, and create TidPaths accordingly. * * What we are looking for here is WHERE conditions of the form * "CTID = pseudoconstant", which can be implemented by just fetching * the tuple directly via heap_fetch(). We can also handle OR conditions * if each OR arm contains such a condition; in particular this allows * WHERE ctid IN (tid1, tid2, ...) * * There is currently no special support for joins involving CTID; in * particular nothing corresponding to best_inner_indexscan(). Since it's * not very useful to store TIDs of one table in another table, there * doesn't seem to be enough use-case to justify adding a lot of code * for that. * * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/optimizer/path/tidpath.c,v 1.25 2005/10/15 02:49:20 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/htup.h"#include "catalog/pg_operator.h"#include "catalog/pg_type.h"#include "optimizer/clauses.h"#include "optimizer/pathnode.h"#include "optimizer/paths.h"#include "parser/parse_expr.h"static Node *IsTidEqualClause(int varno, OpExpr *node);static List *TidQualFromExpr(int varno, Node *expr);static List *TidQualFromRestrictinfo(int varno, List *restrictinfo);/* * Check to see if an opclause is of the form * CTID = pseudoconstant * or * pseudoconstant = CTID * * If it is, return the pseudoconstant subnode; if not, return NULL. * * We check that the CTID Var belongs to relation "varno". That is probably * redundant considering this is only applied to restriction clauses, but * let's be safe. */static Node *IsTidEqualClause(int varno, OpExpr *node){ Node *arg1, *arg2, *other; Var *var; /* Operator must be tideq */ if (node->opno != TIDEqualOperator) return NULL; if (list_length(node->args) != 2) return NULL; arg1 = linitial(node->args); arg2 = lsecond(node->args); /* Look for CTID as either argument */ other = NULL; if (arg1 && IsA(arg1, Var)) { var = (Var *) arg1; if (var->varattno == SelfItemPointerAttributeNumber && var->vartype == TIDOID && var->varno == varno && var->varlevelsup == 0) other = arg2; } if (!other && arg2 && IsA(arg2, Var)) { var = (Var *) arg2; if (var->varattno == SelfItemPointerAttributeNumber && var->vartype == TIDOID && var->varno == varno && var->varlevelsup == 0) other = arg1; } if (!other) return NULL; if (exprType(other) != TIDOID) return NULL; /* probably can't happen */ /* The other argument must be a pseudoconstant */ if (!is_pseudo_constant_clause(other)) return NULL; return other; /* success */}/* * Extract a set of CTID conditions from the given qual expression * * If the expression is an AND clause, we can use a CTID condition * from any sub-clause. If it is an OR clause, we must be able to * extract a CTID condition from every sub-clause, or we can't use it. * * In theory, in the AND case we could get CTID conditions from different * sub-clauses, in which case we could try to pick the most efficient one. * In practice, such usage seems very unlikely, so we don't bother; we * just exit as soon as we find the first candidate. * * Returns a List of pseudoconstant TID expressions, or NIL if no match. * (Has to be a list for the OR case.) */static List *TidQualFromExpr(int varno, Node *expr){ List *rlst = NIL, *frtn; ListCell *l; Node *rnode; if (is_opclause(expr)) { /* base case: check for tideq opclause */ rnode = IsTidEqualClause(varno, (OpExpr *) expr); if (rnode) rlst = list_make1(rnode); } else if (and_clause(expr)) { foreach(l, ((BoolExpr *) expr)->args) { rlst = TidQualFromExpr(varno, (Node *) lfirst(l)); if (rlst) break; } } else if (or_clause(expr)) { foreach(l, ((BoolExpr *) expr)->args) { frtn = TidQualFromExpr(varno, (Node *) lfirst(l)); if (frtn) rlst = list_concat(rlst, frtn); else { if (rlst) list_free(rlst); rlst = NIL; break; } } } return rlst;}/* * Extract a set of CTID conditions from the given restrictinfo list * * This is essentially identical to the AND case of TidQualFromExpr, * except for the format of the input. */static List *TidQualFromRestrictinfo(int varno, List *restrictinfo){ List *rlst = NIL; ListCell *l; foreach(l, restrictinfo) { RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); if (!IsA(rinfo, RestrictInfo)) continue; /* probably should never happen */ rlst = TidQualFromExpr(varno, (Node *) rinfo->clause); if (rlst) break; } return rlst;}/* * create_tidscan_paths * Create paths corresponding to direct TID scans of the given rel. * * Candidate paths are added to the rel's pathlist (using add_path). */voidcreate_tidscan_paths(PlannerInfo *root, RelOptInfo *rel){ List *tideval; tideval = TidQualFromRestrictinfo(rel->relid, rel->baserestrictinfo); if (tideval) add_path(rel, (Path *) create_tidscan_path(root, rel, tideval));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -