ro_dml_rules.v1.patch
text/x-patch
Filename: ro_dml_rules.v1.patch
Type: text/x-patch
Part: 0
Patch
Format: unified
Series: patch v1
| File | + | − |
|---|---|---|
| src/backend/executor/execMain.c | 8 | 0 |
| src/test/regress/expected/transactions.out | 18 | 0 |
| src/test/regress/sql/transactions.sql | 9 | 0 |
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 1383123..0210d35 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -581,6 +581,14 @@ ExecCheckXactReadOnly(PlannedStmt *plannedstmt)
if (plannedstmt->intoClause != NULL)
goto fail;
+ /*
+ * If we're running a SELECT, allow it. This ensures that a
+ * write rule such as ON INSERT DO SELECT can be executed in
+ * a read-only session.
+ */
+ if (plannedstmt->commandType == CMD_SELECT)
+ return;
+
/* Fail if write permissions are requested on any non-temp table */
foreach(l, plannedstmt->rtable)
{
diff --git a/src/test/regress/expected/transactions.out b/src/test/regress/expected/transactions.out
index fc98f01..f9eda6b 100644
--- a/src/test/regress/expected/transactions.out
+++ b/src/test/regress/expected/transactions.out
@@ -65,6 +65,24 @@ SELECT * FROM writetest, temptest; -- ok
CREATE TABLE test AS SELECT * FROM writetest; -- fail
ERROR: transaction is read-only
+BEGIN;
+SET transaction_read_only = false;
+CREATE RULE write2read_rule AS ON INSERT TO writetest DO INSTEAD SELECT new.a;
+COMMIT;
+BEGIN;
+SHOW transaction_read_only;
+ transaction_read_only
+-----------------------
+ on
+(1 row)
+
+INSERT INTO writetest VALUES (1); -- ok
+ a
+---
+ 1
+(1 row)
+
+COMMIT;
START TRANSACTION READ WRITE;
DROP TABLE writetest; -- ok
COMMIT;
diff --git a/src/test/regress/sql/transactions.sql b/src/test/regress/sql/transactions.sql
index c670ae1..12a03fa 100644
--- a/src/test/regress/sql/transactions.sql
+++ b/src/test/regress/sql/transactions.sql
@@ -51,6 +51,15 @@ EXECUTE test; -- fail
SELECT * FROM writetest, temptest; -- ok
CREATE TABLE test AS SELECT * FROM writetest; -- fail
+BEGIN;
+SET transaction_read_only = false;
+CREATE RULE write2read_rule AS ON INSERT TO writetest DO INSTEAD SELECT new.a;
+COMMIT;
+BEGIN;
+SHOW transaction_read_only;
+INSERT INTO writetest VALUES (1); -- ok
+COMMIT;
+
START TRANSACTION READ WRITE;
DROP TABLE writetest; -- ok
COMMIT;