Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * execUtils.c
4 : : * miscellaneous executor utility routines
5 : : *
6 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/executor/execUtils.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : : /*
16 : : * INTERFACE ROUTINES
17 : : * CreateExecutorState Create/delete executor working state
18 : : * FreeExecutorState
19 : : * CreateExprContext
20 : : * CreateStandaloneExprContext
21 : : * FreeExprContext
22 : : * ReScanExprContext
23 : : *
24 : : * ExecAssignExprContext Common code for plan node init routines.
25 : : * etc
26 : : *
27 : : * ExecOpenScanRelation Common code for scan node init routines.
28 : : *
29 : : * ExecInitRangeTable Set up executor's range-table-related data.
30 : : *
31 : : * ExecGetRangeTableRelation Fetch Relation for a rangetable entry.
32 : : *
33 : : * executor_errposition Report syntactic position of an error.
34 : : *
35 : : * RegisterExprContextCallback Register function shutdown callback
36 : : * UnregisterExprContextCallback Deregister function shutdown callback
37 : : *
38 : : * GetAttributeByName Runtime extraction of columns from tuples.
39 : : * GetAttributeByNum
40 : : *
41 : : * NOTES
42 : : * This file has traditionally been the place to stick misc.
43 : : * executor support stuff that doesn't really go anyplace else.
44 : : */
45 : :
46 : : #include "postgres.h"
47 : :
48 : : #include "access/parallel.h"
49 : : #include "access/table.h"
50 : : #include "access/tableam.h"
51 : : #include "access/tupconvert.h"
52 : : #include "executor/executor.h"
53 : : #include "executor/nodeModifyTable.h"
54 : : #include "jit/jit.h"
55 : : #include "mb/pg_wchar.h"
56 : : #include "miscadmin.h"
57 : : #include "parser/parse_relation.h"
58 : : #include "partitioning/partdesc.h"
59 : : #include "port/pg_bitutils.h"
60 : : #include "storage/lmgr.h"
61 : : #include "utils/builtins.h"
62 : : #include "utils/memutils.h"
63 : : #include "utils/rel.h"
64 : : #include "utils/typcache.h"
65 : :
66 : :
67 : : static bool tlist_matches_tupdesc(PlanState *ps, List *tlist, int varno, TupleDesc tupdesc);
68 : : static void ShutdownExprContext(ExprContext *econtext, bool isCommit);
69 : : static RTEPermissionInfo *GetResultRTEPermissionInfo(ResultRelInfo *relinfo, EState *estate);
70 : :
71 : :
72 : : /* ----------------------------------------------------------------
73 : : * Executor state and memory management functions
74 : : * ----------------------------------------------------------------
75 : : */
76 : :
77 : : /* ----------------
78 : : * CreateExecutorState
79 : : *
80 : : * Create and initialize an EState node, which is the root of
81 : : * working storage for an entire Executor invocation.
82 : : *
83 : : * Principally, this creates the per-query memory context that will be
84 : : * used to hold all working data that lives till the end of the query.
85 : : * Note that the per-query context will become a child of the caller's
86 : : * CurrentMemoryContext.
87 : : * ----------------
88 : : */
89 : : EState *
8542 tgl@sss.pgh.pa.us 90 :CBC 772138 : CreateExecutorState(void)
91 : : {
92 : : EState *estate;
93 : : MemoryContext qcontext;
94 : : MemoryContext oldcontext;
95 : :
96 : : /*
97 : : * Create the per-query context for this Executor run.
98 : : */
99 : 772138 : qcontext = AllocSetContextCreate(CurrentMemoryContext,
100 : : "ExecutorState",
101 : : ALLOCSET_DEFAULT_SIZES);
102 : :
103 : : /*
104 : : * Make the EState node within the per-query context. This way, we don't
105 : : * need a separate pfree() operation for it at shutdown.
106 : : */
107 : 772138 : oldcontext = MemoryContextSwitchTo(qcontext);
108 : :
109 : 772138 : estate = makeNode(EState);
110 : :
111 : : /*
112 : : * Initialize all fields of the Executor State structure
113 : : */
114 : 772138 : estate->es_direction = ForwardScanDirection;
3240 115 : 772138 : estate->es_snapshot = InvalidSnapshot; /* caller must initialize this */
7906 116 : 772138 : estate->es_crosscheck_snapshot = InvalidSnapshot; /* no crosscheck */
8542 117 : 772138 : estate->es_range_table = NIL;
2770 118 : 772138 : estate->es_range_table_size = 0;
119 : 772138 : estate->es_relations = NULL;
2766 120 : 772138 : estate->es_rowmarks = NULL;
1156 121 : 772138 : estate->es_rteperminfos = NIL;
6035 122 : 772138 : estate->es_plannedstmt = NULL;
460 amitlan@postgresql.o 123 : 772138 : estate->es_part_prune_infos = NIL;
51 melanieplageman@gmai 124 :GNC 772138 : estate->es_part_prune_states = NIL;
125 : 772138 : estate->es_part_prune_results = NIL;
126 : 772138 : estate->es_unpruned_relids = NULL;
127 : :
6049 tgl@sss.pgh.pa.us 128 :CBC 772138 : estate->es_junkFilter = NULL;
129 : :
6731 130 : 772138 : estate->es_output_cid = (CommandId) 0;
131 : :
8542 132 : 772138 : estate->es_result_relations = NULL;
2030 heikki.linnakangas@i 133 : 772138 : estate->es_opened_result_relations = NIL;
3008 rhaas@postgresql.org 134 : 772138 : estate->es_tuple_routing_result_relations = NIL;
6838 tgl@sss.pgh.pa.us 135 : 772138 : estate->es_trig_target_relations = NIL;
136 : :
1244 efujita@postgresql.o 137 : 772138 : estate->es_insert_pending_result_relations = NIL;
138 : 772138 : estate->es_insert_pending_modifytables = NIL;
139 : :
8542 tgl@sss.pgh.pa.us 140 : 772138 : estate->es_param_list_info = NULL;
141 : 772138 : estate->es_param_exec_vals = NULL;
142 : :
3322 kgrittn@postgresql.o 143 : 772138 : estate->es_queryEnv = NULL;
144 : :
8542 tgl@sss.pgh.pa.us 145 : 772138 : estate->es_query_cxt = qcontext;
146 : :
6064 147 : 772138 : estate->es_tupleTable = NIL;
148 : :
8542 149 : 772138 : estate->es_processed = 0;
1125 michael@paquier.xyz 150 : 772138 : estate->es_total_processed = 0;
151 : :
5546 tgl@sss.pgh.pa.us 152 : 772138 : estate->es_top_eflags = 0;
153 : 772138 : estate->es_instrument = 0;
154 : 772138 : estate->es_finished = false;
155 : :
8542 156 : 772138 : estate->es_exprcontexts = NIL;
157 : :
7007 158 : 772138 : estate->es_subplanstates = NIL;
159 : :
5548 160 : 772138 : estate->es_auxmodifytables = NIL;
161 : :
8542 162 : 772138 : estate->es_per_tuple_exprcontext = NULL;
163 : :
3359 rhaas@postgresql.org 164 : 772138 : estate->es_sourceText = NULL;
165 : :
3112 166 : 772138 : estate->es_use_parallel_mode = false;
573 michael@paquier.xyz 167 : 772138 : estate->es_parallel_workers_to_launch = 0;
168 : 772138 : estate->es_parallel_workers_launched = 0;
169 : :
2966 andres@anarazel.de 170 : 772138 : estate->es_jit_flags = 0;
171 : 772138 : estate->es_jit = NULL;
172 : :
173 : : /*
174 : : * Return the executor state structure
175 : : */
8542 tgl@sss.pgh.pa.us 176 : 772138 : MemoryContextSwitchTo(oldcontext);
177 : :
178 : 772138 : return estate;
179 : : }
180 : :
181 : : /* ----------------
182 : : * FreeExecutorState
183 : : *
184 : : * Release an EState along with all remaining working storage.
185 : : *
186 : : * Note: this is not responsible for releasing non-memory resources, such as
187 : : * open relations or buffer pins. But it will shut down any still-active
188 : : * ExprContexts within the EState and deallocate associated JITed expressions.
189 : : * That is sufficient cleanup for situations where the EState has only been
190 : : * used for expression evaluation, and not to run a complete Plan.
191 : : *
192 : : * This can be called in any memory context ... so long as it's not one
193 : : * of the ones to be freed.
194 : : * ----------------
195 : : */
196 : : void
197 : 748624 : FreeExecutorState(EState *estate)
198 : : {
199 : : /*
200 : : * Shut down and free any remaining ExprContexts. We do this explicitly
201 : : * to ensure that any remaining shutdown callbacks get called (since they
202 : : * might need to release resources that aren't simply memory within the
203 : : * per-query memory context).
204 : : */
205 [ + + ]: 2041295 : while (estate->es_exprcontexts)
206 : : {
207 : : /*
208 : : * XXX: seems there ought to be a faster way to implement this than
209 : : * repeated list_delete(), no?
210 : : */
6135 211 : 1292671 : FreeExprContext((ExprContext *) linitial(estate->es_exprcontexts),
212 : : true);
213 : : /* FreeExprContext removed the list link for us */
214 : : }
215 : :
216 : : /* release JIT context, if allocated */
2841 andres@anarazel.de 217 [ - + ]: 748624 : if (estate->es_jit)
218 : : {
2841 andres@anarazel.de 219 :UBC 0 : jit_release_context(estate->es_jit);
220 : 0 : estate->es_jit = NULL;
221 : : }
222 : :
223 : : /* release partition directory, if allocated */
2616 rhaas@postgresql.org 224 [ + + ]:CBC 748624 : if (estate->es_partition_directory)
225 : : {
226 : 3596 : DestroyPartitionDirectory(estate->es_partition_directory);
227 : 3596 : estate->es_partition_directory = NULL;
228 : : }
229 : :
230 : : /*
231 : : * Free the per-query memory context, thereby releasing all working
232 : : * memory, including the EState node itself.
233 : : */
7007 tgl@sss.pgh.pa.us 234 : 748624 : MemoryContextDelete(estate->es_query_cxt);
10892 scrappy@hub.org 235 : 748624 : }
236 : :
237 : : /*
238 : : * Internal implementation for CreateExprContext() and CreateWorkExprContext()
239 : : * that allows control over the AllocSet parameters.
240 : : */
241 : : static ExprContext *
2219 jdavis@postgresql.or 242 : 1386861 : CreateExprContextInternal(EState *estate, Size minContextSize,
243 : : Size initBlockSize, Size maxBlockSize)
244 : : {
245 : : ExprContext *econtext;
246 : : MemoryContext oldcontext;
247 : :
248 : : /* Create the ExprContext node within the per-query memory context */
8542 tgl@sss.pgh.pa.us 249 : 1386861 : oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
250 : :
251 : 1386861 : econtext = makeNode(ExprContext);
252 : :
253 : : /* Initialize fields of ExprContext */
254 : 1386861 : econtext->ecxt_scantuple = NULL;
9428 255 : 1386861 : econtext->ecxt_innertuple = NULL;
256 : 1386861 : econtext->ecxt_outertuple = NULL;
257 : :
8542 258 : 1386861 : econtext->ecxt_per_query_memory = estate->es_query_cxt;
259 : :
260 : : /*
261 : : * Create working memory for expression evaluation in this context.
262 : : */
9428 263 : 1386861 : econtext->ecxt_per_tuple_memory =
8542 264 : 1386861 : AllocSetContextCreate(estate->es_query_cxt,
265 : : "ExprContext",
266 : : minContextSize,
267 : : initBlockSize,
268 : : maxBlockSize);
269 : :
270 : 1386861 : econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
271 : 1386861 : econtext->ecxt_param_list_info = estate->es_param_list_info;
272 : :
9428 273 : 1386861 : econtext->ecxt_aggvalues = NULL;
274 : 1386861 : econtext->ecxt_aggnulls = NULL;
275 : :
8084 276 : 1386861 : econtext->caseValue_datum = (Datum) 0;
277 : 1386861 : econtext->caseValue_isNull = true;
278 : :
8542 279 : 1386861 : econtext->domainValue_datum = (Datum) 0;
280 : 1386861 : econtext->domainValue_isNull = true;
281 : :
282 : 1386861 : econtext->ecxt_estate = estate;
283 : :
8759 284 : 1386861 : econtext->ecxt_callbacks = NULL;
285 : :
286 : : /*
287 : : * Link the ExprContext into the EState to ensure it is shut down when the
288 : : * EState is freed. Because we use lcons(), shutdowns will occur in
289 : : * reverse order of creation, which may not be essential but can't hurt.
290 : : */
8542 291 : 1386861 : estate->es_exprcontexts = lcons(econtext, estate->es_exprcontexts);
292 : :
293 : 1386861 : MemoryContextSwitchTo(oldcontext);
294 : :
9428 295 : 1386861 : return econtext;
296 : : }
297 : :
298 : : /* ----------------
299 : : * CreateExprContext
300 : : *
301 : : * Create a context for expression evaluation within an EState.
302 : : *
303 : : * An executor run may require multiple ExprContexts (we usually make one
304 : : * for each Plan node, and a separate one for per-output-tuple processing
305 : : * such as constraint checking). Each ExprContext has its own "per-tuple"
306 : : * memory context.
307 : : *
308 : : * Note we make no assumption about the caller's memory context.
309 : : * ----------------
310 : : */
311 : : ExprContext *
2219 jdavis@postgresql.or 312 : 1382000 : CreateExprContext(EState *estate)
313 : : {
314 : 1382000 : return CreateExprContextInternal(estate, ALLOCSET_DEFAULT_SIZES);
315 : : }
316 : :
317 : :
318 : : /* ----------------
319 : : * CreateWorkExprContext
320 : : *
321 : : * Like CreateExprContext, but specifies the AllocSet sizes to be reasonable
322 : : * in proportion to work_mem. If the maximum block allocation size is too
323 : : * large, it's easy to skip right past work_mem with a single allocation.
324 : : * ----------------
325 : : */
326 : : ExprContext *
327 : 4861 : CreateWorkExprContext(EState *estate)
328 : : {
329 : : Size maxBlockSize;
330 : :
407 331 : 4861 : maxBlockSize = pg_prevpower2_size_t(work_mem * (Size) 1024 / 16);
332 : :
333 : : /* But no bigger than ALLOCSET_DEFAULT_MAXSIZE */
334 : 4861 : maxBlockSize = Min(maxBlockSize, ALLOCSET_DEFAULT_MAXSIZE);
335 : :
336 : : /* and no smaller than ALLOCSET_DEFAULT_INITSIZE */
337 : 4861 : maxBlockSize = Max(maxBlockSize, ALLOCSET_DEFAULT_INITSIZE);
338 : :
339 : 4861 : return CreateExprContextInternal(estate, ALLOCSET_DEFAULT_MINSIZE,
340 : : ALLOCSET_DEFAULT_INITSIZE, maxBlockSize);
341 : : }
342 : :
343 : : /* ----------------
344 : : * CreateStandaloneExprContext
345 : : *
346 : : * Create a context for standalone expression evaluation.
347 : : *
348 : : * An ExprContext made this way can be used for evaluation of expressions
349 : : * that contain no Params, subplans, or Var references (it might work to
350 : : * put tuple references into the scantuple field, but it seems unwise).
351 : : *
352 : : * The ExprContext struct is allocated in the caller's current memory
353 : : * context, which also becomes its "per query" context.
354 : : *
355 : : * It is caller's responsibility to free the ExprContext when done,
356 : : * or at least ensure that any shutdown callbacks have been called
357 : : * (ReScanExprContext() is suitable). Otherwise, non-memory resources
358 : : * might be leaked.
359 : : * ----------------
360 : : */
361 : : ExprContext *
7214 tgl@sss.pgh.pa.us 362 : 6769 : CreateStandaloneExprContext(void)
363 : : {
364 : : ExprContext *econtext;
365 : :
366 : : /* Create the ExprContext node within the caller's memory context */
367 : 6769 : econtext = makeNode(ExprContext);
368 : :
369 : : /* Initialize fields of ExprContext */
370 : 6769 : econtext->ecxt_scantuple = NULL;
371 : 6769 : econtext->ecxt_innertuple = NULL;
372 : 6769 : econtext->ecxt_outertuple = NULL;
373 : :
374 : 6769 : econtext->ecxt_per_query_memory = CurrentMemoryContext;
375 : :
376 : : /*
377 : : * Create working memory for expression evaluation in this context.
378 : : */
379 : 6769 : econtext->ecxt_per_tuple_memory =
380 : 6769 : AllocSetContextCreate(CurrentMemoryContext,
381 : : "ExprContext",
382 : : ALLOCSET_DEFAULT_SIZES);
383 : :
384 : 6769 : econtext->ecxt_param_exec_vals = NULL;
385 : 6769 : econtext->ecxt_param_list_info = NULL;
386 : :
387 : 6769 : econtext->ecxt_aggvalues = NULL;
388 : 6769 : econtext->ecxt_aggnulls = NULL;
389 : :
390 : 6769 : econtext->caseValue_datum = (Datum) 0;
391 : 6769 : econtext->caseValue_isNull = true;
392 : :
393 : 6769 : econtext->domainValue_datum = (Datum) 0;
394 : 6769 : econtext->domainValue_isNull = true;
395 : :
396 : 6769 : econtext->ecxt_estate = NULL;
397 : :
398 : 6769 : econtext->ecxt_callbacks = NULL;
399 : :
400 : 6769 : return econtext;
401 : : }
402 : :
403 : : /* ----------------
404 : : * FreeExprContext
405 : : *
406 : : * Free an expression context, including calling any remaining
407 : : * shutdown callbacks.
408 : : *
409 : : * Since we free the temporary context used for expression evaluation,
410 : : * any previously computed pass-by-reference expression result will go away!
411 : : *
412 : : * If isCommit is false, we are being called in error cleanup, and should
413 : : * not call callbacks but only release memory. (It might be better to call
414 : : * the callbacks and pass the isCommit flag to them, but that would require
415 : : * more invasive code changes than currently seems justified.)
416 : : *
417 : : * Note we make no assumption about the caller's memory context.
418 : : * ----------------
419 : : */
420 : : void
6135 421 : 1358603 : FreeExprContext(ExprContext *econtext, bool isCommit)
422 : : {
423 : : EState *estate;
424 : :
425 : : /* Call any registered callbacks */
426 : 1358603 : ShutdownExprContext(econtext, isCommit);
427 : : /* And clean up the memory used */
9428 428 : 1358603 : MemoryContextDelete(econtext->ecxt_per_tuple_memory);
429 : : /* Unlink self from owning EState, if any */
8542 430 : 1358603 : estate = econtext->ecxt_estate;
7214 431 [ + - ]: 1358603 : if (estate)
432 : 1358603 : estate->es_exprcontexts = list_delete_ptr(estate->es_exprcontexts,
433 : : econtext);
434 : : /* And delete the ExprContext node */
9428 435 : 1358603 : pfree(econtext);
10892 scrappy@hub.org 436 : 1358603 : }
437 : :
438 : : /*
439 : : * ReScanExprContext
440 : : *
441 : : * Reset an expression context in preparation for a rescan of its
442 : : * plan node. This requires calling any registered shutdown callbacks,
443 : : * since any partially complete set-returning-functions must be canceled.
444 : : *
445 : : * Note we make no assumption about the caller's memory context.
446 : : */
447 : : void
8174 tgl@sss.pgh.pa.us 448 : 2887313 : ReScanExprContext(ExprContext *econtext)
449 : : {
450 : : /* Call any registered callbacks */
6135 451 : 2887313 : ShutdownExprContext(econtext, true);
452 : : /* And clean up the memory used */
8174 453 : 2887313 : MemoryContextReset(econtext->ecxt_per_tuple_memory);
454 : 2887313 : }
455 : :
456 : : /*
457 : : * Build a per-output-tuple ExprContext for an EState.
458 : : *
459 : : * This is normally invoked via GetPerTupleExprContext() macro,
460 : : * not directly.
461 : : */
462 : : ExprContext *
9234 463 : 427627 : MakePerTupleExprContext(EState *estate)
464 : : {
465 [ + - ]: 427627 : if (estate->es_per_tuple_exprcontext == NULL)
8542 466 : 427627 : estate->es_per_tuple_exprcontext = CreateExprContext(estate);
467 : :
9234 468 : 427627 : return estate->es_per_tuple_exprcontext;
469 : : }
470 : :
471 : :
472 : : /* ----------------------------------------------------------------
473 : : * miscellaneous node-init support functions
474 : : *
475 : : * Note: all of these are expected to be called with CurrentMemoryContext
476 : : * equal to the per-query memory context.
477 : : * ----------------------------------------------------------------
478 : : */
479 : :
480 : : /* ----------------
481 : : * ExecAssignExprContext
482 : : *
483 : : * This initializes the ps_ExprContext field. It is only necessary
484 : : * to do this for nodes which use ExecQual or ExecProject
485 : : * because those routines require an econtext. Other nodes that
486 : : * don't have to evaluate expressions don't need to do this.
487 : : * ----------------
488 : : */
489 : : void
8306 bruce@momjian.us 490 : 874260 : ExecAssignExprContext(EState *estate, PlanState *planstate)
491 : : {
8542 tgl@sss.pgh.pa.us 492 : 874260 : planstate->ps_ExprContext = CreateExprContext(estate);
493 : 874260 : }
494 : :
495 : : /* ----------------
496 : : * ExecGetResultType
497 : : * ----------------
498 : : */
499 : : TupleDesc
8306 bruce@momjian.us 500 : 1084885 : ExecGetResultType(PlanState *planstate)
501 : : {
2734 andres@anarazel.de 502 : 1084885 : return planstate->ps_ResultTupleDesc;
503 : : }
504 : :
505 : : /*
506 : : * ExecGetResultSlotOps - information about node's type of result slot
507 : : */
508 : : const TupleTableSlotOps *
2728 509 : 501870 : ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
510 : : {
511 [ + - + + ]: 501870 : if (planstate->resultopsset && planstate->resultops)
512 : : {
513 [ + + ]: 500732 : if (isfixed)
514 : 453452 : *isfixed = planstate->resultopsfixed;
515 : 500732 : return planstate->resultops;
516 : : }
517 : :
518 [ + + ]: 1138 : if (isfixed)
519 : : {
520 [ + - ]: 1116 : if (planstate->resultopsset)
521 : 1116 : *isfixed = planstate->resultopsfixed;
2728 andres@anarazel.de 522 [ # # ]:UBC 0 : else if (planstate->ps_ResultTupleSlot)
523 : 0 : *isfixed = TTS_FIXED(planstate->ps_ResultTupleSlot);
524 : : else
525 : 0 : *isfixed = false;
526 : : }
527 : :
2728 andres@anarazel.de 528 [ + - ]:CBC 1138 : if (!planstate->ps_ResultTupleSlot)
529 : 1138 : return &TTSOpsVirtual;
530 : :
2728 andres@anarazel.de 531 :UBC 0 : return planstate->ps_ResultTupleSlot->tts_ops;
532 : : }
533 : :
534 : : /*
535 : : * ExecGetCommonSlotOps - identify common result slot type, if any
536 : : *
537 : : * If all the given PlanState nodes return the same fixed tuple slot type,
538 : : * return the slot ops struct for that slot type. Else, return NULL.
539 : : */
540 : : const TupleTableSlotOps *
502 tgl@sss.pgh.pa.us 541 :CBC 13569 : ExecGetCommonSlotOps(PlanState **planstates, int nplans)
542 : : {
543 : : const TupleTableSlotOps *result;
544 : : bool isfixed;
545 : :
546 [ + + ]: 13569 : if (nplans <= 0)
547 : 68 : return NULL;
548 : 13501 : result = ExecGetResultSlotOps(planstates[0], &isfixed);
549 [ + + ]: 13501 : if (!isfixed)
550 : 60 : return NULL;
551 [ + + ]: 40521 : for (int i = 1; i < nplans; i++)
552 : : {
553 : : const TupleTableSlotOps *thisops;
554 : :
555 : 27733 : thisops = ExecGetResultSlotOps(planstates[i], &isfixed);
556 [ + + ]: 27733 : if (!isfixed)
557 : 27 : return NULL;
558 [ + + ]: 27706 : if (result != thisops)
559 : 626 : return NULL;
560 : : }
561 : 12788 : return result;
562 : : }
563 : :
564 : : /*
565 : : * ExecGetCommonChildSlotOps - as above, for the PlanState's standard children
566 : : */
567 : : const TupleTableSlotOps *
568 : 583 : ExecGetCommonChildSlotOps(PlanState *ps)
569 : : {
570 : : PlanState *planstates[2];
571 : :
572 : 583 : planstates[0] = outerPlanState(ps);
573 : 583 : planstates[1] = innerPlanState(ps);
574 : 583 : return ExecGetCommonSlotOps(planstates, 2);
575 : : }
576 : :
577 : :
578 : : /* ----------------
579 : : * ExecAssignProjectionInfo
580 : : *
581 : : * forms the projection information from the node's targetlist
582 : : *
583 : : * Notes for inputDesc are same as for ExecBuildProjectionInfo: supply it
584 : : * for a relation-scan node, can pass NULL for upper-level nodes
585 : : * ----------------
586 : : */
587 : : void
7032 588 : 486381 : ExecAssignProjectionInfo(PlanState *planstate,
589 : : TupleDesc inputDesc)
590 : : {
8514 591 : 486341 : planstate->ps_ProjInfo =
3339 andres@anarazel.de 592 : 486381 : ExecBuildProjectionInfo(planstate->plan->targetlist,
593 : : planstate->ps_ExprContext,
594 : : planstate->ps_ResultTupleSlot,
595 : : planstate,
596 : : inputDesc);
10892 scrappy@hub.org 597 : 486341 : }
598 : :
599 : :
600 : : /* ----------------
601 : : * ExecConditionalAssignProjectionInfo
602 : : *
603 : : * as ExecAssignProjectionInfo, but store NULL rather than building projection
604 : : * info if no projection is required
605 : : * ----------------
606 : : */
607 : : void
3083 rhaas@postgresql.org 608 : 376440 : ExecConditionalAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc,
609 : : int varno)
610 : : {
611 [ + + ]: 376440 : if (tlist_matches_tupdesc(planstate,
612 : 376440 : planstate->plan->targetlist,
613 : : varno,
614 : : inputDesc))
615 : : {
616 : 196267 : planstate->ps_ProjInfo = NULL;
2728 andres@anarazel.de 617 : 196267 : planstate->resultopsset = planstate->scanopsset;
618 : 196267 : planstate->resultopsfixed = planstate->scanopsfixed;
619 : 196267 : planstate->resultops = planstate->scanops;
620 : : }
621 : : else
622 : : {
2734 623 [ + - ]: 180173 : if (!planstate->ps_ResultTupleSlot)
624 : : {
2728 625 : 180173 : ExecInitResultSlot(planstate, &TTSOpsVirtual);
626 : 180173 : planstate->resultops = &TTSOpsVirtual;
627 : 180173 : planstate->resultopsfixed = true;
628 : 180173 : planstate->resultopsset = true;
629 : : }
3083 rhaas@postgresql.org 630 : 180173 : ExecAssignProjectionInfo(planstate, inputDesc);
631 : : }
632 : 376440 : }
633 : :
634 : : static bool
1693 tgl@sss.pgh.pa.us 635 : 376440 : tlist_matches_tupdesc(PlanState *ps, List *tlist, int varno, TupleDesc tupdesc)
636 : : {
3083 rhaas@postgresql.org 637 : 376440 : int numattrs = tupdesc->natts;
638 : : int attrno;
639 : 376440 : ListCell *tlist_item = list_head(tlist);
640 : :
641 : : /* Check the tlist attributes */
642 [ + + ]: 2527958 : for (attrno = 1; attrno <= numattrs; attrno++)
643 : : {
644 : 2323825 : Form_pg_attribute att_tup = TupleDescAttr(tupdesc, attrno - 1);
645 : : Var *var;
646 : :
647 [ + + ]: 2323825 : if (tlist_item == NULL)
648 : 23704 : return false; /* tlist too short */
649 : 2300121 : var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr;
650 [ + - + + ]: 2300121 : if (!var || !IsA(var, Var))
651 : 44776 : return false; /* tlist item not a Var */
652 : : /* if these Asserts fail, planner messed up */
653 [ - + ]: 2255345 : Assert(var->varno == varno);
654 [ - + ]: 2255345 : Assert(var->varlevelsup == 0);
655 [ + + ]: 2255345 : if (var->varattno != attrno)
656 : 103609 : return false; /* out of order */
657 [ - + ]: 2151736 : if (att_tup->attisdropped)
3083 rhaas@postgresql.org 658 :UBC 0 : return false; /* table contains dropped columns */
2960 andrew@dunslane.net 659 [ + + ]:CBC 2151736 : if (att_tup->atthasmissing)
660 : 214 : return false; /* table contains cols with missing values */
661 : :
662 : : /*
663 : : * Note: usually the Var's type should match the tupdesc exactly, but
664 : : * in situations involving unions of columns that have different
665 : : * typmods, the Var may have come from above the union and hence have
666 : : * typmod -1. This is a legitimate situation since the Var still
667 : : * describes the column, just not as exactly as the tupdesc does. We
668 : : * could change the planner to prevent it, but it'd then insert
669 : : * projection steps just to convert from specific typmod to typmod -1,
670 : : * which is pretty silly.
671 : : */
3083 rhaas@postgresql.org 672 [ + + ]: 2151522 : if (var->vartype != att_tup->atttypid ||
673 [ + + ]: 2151518 : (var->vartypmod != att_tup->atttypmod &&
674 [ - + ]: 4 : var->vartypmod != -1))
675 : 4 : return false; /* type mismatch */
676 : :
2486 tgl@sss.pgh.pa.us 677 : 2151518 : tlist_item = lnext(tlist, tlist_item);
678 : : }
679 : :
3083 rhaas@postgresql.org 680 [ + + ]: 204133 : if (tlist_item)
681 : 7866 : return false; /* tlist too long */
682 : :
683 : 196267 : return true;
684 : : }
685 : :
686 : :
687 : : /* ----------------------------------------------------------------
688 : : * Scan node support
689 : : * ----------------------------------------------------------------
690 : : */
691 : :
692 : : /* ----------------
693 : : * ExecAssignScanType
694 : : * ----------------
695 : : */
696 : : void
7263 tgl@sss.pgh.pa.us 697 : 581 : ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc)
698 : : {
8552 699 : 581 : TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;
700 : :
7263 701 : 581 : ExecSetSlotDescriptor(slot, tupDesc);
10892 scrappy@hub.org 702 : 581 : }
703 : :
704 : : /* ----------------
705 : : * ExecCreateScanSlotFromOuterPlan
706 : : * ----------------
707 : : */
708 : : void
2728 andres@anarazel.de 709 : 97415 : ExecCreateScanSlotFromOuterPlan(EState *estate,
710 : : ScanState *scanstate,
711 : : const TupleTableSlotOps *tts_ops)
712 : : {
713 : : PlanState *outerPlan;
714 : : TupleDesc tupDesc;
715 : :
8552 tgl@sss.pgh.pa.us 716 : 97415 : outerPlan = outerPlanState(scanstate);
8401 717 : 97415 : tupDesc = ExecGetResultType(outerPlan);
718 : :
50 drowley@postgresql.o 719 :GNC 97415 : ExecInitScanTupleSlot(estate, scanstate, tupDesc, tts_ops, 0);
10892 scrappy@hub.org 720 :CBC 97415 : }
721 : :
722 : : /* ----------------------------------------------------------------
723 : : * ExecRelationIsTargetRelation
724 : : *
725 : : * Detect whether a relation (identified by rangetable index)
726 : : * is one of the target relations of the query.
727 : : *
728 : : * Note: This is currently no longer used in core. We keep it around
729 : : * because FDWs may wish to use it to determine if their foreign table
730 : : * is a target relation.
731 : : * ----------------------------------------------------------------
732 : : */
733 : : bool
7458 tgl@sss.pgh.pa.us 734 :UBC 0 : ExecRelationIsTargetRelation(EState *estate, Index scanrelid)
735 : : {
36 melanieplageman@gmai 736 :UNC 0 : return bms_is_member(scanrelid, estate->es_plannedstmt->resultRelationRelids);
737 : : }
738 : :
739 : : /*
740 : : * Return true if the scan node's relation is not modified by the query.
741 : : *
742 : : * This is not perfectly accurate. INSERT ... SELECT from the same table does
743 : : * not add the scan relation to resultRelationRelids, so it will be reported
744 : : * as read-only even though the query modifies it.
745 : : *
746 : : * Conversely, when any relation in the query has a modifying row mark, all
747 : : * other relations get a ROW_MARK_REFERENCE, causing them to be reported as
748 : : * not read-only even though they may be.
749 : : */
750 : : bool
36 melanieplageman@gmai 751 :GNC 237758 : ScanRelIsReadOnly(ScanState *ss)
752 : : {
753 : 237758 : Index scanrelid = ((Scan *) ss->ps.plan)->scanrelid;
754 : 237758 : PlannedStmt *pstmt = ss->ps.state->es_plannedstmt;
755 : :
756 [ + + ]: 456795 : return !bms_is_member(scanrelid, pstmt->resultRelationRelids) &&
757 [ + + ]: 219037 : !bms_is_member(scanrelid, pstmt->rowMarkRelids);
758 : : }
759 : :
760 : : /* ----------------------------------------------------------------
761 : : * ExecOpenScanRelation
762 : : *
763 : : * Open the heap relation to be scanned by a base-level scan plan node.
764 : : * This should be called during the node's ExecInit routine.
765 : : * ----------------------------------------------------------------
766 : : */
767 : : Relation
4756 tgl@sss.pgh.pa.us 768 :CBC 305510 : ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
769 : : {
770 : : Relation rel;
771 : :
772 : : /* Open the relation. */
412 amitlan@postgresql.o 773 : 305510 : rel = ExecGetRangeTableRelation(estate, scanrelid, false);
774 : :
775 : : /*
776 : : * Complain if we're attempting a scan of an unscannable relation, except
777 : : * when the query won't actually be run. This is a slightly klugy place
778 : : * to do this, perhaps, but there is no better place.
779 : : */
4756 tgl@sss.pgh.pa.us 780 [ + + ]: 305510 : if ((eflags & (EXEC_FLAG_EXPLAIN_ONLY | EXEC_FLAG_WITH_NO_DATA)) == 0 &&
781 [ + + ]: 282570 : !RelationIsScannable(rel))
782 [ + - ]: 8 : ereport(ERROR,
783 : : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
784 : : errmsg("materialized view \"%s\" has not been populated",
785 : : RelationGetRelationName(rel)),
786 : : errhint("Use the REFRESH MATERIALIZED VIEW command.")));
787 : :
788 : 305502 : return rel;
789 : : }
790 : :
791 : : /*
792 : : * ExecInitRangeTable
793 : : * Set up executor's range-table-related data
794 : : *
795 : : * In addition to the range table proper, initialize arrays that are
796 : : * indexed by rangetable index.
797 : : */
798 : : void
452 amitlan@postgresql.o 799 : 530402 : ExecInitRangeTable(EState *estate, List *rangeTable, List *permInfos,
800 : : Bitmapset *unpruned_relids)
801 : : {
802 : : /* Remember the range table List as-is */
2770 tgl@sss.pgh.pa.us 803 : 530402 : estate->es_range_table = rangeTable;
804 : :
805 : : /* ... and the RTEPermissionInfo List too */
1156 806 : 530402 : estate->es_rteperminfos = permInfos;
807 : :
808 : : /* Set size of associated arrays */
2770 809 : 530402 : estate->es_range_table_size = list_length(rangeTable);
810 : :
811 : : /*
812 : : * Initialize the bitmapset of RT indexes (es_unpruned_relids)
813 : : * representing relations that will be scanned during execution. This set
814 : : * is initially populated by the caller and may be extended later by
815 : : * ExecDoInitialPruning() to include RT indexes of unpruned leaf
816 : : * partitions.
817 : : */
452 amitlan@postgresql.o 818 : 530402 : estate->es_unpruned_relids = unpruned_relids;
819 : :
820 : : /*
821 : : * Allocate an array to store an open Relation corresponding to each
822 : : * rangetable entry, and initialize entries to NULL. Relations are opened
823 : : * and stored here as needed.
824 : : */
2770 tgl@sss.pgh.pa.us 825 : 530402 : estate->es_relations = (Relation *)
826 : 530402 : palloc0(estate->es_range_table_size * sizeof(Relation));
827 : :
828 : : /*
829 : : * es_result_relations and es_rowmarks are also parallel to
830 : : * es_range_table, but are allocated only if needed.
831 : : */
2030 heikki.linnakangas@i 832 : 530402 : estate->es_result_relations = NULL;
2766 tgl@sss.pgh.pa.us 833 : 530402 : estate->es_rowmarks = NULL;
2770 834 : 530402 : }
835 : :
836 : : /*
837 : : * ExecGetRangeTableRelation
838 : : * Open the Relation for a range table entry, if not already done
839 : : *
840 : : * The Relations will be closed in ExecEndPlan().
841 : : *
842 : : * If isResultRel is true, the relation is being used as a result relation.
843 : : * Such a relation might have been pruned, which is OK for result relations,
844 : : * but not for scan relations; see the details in ExecInitModifyTable(). If
845 : : * isResultRel is false, the caller must ensure that 'rti' refers to an
846 : : * unpruned relation (i.e., it is a member of estate->es_unpruned_relids)
847 : : * before calling this function. Attempting to open a pruned relation for
848 : : * scanning will result in an error.
849 : : */
850 : : Relation
412 amitlan@postgresql.o 851 : 391727 : ExecGetRangeTableRelation(EState *estate, Index rti, bool isResultRel)
852 : : {
853 : : Relation rel;
854 : :
2770 tgl@sss.pgh.pa.us 855 [ + - - + ]: 391727 : Assert(rti > 0 && rti <= estate->es_range_table_size);
856 : :
412 amitlan@postgresql.o 857 [ + + - + ]: 391727 : if (!isResultRel && !bms_is_member(rti, estate->es_unpruned_relids))
439 amitlan@postgresql.o 858 [ # # ]:UBC 0 : elog(ERROR, "trying to open a pruned relation");
859 : :
2770 tgl@sss.pgh.pa.us 860 :CBC 391727 : rel = estate->es_relations[rti - 1];
861 [ + + ]: 391727 : if (rel == NULL)
862 : : {
863 : : /* First time through, so open the relation */
864 : 363679 : RangeTblEntry *rte = exec_rt_fetch(rti, estate);
865 : :
866 [ - + ]: 363679 : Assert(rte->rtekind == RTE_RELATION);
867 : :
2768 868 [ + + ]: 363679 : if (!IsParallelWorker())
869 : : {
870 : : /*
871 : : * In a normal query, we should already have the appropriate lock,
872 : : * but verify that through an Assert. Since there's already an
873 : : * Assert inside table_open that insists on holding some lock, it
874 : : * seems sufficient to check this only when rellockmode is higher
875 : : * than the minimum.
876 : : */
2661 andres@anarazel.de 877 : 358829 : rel = table_open(rte->relid, NoLock);
2768 tgl@sss.pgh.pa.us 878 [ + + - + ]: 358829 : Assert(rte->rellockmode == AccessShareLock ||
879 : : CheckRelationLockedByMe(rel, rte->rellockmode, false));
880 : : }
881 : : else
882 : : {
883 : : /*
884 : : * If we are a parallel worker, we need to obtain our own local
885 : : * lock on the relation. This ensures sane behavior in case the
886 : : * parent process exits before we do.
887 : : */
2661 andres@anarazel.de 888 : 4850 : rel = table_open(rte->relid, rte->rellockmode);
889 : : }
890 : :
2768 tgl@sss.pgh.pa.us 891 : 363679 : estate->es_relations[rti - 1] = rel;
892 : : }
893 : :
2770 894 : 391727 : return rel;
895 : : }
896 : :
897 : : /*
898 : : * ExecInitResultRelation
899 : : * Open relation given by the passed-in RT index and fill its
900 : : * ResultRelInfo node
901 : : *
902 : : * Here, we also save the ResultRelInfo in estate->es_result_relations array
903 : : * such that it can be accessed later using the RT index.
904 : : */
905 : : void
2030 heikki.linnakangas@i 906 : 77337 : ExecInitResultRelation(EState *estate, ResultRelInfo *resultRelInfo,
907 : : Index rti)
908 : : {
909 : : Relation resultRelationDesc;
910 : :
412 amitlan@postgresql.o 911 : 77337 : resultRelationDesc = ExecGetRangeTableRelation(estate, rti, true);
2030 heikki.linnakangas@i 912 : 77337 : InitResultRelInfo(resultRelInfo,
913 : : resultRelationDesc,
914 : : rti,
915 : : NULL,
916 : : estate->es_instrument);
917 : :
918 [ + + ]: 77337 : if (estate->es_result_relations == NULL)
919 : 73702 : estate->es_result_relations = (ResultRelInfo **)
920 : 73702 : palloc0(estate->es_range_table_size * sizeof(ResultRelInfo *));
921 : 77337 : estate->es_result_relations[rti - 1] = resultRelInfo;
922 : :
923 : : /*
924 : : * Saving in the list allows to avoid needlessly traversing the whole
925 : : * array when only a few of its entries are possibly non-NULL.
926 : : */
927 : 77337 : estate->es_opened_result_relations =
928 : 77337 : lappend(estate->es_opened_result_relations, resultRelInfo);
929 : 77337 : }
930 : :
931 : : /*
932 : : * UpdateChangedParamSet
933 : : * Add changed parameters to a plan node's chgParam set
934 : : */
935 : : void
8306 bruce@momjian.us 936 : 762983 : UpdateChangedParamSet(PlanState *node, Bitmapset *newchg)
937 : : {
938 : : Bitmapset *parmset;
939 : :
940 : : /*
941 : : * The plan node only depends on params listed in its allParam set. Don't
942 : : * include anything else into its chgParam set.
943 : : */
8486 tgl@sss.pgh.pa.us 944 : 762983 : parmset = bms_intersect(node->plan->allParam, newchg);
1160 945 : 762983 : node->chgParam = bms_join(node->chgParam, parmset);
10308 vadim4o@yahoo.com 946 : 762983 : }
947 : :
948 : : /*
949 : : * executor_errposition
950 : : * Report an execution-time cursor position, if possible.
951 : : *
952 : : * This is expected to be used within an ereport() call. The return value
953 : : * is a dummy (always 0, in fact).
954 : : *
955 : : * The locations stored in parsetrees are byte offsets into the source string.
956 : : * We have to convert them to 1-based character indexes for reporting to
957 : : * clients. (We do things this way to avoid unnecessary overhead in the
958 : : * normal non-error case: computing character indexes would be much more
959 : : * expensive than storing token offsets.)
960 : : */
961 : : int
3304 tgl@sss.pgh.pa.us 962 :GBC 16 : executor_errposition(EState *estate, int location)
963 : : {
964 : : int pos;
965 : :
966 : : /* No-op if location was not provided */
967 [ - + ]: 16 : if (location < 0)
2232 tgl@sss.pgh.pa.us 968 :UBC 0 : return 0;
969 : : /* Can't do anything if source text is not available */
3304 tgl@sss.pgh.pa.us 970 [ + - - + ]:GBC 16 : if (estate == NULL || estate->es_sourceText == NULL)
2232 tgl@sss.pgh.pa.us 971 :UBC 0 : return 0;
972 : : /* Convert offset to character number */
3304 tgl@sss.pgh.pa.us 973 :GBC 16 : pos = pg_mbstrlen_with_len(estate->es_sourceText, location) + 1;
974 : : /* And pass it to the ereport mechanism */
2232 975 : 16 : return errposition(pos);
976 : : }
977 : :
978 : : /*
979 : : * Register a shutdown callback in an ExprContext.
980 : : *
981 : : * Shutdown callbacks will be called (in reverse order of registration)
982 : : * when the ExprContext is deleted or rescanned. This provides a hook
983 : : * for functions called in the context to do any cleanup needed --- it's
984 : : * particularly useful for functions returning sets. Note that the
985 : : * callback will *not* be called in the event that execution is aborted
986 : : * by an error.
987 : : */
988 : : void
8759 tgl@sss.pgh.pa.us 989 :CBC 190738 : RegisterExprContextCallback(ExprContext *econtext,
990 : : ExprContextCallbackFunction function,
991 : : Datum arg)
992 : : {
993 : : ExprContext_CB *ecxt_callback;
994 : :
995 : : /* Save the info in appropriate memory context */
996 : : ecxt_callback = (ExprContext_CB *)
997 : 190738 : MemoryContextAlloc(econtext->ecxt_per_query_memory,
998 : : sizeof(ExprContext_CB));
999 : :
1000 : 190738 : ecxt_callback->function = function;
1001 : 190738 : ecxt_callback->arg = arg;
1002 : :
1003 : : /* link to front of list for appropriate execution order */
1004 : 190738 : ecxt_callback->next = econtext->ecxt_callbacks;
1005 : 190738 : econtext->ecxt_callbacks = ecxt_callback;
1006 : 190738 : }
1007 : :
1008 : : /*
1009 : : * Deregister a shutdown callback in an ExprContext.
1010 : : *
1011 : : * Any list entries matching the function and arg will be removed.
1012 : : * This can be used if it's no longer necessary to call the callback.
1013 : : */
1014 : : void
1015 : 175532 : UnregisterExprContextCallback(ExprContext *econtext,
1016 : : ExprContextCallbackFunction function,
1017 : : Datum arg)
1018 : : {
1019 : : ExprContext_CB **prev_callback;
1020 : : ExprContext_CB *ecxt_callback;
1021 : :
1022 : 175532 : prev_callback = &econtext->ecxt_callbacks;
1023 : :
1024 [ + + ]: 504029 : while ((ecxt_callback = *prev_callback) != NULL)
1025 : : {
1026 [ + + + + ]: 328497 : if (ecxt_callback->function == function && ecxt_callback->arg == arg)
1027 : : {
1028 : 175532 : *prev_callback = ecxt_callback->next;
1029 : 175532 : pfree(ecxt_callback);
1030 : : }
1031 : : else
1032 : 152965 : prev_callback = &ecxt_callback->next;
1033 : : }
1034 : 175532 : }
1035 : :
1036 : : /*
1037 : : * Call all the shutdown callbacks registered in an ExprContext.
1038 : : *
1039 : : * The callback list is emptied (important in case this is only a rescan
1040 : : * reset, and not deletion of the ExprContext).
1041 : : *
1042 : : * If isCommit is false, just clean the callback list but don't call 'em.
1043 : : * (See comment for FreeExprContext.)
1044 : : */
1045 : : static void
6135 1046 : 4245916 : ShutdownExprContext(ExprContext *econtext, bool isCommit)
1047 : : {
1048 : : ExprContext_CB *ecxt_callback;
1049 : : MemoryContext oldcontext;
1050 : :
1051 : : /* Fast path in normal case where there's nothing to do. */
8542 1052 [ + + ]: 4245916 : if (econtext->ecxt_callbacks == NULL)
1053 : 4232365 : return;
1054 : :
1055 : : /*
1056 : : * Call the callbacks in econtext's per-tuple context. This ensures that
1057 : : * any memory they might leak will get cleaned up.
1058 : : */
1059 : 13551 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
1060 : :
1061 : : /*
1062 : : * Call each callback function in reverse registration order.
1063 : : */
8759 1064 [ + + ]: 27481 : while ((ecxt_callback = econtext->ecxt_callbacks) != NULL)
1065 : : {
1066 : 13930 : econtext->ecxt_callbacks = ecxt_callback->next;
6135 1067 [ + - ]: 13930 : if (isCommit)
3162 peter_e@gmx.net 1068 : 13930 : ecxt_callback->function(ecxt_callback->arg);
8759 tgl@sss.pgh.pa.us 1069 : 13930 : pfree(ecxt_callback);
1070 : : }
1071 : :
8542 1072 : 13551 : MemoryContextSwitchTo(oldcontext);
1073 : : }
1074 : :
1075 : : /*
1076 : : * GetAttributeByName
1077 : : * GetAttributeByNum
1078 : : *
1079 : : * These functions return the value of the requested attribute
1080 : : * out of the given tuple Datum.
1081 : : * C functions which take a tuple as an argument are expected
1082 : : * to use these. Ex: overpaid(EMP) might call GetAttributeByNum().
1083 : : * Note: these are actually rather slow because they do a typcache
1084 : : * lookup on each call.
1085 : : */
1086 : : Datum
3339 andres@anarazel.de 1087 : 24 : GetAttributeByName(HeapTupleHeader tuple, const char *attname, bool *isNull)
1088 : : {
1089 : : AttrNumber attrno;
1090 : : Datum result;
1091 : : Oid tupType;
1092 : : int32 tupTypmod;
1093 : : TupleDesc tupDesc;
1094 : : HeapTupleData tmptup;
1095 : : int i;
1096 : :
1097 [ - + ]: 24 : if (attname == NULL)
3339 andres@anarazel.de 1098 [ # # ]:UBC 0 : elog(ERROR, "invalid attribute name");
1099 : :
3339 andres@anarazel.de 1100 [ - + ]:CBC 24 : if (isNull == NULL)
3339 andres@anarazel.de 1101 [ # # ]:UBC 0 : elog(ERROR, "a NULL isNull pointer was passed");
1102 : :
3339 andres@anarazel.de 1103 [ - + ]:CBC 24 : if (tuple == NULL)
1104 : : {
1105 : : /* Kinda bogus but compatible with old behavior... */
3339 andres@anarazel.de 1106 :UBC 0 : *isNull = true;
1107 : 0 : return (Datum) 0;
1108 : : }
1109 : :
3339 andres@anarazel.de 1110 :CBC 24 : tupType = HeapTupleHeaderGetTypeId(tuple);
1111 : 24 : tupTypmod = HeapTupleHeaderGetTypMod(tuple);
1112 : 24 : tupDesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
1113 : :
1114 : 24 : attrno = InvalidAttrNumber;
1115 [ + - ]: 96 : for (i = 0; i < tupDesc->natts; i++)
1116 : : {
3180 1117 : 96 : Form_pg_attribute att = TupleDescAttr(tupDesc, i);
1118 : :
1119 [ + + ]: 96 : if (namestrcmp(&(att->attname), attname) == 0)
1120 : : {
1121 : 24 : attrno = att->attnum;
3339 1122 : 24 : break;
1123 : : }
1124 : : }
1125 : :
1126 [ - + ]: 24 : if (attrno == InvalidAttrNumber)
3339 andres@anarazel.de 1127 [ # # ]:UBC 0 : elog(ERROR, "attribute \"%s\" does not exist", attname);
1128 : :
1129 : : /*
1130 : : * heap_getattr needs a HeapTuple not a bare HeapTupleHeader. We set all
1131 : : * the fields in the struct just in case user tries to inspect system
1132 : : * columns.
1133 : : */
3339 andres@anarazel.de 1134 :CBC 24 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
1135 : 24 : ItemPointerSetInvalid(&(tmptup.t_self));
1136 : 24 : tmptup.t_tableOid = InvalidOid;
1137 : 24 : tmptup.t_data = tuple;
1138 : :
1139 : 24 : result = heap_getattr(&tmptup,
1140 : : attrno,
1141 : : tupDesc,
1142 : : isNull);
1143 : :
1144 [ + - ]: 24 : ReleaseTupleDesc(tupDesc);
1145 : :
1146 : 24 : return result;
1147 : : }
1148 : :
1149 : : Datum
3339 andres@anarazel.de 1150 :UBC 0 : GetAttributeByNum(HeapTupleHeader tuple,
1151 : : AttrNumber attrno,
1152 : : bool *isNull)
1153 : : {
1154 : : Datum result;
1155 : : Oid tupType;
1156 : : int32 tupTypmod;
1157 : : TupleDesc tupDesc;
1158 : : HeapTupleData tmptup;
1159 : :
1160 [ # # ]: 0 : if (!AttributeNumberIsValid(attrno))
1161 [ # # ]: 0 : elog(ERROR, "invalid attribute number %d", attrno);
1162 : :
1163 [ # # ]: 0 : if (isNull == NULL)
1164 [ # # ]: 0 : elog(ERROR, "a NULL isNull pointer was passed");
1165 : :
1166 [ # # ]: 0 : if (tuple == NULL)
1167 : : {
1168 : : /* Kinda bogus but compatible with old behavior... */
1169 : 0 : *isNull = true;
1170 : 0 : return (Datum) 0;
1171 : : }
1172 : :
1173 : 0 : tupType = HeapTupleHeaderGetTypeId(tuple);
1174 : 0 : tupTypmod = HeapTupleHeaderGetTypMod(tuple);
1175 : 0 : tupDesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
1176 : :
1177 : : /*
1178 : : * heap_getattr needs a HeapTuple not a bare HeapTupleHeader. We set all
1179 : : * the fields in the struct just in case user tries to inspect system
1180 : : * columns.
1181 : : */
1182 : 0 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
1183 : 0 : ItemPointerSetInvalid(&(tmptup.t_self));
1184 : 0 : tmptup.t_tableOid = InvalidOid;
1185 : 0 : tmptup.t_data = tuple;
1186 : :
1187 : 0 : result = heap_getattr(&tmptup,
1188 : : attrno,
1189 : : tupDesc,
1190 : : isNull);
1191 : :
1192 [ # # ]: 0 : ReleaseTupleDesc(tupDesc);
1193 : :
1194 : 0 : return result;
1195 : : }
1196 : :
1197 : : /*
1198 : : * Number of items in a tlist (including any resjunk items!)
1199 : : */
1200 : : int
3339 andres@anarazel.de 1201 :CBC 900023 : ExecTargetListLength(List *targetlist)
1202 : : {
1203 : : /* This used to be more complex, but fjoins are dead */
1204 : 900023 : return list_length(targetlist);
1205 : : }
1206 : :
1207 : : /*
1208 : : * Number of items in a tlist, not including any resjunk items
1209 : : */
1210 : : int
1211 : 92856 : ExecCleanTargetListLength(List *targetlist)
1212 : : {
1213 : 92856 : int len = 0;
1214 : : ListCell *tl;
1215 : :
1216 [ + + + + : 391844 : foreach(tl, targetlist)
+ + ]
1217 : : {
3312 tgl@sss.pgh.pa.us 1218 : 298988 : TargetEntry *curTle = lfirst_node(TargetEntry, tl);
1219 : :
3339 andres@anarazel.de 1220 [ + + ]: 298988 : if (!curTle->resjunk)
1221 : 278608 : len++;
1222 : : }
1223 : 92856 : return len;
1224 : : }
1225 : :
1226 : : /*
1227 : : * Return a relInfo's tuple slot for a trigger's OLD tuples.
1228 : : */
1229 : : TupleTableSlot *
2625 1230 : 617682 : ExecGetTriggerOldSlot(EState *estate, ResultRelInfo *relInfo)
1231 : : {
1232 [ + + ]: 617682 : if (relInfo->ri_TrigOldSlot == NULL)
1233 : : {
1234 : 6894 : Relation rel = relInfo->ri_RelationDesc;
1235 : 6894 : MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1236 : :
1237 : 6894 : relInfo->ri_TrigOldSlot =
1238 : 6894 : ExecInitExtraTupleSlot(estate,
1239 : : RelationGetDescr(rel),
1240 : : table_slot_callbacks(rel));
1241 : :
1242 : 6894 : MemoryContextSwitchTo(oldcontext);
1243 : : }
1244 : :
1245 : 617682 : return relInfo->ri_TrigOldSlot;
1246 : : }
1247 : :
1248 : : /*
1249 : : * Return a relInfo's tuple slot for a trigger's NEW tuples.
1250 : : */
1251 : : TupleTableSlot *
1252 : 2386 : ExecGetTriggerNewSlot(EState *estate, ResultRelInfo *relInfo)
1253 : : {
1254 [ + + ]: 2386 : if (relInfo->ri_TrigNewSlot == NULL)
1255 : : {
1256 : 1502 : Relation rel = relInfo->ri_RelationDesc;
1257 : 1502 : MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1258 : :
1259 : 1502 : relInfo->ri_TrigNewSlot =
1260 : 1502 : ExecInitExtraTupleSlot(estate,
1261 : : RelationGetDescr(rel),
1262 : : table_slot_callbacks(rel));
1263 : :
1264 : 1502 : MemoryContextSwitchTo(oldcontext);
1265 : : }
1266 : :
1267 : 2386 : return relInfo->ri_TrigNewSlot;
1268 : : }
1269 : :
1270 : : /*
1271 : : * Return a relInfo's tuple slot for processing returning tuples.
1272 : : */
1273 : : TupleTableSlot *
1274 : 817 : ExecGetReturningSlot(EState *estate, ResultRelInfo *relInfo)
1275 : : {
1276 [ + + ]: 817 : if (relInfo->ri_ReturningSlot == NULL)
1277 : : {
1278 : 443 : Relation rel = relInfo->ri_RelationDesc;
1279 : 443 : MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1280 : :
1281 : 443 : relInfo->ri_ReturningSlot =
1282 : 443 : ExecInitExtraTupleSlot(estate,
1283 : : RelationGetDescr(rel),
1284 : : table_slot_callbacks(rel));
1285 : :
1286 : 443 : MemoryContextSwitchTo(oldcontext);
1287 : : }
1288 : :
1289 : 817 : return relInfo->ri_ReturningSlot;
1290 : : }
1291 : :
1292 : : /*
1293 : : * Return a relInfo's all-NULL tuple slot for processing returning tuples.
1294 : : *
1295 : : * Note: this slot is intentionally filled with NULLs in every column, and
1296 : : * should be considered read-only --- the caller must not update it.
1297 : : */
1298 : : TupleTableSlot *
474 dean.a.rasheed@gmail 1299 : 236 : ExecGetAllNullSlot(EState *estate, ResultRelInfo *relInfo)
1300 : : {
1301 [ + + ]: 236 : if (relInfo->ri_AllNullSlot == NULL)
1302 : : {
1303 : 162 : Relation rel = relInfo->ri_RelationDesc;
1304 : 162 : MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1305 : : TupleTableSlot *slot;
1306 : :
1307 : 162 : slot = ExecInitExtraTupleSlot(estate,
1308 : : RelationGetDescr(rel),
1309 : : table_slot_callbacks(rel));
1310 : 162 : ExecStoreAllNullTuple(slot);
1311 : :
1312 : 162 : relInfo->ri_AllNullSlot = slot;
1313 : :
1314 : 162 : MemoryContextSwitchTo(oldcontext);
1315 : : }
1316 : :
1317 : 236 : return relInfo->ri_AllNullSlot;
1318 : : }
1319 : :
1320 : : /*
1321 : : * Return the map needed to convert given child result relation's tuples to
1322 : : * the rowtype of the query's main target ("root") relation. Note that a
1323 : : * NULL result is valid and means that no conversion is needed.
1324 : : */
1325 : : TupleConversionMap *
1855 tgl@sss.pgh.pa.us 1326 : 45404 : ExecGetChildToRootMap(ResultRelInfo *resultRelInfo)
1327 : : {
1328 : : /* If we didn't already do so, compute the map for this child. */
1329 [ + + ]: 45404 : if (!resultRelInfo->ri_ChildToRootMapValid)
1330 : : {
1331 : 1196 : ResultRelInfo *rootRelInfo = resultRelInfo->ri_RootResultRelInfo;
1332 : :
1333 [ + + ]: 1196 : if (rootRelInfo)
1334 : 937 : resultRelInfo->ri_ChildToRootMap =
1335 : 937 : convert_tuples_by_name(RelationGetDescr(resultRelInfo->ri_RelationDesc),
1336 : 937 : RelationGetDescr(rootRelInfo->ri_RelationDesc));
1337 : : else /* this isn't a child result rel */
1338 : 259 : resultRelInfo->ri_ChildToRootMap = NULL;
1339 : :
1340 : 1196 : resultRelInfo->ri_ChildToRootMapValid = true;
1341 : : }
1342 : :
1343 : 45404 : return resultRelInfo->ri_ChildToRootMap;
1344 : : }
1345 : :
1346 : : /*
1347 : : * Returns the map needed to convert given root result relation's tuples to
1348 : : * the rowtype of the given child relation. Note that a NULL result is valid
1349 : : * and means that no conversion is needed.
1350 : : */
1351 : : TupleConversionMap *
1250 alvherre@alvh.no-ip. 1352 : 636302 : ExecGetRootToChildMap(ResultRelInfo *resultRelInfo, EState *estate)
1353 : : {
1354 : : /* Mustn't get called for a non-child result relation. */
1355 [ - + ]: 636302 : Assert(resultRelInfo->ri_RootResultRelInfo);
1356 : :
1357 : : /* If we didn't already do so, compute the map for this child. */
1358 [ + + ]: 636302 : if (!resultRelInfo->ri_RootToChildMapValid)
1359 : : {
1360 : 5649 : ResultRelInfo *rootRelInfo = resultRelInfo->ri_RootResultRelInfo;
1361 : 5649 : TupleDesc indesc = RelationGetDescr(rootRelInfo->ri_RelationDesc);
1362 : 5649 : TupleDesc outdesc = RelationGetDescr(resultRelInfo->ri_RelationDesc);
1363 : 5649 : Relation childrel = resultRelInfo->ri_RelationDesc;
1364 : : AttrMap *attrMap;
1365 : : MemoryContext oldcontext;
1366 : :
1367 : : /*
1368 : : * When this child table is not a partition (!relispartition), it may
1369 : : * have columns that are not present in the root table, which we ask
1370 : : * to ignore by passing true for missing_ok.
1371 : : */
1372 : 5649 : oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1373 : 5649 : attrMap = build_attrmap_by_name_if_req(indesc, outdesc,
1374 : 5649 : !childrel->rd_rel->relispartition);
1375 [ + + ]: 5649 : if (attrMap)
1376 : 1062 : resultRelInfo->ri_RootToChildMap =
1377 : 1062 : convert_tuples_by_name_attrmap(indesc, outdesc, attrMap);
1378 : 5649 : MemoryContextSwitchTo(oldcontext);
1379 : 5649 : resultRelInfo->ri_RootToChildMapValid = true;
1380 : : }
1381 : :
1382 : 636302 : return resultRelInfo->ri_RootToChildMap;
1383 : : }
1384 : :
1385 : : /* Return a bitmap representing columns being inserted */
1386 : : Bitmapset *
1912 heikki.linnakangas@i 1387 : 980 : ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate)
1388 : : {
1246 alvherre@alvh.no-ip. 1389 : 980 : RTEPermissionInfo *perminfo = GetResultRTEPermissionInfo(relinfo, estate);
1390 : :
1391 [ - + ]: 980 : if (perminfo == NULL)
1246 alvherre@alvh.no-ip. 1392 :UBC 0 : return NULL;
1393 : :
1394 : : /* Map the columns to child's attribute numbers if needed. */
1246 alvherre@alvh.no-ip. 1395 [ + + ]:CBC 980 : if (relinfo->ri_RootResultRelInfo)
1396 : : {
1250 1397 : 53 : TupleConversionMap *map = ExecGetRootToChildMap(relinfo, estate);
1398 : :
1246 1399 [ + + ]: 53 : if (map)
1400 : 2 : return execute_attr_map_cols(map->attrMap, perminfo->insertedCols);
1401 : : }
1402 : :
1403 : 978 : return perminfo->insertedCols;
1404 : : }
1405 : :
1406 : : /* Return a bitmap representing columns being updated */
1407 : : Bitmapset *
1912 heikki.linnakangas@i 1408 : 32491 : ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
1409 : : {
1246 alvherre@alvh.no-ip. 1410 : 32491 : RTEPermissionInfo *perminfo = GetResultRTEPermissionInfo(relinfo, estate);
1411 : :
1412 [ + + ]: 32491 : if (perminfo == NULL)
1246 alvherre@alvh.no-ip. 1413 :GBC 2 : return NULL;
1414 : :
1415 : : /* Map the columns to child's attribute numbers if needed. */
1246 alvherre@alvh.no-ip. 1416 [ + + ]:CBC 32489 : if (relinfo->ri_RootResultRelInfo)
1417 : : {
1250 1418 : 1163 : TupleConversionMap *map = ExecGetRootToChildMap(relinfo, estate);
1419 : :
1246 1420 [ + + ]: 1163 : if (map)
1421 : 329 : return execute_attr_map_cols(map->attrMap, perminfo->updatedCols);
1422 : : }
1423 : :
1424 : 32160 : return perminfo->updatedCols;
1425 : : }
1426 : :
1427 : : /* Return a bitmap representing generated columns being updated */
1428 : : Bitmapset *
1912 heikki.linnakangas@i 1429 : 31360 : ExecGetExtraUpdatedCols(ResultRelInfo *relinfo, EState *estate)
1430 : : {
1431 : : /* Compute the info if we didn't already */
452 peter@eisentraut.org 1432 [ + + ]: 31360 : if (!relinfo->ri_extraUpdatedCols_valid)
1433 : 31230 : ExecInitGenerated(relinfo, estate, CMD_UPDATE);
1216 tgl@sss.pgh.pa.us 1434 : 31360 : return relinfo->ri_extraUpdatedCols;
1435 : : }
1436 : :
1437 : : /*
1438 : : * Return columns being updated, including generated columns
1439 : : *
1440 : : * The bitmap is allocated in per-tuple memory context. It's up to the caller to
1441 : : * copy it into a different context with the appropriate lifespan, if needed.
1442 : : */
1443 : : Bitmapset *
1912 heikki.linnakangas@i 1444 : 8779 : ExecGetAllUpdatedCols(ResultRelInfo *relinfo, EState *estate)
1445 : : {
1446 : : Bitmapset *ret;
1447 : : MemoryContext oldcxt;
1448 : :
1063 tomas.vondra@postgre 1449 [ + + ]: 8779 : oldcxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
1450 : :
1451 : 8779 : ret = bms_union(ExecGetUpdatedCols(relinfo, estate),
1452 : 8779 : ExecGetExtraUpdatedCols(relinfo, estate));
1453 : :
1454 : 8779 : MemoryContextSwitchTo(oldcxt);
1455 : :
1456 : 8779 : return ret;
1457 : : }
1458 : :
1459 : : /*
1460 : : * GetResultRTEPermissionInfo
1461 : : * Looks up RTEPermissionInfo for ExecGet*Cols() routines
1462 : : */
1463 : : static RTEPermissionInfo *
1246 alvherre@alvh.no-ip. 1464 : 33653 : GetResultRTEPermissionInfo(ResultRelInfo *relinfo, EState *estate)
1465 : : {
1466 : : Index rti;
1467 : : RangeTblEntry *rte;
1468 : 33653 : RTEPermissionInfo *perminfo = NULL;
1469 : :
1470 [ + + ]: 33653 : if (relinfo->ri_RootResultRelInfo)
1471 : : {
1472 : : /*
1473 : : * For inheritance child result relations (a partition routing target
1474 : : * of an INSERT or a child UPDATE target), this returns the root
1475 : : * parent's RTE to fetch the RTEPermissionInfo because that's the only
1476 : : * one that has one assigned.
1477 : : */
1478 : 1272 : rti = relinfo->ri_RootResultRelInfo->ri_RangeTableIndex;
1479 : : }
1480 [ + + ]: 32381 : else if (relinfo->ri_RangeTableIndex != 0)
1481 : : {
1482 : : /*
1483 : : * Non-child result relation should have their own RTEPermissionInfo.
1484 : : */
1485 : 32379 : rti = relinfo->ri_RangeTableIndex;
1486 : : }
1487 : : else
1488 : : {
1489 : : /*
1490 : : * The relation isn't in the range table and it isn't a partition
1491 : : * routing target. This ResultRelInfo must've been created only for
1492 : : * firing triggers and the relation is not being inserted into. (See
1493 : : * ExecGetTriggerResultRel.)
1494 : : */
1246 alvherre@alvh.no-ip. 1495 :GBC 2 : rti = 0;
1496 : : }
1497 : :
1246 alvherre@alvh.no-ip. 1498 [ + + ]:CBC 33653 : if (rti > 0)
1499 : : {
1500 : 33651 : rte = exec_rt_fetch(rti, estate);
1501 : 33651 : perminfo = getRTEPermissionInfo(estate->es_rteperminfos, rte);
1502 : : }
1503 : :
1504 : 33653 : return perminfo;
1505 : : }
1506 : :
1507 : : /*
1508 : : * ExecGetResultRelCheckAsUser
1509 : : * Returns the user to modify passed-in result relation as
1510 : : *
1511 : : * The user is chosen by looking up the relation's or, if a child table, its
1512 : : * root parent's RTEPermissionInfo.
1513 : : */
1514 : : Oid
1515 : 182 : ExecGetResultRelCheckAsUser(ResultRelInfo *relInfo, EState *estate)
1516 : : {
1517 : 182 : RTEPermissionInfo *perminfo = GetResultRTEPermissionInfo(relInfo, estate);
1518 : :
1519 : : /* XXX - maybe ok to return GetUserId() in this case? */
1520 [ - + ]: 182 : if (perminfo == NULL)
1246 alvherre@alvh.no-ip. 1521 [ # # ]:UBC 0 : elog(ERROR, "no RTEPermissionInfo found for result relation with OID %u",
1522 : : RelationGetRelid(relInfo->ri_RelationDesc));
1523 : :
1246 alvherre@alvh.no-ip. 1524 [ + + ]:CBC 182 : return perminfo->checkAsUser ? perminfo->checkAsUser : GetUserId();
1525 : : }
|