Skip to content

Commit 7e5a18c

Browse files
committed
Fix transaction errors and more
1 parent ab2d2a3 commit 7e5a18c

6 files changed

Lines changed: 25 additions & 55 deletions

File tree

src/duckdb_py/pyrelation.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ unique_ptr<DuckDBPyRelation> DuckDBPyRelation::ProjectFromTypes(const py::object
128128
LogicalType type;
129129
if (py::isinstance<py::str>(item)) {
130130
string type_str = py::str(item);
131-
type = TransformStringToLogicalType(type_str, *rel->context->GetContext());
131+
rel->context->GetContext()->RunFunctionInTransaction(
132+
[&]() { type = TransformStringToLogicalType(type_str, *rel->context->GetContext().get()); });
132133
} else if (py::isinstance<DuckDBPyType>(item)) {
133134
auto *type_p = item.cast<DuckDBPyType *>();
134135
type = type_p->Type();

src/duckdb_py/typing/pytype.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,10 @@ static LogicalType FromString(const string &type_str, shared_ptr<DuckDBPyConnect
122122
pycon = DuckDBPyConnection::DefaultConnection();
123123
}
124124
auto &connection = pycon->con.GetConnection();
125-
if (connection.HasActiveTransaction()) {
126-
return TransformStringToLogicalType(type_str, *connection.context);
127-
}
128-
connection.BeginTransaction();
129-
auto type = TransformStringToLogicalType(type_str, *connection.context);
130-
connection.Commit();
125+
126+
LogicalType type;
127+
connection.context->RunFunctionInTransaction(
128+
[&]() { type = TransformStringToLogicalType(type_str, *connection.context); });
131129
return type;
132130
}
133131

tests/fast/arrow/test_filter_pushdown.py

Lines changed: 17 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,25 @@
22
import sys
33

44
import pytest
5-
from conftest import pandas_supports_arrow_backend
5+
from conftest import PANDAS_GE_3
66
from packaging.version import Version
77

88
import duckdb
99

1010
pa = pytest.importorskip("pyarrow")
11-
pd = pytest.importorskip("pyarrow.dataset")
11+
pa_ds = pytest.importorskip("pyarrow.dataset")
1212
pa_lib = pytest.importorskip("pyarrow.lib")
13-
pq = pytest.importorskip("pyarrow.parquet")
13+
pa_parquet = pytest.importorskip("pyarrow.parquet")
14+
pd = pytest.importorskip("pandas")
1415
np = pytest.importorskip("numpy")
1516
re = pytest.importorskip("re")
1617

1718

1819
def create_pyarrow_pandas(rel):
19-
if not pandas_supports_arrow_backend():
20-
pytest.skip(reason="Pandas version doesn't support 'pyarrow' backend")
21-
return rel.df().convert_dtypes(dtype_backend="pyarrow")
20+
if PANDAS_GE_3:
21+
return rel.df()
22+
else:
23+
return rel.df().convert_dtypes(dtype_backend="pyarrow")
2224

2325

2426
def create_pyarrow_table(rel):
@@ -27,7 +29,7 @@ def create_pyarrow_table(rel):
2729

2830
def create_pyarrow_dataset(rel):
2931
table = create_pyarrow_table(rel)
30-
return pd.dataset(table)
32+
return pa_ds.dataset(table)
3133

3234

3335
def test_decimal_filter_pushdown(duckdb_cursor):
@@ -550,7 +552,7 @@ def test_9371(self, duckdb_cursor, tmp_path):
550552
df = df.set_index("ts") # SET INDEX! (It all works correctly when the index is not set)
551553
df.to_parquet(str(file_path))
552554

553-
my_arrow_dataset = pd.dataset(str(file_path))
555+
my_arrow_dataset = pa_ds.dataset(str(file_path))
554556
res = duckdb_cursor.execute("SELECT * FROM my_arrow_dataset WHERE ts = ?", parameters=[dt]).fetch_arrow_table()
555557
output = duckdb_cursor.sql("select * from res").fetchall()
556558
expected = [(1, dt), (2, dt), (3, dt)]
@@ -708,34 +710,6 @@ def test_filter_pushdown_2145(self, duckdb_cursor, tmp_path, create_table):
708710
expected_df = duckdb.from_parquet(glob_pattern.as_posix()).filter("date > '2019-01-01'").df()
709711
pandas.testing.assert_frame_equal(expected_df, output_df)
710712

711-
# https://github.com/duckdb/duckdb/pull/4817/files#r1339973721
712-
@pytest.mark.parametrize("create_table", [create_pyarrow_pandas, create_pyarrow_table])
713-
def test_filter_column_removal(self, duckdb_cursor, create_table):
714-
duckdb_cursor.execute(
715-
"""
716-
CREATE TABLE test AS SELECT
717-
range a,
718-
100 - range b
719-
FROM range(100)
720-
"""
721-
)
722-
duck_test_table = duckdb_cursor.table("test")
723-
arrow_table = create_table(duck_test_table)
724-
725-
# PR 4817 - remove filter columns that are unused in the remainder of the query plan from the table function
726-
query_res = duckdb_cursor.execute(
727-
"""
728-
EXPLAIN SELECT count(*) FROM arrow_table WHERE
729-
a > 25 AND b > 25
730-
"""
731-
).fetchall()
732-
733-
# scanned columns that come out of the scan are displayed like this, so we shouldn't see them
734-
match = re.search("│ +a +│", query_res[0][1])
735-
assert not match
736-
match = re.search("│ +b +│", query_res[0][1])
737-
assert not match
738-
739713
@pytest.mark.skipif(sys.version_info < (3, 9), reason="Requires python 3.9")
740714
@pytest.mark.parametrize("create_table", [create_pyarrow_pandas, create_pyarrow_table])
741715
def test_struct_filter_pushdown(self, duckdb_cursor, create_table):
@@ -1023,36 +997,36 @@ def test_dynamic_filter(self, duckdb_cursor):
1023997
def test_binary_view_filter(self, duckdb_cursor):
1024998
"""Filters on a view column work (without pushdown because pyarrow does not support view filters yet)."""
1025999
table = pa.table({"col": pa.array([b"abc", b"efg"], type=pa.binary_view())})
1026-
dset = pd.dataset(table)
1000+
dset = pa_ds.dataset(table)
10271001
res = duckdb_cursor.sql("select * from dset where col = 'abc'::binary")
10281002
assert len(res) == 1
10291003

10301004
def test_string_view_filter(self, duckdb_cursor):
10311005
"""Filters on a view column work (without pushdown because pyarrow does not support view filters yet)."""
10321006
table = pa.table({"col": pa.array(["abc", "efg"], type=pa.string_view())})
1033-
dset = pd.dataset(table)
1007+
dset = pa_ds.dataset(table)
10341008
res = duckdb_cursor.sql("select * from dset where col = 'abc'")
10351009
assert len(res) == 1
10361010

10371011
@pytest.mark.xfail(raises=pa_lib.ArrowNotImplementedError)
10381012
def test_canary_for_pyarrow_string_view_filter_support(self, duckdb_cursor):
10391013
"""This canary will xpass when pyarrow implements string view filter support."""
10401014
# predicate: field == "string value"
1041-
filter_expr = pd.field("col") == pd.scalar("val1")
1015+
filter_expr = pa_ds.field("col") == pa_ds.scalar("val1")
10421016
# dataset with a string view column
10431017
table = pa.table({"col": pa.array(["val1", "val2"], type=pa.string_view())})
1044-
dset = pd.dataset(table)
1018+
dset = pa_ds.dataset(table)
10451019
# creating the scanner fails
10461020
dset.scanner(columns=["col"], filter=filter_expr)
10471021

10481022
@pytest.mark.xfail(raises=pa_lib.ArrowNotImplementedError)
10491023
def test_canary_for_pyarrow_binary_view_filter_support(self, duckdb_cursor):
10501024
"""This canary will xpass when pyarrow implements binary view filter support."""
10511025
# predicate: field == const
1052-
const = pd.scalar(pa.scalar(b"bin1", pa.binary_view()))
1053-
filter_expr = pd.field("col") == const
1026+
const = pa_ds.scalar(pa.scalar(b"bin1", pa.binary_view()))
1027+
filter_expr = pa_ds.field("col") == const
10541028
# dataset with a string view column
10551029
table = pa.table({"col": pa.array([b"bin1", b"bin2"], type=pa.binary_view())})
1056-
dset = pd.dataset(table)
1030+
dset = pa_ds.dataset(table)
10571031
# creating the scanner fails
10581032
dset.scanner(columns=["col"], filter=filter_expr)

tests/fast/pandas/test_pandas_arrow.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import numpy as np
44
import pytest
5-
from conftest import pandas_supports_arrow_backend
65

76
import duckdb
87

@@ -11,7 +10,6 @@
1110
from pandas.api.types import is_integer_dtype # noqa: E402
1211

1312

14-
@pytest.mark.skipif(not pandas_supports_arrow_backend(), reason="pandas does not support the 'pyarrow' backend")
1513
class TestPandasArrow:
1614
def test_pandas_arrow(self, duckdb_cursor):
1715
pd = pytest.importorskip("pandas")

tests/fast/pandas/test_pyarrow_projection_pushdown.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import pytest
2-
from conftest import pandas_supports_arrow_backend
32

43
import duckdb
54

@@ -8,7 +7,6 @@
87
_ = pytest.importorskip("pandas", "2.0.0")
98

109

11-
@pytest.mark.skipif(not pandas_supports_arrow_backend(), reason="pandas does not support the 'pyarrow' backend")
1210
class TestArrowDFProjectionPushdown:
1311
def test_projection_pushdown_no_filter(self, duckdb_cursor):
1412
duckdb_conn = duckdb.connect()

tests/fast/test_replacement_scan.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,8 @@ def test_replacement_disabled(self):
469469
with pytest.raises(duckdb.CatalogException, match="Table with name df does not exist!"):
470470
create_relation(con, "select * from df")
471471
with pytest.raises(
472-
duckdb.InvalidInputException, match="Cannot change enable_external_access setting while database is running"
472+
duckdb.InvalidInputException,
473+
match="Invalid Input Error: Cannot enable external access while database is running",
473474
):
474475
con.execute("set enable_external_access=true")
475476

0 commit comments

Comments
 (0)