diff options
Diffstat (limited to 'src/backend/tcop/utility.c')
-rw-r--r-- | src/backend/tcop/utility.c | 77 |
1 files changed, 52 insertions, 25 deletions
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 07f4d0c57ad..6dc5a51cd2a 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.333 2010/02/16 22:34:50 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.334 2010/02/20 21:24:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -151,7 +151,8 @@ check_xact_readonly(Node *parsetree) /* * Note: Commands that need to do more complicated checking are handled * elsewhere, in particular COPY and plannable statements do their own - * checking. + * checking. However they should all call PreventCommandIfReadOnly to + * actually throw the error. */ switch (nodeTag(parsetree)) @@ -217,9 +218,7 @@ check_xact_readonly(Node *parsetree) case T_AlterUserMappingStmt: case T_DropUserMappingStmt: case T_AlterTableSpaceOptionsStmt: - ereport(ERROR, - (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION), - errmsg("transaction is read-only"))); + PreventCommandIfReadOnly(CreateCommandTag(parsetree)); break; default: /* do nothing */ @@ -227,6 +226,41 @@ check_xact_readonly(Node *parsetree) } } +/* + * PreventCommandIfReadOnly: throw error if XactReadOnly + * + * This is useful mainly to ensure consistency of the error message wording; + * most callers have checked XactReadOnly for themselves. + */ +void +PreventCommandIfReadOnly(const char *cmdname) +{ + if (XactReadOnly) + ereport(ERROR, + (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION), + /* translator: %s is name of a SQL command, eg CREATE */ + errmsg("cannot execute %s in a read-only transaction", + cmdname))); +} + +/* + * PreventCommandDuringRecovery: throw error if RecoveryInProgress + * + * The majority of operations that are unsafe in a Hot Standby slave + * will be rejected by XactReadOnly tests. However there are a few + * commands that are allowed in "read-only" xacts but cannot be allowed + * in Hot Standby mode. Those commands should call this function. + */ +void +PreventCommandDuringRecovery(const char *cmdname) +{ + if (RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION), + /* translator: %s is name of a SQL command, eg CREATE */ + errmsg("cannot execute %s during recovery", + cmdname))); +} /* * CheckRestrictedOperation: throw error for hazardous command if we're @@ -350,7 +384,7 @@ standard_ProcessUtility(Node *parsetree, break; case TRANS_STMT_PREPARE: - PreventCommandDuringRecovery(); + PreventCommandDuringRecovery("PREPARE TRANSACTION"); if (!PrepareTransactionBlock(stmt->gid)) { /* report unsuccessful commit in completionTag */ @@ -360,14 +394,14 @@ standard_ProcessUtility(Node *parsetree, break; case TRANS_STMT_COMMIT_PREPARED: - PreventCommandDuringRecovery(); PreventTransactionChain(isTopLevel, "COMMIT PREPARED"); + PreventCommandDuringRecovery("COMMIT PREPARED"); FinishPreparedTransaction(stmt->gid, true); break; case TRANS_STMT_ROLLBACK_PREPARED: - PreventCommandDuringRecovery(); PreventTransactionChain(isTopLevel, "ROLLBACK PREPARED"); + PreventCommandDuringRecovery("ROLLBACK PREPARED"); FinishPreparedTransaction(stmt->gid, false); break; @@ -744,7 +778,6 @@ standard_ProcessUtility(Node *parsetree, break; case T_GrantStmt: - PreventCommandDuringRecovery(); ExecuteGrantStmt((GrantStmt *) parsetree); break; @@ -927,7 +960,7 @@ standard_ProcessUtility(Node *parsetree, { NotifyStmt *stmt = (NotifyStmt *) parsetree; - PreventCommandDuringRecovery(); + PreventCommandDuringRecovery("NOTIFY"); Async_Notify(stmt->conditionname, stmt->payload); } break; @@ -936,7 +969,7 @@ standard_ProcessUtility(Node *parsetree, { ListenStmt *stmt = (ListenStmt *) parsetree; - PreventCommandDuringRecovery(); + PreventCommandDuringRecovery("LISTEN"); CheckRestrictedOperation("LISTEN"); Async_Listen(stmt->conditionname); } @@ -946,7 +979,7 @@ standard_ProcessUtility(Node *parsetree, { UnlistenStmt *stmt = (UnlistenStmt *) parsetree; - PreventCommandDuringRecovery(); + PreventCommandDuringRecovery("UNLISTEN"); CheckRestrictedOperation("UNLISTEN"); if (stmt->conditionname) Async_Unlisten(stmt->conditionname); @@ -966,12 +999,14 @@ standard_ProcessUtility(Node *parsetree, break; case T_ClusterStmt: - PreventCommandDuringRecovery(); + /* we choose to allow this during "read only" transactions */ + PreventCommandDuringRecovery("CLUSTER"); cluster((ClusterStmt *) parsetree, isTopLevel); break; case T_VacuumStmt: - PreventCommandDuringRecovery(); + /* we choose to allow this during "read only" transactions */ + PreventCommandDuringRecovery("VACUUM"); vacuum((VacuumStmt *) parsetree, InvalidOid, true, NULL, false, isTopLevel); break; @@ -1099,14 +1134,15 @@ standard_ProcessUtility(Node *parsetree, * using various forms of replication. */ RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_WAIT | - (RecoveryInProgress() ? 0 : CHECKPOINT_FORCE)); + (RecoveryInProgress() ? 0 : CHECKPOINT_FORCE)); break; case T_ReindexStmt: { ReindexStmt *stmt = (ReindexStmt *) parsetree; - PreventCommandDuringRecovery(); + /* we choose to allow this during "read only" transactions */ + PreventCommandDuringRecovery("REINDEX"); switch (stmt->kind) { case OBJECT_INDEX: @@ -2630,12 +2666,3 @@ GetCommandLogLevel(Node *parsetree) return lev; } - -void -PreventCommandDuringRecovery(void) -{ - if (RecoveryInProgress()) - ereport(ERROR, - (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION), - errmsg("cannot be executed during recovery"))); -} |