Skip to content

Commit 679bb52

Browse files
cpcloudgforsyth
authored andcommitted
feat(duckdb): support sqlalchemy 2
1 parent 7d29c63 commit 679bb52

File tree

5 files changed

+26
-12
lines changed

5 files changed

+26
-12
lines changed

.github/workflows/ibis-backends.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ jobs:
454454
- run: python -m pip install --upgrade pip 'poetry<1.4'
455455

456456
- name: remove deps that are not compatible with sqlalchemy 2
457-
run: poetry remove duckdb-engine snowflake-sqlalchemy
457+
run: poetry remove snowflake-sqlalchemy
458458

459459
- name: add sqlalchemy 2
460460
run: poetry add --lock --optional 'sqlalchemy>=2,<3'
@@ -522,6 +522,10 @@ jobs:
522522
extras:
523523
- trino
524524
- postgres
525+
- name: duckdb
526+
title: DuckDB
527+
extras:
528+
- duckdb
525529
steps:
526530
- name: checkout
527531
uses: actions/checkout@v3

ibis/backends/duckdb/__init__.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,16 @@ def to_pyarrow_batches(
525525
query_ast = self.compiler.to_ast_ensure_limit(expr, limit, params=params)
526526
sql = query_ast.compile()
527527

528-
cursor = self.con.connect().execute(sql)
528+
con = self.con.connect()
529+
530+
# end the current transaction started by sqlalchemy; without this
531+
# duckdb-engine raises an exception disallowing nested transactions
532+
#
533+
# not clear if the value of returning a RecordBatchReader versus an
534+
# iterator of record batches is worth the cursor leakage here
535+
con.exec_driver_sql("COMMIT")
536+
537+
cursor = con.execute(sql)
529538

530539
reader = cursor.cursor.fetch_record_batch(chunk_size=chunk_size)
531540
return IbisRecordBatchReader(reader, cursor)

ibis/backends/duckdb/registry.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,23 +53,24 @@ def _round(t, op):
5353
}
5454

5555

56-
def _generic_log(arg, base):
57-
return sa.func.ln(arg) / sa.func.ln(base)
56+
def _generic_log(arg, base, *, type_):
57+
return sa.func.ln(arg, type_=type_) / sa.func.ln(base, type_=type_)
5858

5959

6060
def _log(t, op):
6161
arg, base = op.args
62+
sqla_type = t.get_sqla_type(op.output_dtype)
6263
sa_arg = t.translate(arg)
6364
if base is not None:
6465
sa_base = t.translate(base)
6566
try:
6667
base_value = sa_base.value
6768
except AttributeError:
68-
return _generic_log(sa_arg, sa_base)
69+
return _generic_log(sa_arg, sa_base, type_=sqla_type)
6970
else:
7071
func = _LOG_BASE_FUNCS.get(base_value, _generic_log)
71-
return func(sa_arg)
72-
return sa.func.ln(sa_arg)
72+
return func(sa_arg, type_=sqla_type)
73+
return sa.func.ln(sa_arg, type_=sqla_type)
7374

7475

7576
def _timestamp_from_unix(t, op):

poetry.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

requirements.txt

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)