sqlalchemy: CTEs does not work with UPDATE statements using`engine.execute` (in Postgres)
Describe the bug
I first notice this from the python archived records library, which uses sqlalchemy under the hood. We have a query that uses two CTEs and an update statement at the end, what we have noticed is the query is not working if you executed in code, but works if copied the query and executed in DataGrip (or any SQL client i presume).
Expected behavior
Based on the reproduction steps below, record should be (1, 3), but it is still (1, 2), with no error given.
To Reproduce
Setup your table:
CREATE TABLE public.pg_test (
id int,
name varchar
);
INSERT INTO public.pg_test VALUES (1, 2);
Setup engine connection and run the following: Of course this is a very naive example, where the update statement has nothing to do with the CTE.
query = """
WITH to_update AS (
SELECT * FROM playground.pg_test
)
UPDATE playground.pg_test
SET name = 3"""
hook.sqla_engine.execute(
query
)
where the hook.sqla_engine is a Postgres engine.
However if I removed the CTE, left with only the UPDATE statement, it works as expected.
Tested with SELECT queries, they work fine. Not sure about INSERT (vaguely remember it works) AND DELETE
**Versions.**
- OS: Mac OS Catalina
- Python: 3.7
- SQLAlchemy: 1.3.0 and above
- Database: Postgres
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 1
- Comments: 16 (11 by maintainers)
#4846 addresses more verbiage around implicit application level autocommit being deprecated.
Regarding why the update version succeeds while the cte version does not, it is due to the way sqlalchemy detects if it should auto-commit or not. https://github.com/sqlalchemy/sqlalchemy/blob/9a3fee2cb6b608eb5c0263cf5a7e9085f74f2e73/lib/sqlalchemy/engine/default.py#L34-L36
This regexp does not match
CTE ...but does matchUPDATE ...Did a few more testing (maybe I am testing it wrongly but yeah just showing the code I tested below),
Engine.begin()with context manager works as intendedEngine.connect()it does not work, with no error message, echoed SQL is the original SQL, this result matches my experience withrecordspackage since it uses Connection.execute() as well in source, notEngine.execute.I guess you need to commit explicitly then…
By it I mean that you should probably use Engine.begin or Engine.connect instead of execute.