1996-07-09 02:22:35 -04:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
|
*
|
1999-02-13 18:22:53 -05:00
|
|
|
* execScan.c
|
1997-09-07 01:04:48 -04:00
|
|
|
* This code provides support for generalized relation scans. ExecScan
|
|
|
|
|
* is passed a node and a pointer to a function to "do the right thing"
|
|
|
|
|
* and return a tuple from the relation. ExecScan then does the tedious
|
|
|
|
|
* stuff - checking the qualification and projecting the tuple
|
|
|
|
|
* appropriately.
|
1996-07-09 02:22:35 -04:00
|
|
|
*
|
2019-01-02 12:44:25 -05:00
|
|
|
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
|
2000-01-26 00:58:53 -05:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 02:22:35 -04:00
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* IDENTIFICATION
|
2010-09-20 16:08:53 -04:00
|
|
|
* src/backend/executor/execScan.c
|
1996-07-09 02:22:35 -04:00
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
2002-01-05 19:37:44 -05:00
|
|
|
#include "postgres.h"
|
1996-07-09 02:22:35 -04:00
|
|
|
|
|
|
|
|
#include "executor/executor.h"
|
2002-01-05 19:37:44 -05:00
|
|
|
#include "miscadmin.h"
|
2000-07-16 23:05:41 -04:00
|
|
|
#include "utils/memutils.h"
|
|
|
|
|
|
1996-07-09 02:22:35 -04:00
|
|
|
|
2003-02-03 10:07:08 -05:00
|
|
|
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-25 22:26:45 -04:00
|
|
|
/*
|
2017-09-14 04:53:10 -04:00
|
|
|
* ExecScanFetch -- check interrupts & fetch next potential tuple
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-25 22:26:45 -04:00
|
|
|
*
|
|
|
|
|
* This routine is concerned with substituting a test tuple if we are
|
2014-05-06 12:12:18 -04:00
|
|
|
* inside an EvalPlanQual recheck. If we aren't, just execute
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-25 22:26:45 -04:00
|
|
|
* the access method's next-tuple routine.
|
|
|
|
|
*/
|
|
|
|
|
static inline TupleTableSlot *
|
|
|
|
|
ExecScanFetch(ScanState *node,
|
|
|
|
|
ExecScanAccessMtd accessMtd,
|
|
|
|
|
ExecScanRecheckMtd recheckMtd)
|
|
|
|
|
{
|
|
|
|
|
EState *estate = node->ps.state;
|
|
|
|
|
|
2017-09-14 04:53:10 -04:00
|
|
|
CHECK_FOR_INTERRUPTS();
|
|
|
|
|
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-25 22:26:45 -04:00
|
|
|
if (estate->es_epqTuple != NULL)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* We are inside an EvalPlanQual recheck. Return the test tuple if
|
|
|
|
|
* one is available, after rechecking any access-method-specific
|
|
|
|
|
* conditions.
|
|
|
|
|
*/
|
|
|
|
|
Index scanrelid = ((Scan *) node->ps.plan)->scanrelid;
|
|
|
|
|
|
Allow foreign and custom joins to handle EvalPlanQual rechecks.
Commit e7cb7ee14555cc9c5773e2c102efd6371f6f2005 provided basic
infrastructure for allowing a foreign data wrapper or custom scan
provider to replace a join of one or more tables with a scan.
However, this infrastructure failed to take into account the need
for possible EvalPlanQual rechecks, and ExecScanFetch would fail
an assertion (or just overwrite memory) if such a check was attempted
for a plan containing a pushed-down join. To fix, adjust the EPQ
machinery to skip some processing steps when scanrelid == 0, making
those the responsibility of scan's recheck method, which also has
the responsibility in this case of correctly populating the relevant
slot.
To allow foreign scans to gain control in the right place to make
use of this new facility, add a new, optional RecheckForeignScan
method. Also, allow a foreign scan to have a child plan, which can
be used to correctly populate the slot (or perhaps for something
else, but this is the only use currently envisioned).
KaiGai Kohei, reviewed by Robert Haas, Etsuro Fujita, and Kyotaro
Horiguchi.
2015-12-08 12:31:03 -05:00
|
|
|
if (scanrelid == 0)
|
|
|
|
|
{
|
|
|
|
|
TupleTableSlot *slot = node->ss_ScanTupleSlot;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This is a ForeignScan or CustomScan which has pushed down a
|
|
|
|
|
* join to the remote side. The recheck method is responsible not
|
|
|
|
|
* only for rechecking the scan/join quals but also for storing
|
|
|
|
|
* the correct tuple in the slot.
|
|
|
|
|
*/
|
|
|
|
|
if (!(*recheckMtd) (node, slot))
|
|
|
|
|
ExecClearTuple(slot); /* would not be returned by scan */
|
|
|
|
|
return slot;
|
|
|
|
|
}
|
|
|
|
|
else if (estate->es_epqTupleSet[scanrelid - 1])
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-25 22:26:45 -04:00
|
|
|
{
|
|
|
|
|
TupleTableSlot *slot = node->ss_ScanTupleSlot;
|
|
|
|
|
|
|
|
|
|
/* Return empty slot if we already returned a tuple */
|
|
|
|
|
if (estate->es_epqScanDone[scanrelid - 1])
|
|
|
|
|
return ExecClearTuple(slot);
|
|
|
|
|
/* Else mark to remember that we shouldn't return more */
|
|
|
|
|
estate->es_epqScanDone[scanrelid - 1] = true;
|
|
|
|
|
|
|
|
|
|
/* Return empty slot if we haven't got a test tuple */
|
|
|
|
|
if (estate->es_epqTuple[scanrelid - 1] == NULL)
|
|
|
|
|
return ExecClearTuple(slot);
|
|
|
|
|
|
|
|
|
|
/* Store test tuple in the plan node's scan slot */
|
Make TupleTableSlots extensible, finish split of existing slot type.
This commit completes the work prepared in 1a0586de36, splitting the
old TupleTableSlot implementation (which could store buffer, heap,
minimal and virtual slots) into four different slot types. As
described in the aforementioned commit, this is done with the goal of
making tuple table slots extensible, to allow for pluggable table
access methods.
To achieve runtime extensibility for TupleTableSlots, operations on
slots that can differ between types of slots are performed using the
TupleTableSlotOps struct provided at slot creation time. That
includes information from the size of TupleTableSlot struct to be
allocated, initialization, deforming etc. See the struct's definition
for more detailed information about callbacks TupleTableSlotOps.
I decided to rename TTSOpsBufferTuple to TTSOpsBufferHeapTuple and
ExecCopySlotTuple to ExecCopySlotHeapTuple, as that seems more
consistent with other naming introduced in recent patches.
There's plenty optimization potential in the slot implementation, but
according to benchmarking the state after this commit has similar
performance characteristics to before this set of changes, which seems
sufficient.
There's a few changes in execReplication.c that currently need to poke
through the slot abstraction, that'll be repaired once the pluggable
storage patchset provides the necessary infrastructure.
Author: Andres Freund and Ashutosh Bapat, with changes by Amit Khandekar
Discussion: https://postgr.es/m/20181105210039.hh4vvi4vwoq5ba2q@alap3.anarazel.de
2018-11-16 19:35:11 -05:00
|
|
|
ExecForceStoreHeapTuple(estate->es_epqTuple[scanrelid - 1],
|
|
|
|
|
slot);
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-25 22:26:45 -04:00
|
|
|
|
|
|
|
|
/* Check if it meets the access-method conditions */
|
|
|
|
|
if (!(*recheckMtd) (node, slot))
|
|
|
|
|
ExecClearTuple(slot); /* would not be returned by scan */
|
|
|
|
|
|
|
|
|
|
return slot;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Run the node-type-specific access method function to get the next tuple
|
|
|
|
|
*/
|
|
|
|
|
return (*accessMtd) (node);
|
|
|
|
|
}
|
|
|
|
|
|
1996-07-09 02:22:35 -04:00
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 01:04:48 -04:00
|
|
|
* ExecScan
|
1996-07-09 02:22:35 -04:00
|
|
|
*
|
1997-09-07 01:04:48 -04:00
|
|
|
* Scans the relation using the 'access method' indicated and
|
|
|
|
|
* returns the next qualifying tuple in the direction specified
|
|
|
|
|
* in the global variable ExecDirection.
|
2014-08-05 15:17:21 -04:00
|
|
|
* The access method returns the next tuple and ExecScan() is
|
2000-07-11 22:37:39 -04:00
|
|
|
* responsible for checking the tuple returned against the qual-clause.
|
1997-09-07 01:04:48 -04:00
|
|
|
*
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-25 22:26:45 -04:00
|
|
|
* A 'recheck method' must also be provided that can check an
|
|
|
|
|
* arbitrary tuple of the relation against any qual conditions
|
|
|
|
|
* that are implemented internal to the access method.
|
|
|
|
|
*
|
1997-09-07 01:04:48 -04:00
|
|
|
* Conditions:
|
|
|
|
|
* -- the "cursor" maintained by the AMI is positioned at the tuple
|
|
|
|
|
* returned previously.
|
|
|
|
|
*
|
|
|
|
|
* Initial States:
|
|
|
|
|
* -- the relation indicated is opened for scanning so that the
|
|
|
|
|
* "cursor" is positioned before the first qualifying tuple.
|
1996-07-09 02:22:35 -04:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
TupleTableSlot *
|
2003-08-08 17:42:59 -04:00
|
|
|
ExecScan(ScanState *node,
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-25 22:26:45 -04:00
|
|
|
ExecScanAccessMtd accessMtd, /* function returning a tuple */
|
|
|
|
|
ExecScanRecheckMtd recheckMtd)
|
1996-07-09 02:22:35 -04:00
|
|
|
{
|
2000-08-23 23:29:15 -04:00
|
|
|
ExprContext *econtext;
|
Faster expression evaluation and targetlist projection.
This replaces the old, recursive tree-walk based evaluation, with
non-recursive, opcode dispatch based, expression evaluation.
Projection is now implemented as part of expression evaluation.
This both leads to significant performance improvements, and makes
future just-in-time compilation of expressions easier.
The speed gains primarily come from:
- non-recursive implementation reduces stack usage / overhead
- simple sub-expressions are implemented with a single jump, without
function calls
- sharing some state between different sub-expressions
- reduced amount of indirect/hard to predict memory accesses by laying
out operation metadata sequentially; including the avoidance of
nearly all of the previously used linked lists
- more code has been moved to expression initialization, avoiding
constant re-checks at evaluation time
Future just-in-time compilation (JIT) has become easier, as
demonstrated by released patches intended to be merged in a later
release, for primarily two reasons: Firstly, due to a stricter split
between expression initialization and evaluation, less code has to be
handled by the JIT. Secondly, due to the non-recursive nature of the
generated "instructions", less performance-critical code-paths can
easily be shared between interpreted and compiled evaluation.
The new framework allows for significant future optimizations. E.g.:
- basic infrastructure for to later reduce the per executor-startup
overhead of expression evaluation, by caching state in prepared
statements. That'd be helpful in OLTPish scenarios where
initialization overhead is measurable.
- optimizing the generated "code". A number of proposals for potential
work has already been made.
- optimizing the interpreter. Similarly a number of proposals have
been made here too.
The move of logic into the expression initialization step leads to some
backward-incompatible changes:
- Function permission checks are now done during expression
initialization, whereas previously they were done during
execution. In edge cases this can lead to errors being raised that
previously wouldn't have been, e.g. a NULL array being coerced to a
different array type previously didn't perform checks.
- The set of domain constraints to be checked, is now evaluated once
during expression initialization, previously it was re-built
every time a domain check was evaluated. For normal queries this
doesn't change much, but e.g. for plpgsql functions, which caches
ExprStates, the old set could stick around longer. The behavior
around might still change.
Author: Andres Freund, with significant changes by Tom Lane,
changes by Heikki Linnakangas
Reviewed-By: Tom Lane, Heikki Linnakangas
Discussion: https://postgr.es/m/20161206034955.bh33paeralxbtluv@alap3.anarazel.de
2017-03-14 18:45:36 -04:00
|
|
|
ExprState *qual;
|
2003-02-03 10:07:08 -05:00
|
|
|
ProjectionInfo *projInfo;
|
1997-09-07 01:04:48 -04:00
|
|
|
|
2001-03-22 01:16:21 -05:00
|
|
|
/*
|
|
|
|
|
* Fetch data from node
|
1996-07-09 02:22:35 -04:00
|
|
|
*/
|
2002-12-05 10:50:39 -05:00
|
|
|
qual = node->ps.qual;
|
2003-02-03 10:07:08 -05:00
|
|
|
projInfo = node->ps.ps_ProjInfo;
|
2011-05-21 14:30:11 -04:00
|
|
|
econtext = node->ps.ps_ExprContext;
|
1997-09-07 01:04:48 -04:00
|
|
|
|
2017-09-14 04:53:10 -04:00
|
|
|
/* interrupt checks are in ExecScanFetch */
|
|
|
|
|
|
2005-05-22 18:30:20 -04:00
|
|
|
/*
|
2005-10-14 22:49:52 -04:00
|
|
|
* If we have neither a qual to check nor a projection to do, just skip
|
|
|
|
|
* all the overhead and return the raw scan tuple.
|
2005-05-22 18:30:20 -04:00
|
|
|
*/
|
|
|
|
|
if (!qual && !projInfo)
|
2011-05-21 14:30:11 -04:00
|
|
|
{
|
|
|
|
|
ResetExprContext(econtext);
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-25 22:26:45 -04:00
|
|
|
return ExecScanFetch(node, accessMtd, recheckMtd);
|
2011-05-21 14:30:11 -04:00
|
|
|
}
|
2005-05-22 18:30:20 -04:00
|
|
|
|
2001-03-22 01:16:21 -05:00
|
|
|
/*
|
|
|
|
|
* Reset per-tuple memory context to free any expression evaluation
|
2017-01-19 17:12:38 -05:00
|
|
|
* storage allocated in the previous tuple cycle.
|
2000-08-23 23:29:15 -04:00
|
|
|
*/
|
|
|
|
|
ResetExprContext(econtext);
|
|
|
|
|
|
1997-09-07 01:04:48 -04:00
|
|
|
/*
|
2014-05-06 12:12:18 -04:00
|
|
|
* get a tuple from the access method. Loop until we obtain a tuple that
|
2005-10-14 22:49:52 -04:00
|
|
|
* passes the qualification.
|
1997-09-07 01:04:48 -04:00
|
|
|
*/
|
|
|
|
|
for (;;)
|
|
|
|
|
{
|
2000-07-11 22:37:39 -04:00
|
|
|
TupleTableSlot *slot;
|
|
|
|
|
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-25 22:26:45 -04:00
|
|
|
slot = ExecScanFetch(node, accessMtd, recheckMtd);
|
1997-09-07 01:04:48 -04:00
|
|
|
|
2001-03-22 01:16:21 -05:00
|
|
|
/*
|
2005-10-14 22:49:52 -04:00
|
|
|
* if the slot returned by the accessMtd contains NULL, then it means
|
|
|
|
|
* there is nothing more to scan so we just return an empty slot,
|
|
|
|
|
* being careful to use the projection result slot so it has correct
|
|
|
|
|
* tupleDesc.
|
1997-09-07 01:04:48 -04:00
|
|
|
*/
|
|
|
|
|
if (TupIsNull(slot))
|
1998-02-26 07:13:11 -05:00
|
|
|
{
|
2003-02-03 10:07:08 -05:00
|
|
|
if (projInfo)
|
Faster expression evaluation and targetlist projection.
This replaces the old, recursive tree-walk based evaluation, with
non-recursive, opcode dispatch based, expression evaluation.
Projection is now implemented as part of expression evaluation.
This both leads to significant performance improvements, and makes
future just-in-time compilation of expressions easier.
The speed gains primarily come from:
- non-recursive implementation reduces stack usage / overhead
- simple sub-expressions are implemented with a single jump, without
function calls
- sharing some state between different sub-expressions
- reduced amount of indirect/hard to predict memory accesses by laying
out operation metadata sequentially; including the avoidance of
nearly all of the previously used linked lists
- more code has been moved to expression initialization, avoiding
constant re-checks at evaluation time
Future just-in-time compilation (JIT) has become easier, as
demonstrated by released patches intended to be merged in a later
release, for primarily two reasons: Firstly, due to a stricter split
between expression initialization and evaluation, less code has to be
handled by the JIT. Secondly, due to the non-recursive nature of the
generated "instructions", less performance-critical code-paths can
easily be shared between interpreted and compiled evaluation.
The new framework allows for significant future optimizations. E.g.:
- basic infrastructure for to later reduce the per executor-startup
overhead of expression evaluation, by caching state in prepared
statements. That'd be helpful in OLTPish scenarios where
initialization overhead is measurable.
- optimizing the generated "code". A number of proposals for potential
work has already been made.
- optimizing the interpreter. Similarly a number of proposals have
been made here too.
The move of logic into the expression initialization step leads to some
backward-incompatible changes:
- Function permission checks are now done during expression
initialization, whereas previously they were done during
execution. In edge cases this can lead to errors being raised that
previously wouldn't have been, e.g. a NULL array being coerced to a
different array type previously didn't perform checks.
- The set of domain constraints to be checked, is now evaluated once
during expression initialization, previously it was re-built
every time a domain check was evaluated. For normal queries this
doesn't change much, but e.g. for plpgsql functions, which caches
ExprStates, the old set could stick around longer. The behavior
around might still change.
Author: Andres Freund, with significant changes by Tom Lane,
changes by Heikki Linnakangas
Reviewed-By: Tom Lane, Heikki Linnakangas
Discussion: https://postgr.es/m/20161206034955.bh33paeralxbtluv@alap3.anarazel.de
2017-03-14 18:45:36 -04:00
|
|
|
return ExecClearTuple(projInfo->pi_state.resultslot);
|
2003-02-03 10:07:08 -05:00
|
|
|
else
|
|
|
|
|
return slot;
|
1998-02-26 07:13:11 -05:00
|
|
|
}
|
1997-09-07 01:04:48 -04:00
|
|
|
|
2001-03-22 01:16:21 -05:00
|
|
|
/*
|
|
|
|
|
* place the current tuple into the expr context
|
1997-09-07 01:04:48 -04:00
|
|
|
*/
|
|
|
|
|
econtext->ecxt_scantuple = slot;
|
|
|
|
|
|
2001-03-22 01:16:21 -05:00
|
|
|
/*
|
|
|
|
|
* check that the current tuple satisfies the qual-clause
|
2000-07-11 22:37:39 -04:00
|
|
|
*
|
Faster expression evaluation and targetlist projection.
This replaces the old, recursive tree-walk based evaluation, with
non-recursive, opcode dispatch based, expression evaluation.
Projection is now implemented as part of expression evaluation.
This both leads to significant performance improvements, and makes
future just-in-time compilation of expressions easier.
The speed gains primarily come from:
- non-recursive implementation reduces stack usage / overhead
- simple sub-expressions are implemented with a single jump, without
function calls
- sharing some state between different sub-expressions
- reduced amount of indirect/hard to predict memory accesses by laying
out operation metadata sequentially; including the avoidance of
nearly all of the previously used linked lists
- more code has been moved to expression initialization, avoiding
constant re-checks at evaluation time
Future just-in-time compilation (JIT) has become easier, as
demonstrated by released patches intended to be merged in a later
release, for primarily two reasons: Firstly, due to a stricter split
between expression initialization and evaluation, less code has to be
handled by the JIT. Secondly, due to the non-recursive nature of the
generated "instructions", less performance-critical code-paths can
easily be shared between interpreted and compiled evaluation.
The new framework allows for significant future optimizations. E.g.:
- basic infrastructure for to later reduce the per executor-startup
overhead of expression evaluation, by caching state in prepared
statements. That'd be helpful in OLTPish scenarios where
initialization overhead is measurable.
- optimizing the generated "code". A number of proposals for potential
work has already been made.
- optimizing the interpreter. Similarly a number of proposals have
been made here too.
The move of logic into the expression initialization step leads to some
backward-incompatible changes:
- Function permission checks are now done during expression
initialization, whereas previously they were done during
execution. In edge cases this can lead to errors being raised that
previously wouldn't have been, e.g. a NULL array being coerced to a
different array type previously didn't perform checks.
- The set of domain constraints to be checked, is now evaluated once
during expression initialization, previously it was re-built
every time a domain check was evaluated. For normal queries this
doesn't change much, but e.g. for plpgsql functions, which caches
ExprStates, the old set could stick around longer. The behavior
around might still change.
Author: Andres Freund, with significant changes by Tom Lane,
changes by Heikki Linnakangas
Reviewed-By: Tom Lane, Heikki Linnakangas
Discussion: https://postgr.es/m/20161206034955.bh33paeralxbtluv@alap3.anarazel.de
2017-03-14 18:45:36 -04:00
|
|
|
* check for non-null qual here to avoid a function call to ExecQual()
|
|
|
|
|
* when the qual is null ... saves only a few cycles, but they add up
|
2005-10-14 22:49:52 -04:00
|
|
|
* ...
|
1997-09-07 01:04:48 -04:00
|
|
|
*/
|
Faster expression evaluation and targetlist projection.
This replaces the old, recursive tree-walk based evaluation, with
non-recursive, opcode dispatch based, expression evaluation.
Projection is now implemented as part of expression evaluation.
This both leads to significant performance improvements, and makes
future just-in-time compilation of expressions easier.
The speed gains primarily come from:
- non-recursive implementation reduces stack usage / overhead
- simple sub-expressions are implemented with a single jump, without
function calls
- sharing some state between different sub-expressions
- reduced amount of indirect/hard to predict memory accesses by laying
out operation metadata sequentially; including the avoidance of
nearly all of the previously used linked lists
- more code has been moved to expression initialization, avoiding
constant re-checks at evaluation time
Future just-in-time compilation (JIT) has become easier, as
demonstrated by released patches intended to be merged in a later
release, for primarily two reasons: Firstly, due to a stricter split
between expression initialization and evaluation, less code has to be
handled by the JIT. Secondly, due to the non-recursive nature of the
generated "instructions", less performance-critical code-paths can
easily be shared between interpreted and compiled evaluation.
The new framework allows for significant future optimizations. E.g.:
- basic infrastructure for to later reduce the per executor-startup
overhead of expression evaluation, by caching state in prepared
statements. That'd be helpful in OLTPish scenarios where
initialization overhead is measurable.
- optimizing the generated "code". A number of proposals for potential
work has already been made.
- optimizing the interpreter. Similarly a number of proposals have
been made here too.
The move of logic into the expression initialization step leads to some
backward-incompatible changes:
- Function permission checks are now done during expression
initialization, whereas previously they were done during
execution. In edge cases this can lead to errors being raised that
previously wouldn't have been, e.g. a NULL array being coerced to a
different array type previously didn't perform checks.
- The set of domain constraints to be checked, is now evaluated once
during expression initialization, previously it was re-built
every time a domain check was evaluated. For normal queries this
doesn't change much, but e.g. for plpgsql functions, which caches
ExprStates, the old set could stick around longer. The behavior
around might still change.
Author: Andres Freund, with significant changes by Tom Lane,
changes by Heikki Linnakangas
Reviewed-By: Tom Lane, Heikki Linnakangas
Discussion: https://postgr.es/m/20161206034955.bh33paeralxbtluv@alap3.anarazel.de
2017-03-14 18:45:36 -04:00
|
|
|
if (qual == NULL || ExecQual(qual, econtext))
|
2000-08-23 23:29:15 -04:00
|
|
|
{
|
2001-03-22 01:16:21 -05:00
|
|
|
/*
|
|
|
|
|
* Found a satisfactory scan tuple.
|
2000-08-23 23:29:15 -04:00
|
|
|
*/
|
2003-02-03 10:07:08 -05:00
|
|
|
if (projInfo)
|
2000-08-23 23:29:15 -04:00
|
|
|
{
|
2003-02-03 10:07:08 -05:00
|
|
|
/*
|
2005-10-14 22:49:52 -04:00
|
|
|
* Form a projection tuple, store it in the result tuple slot
|
2017-01-19 17:12:38 -05:00
|
|
|
* and return it.
|
2003-02-03 10:07:08 -05:00
|
|
|
*/
|
2017-01-19 17:12:38 -05:00
|
|
|
return ExecProject(projInfo);
|
2003-02-03 10:07:08 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Here, we aren't projecting, so just return scan tuple.
|
|
|
|
|
*/
|
|
|
|
|
return slot;
|
2000-08-23 23:29:15 -04:00
|
|
|
}
|
|
|
|
|
}
|
2011-09-22 11:29:18 -04:00
|
|
|
else
|
|
|
|
|
InstrCountFiltered1(node, 1);
|
2000-07-11 22:37:39 -04:00
|
|
|
|
2001-03-22 01:16:21 -05:00
|
|
|
/*
|
|
|
|
|
* Tuple fails qual, so free per-tuple memory and try again.
|
2000-07-11 22:37:39 -04:00
|
|
|
*/
|
|
|
|
|
ResetExprContext(econtext);
|
1997-09-07 01:04:48 -04:00
|
|
|
}
|
1996-07-09 02:22:35 -04:00
|
|
|
}
|
2003-02-03 10:07:08 -05:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ExecAssignScanProjectionInfo
|
|
|
|
|
* Set up projection info for a scan node, if necessary.
|
|
|
|
|
*
|
|
|
|
|
* We can avoid a projection step if the requested tlist exactly matches
|
|
|
|
|
* the underlying tuple type. If so, we just set ps_ProjInfo to NULL.
|
|
|
|
|
* Note that this case occurs not only for simple "SELECT * FROM ...", but
|
|
|
|
|
* also in most cases where there are joins or other processing nodes above
|
|
|
|
|
* the scan node, because the planner will preferentially generate a matching
|
|
|
|
|
* tlist.
|
|
|
|
|
*
|
2018-02-17 00:17:38 -05:00
|
|
|
* The scan slot's descriptor must have been set already.
|
2003-02-03 10:07:08 -05:00
|
|
|
*/
|
|
|
|
|
void
|
2003-08-08 17:42:59 -04:00
|
|
|
ExecAssignScanProjectionInfo(ScanState *node)
|
2003-02-03 10:07:08 -05:00
|
|
|
{
|
2003-08-03 20:43:34 -04:00
|
|
|
Scan *scan = (Scan *) node->ps.plan;
|
2017-11-25 10:49:17 -05:00
|
|
|
TupleDesc tupdesc = node->ss_ScanTupleSlot->tts_tupleDescriptor;
|
2011-10-11 14:20:06 -04:00
|
|
|
|
2017-11-25 10:49:17 -05:00
|
|
|
ExecConditionalAssignProjectionInfo(&node->ps, tupdesc, scan->scanrelid);
|
Code review for foreign/custom join pushdown patch.
Commit e7cb7ee14555cc9c5773e2c102efd6371f6f2005 included some design
decisions that seem pretty questionable to me, and there was quite a lot
of stuff not to like about the documentation and comments. Clean up
as follows:
* Consider foreign joins only between foreign tables on the same server,
rather than between any two foreign tables with the same underlying FDW
handler function. In most if not all cases, the FDW would simply have had
to apply the same-server restriction itself (far more expensively, both for
lack of caching and because it would be repeated for each combination of
input sub-joins), or else risk nasty bugs. Anyone who's really intent on
doing something outside this restriction can always use the
set_join_pathlist_hook.
* Rename fdw_ps_tlist/custom_ps_tlist to fdw_scan_tlist/custom_scan_tlist
to better reflect what they're for, and allow these custom scan tlists
to be used even for base relations.
* Change make_foreignscan() API to include passing the fdw_scan_tlist
value, since the FDW is required to set that. Backwards compatibility
doesn't seem like an adequate reason to expect FDWs to set it in some
ad-hoc extra step, and anyway existing FDWs can just pass NIL.
* Change the API of path-generating subroutines of add_paths_to_joinrel,
and in particular that of GetForeignJoinPaths and set_join_pathlist_hook,
so that various less-used parameters are passed in a struct rather than
as separate parameter-list entries. The objective here is to reduce the
probability that future additions to those parameter lists will result in
source-level API breaks for users of these hooks. It's possible that this
is even a small win for the core code, since most CPU architectures can't
pass more than half a dozen parameters efficiently anyway. I kept root,
joinrel, outerrel, innerrel, and jointype as separate parameters to reduce
code churn in joinpath.c --- in particular, putting jointype into the
struct would have been problematic because of the subroutines' habit of
changing their local copies of that variable.
* Avoid ad-hocery in ExecAssignScanProjectionInfo. It was probably all
right for it to know about IndexOnlyScan, but if the list is to grow
we should refactor the knowledge out to the callers.
* Restore nodeForeignscan.c's previous use of the relcache to avoid
extra GetFdwRoutine lookups for base-relation scans.
* Lots of cleanup of documentation and missed comments. Re-order some
code additions into more logical places.
2015-05-10 14:36:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ExecAssignScanProjectionInfoWithVarno
|
|
|
|
|
* As above, but caller can specify varno expected in Vars in the tlist.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
ExecAssignScanProjectionInfoWithVarno(ScanState *node, Index varno)
|
|
|
|
|
{
|
2017-11-25 10:49:17 -05:00
|
|
|
TupleDesc tupdesc = node->ss_ScanTupleSlot->tts_tupleDescriptor;
|
2004-01-21 21:23:21 -05:00
|
|
|
|
2017-11-25 10:49:17 -05:00
|
|
|
ExecConditionalAssignProjectionInfo(&node->ps, tupdesc, varno);
|
2003-02-03 10:07:08 -05:00
|
|
|
}
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-25 22:26:45 -04:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ExecScanReScan
|
|
|
|
|
*
|
|
|
|
|
* This must be called within the ReScan function of any plan node type
|
|
|
|
|
* that uses ExecScan().
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
ExecScanReScan(ScanState *node)
|
|
|
|
|
{
|
|
|
|
|
EState *estate = node->ps.state;
|
|
|
|
|
|
Fix failure in WHERE CURRENT OF after rewinding the referenced cursor.
In a case where we have multiple relation-scan nodes in a cursor plan,
such as a scan of an inheritance tree, it's possible to fetch from a
given scan node, then rewind the cursor and fetch some row from an
earlier scan node. In such a case, execCurrent.c mistakenly thought
that the later scan node was still active, because ExecReScan hadn't
done anything to make it look not-active. We'd get some sort of
failure in the case of a SeqScan node, because the node's scan tuple
slot would be pointing at a HeapTuple whose t_self gets reset to
invalid by heapam.c. But it seems possible that for other relation
scan node types we'd actually return a valid tuple TID to the caller,
resulting in updating or deleting a tuple that shouldn't have been
considered current. To fix, forcibly clear the ScanTupleSlot in
ExecScanReScan.
Another issue here, which seems only latent at the moment but could
easily become a live bug in future, is that rewinding a cursor does
not necessarily lead to *immediately* applying ExecReScan to every
scan-level node in the plan tree. Upper-level nodes will think that
they can postpone that call if their child node is already marked
with chgParam flags. I don't see a way for that to happen today in
a plan tree that's simple enough for execCurrent.c's search_plan_tree
to understand, but that's one heck of a fragile assumption. So, add
some logic in search_plan_tree to detect chgParam flags being set on
nodes that it descended to/through, and assume that that means we
should consider lower scan nodes to be logically reset even if their
ReScan call hasn't actually happened yet.
Per bug #15395 from Matvey Arye. This has been broken for a long time,
so back-patch to all supported branches.
Discussion: https://postgr.es/m/153764171023.14986.280404050547008575@wrigleys.postgresql.org
2018-09-23 16:05:45 -04:00
|
|
|
/*
|
|
|
|
|
* We must clear the scan tuple so that observers (e.g., execCurrent.c)
|
|
|
|
|
* can tell that this plan node is not positioned on a tuple.
|
|
|
|
|
*/
|
|
|
|
|
ExecClearTuple(node->ss_ScanTupleSlot);
|
|
|
|
|
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-25 22:26:45 -04:00
|
|
|
/* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */
|
|
|
|
|
if (estate->es_epqScanDone != NULL)
|
|
|
|
|
{
|
|
|
|
|
Index scanrelid = ((Scan *) node->ps.plan)->scanrelid;
|
|
|
|
|
|
Allow foreign and custom joins to handle EvalPlanQual rechecks.
Commit e7cb7ee14555cc9c5773e2c102efd6371f6f2005 provided basic
infrastructure for allowing a foreign data wrapper or custom scan
provider to replace a join of one or more tables with a scan.
However, this infrastructure failed to take into account the need
for possible EvalPlanQual rechecks, and ExecScanFetch would fail
an assertion (or just overwrite memory) if such a check was attempted
for a plan containing a pushed-down join. To fix, adjust the EPQ
machinery to skip some processing steps when scanrelid == 0, making
those the responsibility of scan's recheck method, which also has
the responsibility in this case of correctly populating the relevant
slot.
To allow foreign scans to gain control in the right place to make
use of this new facility, add a new, optional RecheckForeignScan
method. Also, allow a foreign scan to have a child plan, which can
be used to correctly populate the slot (or perhaps for something
else, but this is the only use currently envisioned).
KaiGai Kohei, reviewed by Robert Haas, Etsuro Fujita, and Kyotaro
Horiguchi.
2015-12-08 12:31:03 -05:00
|
|
|
if (scanrelid > 0)
|
|
|
|
|
estate->es_epqScanDone[scanrelid - 1] = false;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Bitmapset *relids;
|
|
|
|
|
int rtindex = -1;
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-25 22:26:45 -04:00
|
|
|
|
Allow foreign and custom joins to handle EvalPlanQual rechecks.
Commit e7cb7ee14555cc9c5773e2c102efd6371f6f2005 provided basic
infrastructure for allowing a foreign data wrapper or custom scan
provider to replace a join of one or more tables with a scan.
However, this infrastructure failed to take into account the need
for possible EvalPlanQual rechecks, and ExecScanFetch would fail
an assertion (or just overwrite memory) if such a check was attempted
for a plan containing a pushed-down join. To fix, adjust the EPQ
machinery to skip some processing steps when scanrelid == 0, making
those the responsibility of scan's recheck method, which also has
the responsibility in this case of correctly populating the relevant
slot.
To allow foreign scans to gain control in the right place to make
use of this new facility, add a new, optional RecheckForeignScan
method. Also, allow a foreign scan to have a child plan, which can
be used to correctly populate the slot (or perhaps for something
else, but this is the only use currently envisioned).
KaiGai Kohei, reviewed by Robert Haas, Etsuro Fujita, and Kyotaro
Horiguchi.
2015-12-08 12:31:03 -05:00
|
|
|
/*
|
|
|
|
|
* If an FDW or custom scan provider has replaced the join with a
|
|
|
|
|
* scan, there are multiple RTIs; reset the epqScanDone flag for
|
|
|
|
|
* all of them.
|
|
|
|
|
*/
|
|
|
|
|
if (IsA(node->ps.plan, ForeignScan))
|
|
|
|
|
relids = ((ForeignScan *) node->ps.plan)->fs_relids;
|
|
|
|
|
else if (IsA(node->ps.plan, CustomScan))
|
|
|
|
|
relids = ((CustomScan *) node->ps.plan)->custom_relids;
|
|
|
|
|
else
|
|
|
|
|
elog(ERROR, "unexpected scan node: %d",
|
|
|
|
|
(int) nodeTag(node->ps.plan));
|
|
|
|
|
|
|
|
|
|
while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
|
|
|
|
|
{
|
|
|
|
|
Assert(rtindex > 0);
|
|
|
|
|
estate->es_epqScanDone[rtindex - 1] = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-25 22:26:45 -04:00
|
|
|
}
|
|
|
|
|
}
|