Allow CustomScan providers to say whether they support projections.
authorTom Lane <[email protected]>
Tue, 6 Jul 2021 22:10:11 +0000 (18:10 -0400)
committerTom Lane <[email protected]>
Tue, 6 Jul 2021 22:10:20 +0000 (18:10 -0400)
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

doc/src/sgml/custom-scan.sgml
src/backend/executor/execAmi.c
src/backend/optimizer/plan/createplan.c
src/include/nodes/extensible.h

index 239ba29de72a495b8c16ff516f0a25a90b9288eb..93d96f2f5669090db46d81ae5aadd5547fb6ff48 100644 (file)
@@ -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.
index 10f0b349b583ab20535dbeda1dd97d7d80722f45..522b1c2086377eb293e09d599614ce8e28b62b85 100644 (file)
@@ -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:
index 439e6b6426c8df120e1199d2ca54cd7b2a2f9a34..c13da7a879ffe668856f1b2be8961a17df9d008a 100644 (file)
@@ -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:
 
            /*
index 9e425e56518944e490d56ffd26fa4092795d6fff..cc9b7e9928d2ceeac641996123b02d2df69e4f90 100644 (file)
@@ -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