summaryrefslogtreecommitdiff
path: root/src/backend/tcop/utility.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/tcop/utility.c')
-rw-r--r--src/backend/tcop/utility.c77
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")));
-}