aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execMain.c50
1 files changed, 49 insertions, 1 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 613a62c3c37..a1a8134a6a7 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.196 2003/01/08 23:32:29 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.197 2003/01/10 22:03:27 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -85,6 +85,7 @@ static void ExecUpdate(TupleTableSlot *slot, ItemPointer tupleid,
static TupleTableSlot *EvalPlanQualNext(EState *estate);
static void EndEvalPlanQual(EState *estate);
static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
+static void ExecCheckXactReadOnly(Query *parsetree, CmdType operation);
static void EvalPlanQualStart(evalPlanQual *epq, EState *estate,
evalPlanQual *priorepq);
static void EvalPlanQualStop(evalPlanQual *epq);
@@ -202,6 +203,14 @@ ExecutorRun(QueryDesc *queryDesc,
dest = queryDesc->dest;
/*
+ * If the transaction is read-only, we need to check if any writes
+ * are planned to non-temporary tables. This is done here at this
+ * rather late stage so that we can handle EXPLAIN vs. EXPLAIN
+ * ANALYZE easily.
+ */
+ ExecCheckXactReadOnly(queryDesc->parsetree, operation);
+
+ /*
* startup tuple receiver
*/
estate->es_processed = 0;
@@ -385,6 +394,45 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
*/
+static void
+ExecCheckXactReadOnly(Query *parsetree, CmdType operation)
+{
+ if (!XactReadOnly)
+ return;
+
+ /* CREATE TABLE AS or SELECT INTO */
+ if (operation == CMD_SELECT && parsetree->into != NULL)
+ goto fail;
+
+ if (operation == CMD_DELETE || operation == CMD_INSERT
+ || operation == CMD_UPDATE)
+ {
+ List *lp;
+
+ foreach(lp, parsetree->rtable)
+ {
+ RangeTblEntry *rte = lfirst(lp);
+
+ if (rte->rtekind != RTE_RELATION)
+ continue;
+
+ if (!rte->checkForWrite)
+ continue;
+
+ if (isTempNamespace(RelidGetNamespaceId(rte->relid)))
+ continue;
+
+ goto fail;
+ }
+ }
+
+ return;
+
+fail:
+ elog(ERROR, "transaction is read-only");
+}
+
+
/* ----------------------------------------------------------------
* InitPlan
*