Change CREATE TABLE AS / SELECT INTO to create the new table with OIDs,
authorTom Lane
Thu, 23 Jan 2003 05:10:41 +0000 (05:10 +0000)
committerTom Lane
Thu, 23 Jan 2003 05:10:41 +0000 (05:10 +0000)
for backwards compatibility with pre-7.3 behavior.  Per discussion on
pgsql-general and pgsql-hackers.

src/backend/executor/execMain.c
src/backend/executor/execUtils.c
src/include/nodes/execnodes.h

index 04aed372c004e856aae44576f1373d33e080b65f..e1178cd6a69cfa33703ee32302e0c76047cab23b 100644 (file)
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.198 2003/01/12 18:19:37 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.199 2003/01/23 05:10:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -450,6 +450,7 @@ InitPlan(QueryDesc *queryDesc)
    PlanState  *planstate;
    List       *rangeTable;
    Relation    intoRelationDesc;
+   bool        do_select_into;
    TupleDesc   tupType;
 
    /*
@@ -529,6 +530,26 @@ InitPlan(QueryDesc *queryDesc)
        estate->es_result_relation_info = NULL;
    }
 
+   /*
+    * Detect whether we're doing SELECT INTO.  If so, set the force_oids
+    * flag appropriately so that the plan tree will be initialized with
+    * the correct tuple descriptors.
+    */
+   do_select_into = false;
+
+   if (operation == CMD_SELECT &&
+       !parseTree->isPortal &&
+       parseTree->into != NULL)
+   {
+       do_select_into = true;
+       /*
+        * For now, always create OIDs in SELECT INTO; this is for backwards
+        * compatibility with pre-7.3 behavior.  Eventually we might want
+        * to allow the user to choose.
+        */
+       estate->es_force_oids = true;
+   }
+
    /*
     * Have to lock relations selected for update
     */
@@ -687,79 +708,64 @@ InitPlan(QueryDesc *queryDesc)
    }
 
    /*
-    * initialize the "into" relation
+    * If doing SELECT INTO, initialize the "into" relation.  We must wait
+    * till now so we have the "clean" result tuple type to create the
+    * new table from.
     */
    intoRelationDesc = (Relation) NULL;
 
-   if (operation == CMD_SELECT)
+   if (do_select_into)
    {
-       if (!parseTree->isPortal)
-       {
-           /*
-            * a select into table --- need to create the "into" table
-            */
-           if (parseTree->into != NULL)
-           {
-               char       *intoName;
-               Oid         namespaceId;
-               AclResult   aclresult;
-               Oid         intoRelationId;
-               TupleDesc   tupdesc;
+       char       *intoName;
+       Oid         namespaceId;
+       AclResult   aclresult;
+       Oid         intoRelationId;
+       TupleDesc   tupdesc;
 
-               /*
-                * find namespace to create in, check permissions
-                */
-               intoName = parseTree->into->relname;
-               namespaceId = RangeVarGetCreationNamespace(parseTree->into);
+       /*
+        * find namespace to create in, check permissions
+        */
+       intoName = parseTree->into->relname;
+       namespaceId = RangeVarGetCreationNamespace(parseTree->into);
 
-               aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
-                                                 ACL_CREATE);
-               if (aclresult != ACLCHECK_OK)
-                   aclcheck_error(aclresult,
-                                  get_namespace_name(namespaceId));
+       aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
+                                         ACL_CREATE);
+       if (aclresult != ACLCHECK_OK)
+           aclcheck_error(aclresult, get_namespace_name(namespaceId));
 
-               /*
-                * have to copy tupType to get rid of constraints
-                */
-               tupdesc = CreateTupleDescCopy(tupType);
-
-               /*
-                * Formerly we forced the output table to have OIDs, but
-                * as of 7.3 it will not have OIDs, because it's too late
-                * here to change the tupdescs of the already-initialized
-                * plan tree.  (Perhaps we could recurse and change them
-                * all, but it's not really worth the trouble IMHO...)
-                */
+       /*
+        * have to copy tupType to get rid of constraints
+        */
+       tupdesc = CreateTupleDescCopy(tupType);
 
-               intoRelationId =
-                   heap_create_with_catalog(intoName,
-                                            namespaceId,
-                                            tupdesc,
-                                            RELKIND_RELATION,
-                                            false,
-                                            ONCOMMIT_NOOP,
-                                            allowSystemTableMods);
+       intoRelationId = heap_create_with_catalog(intoName,
+                                                 namespaceId,
+                                                 tupdesc,
+                                                 RELKIND_RELATION,
+                                                 false,
+                                                 ONCOMMIT_NOOP,
+                                                 allowSystemTableMods);
 
-               FreeTupleDesc(tupdesc);
+       FreeTupleDesc(tupdesc);
 
-               /*
-                * Advance command counter so that the newly-created
-                * relation's catalog tuples will be visible to heap_open.
-                */
-               CommandCounterIncrement();
+       /*
+        * Advance command counter so that the newly-created
+        * relation's catalog tuples will be visible to heap_open.
+        */
+       CommandCounterIncrement();
 
-               /*
-                * If necessary, create a TOAST table for the into
-                * relation. Note that AlterTableCreateToastTable ends
-                * with CommandCounterIncrement(), so that the TOAST table
-                * will be visible for insertion.
-                */
-               AlterTableCreateToastTable(intoRelationId, true);
+       /*
+        * If necessary, create a TOAST table for the into
+        * relation. Note that AlterTableCreateToastTable ends
+        * with CommandCounterIncrement(), so that the TOAST table
+        * will be visible for insertion.
+        */
+       AlterTableCreateToastTable(intoRelationId, true);
 
-               intoRelationDesc = heap_open(intoRelationId,
-                                            AccessExclusiveLock);
-           }
-       }
+       /*
+        * And open the constructed table for writing.
+        */
+       intoRelationDesc = heap_open(intoRelationId, AccessExclusiveLock);
    }
 
    estate->es_into_relation_descriptor = intoRelationDesc;
@@ -1964,6 +1970,7 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
            palloc0(estate->es_topPlan->nParamExec * sizeof(ParamExecData));
    epqstate->es_rowMark = estate->es_rowMark;
    epqstate->es_instrument = estate->es_instrument;
+   epqstate->es_force_oids = estate->es_force_oids;
    epqstate->es_topPlan = estate->es_topPlan;
    /*
     * Each epqstate must have its own es_evTupleNull state, but
index 63eede2280234d613b4cbb1ef595fd4c65e17dea..90bd8adf1ae13beef3fb1230e223979127473bae 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.95 2003/01/12 04:03:34 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.96 2003/01/23 05:10:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -199,6 +199,7 @@ CreateExecutorState(void)
    estate->es_rowMark = NIL;
 
    estate->es_instrument = false;
+   estate->es_force_oids = false;
 
    estate->es_exprcontexts = NIL;
 
@@ -424,7 +425,6 @@ ExecAssignResultTypeFromOuterPlan(PlanState *planstate)
 void
 ExecAssignResultTypeFromTL(PlanState *planstate)
 {
-   ResultRelInfo *ri;
    bool        hasoid = false;
    TupleDesc   tupDesc;
 
@@ -444,14 +444,24 @@ ExecAssignResultTypeFromTL(PlanState *planstate)
     * have to make the decision on a per-relation basis as we initialize
     * each of the child plans of the topmost Append plan.  So, this is
     * ugly but it works, for now ...
+    *
+    * SELECT INTO is also pretty grotty, because we don't yet have the
+    * INTO relation's descriptor at this point; we have to look aside
+    * at a flag set by InitPlan().
     */
-   ri = planstate->state->es_result_relation_info;
-   if (ri != NULL)
+   if (planstate->state->es_force_oids)
+       hasoid = true;
+   else
    {
-       Relation    rel = ri->ri_RelationDesc;
+       ResultRelInfo *ri = planstate->state->es_result_relation_info;
 
-       if (rel != NULL)
-           hasoid = rel->rd_rel->relhasoids;
+       if (ri != NULL)
+       {
+           Relation    rel = ri->ri_RelationDesc;
+
+           if (rel != NULL)
+               hasoid = rel->rd_rel->relhasoids;
+       }
    }
 
    /*
index 2aa672b65ea345f22ce67ecac7afecb292945b85..98c6f1ddfbd0b3f013da586e70f5485b12ed7e8b 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: execnodes.h,v 1.91 2003/01/12 04:03:34 tgl Exp $
+ * $Id: execnodes.h,v 1.92 2003/01/23 05:10:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -311,6 +311,8 @@ typedef struct EState
    List       *es_rowMark;     /* not good place, but there is no other */
 
    bool        es_instrument;  /* true requests runtime instrumentation */
+   bool        es_force_oids;  /* true forces result tuples to have (space
+                                * for) OIDs --- used for SELECT INTO */
 
    List       *es_exprcontexts; /* List of ExprContexts within EState */