Fix xslt_process() to ensure that it inserts a NULL terminator after the
[PostgreSQL.git] / src / backend / optimizer / path / tidpath.c
blobca9137933761df20305b5773e25baece5175701f
1 /*-------------------------------------------------------------------------
3 * tidpath.c
4 * Routines to determine which TID conditions are usable for scanning
5 * a given relation, and create TidPaths accordingly.
7 * What we are looking for here is WHERE conditions of the form
8 * "CTID = pseudoconstant", which can be implemented by just fetching
9 * the tuple directly via heap_fetch(). We can also handle OR'd conditions
10 * such as (CTID = const1) OR (CTID = const2), as well as ScalarArrayOpExpr
11 * conditions of the form CTID = ANY(pseudoconstant_array). In particular
12 * this allows
13 * WHERE ctid IN (tid1, tid2, ...)
15 * We also support "WHERE CURRENT OF cursor" conditions (CurrentOfExpr),
16 * which amount to "CTID = run-time-determined-TID". These could in
17 * theory be translated to a simple comparison of CTID to the result of
18 * a function, but in practice it works better to keep the special node
19 * representation all the way through to execution.
21 * There is currently no special support for joins involving CTID; in
22 * particular nothing corresponding to best_inner_indexscan(). Since it's
23 * not very useful to store TIDs of one table in another table, there
24 * doesn't seem to be enough use-case to justify adding a lot of code
25 * for that.
28 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
29 * Portions Copyright (c) 1994, Regents of the University of California
32 * IDENTIFICATION
33 * $PostgreSQL$
35 *-------------------------------------------------------------------------
37 #include "postgres.h"
39 #include "access/sysattr.h"
40 #include "catalog/pg_operator.h"
41 #include "catalog/pg_type.h"
42 #include "nodes/nodeFuncs.h"
43 #include "optimizer/clauses.h"
44 #include "optimizer/pathnode.h"
45 #include "optimizer/paths.h"
48 static bool IsTidEqualClause(OpExpr *node, int varno);
49 static bool IsTidEqualAnyClause(ScalarArrayOpExpr *node, int varno);
50 static List *TidQualFromExpr(Node *expr, int varno);
51 static List *TidQualFromRestrictinfo(List *restrictinfo, int varno);
55 * Check to see if an opclause is of the form
56 * CTID = pseudoconstant
57 * or
58 * pseudoconstant = CTID
60 * We check that the CTID Var belongs to relation "varno". That is probably
61 * redundant considering this is only applied to restriction clauses, but
62 * let's be safe.
64 static bool
65 IsTidEqualClause(OpExpr *node, int varno)
67 Node *arg1,
68 *arg2,
69 *other;
70 Var *var;
72 /* Operator must be tideq */
73 if (node->opno != TIDEqualOperator)
74 return false;
75 if (list_length(node->args) != 2)
76 return false;
77 arg1 = linitial(node->args);
78 arg2 = lsecond(node->args);
80 /* Look for CTID as either argument */
81 other = NULL;
82 if (arg1 && IsA(arg1, Var))
84 var = (Var *) arg1;
85 if (var->varattno == SelfItemPointerAttributeNumber &&
86 var->vartype == TIDOID &&
87 var->varno == varno &&
88 var->varlevelsup == 0)
89 other = arg2;
91 if (!other && arg2 && IsA(arg2, Var))
93 var = (Var *) arg2;
94 if (var->varattno == SelfItemPointerAttributeNumber &&
95 var->vartype == TIDOID &&
96 var->varno == varno &&
97 var->varlevelsup == 0)
98 other = arg1;
100 if (!other)
101 return false;
102 if (exprType(other) != TIDOID)
103 return false; /* probably can't happen */
105 /* The other argument must be a pseudoconstant */
106 if (!is_pseudo_constant_clause(other))
107 return false;
109 return true; /* success */
113 * Check to see if a clause is of the form
114 * CTID = ANY (pseudoconstant_array)
116 static bool
117 IsTidEqualAnyClause(ScalarArrayOpExpr *node, int varno)
119 Node *arg1,
120 *arg2;
122 /* Operator must be tideq */
123 if (node->opno != TIDEqualOperator)
124 return false;
125 if (!node->useOr)
126 return false;
127 Assert(list_length(node->args) == 2);
128 arg1 = linitial(node->args);
129 arg2 = lsecond(node->args);
131 /* CTID must be first argument */
132 if (arg1 && IsA(arg1, Var))
134 Var *var = (Var *) arg1;
136 if (var->varattno == SelfItemPointerAttributeNumber &&
137 var->vartype == TIDOID &&
138 var->varno == varno &&
139 var->varlevelsup == 0)
141 /* The other argument must be a pseudoconstant */
142 if (is_pseudo_constant_clause(arg2))
143 return true; /* success */
147 return false;
151 * Extract a set of CTID conditions from the given qual expression
153 * Returns a List of CTID qual expressions (with implicit OR semantics
154 * across the list), or NIL if there are no usable conditions.
156 * If the expression is an AND clause, we can use a CTID condition
157 * from any sub-clause. If it is an OR clause, we must be able to
158 * extract a CTID condition from every sub-clause, or we can't use it.
160 * In theory, in the AND case we could get CTID conditions from different
161 * sub-clauses, in which case we could try to pick the most efficient one.
162 * In practice, such usage seems very unlikely, so we don't bother; we
163 * just exit as soon as we find the first candidate.
165 static List *
166 TidQualFromExpr(Node *expr, int varno)
168 List *rlst = NIL;
169 ListCell *l;
171 if (is_opclause(expr))
173 /* base case: check for tideq opclause */
174 if (IsTidEqualClause((OpExpr *) expr, varno))
175 rlst = list_make1(expr);
177 else if (expr && IsA(expr, ScalarArrayOpExpr))
179 /* another base case: check for tid = ANY clause */
180 if (IsTidEqualAnyClause((ScalarArrayOpExpr *) expr, varno))
181 rlst = list_make1(expr);
183 else if (expr && IsA(expr, CurrentOfExpr))
185 /* another base case: check for CURRENT OF on this rel */
186 if (((CurrentOfExpr *) expr)->cvarno == varno)
187 rlst = list_make1(expr);
189 else if (and_clause(expr))
191 foreach(l, ((BoolExpr *) expr)->args)
193 rlst = TidQualFromExpr((Node *) lfirst(l), varno);
194 if (rlst)
195 break;
198 else if (or_clause(expr))
200 foreach(l, ((BoolExpr *) expr)->args)
202 List *frtn = TidQualFromExpr((Node *) lfirst(l), varno);
204 if (frtn)
205 rlst = list_concat(rlst, frtn);
206 else
208 if (rlst)
209 list_free(rlst);
210 rlst = NIL;
211 break;
215 return rlst;
219 * Extract a set of CTID conditions from the given restrictinfo list
221 * This is essentially identical to the AND case of TidQualFromExpr,
222 * except for the format of the input.
224 static List *
225 TidQualFromRestrictinfo(List *restrictinfo, int varno)
227 List *rlst = NIL;
228 ListCell *l;
230 foreach(l, restrictinfo)
232 RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
234 if (!IsA(rinfo, RestrictInfo))
235 continue; /* probably should never happen */
236 rlst = TidQualFromExpr((Node *) rinfo->clause, varno);
237 if (rlst)
238 break;
240 return rlst;
244 * create_tidscan_paths
245 * Create paths corresponding to direct TID scans of the given rel.
247 * Candidate paths are added to the rel's pathlist (using add_path).
249 void
250 create_tidscan_paths(PlannerInfo *root, RelOptInfo *rel)
252 List *tidquals;
254 tidquals = TidQualFromRestrictinfo(rel->baserestrictinfo, rel->relid);
256 if (tidquals)
257 add_path(rel, (Path *) create_tidscan_path(root, rel, tidquals));