* If the transaction is read-only, we need to check if any writes are
* planned to non-temporary tables. EXPLAIN is considered read-only.
*
- * Don't allow writes in parallel mode. Supporting UPDATE and DELETE would
- * require (a) storing the combocid hash in shared memory, rather than
- * synchronizing it just once at the start of parallelism, and (b) an
+ * Don't allow writes in parallel mode. Supporting UPDATE and DELETE
+ * would require (a) storing the combocid hash in shared memory, rather
+ * than synchronizing it just once at the start of parallelism, and (b) an
* alternative to heap_update()'s reliance on xmax for mutual exclusion.
* INSERT may have no such troubles, but we forbid it to simplify the
* checks.
*
* We have lower-level defenses in CommandCounterIncrement and elsewhere
- * against performing unsafe operations in parallel mode, but this gives
- * a more user-friendly error message.
+ * against performing unsafe operations in parallel mode, but this gives a
+ * more user-friendly error message.
*/
if ((XactReadOnly || IsInParallelMode()) &&
!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
if (!(eflags & (EXEC_FLAG_SKIP_TRIGGERS | EXEC_FLAG_EXPLAIN_ONLY)))
AfterTriggerBeginQuery();
+ /* Enter parallel mode, if required by the query. */
+ if (queryDesc->plannedstmt->parallelModeNeeded &&
+ !(eflags & EXEC_FLAG_EXPLAIN_ONLY))
+ EnterParallelMode();
+
MemoryContextSwitchTo(oldcontext);
}
direction,
dest);
+ /* Allow nodes to release or shut down resources. */
+ (void) ExecShutdownNode(queryDesc->planstate);
+
/*
* shutdown tuple receiver, if we started it
*/
*/
MemoryContextSwitchTo(oldcontext);
+ /* Exit parallel mode, if it was required by the query. */
+ if (queryDesc->plannedstmt->parallelModeNeeded &&
+ !(estate->es_top_eflags & EXEC_FLAG_EXPLAIN_ONLY))
+ ExitParallelMode();
+
/*
* Release EState and per-query memory context. This should release
* everything the executor has allocated.
*/
if (remainingPerms & ACL_INSERT && !ExecCheckRTEPermsModified(relOid,
userid,
- rte->insertedCols,
- ACL_INSERT))
+ rte->insertedCols,
+ ACL_INSERT))
return false;
if (remainingPerms & ACL_UPDATE && !ExecCheckRTEPermsModified(relOid,
userid,
- rte->updatedCols,
- ACL_UPDATE))
+ rte->updatedCols,
+ ACL_UPDATE))
return false;
}
return true;
int col = -1;
/*
- * When the query doesn't explicitly update any columns, allow the
- * query if we have permission on any column of the rel. This is
- * to handle SELECT FOR UPDATE as well as possible corner cases in
- * UPDATE.
+ * When the query doesn't explicitly update any columns, allow the query
+ * if we have permission on any column of the rel. This is to handle
+ * SELECT FOR UPDATE as well as possible corner cases in UPDATE.
*/
if (bms_is_empty(modifiedCols))
{
ListCell *l;
/*
- * Fail if write permissions are requested in parallel mode for
- * table (temp or non-temp), otherwise fail for any non-temp table.
+ * Fail if write permissions are requested in parallel mode for table
+ * (temp or non-temp), otherwise fail for any non-temp table.
*/
foreach(l, plannedstmt->rtable)
{
Relation rel = resultRelInfo->ri_RelationDesc;
TupleDesc tupdesc = RelationGetDescr(rel);
TupleConstr *constr = tupdesc->constr;
- Bitmapset *modifiedCols;
- Bitmapset *insertedCols;
- Bitmapset *updatedCols;
+ Bitmapset *modifiedCols;
+ Bitmapset *insertedCols;
+ Bitmapset *updatedCols;
Assert(constr);
(errcode(ERRCODE_CHECK_VIOLATION),
errmsg("new row for relation \"%s\" violates check constraint \"%s\"",
RelationGetRelationName(rel), failed),
- val_desc ? errdetail("Failing row contains %s.", val_desc) : 0,
+ val_desc ? errdetail("Failing row contains %s.", val_desc) : 0,
errtableconstraint(rel, failed)));
}
}
/*
* WITH CHECK OPTION checks are intended to ensure that the new tuple
* is visible (in the case of a view) or that it passes the
- * 'with-check' policy (in the case of row security).
- * If the qual evaluates to NULL or FALSE, then the new tuple won't be
- * included in the view or doesn't pass the 'with-check' policy for the
- * table. We need ExecQual to return FALSE for NULL to handle the view
- * case (the opposite of what we do above for CHECK constraints).
+ * 'with-check' policy (in the case of row security). If the qual
+ * evaluates to NULL or FALSE, then the new tuple won't be included in
+ * the view or doesn't pass the 'with-check' policy for the table. We
+ * need ExecQual to return FALSE for NULL to handle the view case (the
+ * opposite of what we do above for CHECK constraints).
*/
if (!ExecQual((List *) wcoExpr, econtext, false))
{
switch (wco->kind)
{
- /*
- * For WITH CHECK OPTIONs coming from views, we might be able to
- * provide the details on the row, depending on the permissions
- * on the relation (that is, if the user could view it directly
- * anyway). For RLS violations, we don't include the data since
- * we don't know if the user should be able to view the tuple as
- * as that depends on the USING policy.
- */
+ /*
+ * For WITH CHECK OPTIONs coming from views, we might be
+ * able to provide the details on the row, depending on
+ * the permissions on the relation (that is, if the user
+ * could view it directly anyway). For RLS violations, we
+ * don't include the data since we don't know if the user
+ * should be able to view the tuple as as that depends on
+ * the USING policy.
+ */
case WCO_VIEW_CHECK:
insertedCols = GetInsertedColumns(resultRelInfo, estate);
updatedCols = GetUpdatedColumns(resultRelInfo, estate);
ereport(ERROR,
(errcode(ERRCODE_WITH_CHECK_OPTION_VIOLATION),
- errmsg("new row violates WITH CHECK OPTION for \"%s\"",
- wco->relname),
+ errmsg("new row violates WITH CHECK OPTION for \"%s\"",
+ wco->relname),
val_desc ? errdetail("Failing row contains %s.",
val_desc) : 0));
break;
case WCO_RLS_INSERT_CHECK:
case WCO_RLS_UPDATE_CHECK:
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("new row violates row level security policy for \"%s\"",
- wco->relname)));
+ if (wco->polname != NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("new row violates row level security policy \"%s\" for \"%s\"",
+ wco->polname, wco->relname)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("new row violates row level security policy for \"%s\"",
+ wco->relname)));
break;
case WCO_RLS_CONFLICT_CHECK:
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("new row violates row level security policy (USING expression) for \"%s\"",
- wco->relname)));
+ if (wco->polname != NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("new row violates row level security policy \"%s\" (USING expression) for \"%s\"",
+ wco->polname, wco->relname)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("new row violates row level security policy (USING expression) for \"%s\"",
+ wco->relname)));
break;
default:
elog(ERROR, "unrecognized WCO kind: %u", wco->kind);
* then don't return anything. Otherwise, go through normal permission
* checks.
*/
- if (check_enable_rls(reloid, GetUserId(), true) == RLS_ENABLED)
+ if (check_enable_rls(reloid, InvalidOid, true) == RLS_ENABLED)
return NULL;
initStringInfo(&buf);
{
/*
* No table-level SELECT, so need to make sure they either have
- * SELECT rights on the column or that they have provided the
- * data for the column. If not, omit this column from the error
+ * SELECT rights on the column or that they have provided the data
+ * for the column. If not, omit this column from the error
* message.
*/
aclresult = pg_attribute_aclcheck(reloid, tupdesc->attrs[i]->attnum,
break;
case LockWaitSkip:
if (!ConditionalXactLockTableWait(SnapshotDirty.xmax))
- return NULL; /* skip instead of waiting */
+ return NULL; /* skip instead of waiting */
break;
case LockWaitError:
if (!ConditionalXactLockTableWait(SnapshotDirty.xmax))
ereport(ERROR,
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
errmsg("could not obtain lock on row in relation \"%s\"",
- RelationGetRelationName(relation))));
+ RelationGetRelationName(relation))));
break;
}
continue; /* loop back to repeat heap_fetch */
* doing so would require changing heap_update and
* heap_delete to not complain about updating "invisible"
* tuples, which seems pretty scary (heap_lock_tuple will
- * not complain, but few callers expect HeapTupleInvisible,
- * and we're not one of them). So for now, treat the tuple
- * as deleted and do not process.
+ * not complain, but few callers expect
+ * HeapTupleInvisible, and we're not one of them). So for
+ * now, treat the tuple as deleted and do not process.
*/
ReleaseBuffer(buffer);
return NULL;
if (fdwroutine->RefetchForeignRow == NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot lock rows in foreign table \"%s\"",
- RelationGetRelationName(erm->relation))));
+ errmsg("cannot lock rows in foreign table \"%s\"",
+ RelationGetRelationName(erm->relation))));
copyTuple = fdwroutine->RefetchForeignRow(epqstate->estate,
erm,
datum,