Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow READ COMMITTED isolation level #236

Merged
merged 3 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
crdb-version: [
"cockroach:latest-v22.2",
"cockroach:latest-v23.1",
"cockroach-unstable:v23.2.0-beta.2"
"cockroach:latest-v23.2"
]
db-alias: [
"psycopg2",
Expand All @@ -53,8 +53,8 @@ jobs:
TOXENV: py39
TOX_VERSION: 3.23.1
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.9'
- name: Start CockroachDB
Expand All @@ -73,8 +73,8 @@ jobs:
TOXENV: py39
TOX_VERSION: 3.23.1
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.9'
- name: Install testrunner
Expand Down
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Version 2.0.3
Unreleased

- Add support for READ COMMITTED transaction isolation
(see [README.read_committed.md](README.read_committed.md))


# Version 2.0.2
January 10, 2023
Expand Down
37 changes: 37 additions & 0 deletions README.read_committed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
## READ COMMITTED transaction isolation

CockroachDB v23.2.0 added support for READ COMMITTED transaction isolation as
a "preview feature", meaning that we must opt-in to activate it by sending
the statement

```
SET CLUSTER SETTING sql.txn.read_committed_isolation.enabled = true;
```

This statement changes a persisted setting in the CockroachDB cluster. It is meant
to be executed one time by a database operator/administrator.

For testing purposes, this adapter offers a custom `connect=` function that we
can pass to `create_engine()`, which will configure this setting:

```python
import psycopg2
from sqlalchemy import create_engine

def connect_for_read_committed():
cnx = psycopg2.connect("host=localhost port=26257 user=root dbname=defaultdb")
cnx.autocommit = True
crs = cnx.cursor()
crs.execute("SET CLUSTER SETTING sql.txn.read_committed_isolation.enabled = true;")
cnx.autocommit = False
return cnx

engine = create_engine(
"cockroachdb+psycopg2://",
creator=connect_for_read_committed,
isolation_level="READ COMMITTED",
)

with engine.begin() as conn:
conn.exec_driver_sql("UPDATE tbl SET txt = 'SQLAlchemy' WHERE id = 1")
```
2 changes: 1 addition & 1 deletion sqlalchemy_cockroachdb/_psycopg_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ class _CockroachDBDialect_common_psycopg(CockroachDBDialect):
supports_sane_rowcount = False # for psycopg2, at least

def get_isolation_level_values(self, dbapi_conn):
return ("SERIALIZABLE", "AUTOCOMMIT")
return ("SERIALIZABLE", "AUTOCOMMIT", "READ COMMITTED")
2 changes: 1 addition & 1 deletion sqlalchemy_cockroachdb/asyncpg.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ async def setup_asyncpg_json_codec(self, conn):
pass

def get_isolation_level_values(self, dbapi_conn):
return ("SERIALIZABLE", "AUTOCOMMIT")
return ("SERIALIZABLE", "AUTOCOMMIT", "READ COMMITTED")
12 changes: 8 additions & 4 deletions sqlalchemy_cockroachdb/requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,16 @@ def uuid_data_type(self):

@property
def json_deserializer_binary(self):
return exclusions.only_if(
lambda config: config.db.dialect.driver in ["psycopg"]
)
return exclusions.only_if(lambda config: config.db.dialect.driver in ["psycopg"])

def get_isolation_levels(self, config):
return {"default": "SERIALIZABLE", "supported": ["SERIALIZABLE", "AUTOCOMMIT"]}
info = {
"default": "SERIALIZABLE",
"supported": ["SERIALIZABLE", "AUTOCOMMIT"],
}
if config.db.dialect._is_v232plus:
info["supported"].append("READ COMMITTED")
return info

@property
def autocommit(self):
Expand Down
12 changes: 12 additions & 0 deletions test/test_suite_sqlalchemy.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,11 +277,23 @@ def test_no_results_for_non_returning_insert(self):


class IsolationLevelTest(_IsolationLevelTest):
def test_all_levels(self):
if not config.db.dialect._is_v232plus:
# TODO: enable when READ COMMITTED no longer a preview feature, since
# SET CLUSTER SETTING cannot be used inside a multi-statement transaction
super().test_all_levels()

@skip("cockroachdb")
def test_dialect_user_setting_is_restored(self):
# IndexError: list index out of range
pass

def test_non_default_isolation_level(self):
if not config.db.dialect._is_v232plus:
# TODO: enable when READ COMMITTED no longer a preview feature, since
# SET CLUSTER SETTING cannot be used inside a multi-statement transaction
super().test_non_default_isolation_level()


class LongNameBlowoutTest(_LongNameBlowoutTest):
@testing.combinations(
Expand Down