/* 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,
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;
* 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)
}
/*
+ * 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
Oid tablespaceId;
Datum reloptions;
Oid intoRelationId;
- TupleDesc tupdesc;
DR_intorel *myState;
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
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.
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).
*/
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,
InvalidOid,
InvalidOid,
GetUserId(),
- tupdesc,
+ queryDesc->tupDesc,
NIL,
RELKIND_RELATION,
into->rel->relpersistence,
allowSystemTableMods);
Assert(intoRelationId != InvalidOid);
- FreeTupleDesc(tupdesc);
-
/*
* Advance command counter so that the newly-created relation's catalog
* tuples will be visible to heap_open.