summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2021-07-06 22:10:11 +0000
committerTom Lane2021-07-06 22:10:20 +0000
commit955b3e0f9269639fb916cee3dea37aee50b82df0 (patch)
tree395cf4010f26d0e3f2383f9ad724cb683135acce
parent5798ca529935698ab976780565fb2b4d8d34d810 (diff)
Allow CustomScan providers to say whether they support projections.
Previously, all CustomScan providers had to support projections, but there may be cases where this is inconvenient. Add a flag bit to say if it's supported. Important item for the release notes: this is non-backwards-compatible since the default is now to assume that CustomScan providers can't project, instead of assuming that they can. It's fail-soft, but could result in visible performance penalties due to adding unnecessary Result nodes. Sven Klemm, reviewed by Aleksander Alekseev; some cosmetic fiddling by me. Discussion: https://postgr.es/m/CAMCrgp1kyakOz6c8aKhNDJXjhQ1dEjEnp+6KNT3KxPrjNtsrDg@mail.gmail.com
-rw-r--r--doc/src/sgml/custom-scan.sgml13
-rw-r--r--src/backend/executor/execAmi.c17
-rw-r--r--src/backend/optimizer/plan/createplan.c8
-rw-r--r--src/include/nodes/extensible.h4
4 files changed, 26 insertions, 16 deletions
diff --git a/doc/src/sgml/custom-scan.sgml b/doc/src/sgml/custom-scan.sgml
index 239ba29de72..93d96f2f566 100644
--- a/doc/src/sgml/custom-scan.sgml
+++ b/doc/src/sgml/custom-scan.sgml
@@ -71,10 +71,17 @@ typedef struct CustomPath
<para>
<structfield>path</structfield> must be initialized as for any other path, including
the row-count estimate, start and total cost, and sort ordering provided
- by this path. <structfield>flags</structfield> is a bit mask, which should include
+ by this path. <structfield>flags</structfield> is a bit mask, which
+ specifies whether the scan provider can support certain optional
+ capabilities. <structfield>flags</structfield> should include
<literal>CUSTOMPATH_SUPPORT_BACKWARD_SCAN</literal> if the custom path can support
- a backward scan and <literal>CUSTOMPATH_SUPPORT_MARK_RESTORE</literal> if it
- can support mark and restore. Both capabilities are optional.
+ a backward scan, <literal>CUSTOMPATH_SUPPORT_MARK_RESTORE</literal> if it
+ can support mark and restore,
+ and <literal>CUSTOMPATH_SUPPORT_PROJECTION</literal> if it can perform
+ projections. (If <literal>CUSTOMPATH_SUPPORT_PROJECTION</literal> is not
+ set, the scan node will only be asked to produce Vars of the scanned
+ relation; while if that flag is set, the scan node must be able to
+ evaluate scalar expressions over these Vars.)
An optional <structfield>custom_paths</structfield> is a list of <structname>Path</structname>
nodes used by this custom-path node; these will be transformed into
<structname>Plan</structname> nodes by planner.
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index 10f0b349b58..522b1c20863 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -438,13 +438,10 @@ ExecSupportsMarkRestore(Path *pathnode)
return true;
case T_CustomScan:
- {
- CustomPath *customPath = castNode(CustomPath, pathnode);
+ if (castNode(CustomPath, pathnode)->flags & CUSTOMPATH_SUPPORT_MARK_RESTORE)
+ return true;
+ return false;
- if (customPath->flags & CUSTOMPATH_SUPPORT_MARK_RESTORE)
- return true;
- return false;
- }
case T_Result:
/*
@@ -567,12 +564,8 @@ ExecSupportsBackwardScan(Plan *node)
return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan);
case T_CustomScan:
- {
- uint32 flags = ((CustomScan *) node)->flags;
-
- if (flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN)
- return true;
- }
+ if (((CustomScan *) node)->flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN)
+ return true;
return false;
case T_SeqScan:
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 439e6b6426c..c13da7a879f 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -7046,6 +7046,10 @@ is_projection_capable_path(Path *path)
case T_MergeAppend:
case T_RecursiveUnion:
return false;
+ case T_CustomScan:
+ if (castNode(CustomPath, path)->flags & CUSTOMPATH_SUPPORT_PROJECTION)
+ return true;
+ return false;
case T_Append:
/*
@@ -7092,6 +7096,10 @@ is_projection_capable_plan(Plan *plan)
case T_MergeAppend:
case T_RecursiveUnion:
return false;
+ case T_CustomScan:
+ if (((CustomScan *) plan)->flags & CUSTOMPATH_SUPPORT_PROJECTION)
+ return true;
+ return false;
case T_ProjectSet:
/*
diff --git a/src/include/nodes/extensible.h b/src/include/nodes/extensible.h
index 9e425e56518..cc9b7e9928d 100644
--- a/src/include/nodes/extensible.h
+++ b/src/include/nodes/extensible.h
@@ -76,10 +76,12 @@ extern const ExtensibleNodeMethods *GetExtensibleNodeMethods(const char *name,
/*
* Flags for custom paths, indicating what capabilities the resulting scan
- * will have.
+ * will have. The flags fields of CustomPath and CustomScan nodes are
+ * bitmasks of these flags.
*/
#define CUSTOMPATH_SUPPORT_BACKWARD_SCAN 0x0001
#define CUSTOMPATH_SUPPORT_MARK_RESTORE 0x0002
+#define CUSTOMPATH_SUPPORT_PROJECTION 0x0004
/*
* Custom path methods. Mostly, we just need to know how to convert a