Junkfilter logic to force a projection step during SELECT INTO was too
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 2 Mar 2004 18:56:15 +0000 (18:56 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 2 Mar 2004 18:56:15 +0000 (18:56 +0000)
simplistic; it recognized SELECT * FROM but not SELECT * FROM LIMIT.
Per bug report from Jeff Bohmer.

src/backend/executor/execAmi.c
src/backend/executor/execMain.c
src/include/executor/executor.h

index d9a24a344848da8c1d7caeb1fe92627798794da6..8bbd1942eba02fa7a0c7c51be0a02501c28a651c 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.77 2003/12/18 20:21:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.78 2004/03/02 18:56:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -348,3 +348,68 @@ ExecSupportsBackwardScan(Plan *node)
            return false;
    }
 }
+
+/*
+ * ExecMayReturnRawTuples
+ *     Check whether a plan tree may return "raw" disk tuples (that is,
+ *     pointers to original data in disk buffers, as opposed to temporary
+ *     tuples constructed by projection steps).  In the case of Append,
+ *     some subplans may return raw tuples and others projected tuples;
+ *     we return "true" if any of the returned tuples could be raw.
+ *
+ * This must be passed an already-initialized planstate tree, because we
+ * need to look at the results of ExecAssignScanProjectionInfo().
+ */
+bool
+ExecMayReturnRawTuples(PlanState *node)
+{
+   /*
+    * At a table scan node, we check whether ExecAssignScanProjectionInfo
+    * decided to do projection or not.  Most non-scan nodes always project
+    * and so we can return "false" immediately.  For nodes that don't
+    * project but just pass up input tuples, we have to recursively
+    * examine the input plan node.
+    *
+    * Note: Hash and Material are listed here because they sometimes
+    * return an original input tuple, not a copy.  But Sort and SetOp
+    * never return an original tuple, so they can be treated like
+    * projecting nodes.
+    */
+   switch (nodeTag(node))
+   {
+       /* Table scan nodes */
+       case T_SeqScanState:
+       case T_IndexScanState:
+       case T_TidScanState:
+       case T_SubqueryScanState:
+       case T_FunctionScanState:
+           if (node->ps_ProjInfo == NULL)
+               return true;
+           break;
+
+       /* Non-projecting nodes */
+       case T_HashState:
+       case T_MaterialState:
+       case T_UniqueState:
+       case T_LimitState:
+           return ExecMayReturnRawTuples(node->lefttree);
+
+       case T_AppendState:
+       {
+           AppendState *appendstate = (AppendState *) node;
+           int         j;
+
+           for (j = 0; j < appendstate->as_nplans; j++)
+           {
+               if (ExecMayReturnRawTuples(appendstate->appendplans[j]))
+                   return true;
+           }
+           break;
+       }
+
+       /* All projecting node types come here */
+       default:
+           break;
+   }
+   return false;
+}
index 4f36602aa048ffb4f656df80b902f5620e86b195..caae6e880e5ed3edb88072336cedd1260bbd7176 100644 (file)
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.228 2004/01/22 02:23:21 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.229 2004/03/02 18:56:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -659,10 +659,10 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly)
    /*
     * Initialize the junk filter if needed.  SELECT and INSERT queries
     * need a filter if there are any junk attrs in the tlist.  INSERT and
-    * SELECT INTO also need a filter if the top plan node is a scan node
-    * that's not doing projection (else we'll be scribbling on the scan
-    * tuple!)  UPDATE and DELETE always need a filter, since there's
-    * always a junk 'ctid' attribute present --- no need to look first.
+    * SELECT INTO also need a filter if the plan may return raw disk tuples
+    * (else heap_insert will be scribbling on the source relation!).
+    * UPDATE and DELETE always need a filter, since there's always a junk
+    * 'ctid' attribute present --- no need to look first.
     */
    {
        bool        junk_filter_needed = false;
@@ -683,18 +683,9 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly)
                    }
                }
                if (!junk_filter_needed &&
-                   (operation == CMD_INSERT || do_select_into))
-               {
-                   if (IsA(planstate, SeqScanState) ||
-                       IsA(planstate, IndexScanState) ||
-                       IsA(planstate, TidScanState) ||
-                       IsA(planstate, SubqueryScanState) ||
-                       IsA(planstate, FunctionScanState))
-                   {
-                       if (planstate->ps_ProjInfo == NULL)
-                           junk_filter_needed = true;
-                   }
-               }
+                   (operation == CMD_INSERT || do_select_into) &&
+                   ExecMayReturnRawTuples(planstate))
+                   junk_filter_needed = true;
                break;
            case CMD_UPDATE:
            case CMD_DELETE:
index 39e07da8afb56cd716387e29a95ad80144de47e9..cc2e49efafc2653216d25102d408a64a0478e6a1 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.106 2004/01/22 02:23:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.107 2004/03/02 18:56:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,6 +36,7 @@ extern void ExecMarkPos(PlanState *node);
 extern void ExecRestrPos(PlanState *node);
 extern bool ExecSupportsMarkRestore(NodeTag plantype);
 extern bool ExecSupportsBackwardScan(Plan *node);
+extern bool ExecMayReturnRawTuples(PlanState *node);
 
 /*
  * prototypes from functions in execGrouping.c