OSDN Git Service

Fix bugs in relpersistence handling during table creation.
[pg-rex/syncrep.git] / src / backend / executor / execMain.c
index 620efda..eacd863 100644 (file)
@@ -74,6 +74,7 @@ ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook = NULL;
 
 /* decls for local routines only used within this module */
 static void InitPlan(QueryDesc *queryDesc, int eflags);
+static void CheckValidRowMarkRel(Relation rel, RowMarkType markType);
 static void ExecPostprocessPlan(EState *estate);
 static void ExecEndPlan(PlanState *planstate, EState *estate);
 static void ExecutePlan(EState *estate, PlanState *planstate,
@@ -837,12 +838,9 @@ InitPlan(QueryDesc *queryDesc, int eflags)
                                break;
                }
 
-               /* if foreign table, tuples can't be locked */
-               if (relation && relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                        errmsg("SELECT FOR UPDATE/SHARE cannot be used with foreign table \"%s\"",
-                                                       RelationGetRelationName(relation))));
+               /* Check that relation is a legal target for marking */
+               if (relation)
+                       CheckValidRowMarkRel(relation, rc->markType);
 
                erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
                erm->relation = relation;
@@ -977,6 +975,9 @@ InitPlan(QueryDesc *queryDesc, int eflags)
  * In most cases parser and/or planner should have noticed this already, but
  * let's make sure.  In the view case we do need a test here, because if the
  * view wasn't rewritten by a rule, it had better have an INSTEAD trigger.
+ *
+ * Note: when changing this function, you probably also need to look at
+ * CheckValidRowMarkRel.
  */
 void
 CheckValidResultRel(Relation resultRel, CmdType operation)
@@ -1048,6 +1049,57 @@ CheckValidResultRel(Relation resultRel, CmdType operation)
 }
 
 /*
+ * Check that a proposed rowmark target relation is a legal target
+ *
+ * In most cases parser and/or planner should have noticed this already, but
+ * they don't cover all cases.
+ */
+static void
+CheckValidRowMarkRel(Relation rel, RowMarkType markType)
+{
+       switch (rel->rd_rel->relkind)
+       {
+               case RELKIND_RELATION:
+                       /* OK */
+                       break;
+               case RELKIND_SEQUENCE:
+                       /* Must disallow this because we don't vacuum sequences */
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                                        errmsg("cannot lock rows in sequence \"%s\"",
+                                                       RelationGetRelationName(rel))));
+                       break;
+               case RELKIND_TOASTVALUE:
+                       /* We could allow this, but there seems no good reason to */
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                                        errmsg("cannot lock rows in TOAST relation \"%s\"",
+                                                       RelationGetRelationName(rel))));
+                       break;
+               case RELKIND_VIEW:
+                       /* Should not get here */
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                                        errmsg("cannot lock rows in view \"%s\"",
+                                                       RelationGetRelationName(rel))));
+                       break;
+               case RELKIND_FOREIGN_TABLE:
+                       /* Perhaps we can support this someday, but not today */
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                                        errmsg("cannot lock rows in foreign table \"%s\"",
+                                                       RelationGetRelationName(rel))));
+                       break;
+               default:
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                                        errmsg("cannot lock rows in relation \"%s\"",
+                                                       RelationGetRelationName(rel))));
+                       break;
+       }
+}
+
+/*
  * Initialize ResultRelInfo data for one result relation
  *
  * Caution: before Postgres 9.1, this function included the relkind checking
@@ -2342,7 +2394,6 @@ OpenIntoRel(QueryDesc *queryDesc)
        Oid                     tablespaceId;
        Datum           reloptions;
        Oid                     intoRelationId;
-       TupleDesc       tupdesc;
        DR_intorel *myState;
        static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
 
@@ -2363,6 +2414,13 @@ OpenIntoRel(QueryDesc *queryDesc)
                                 errmsg("ON COMMIT can only be used on temporary tables")));
 
        /*
+        * Find namespace to create in, check its permissions
+        */
+       intoName = into->rel->relname;
+       namespaceId = RangeVarGetAndCheckCreationNamespace(into->rel);
+       RangeVarAdjustRelationPersistence(into->rel, namespaceId);
+
+       /*
         * Security check: disallow creating temp tables from security-restricted
         * code.  This is needed because calling code might not expect untrusted
         * tables to appear in pg_temp at the front of its search path.
@@ -2374,12 +2432,6 @@ OpenIntoRel(QueryDesc *queryDesc)
                                 errmsg("cannot create temporary table within security-restricted operation")));
 
        /*
-        * Find namespace to create in, check its permissions
-        */
-       intoName = into->rel->relname;
-       namespaceId = RangeVarGetAndCheckCreationNamespace(into->rel);
-
-       /*
         * Select tablespace to use.  If not specified, use default tablespace
         * (which may in turn default to database's default).
         */
@@ -2415,9 +2467,6 @@ OpenIntoRel(QueryDesc *queryDesc)
                                                                         false);
        (void) heap_reloptions(RELKIND_RELATION, reloptions, true);
 
-       /* Copy the tupdesc because heap_create_with_catalog modifies it */
-       tupdesc = CreateTupleDescCopy(queryDesc->tupDesc);
-
        /* Now we can actually create the new relation */
        intoRelationId = heap_create_with_catalog(intoName,
                                                                                          namespaceId,
@@ -2426,7 +2475,7 @@ OpenIntoRel(QueryDesc *queryDesc)
                                                                                          InvalidOid,
                                                                                          InvalidOid,
                                                                                          GetUserId(),
-                                                                                         tupdesc,
+                                                                                         queryDesc->tupDesc,
                                                                                          NIL,
                                                                                          RELKIND_RELATION,
                                                                                          into->rel->relpersistence,
@@ -2440,8 +2489,6 @@ OpenIntoRel(QueryDesc *queryDesc)
                                                                                          allowSystemTableMods);
        Assert(intoRelationId != InvalidOid);
 
-       FreeTupleDesc(tupdesc);
-
        /*
         * Advance command counter so that the newly-created relation's catalog
         * tuples will be visible to heap_open.