← Back to Overview

src/backend/rewrite/rewriteHandler.c

Coverage: 2/2 lines (100.0%)
Total Lines
2
modified
Covered
2
100.0%
Uncovered
0
0.0%
키보드 네비게이션
AcquireRewriteLocks() lines 149-306
Modified Lines Coverage: 0/0 lines (0.0%)
LineHitsSourceCommit
149 - AcquireRewriteLocks(Query *parsetree, -
150 - bool forExecute, -
151 - bool forUpdatePushedDown) -
152 - { -
153 - ListCell *l; -
154 - int rt_index; -
155 - acquireLocksOnSubLinks_context context; -
156 - -
157 - context.for_execute = forExecute; -
158 - -
159 - /* -
160 - * First, process RTEs of the current query level. -
161 - */ -
162 - rt_index = 0; -
163 - foreach(l, parsetree->rtable) -
164 - { -
165 - RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); -
166 - Relation rel; -
167 - LOCKMODE lockmode; -
168 - List *newaliasvars; -
169 - Index curinputvarno; -
170 - RangeTblEntry *curinputrte; -
171 - ListCell *ll; -
172 - -
173 - ++rt_index; -
174 - switch (rte->rtekind) -
175 - { -
176 - case RTE_RELATION: -
177 - case RTE_GRAPH_TABLE: 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
178 - -
179 - /* -
180 - * Grab the appropriate lock type for the relation, and do not -
181 - * release it until end of transaction. This protects the -
182 - * rewriter, planner, and executor against schema changes -
183 - * mid-query. -
184 - * -
185 - * If forExecute is false, ignore rellockmode and just use -
186 - * AccessShareLock. -
187 - */ -
188 - if (!forExecute) -
189 - lockmode = AccessShareLock; -
190 - else if (forUpdatePushedDown) -
191 - { -
192 - /* Upgrade RTE's lock mode to reflect pushed-down lock */ -
193 - if (rte->rellockmode == AccessShareLock) -
194 - rte->rellockmode = RowShareLock; -
195 - lockmode = rte->rellockmode; -
196 - } -
197 - else -
198 - lockmode = rte->rellockmode; -
199 - -
200 - rel = table_open(rte->relid, lockmode); -
201 - -
202 - /* -
203 - * While we have the relation open, update the RTE's relkind, -
204 - * just in case it changed since this rule was made. -
205 - */ -
206 - rte->relkind = rel->rd_rel->relkind; -
207 - -
208 - table_close(rel, NoLock); -
209 - break; -
210 - -
211 - case RTE_JOIN: -
212 - -
213 - /* -
214 - * Scan the join's alias var list to see if any columns have -
215 - * been dropped, and if so replace those Vars with null -
216 - * pointers. -
217 - * -
218 - * Since a join has only two inputs, we can expect to see -
219 - * multiple references to the same input RTE; optimize away -
220 - * multiple fetches. -
221 - */ -
222 - newaliasvars = NIL; -
223 - curinputvarno = 0; -
224 - curinputrte = NULL; -
225 - foreach(ll, rte->joinaliasvars) -
226 - { -
227 - Var *aliasitem = (Var *) lfirst(ll); -
228 - Var *aliasvar = aliasitem; -
229 - -
230 - /* Look through any implicit coercion */ -
231 - aliasvar = (Var *) strip_implicit_coercions((Node *) aliasvar); -
232 - -
233 - /* -
234 - * If the list item isn't a simple Var, then it must -
235 - * represent a merged column, ie a USING column, and so it -
236 - * couldn't possibly be dropped, since it's referenced in -
237 - * the join clause. (Conceivably it could also be a null -
238 - * pointer already? But that's OK too.) -
239 - */ -
240 - if (aliasvar && IsA(aliasvar, Var)) -
241 - { -
242 - /* -
243 - * The elements of an alias list have to refer to -
244 - * earlier RTEs of the same rtable, because that's the -
245 - * order the planner builds things in. So we already -
246 - * processed the referenced RTE, and so it's safe to -
247 - * use get_rte_attribute_is_dropped on it. (This might -
248 - * not hold after rewriting or planning, but it's OK -
249 - * to assume here.) -
250 - */ -
251 - Assert(aliasvar->varlevelsup == 0); -
252 - if (aliasvar->varno != curinputvarno) -
253 - { -
254 - curinputvarno = aliasvar->varno; -
255 - if (curinputvarno >= rt_index) -
256 - elog(ERROR, "unexpected varno %d in JOIN RTE %d", -
257 - curinputvarno, rt_index); -
258 - curinputrte = rt_fetch(curinputvarno, -
259 - parsetree->rtable); -
260 - } -
261 - if (get_rte_attribute_is_dropped(curinputrte, -
262 - aliasvar->varattno)) -
263 - { -
264 - /* Replace the join alias item with a NULL */ -
265 - aliasitem = NULL; -
266 - } -
267 - } -
268 - newaliasvars = lappend(newaliasvars, aliasitem); -
269 - } -
270 - rte->joinaliasvars = newaliasvars; -
271 - break; -
272 - -
273 - case RTE_SUBQUERY: -
274 - -
275 - /* -
276 - * The subquery RTE itself is all right, but we have to -
277 - * recurse to process the represented subquery. -
278 - */ -
279 - AcquireRewriteLocks(rte->subquery, -
280 - forExecute, -
281 - (forUpdatePushedDown || -
282 - get_parse_rowmark(parsetree, rt_index) != NULL)); -
283 - break; -
284 - -
285 - default: -
286 - /* ignore other types of RTEs */ -
287 - break; -
288 - } -
289 - } -
290 - -
291 - /* Recurse into subqueries in WITH */ -
292 - foreach(l, parsetree->cteList) -
293 - { -
294 - CommonTableExpr *cte = (CommonTableExpr *) lfirst(l); -
295 - -
296 - AcquireRewriteLocks((Query *) cte->ctequery, forExecute, false); -
297 - } -
298 - -
299 - /* -
300 - * Recurse into sublink subqueries, too. But we already did the ones in -
301 - * the rtable and cteList. -
302 - */ -
303 - if (parsetree->hasSubLinks) -
304 - query_tree_walker(parsetree, acquireLocksOnSubLinks, &context, -
305 - QTW_IGNORE_RC_SUBQUERIES); -
306 - } -
fireRIRrules() lines 1996-2318
Modified Lines Coverage: 2/2 lines (100.0%)
LineHitsSourceCommit
1996 - fireRIRrules(Query *parsetree, List *activeRIRs) -
1997 - { -
1998 - int origResultRelation = parsetree->resultRelation; -
1999 - int rt_index; -
2000 - ListCell *lc; -
2001 - -
2002 - /* -
2003 - * Expand SEARCH and CYCLE clauses in CTEs. -
2004 - * -
2005 - * This is just a convenient place to do this, since we are already -
2006 - * looking at each Query. -
2007 - */ -
2008 - foreach(lc, parsetree->cteList) -
2009 - { -
2010 - CommonTableExpr *cte = lfirst_node(CommonTableExpr, lc); -
2011 - -
2012 - if (cte->search_clause || cte->cycle_clause) -
2013 - { -
2014 - cte = rewriteSearchAndCycle(cte); -
2015 - lfirst(lc) = cte; -
2016 - } -
2017 - } -
2018 - -
2019 - /* -
2020 - * don't try to convert this into a foreach loop, because rtable list can -
2021 - * get changed each time through... -
2022 - */ -
2023 - rt_index = 0; -
2024 - while (rt_index < list_length(parsetree->rtable)) -
2025 - { -
2026 - RangeTblEntry *rte; -
2027 - Relation rel; -
2028 - List *locks; -
2029 - RuleLock *rules; -
2030 - RewriteRule *rule; -
2031 - int i; -
2032 - -
2033 - ++rt_index; -
2034 - -
2035 - rte = rt_fetch(rt_index, parsetree->rtable); -
2036 - -
2037 - /* 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
2038 - * Convert GRAPH_TABLE clause into a subquery using relational 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
2039 - * operators. (This will change the rtekind to subquery, so it must 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
2040 - * be done before the subquery handling below.) 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
2041 - */ 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
2042 363946 if (rte->rtekind == RTE_GRAPH_TABLE) 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
2043 - { 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
2044 349 parsetree = rewriteGraphTable(parsetree, rt_index); 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
2045 - } 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
2046 - 86c14eaWIP: SQL Property Graph Queries (SQL/PGQ)
2047 - /* -
2048 - * A subquery RTE can't have associated rules, so there's nothing to -
2049 - * do to this level of the query, but we must recurse into the -
2050 - * subquery to expand any rule references in it. -
2051 - */ -
2052 - if (rte->rtekind == RTE_SUBQUERY) -
2053 - { -
2054 - rte->subquery = fireRIRrules(rte->subquery, activeRIRs); -
2055 - -
2056 - /* -
2057 - * While we are here, make sure the query is marked as having row -
2058 - * security if any of its subqueries do. -
2059 - */ -
2060 - parsetree->hasRowSecurity |= rte->subquery->hasRowSecurity; -
2061 - -
2062 - continue; -
2063 - } -
2064 - -
2065 - /* -
2066 - * Joins and other non-relation RTEs can be ignored completely. -
2067 - */ -
2068 - if (rte->rtekind != RTE_RELATION) -
2069 - continue; -
2070 - -
2071 - /* -
2072 - * Always ignore RIR rules for materialized views referenced in -
2073 - * queries. (This does not prevent refreshing MVs, since they aren't -
2074 - * referenced in their own query definitions.) -
2075 - * -
2076 - * Note: in the future we might want to allow MVs to be conditionally -
2077 - * expanded as if they were regular views, if they are not scannable. -
2078 - * In that case this test would need to be postponed till after we've -
2079 - * opened the rel, so that we could check its state. -
2080 - */ -
2081 - if (rte->relkind == RELKIND_MATVIEW) -
2082 - continue; -
2083 - -
2084 - /* -
2085 - * In INSERT ... ON CONFLICT, ignore the EXCLUDED pseudo-relation; -
2086 - * even if it points to a view, we needn't expand it, and should not -
2087 - * because we want the RTE to remain of RTE_RELATION type. Otherwise, -
2088 - * it would get changed to RTE_SUBQUERY type, which is an -
2089 - * untested/unsupported situation. -
2090 - */ -
2091 - if (parsetree->onConflict && -
2092 - rt_index == parsetree->onConflict->exclRelIndex) -
2093 - continue; -
2094 - -
2095 - /* -
2096 - * If the table is not referenced in the query, then we ignore it. -
2097 - * This prevents infinite expansion loop due to new rtable entries -
2098 - * inserted by expansion of a rule. A table is referenced if it is -
2099 - * part of the join set (a source table), or is referenced by any Var -
2100 - * nodes, or is the result table. -
2101 - */ -
2102 - if (rt_index != parsetree->resultRelation && -
2103 - !rangeTableEntry_used((Node *) parsetree, rt_index, 0)) -
2104 - continue; -
2105 - -
2106 - /* -
2107 - * Also, if this is a new result relation introduced by -
2108 - * ApplyRetrieveRule, we don't want to do anything more with it. -
2109 - */ -
2110 - if (rt_index == parsetree->resultRelation && -
2111 - rt_index != origResultRelation) -
2112 - continue; -
2113 - -
2114 - /* -
2115 - * We can use NoLock here since either the parser or -
2116 - * AcquireRewriteLocks should have locked the rel already. -
2117 - */ -
2118 - rel = table_open(rte->relid, NoLock); -
2119 - -
2120 - /* -
2121 - * Collect the RIR rules that we must apply -
2122 - */ -
2123 - rules = rel->rd_rules; -
2124 - if (rules != NULL) -
2125 - { -
2126 - locks = NIL; -
2127 - for (i = 0; i < rules->numLocks; i++) -
2128 - { -
2129 - rule = rules->rules[i]; -
2130 - if (rule->event != CMD_SELECT) -
2131 - continue; -
2132 - -
2133 - locks = lappend(locks, rule); -
2134 - } -
2135 - -
2136 - /* -
2137 - * If we found any, apply them --- but first check for recursion! -
2138 - */ -
2139 - if (locks != NIL) -
2140 - { -
2141 - ListCell *l; -
2142 - -
2143 - if (list_member_oid(activeRIRs, RelationGetRelid(rel))) -
2144 - ereport(ERROR, -
2145 - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), -
2146 - errmsg("infinite recursion detected in rules for relation \"%s\"", -
2147 - RelationGetRelationName(rel)))); -
2148 - activeRIRs = lappend_oid(activeRIRs, RelationGetRelid(rel)); -
2149 - -
2150 - foreach(l, locks) -
2151 - { -
2152 - rule = lfirst(l); -
2153 - -
2154 - parsetree = ApplyRetrieveRule(parsetree, -
2155 - rule, -
2156 - rt_index, -
2157 - rel, -
2158 - activeRIRs); -
2159 - } -
2160 - -
2161 - activeRIRs = list_delete_last(activeRIRs); -
2162 - } -
2163 - } -
2164 - -
2165 - table_close(rel, NoLock); -
2166 - } -
2167 - -
2168 - /* Recurse into subqueries in WITH */ -
2169 - foreach(lc, parsetree->cteList) -
2170 - { -
2171 - CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc); -
2172 - -
2173 - cte->ctequery = (Node *) -
2174 - fireRIRrules((Query *) cte->ctequery, activeRIRs); -
2175 - -
2176 - /* -
2177 - * While we are here, make sure the query is marked as having row -
2178 - * security if any of its CTEs do. -
2179 - */ -
2180 - parsetree->hasRowSecurity |= ((Query *) cte->ctequery)->hasRowSecurity; -
2181 - } -
2182 - -
2183 - /* -
2184 - * Recurse into sublink subqueries, too. But we already did the ones in -
2185 - * the rtable and cteList. -
2186 - */ -
2187 - if (parsetree->hasSubLinks) -
2188 - { -
2189 - fireRIRonSubLink_context context; -
2190 - -
2191 - context.activeRIRs = activeRIRs; -
2192 - context.hasRowSecurity = false; -
2193 - -
2194 - query_tree_walker(parsetree, fireRIRonSubLink, &context, -
2195 - QTW_IGNORE_RC_SUBQUERIES); -
2196 - -
2197 - /* -
2198 - * Make sure the query is marked as having row security if any of its -
2199 - * sublinks do. -
2200 - */ -
2201 - parsetree->hasRowSecurity |= context.hasRowSecurity; -
2202 - } -
2203 - -
2204 - /* -
2205 - * Apply any row-level security policies. We do this last because it -
2206 - * requires special recursion detection if the new quals have sublink -
2207 - * subqueries, and if we did it in the loop above query_tree_walker would -
2208 - * then recurse into those quals a second time. -
2209 - */ -
2210 - rt_index = 0; -
2211 - foreach(lc, parsetree->rtable) -
2212 - { -
2213 - RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); -
2214 - Relation rel; -
2215 - List *securityQuals; -
2216 - List *withCheckOptions; -
2217 - bool hasRowSecurity; -
2218 - bool hasSubLinks; -
2219 - -
2220 - ++rt_index; -
2221 - -
2222 - /* Only normal relations can have RLS policies */ -
2223 - if (rte->rtekind != RTE_RELATION || -
2224 - (rte->relkind != RELKIND_RELATION && -
2225 - rte->relkind != RELKIND_PARTITIONED_TABLE)) -
2226 - continue; -
2227 - -
2228 - rel = table_open(rte->relid, NoLock); -
2229 - -
2230 - /* -
2231 - * Fetch any new security quals that must be applied to this RTE. -
2232 - */ -
2233 - get_row_security_policies(parsetree, rte, rt_index, -
2234 - &securityQuals, &withCheckOptions, -
2235 - &hasRowSecurity, &hasSubLinks); -
2236 - -
2237 - if (securityQuals != NIL || withCheckOptions != NIL) -
2238 - { -
2239 - if (hasSubLinks) -
2240 - { -
2241 - acquireLocksOnSubLinks_context context; -
2242 - fireRIRonSubLink_context fire_context; -
2243 - -
2244 - /* -
2245 - * Recursively process the new quals, checking for infinite -
2246 - * recursion. -
2247 - */ -
2248 - if (list_member_oid(activeRIRs, RelationGetRelid(rel))) -
2249 - ereport(ERROR, -
2250 - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), -
2251 - errmsg("infinite recursion detected in policy for relation \"%s\"", -
2252 - RelationGetRelationName(rel)))); -
2253 - -
2254 - activeRIRs = lappend_oid(activeRIRs, RelationGetRelid(rel)); -
2255 - -
2256 - /* -
2257 - * get_row_security_policies just passed back securityQuals -
2258 - * and/or withCheckOptions, and there were SubLinks, make sure -
2259 - * we lock any relations which are referenced. -
2260 - * -
2261 - * These locks would normally be acquired by the parser, but -
2262 - * securityQuals and withCheckOptions are added post-parsing. -
2263 - */ -
2264 - context.for_execute = true; -
2265 - (void) acquireLocksOnSubLinks((Node *) securityQuals, &context); -
2266 - (void) acquireLocksOnSubLinks((Node *) withCheckOptions, -
2267 - &context); -
2268 - -
2269 - /* -
2270 - * Now that we have the locks on anything added by -
2271 - * get_row_security_policies, fire any RIR rules for them. -
2272 - */ -
2273 - fire_context.activeRIRs = activeRIRs; -
2274 - fire_context.hasRowSecurity = false; -
2275 - -
2276 - expression_tree_walker((Node *) securityQuals, -
2277 - fireRIRonSubLink, &fire_context); -
2278 - -
2279 - expression_tree_walker((Node *) withCheckOptions, -
2280 - fireRIRonSubLink, &fire_context); -
2281 - -
2282 - /* -
2283 - * We can ignore the value of fire_context.hasRowSecurity -
2284 - * since we only reach this code in cases where hasRowSecurity -
2285 - * is already true. -
2286 - */ -
2287 - Assert(hasRowSecurity); -
2288 - -
2289 - activeRIRs = list_delete_last(activeRIRs); -
2290 - } -
2291 - -
2292 - /* -
2293 - * Add the new security barrier quals to the start of the RTE's -
2294 - * list so that they get applied before any existing barrier quals -
2295 - * (which would have come from a security-barrier view, and should -
2296 - * get lower priority than RLS conditions on the table itself). -
2297 - */ -
2298 - rte->securityQuals = list_concat(securityQuals, -
2299 - rte->securityQuals); -
2300 - -
2301 - parsetree->withCheckOptions = list_concat(withCheckOptions, -
2302 - parsetree->withCheckOptions); -
2303 - } -
2304 - -
2305 - /* -
2306 - * Make sure the query is marked correctly if row-level security -
2307 - * applies, or if the new quals had sublinks. -
2308 - */ -
2309 - if (hasRowSecurity) -
2310 - parsetree->hasRowSecurity = true; -
2311 - if (hasSubLinks) -
2312 - parsetree->hasSubLinks = true; -
2313 - -
2314 - table_close(rel, NoLock); -
2315 - } -
2316 - -
2317 - return parsetree; -
2318 - } -