fix: Execute deferred constraint triggers when using Prefer: tx=rollback

Resolves #2020
This commit is contained in:
Wolfgang Walther
2021-11-30 15:54:12 +01:00
committed by Wolfgang Walther
parent bbc07d3f40
commit 1cb00d3c62
5 changed files with 63 additions and 2 deletions
+2
View File
@@ -9,6 +9,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Fixed
- #2020, Execute deferred constraint triggers when using `Prefer: tx=rollback` - @wolfgangwalther
## [9.0.0] - 2021-11-25
### Added
+4 -2
View File
@@ -2,6 +2,7 @@
Module : PostgREST.Middleware
Description : Sets CORS policy. Also the PostgreSQL GUCs, role, search_path and pre-request function.
-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE RecordWildCards #-}
module PostgREST.Middleware
( runPgLocals
@@ -170,8 +171,9 @@ optionalRollback
-> ExceptT Error SQL.Transaction Wai.Response
optionalRollback AppConfig{..} ApiRequest{..} transaction = do
resp <- catchError transaction $ return . errorResponseFor
when (shouldRollback || (configDbTxRollbackAll && not shouldCommit))
(lift SQL.condemn)
when (shouldRollback || (configDbTxRollbackAll && not shouldCommit)) $ lift do
SQL.sql "SET CONSTRAINTS ALL IMMEDIATE"
SQL.condemn
return $ Wai.mapResponseHeaders preferenceApplied resp
where
shouldCommit =
+42
View File
@@ -70,6 +70,35 @@ shouldRespondToReads reqHeaders respHeaders = do
[json|[{"id":1}]|]
{ matchHeaders = respHeaders }
shouldRaiseExceptions reqHeaders respHeaders = do
it "raises immediate constraints" $ do
request methodPost "/rpc/raise_constraint"
reqHeaders
""
`shouldRespondWith`
[json|{
"hint":null,
"details":"Key (col)=(1) already exists.",
"code":"23505",
"message":"duplicate key value violates unique constraint \"deferrable_unique_constraint_col_key\""
}|]
{ matchStatus = 409
, matchHeaders = respHeaders }
it "raises deferred constraints" $ do
request methodPost "/rpc/raise_constraint"
reqHeaders
[json|{"deferred": true}|]
`shouldRespondWith`
[json|{
"hint":null,
"details":"Key (col)=(1) already exists.",
"code":"23505",
"message":"duplicate key value violates unique constraint \"deferrable_unique_constraint_col_key\""
}|]
{ matchStatus = 409
, matchHeaders = respHeaders }
shouldPersistMutations reqHeaders respHeaders = do
it "does persist post" $ do
request methodPost "/items"
@@ -178,28 +207,38 @@ allowed = describe "tx-allow-override = true" $ do
describe "without Prefer tx" $ do
preferDefault `shouldRespondToReads` withoutPreferenceApplied
preferDefault `shouldNotPersistMutations` withoutPreferenceApplied
preferDefault `shouldRaiseExceptions` withoutPreferenceApplied
describe "Prefer tx=commit" $ do
preferCommit `shouldRespondToReads` withPreferenceCommitApplied
preferCommit `shouldPersistMutations` withPreferenceCommitApplied
-- Exceptions are always without preference applied,
-- because they return before the end of the transaction.
preferCommit `shouldRaiseExceptions` withoutPreferenceApplied
describe "Prefer tx=rollback" $ do
preferRollback `shouldRespondToReads` withPreferenceRollbackApplied
preferRollback `shouldNotPersistMutations` withPreferenceRollbackApplied
-- Exceptions are always without preference applied,
-- because they return before the end of the transaction.
preferRollback `shouldRaiseExceptions` withoutPreferenceApplied
disallowed :: SpecWith ((), Application)
disallowed = describe "tx-rollback-all = false, tx-allow-override = false" $ do
describe "without Prefer tx" $ do
preferDefault `shouldRespondToReads` withoutPreferenceApplied
preferDefault `shouldPersistMutations` withoutPreferenceApplied
preferDefault `shouldRaiseExceptions` withoutPreferenceApplied
describe "Prefer tx=commit" $ do
preferCommit `shouldRespondToReads` withoutPreferenceApplied
preferCommit `shouldPersistMutations` withoutPreferenceApplied
preferCommit `shouldRaiseExceptions` withoutPreferenceApplied
describe "Prefer tx=rollback" $ do
preferRollback `shouldRespondToReads` withoutPreferenceApplied
preferRollback `shouldPersistMutations` withoutPreferenceApplied
preferRollback `shouldRaiseExceptions` withoutPreferenceApplied
forced :: SpecWith ((), Application)
@@ -207,12 +246,15 @@ forced = describe "tx-rollback-all = true, tx-allow-override = false" $ do
describe "without Prefer tx" $ do
preferDefault `shouldRespondToReads` withoutPreferenceApplied
preferDefault `shouldNotPersistMutations` withoutPreferenceApplied
preferDefault `shouldRaiseExceptions` withoutPreferenceApplied
describe "Prefer tx=commit" $ do
preferCommit `shouldRespondToReads` withoutPreferenceApplied
preferCommit `shouldNotPersistMutations` withoutPreferenceApplied
preferCommit `shouldRaiseExceptions` withoutPreferenceApplied
describe "Prefer tx=rollback" $ do
preferRollback `shouldRespondToReads` withoutPreferenceApplied
preferRollback `shouldNotPersistMutations` withoutPreferenceApplied
preferRollback `shouldRaiseExceptions` withoutPreferenceApplied
+1
View File
@@ -25,6 +25,7 @@ GRANT ALL ON TABLE
, complex_items
, compound_pk
, compound_pk_view
, deferrable_unique_constraint
, empty_table
, has_count_column
, has_fk
+14
View File
@@ -2448,3 +2448,17 @@ CREATE TABLE chores (
, name text
, done bool
);
CREATE TABLE deferrable_unique_constraint (
col INT UNIQUE DEFERRABLE INITIALLY IMMEDIATE
);
CREATE FUNCTION raise_constraint(deferred BOOL DEFAULT FALSE) RETURNS void
LANGUAGE plpgsql AS $$
BEGIN
IF deferred THEN
SET CONSTRAINTS ALL DEFERRED;
END IF;
INSERT INTO deferrable_unique_constraint VALUES (1), (1);
END$$;