From 95a9968bc10720401f41e982d2cf99b64399fe5d Mon Sep 17 00:00:00 2001 From: Evert Lammerts Date: Sat, 1 Nov 2025 11:25:23 +0100 Subject: [PATCH 1/2] Fix InsertRelation on attached database --- src/duckdb_py/pyrelation.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/duckdb_py/pyrelation.cpp b/src/duckdb_py/pyrelation.cpp index 3553bff0..5d77dc9f 100644 --- a/src/duckdb_py/pyrelation.cpp +++ b/src/duckdb_py/pyrelation.cpp @@ -23,6 +23,8 @@ #include "duckdb/common/arrow/physical_arrow_collector.hpp" #include "duckdb_python/arrow/arrow_export_utils.hpp" +#include + namespace duckdb { DuckDBPyRelation::DuckDBPyRelation(shared_ptr rel_p) : rel(std::move(rel_p)) { @@ -1511,7 +1513,7 @@ DuckDBPyRelation &DuckDBPyRelation::Execute() { void DuckDBPyRelation::InsertInto(const string &table) { AssertRelation(); auto parsed_info = QualifiedName::Parse(table); - auto insert = rel->InsertRel(parsed_info.schema, parsed_info.name); + auto insert = rel->InsertRel(parsed_info.catalog, parsed_info.schema, parsed_info.name); PyExecuteRelation(insert); } @@ -1565,14 +1567,24 @@ void DuckDBPyRelation::Update(const py::object &set_p, const py::object &where) void DuckDBPyRelation::Insert(const py::object ¶ms) { AssertRelation(); - if (!IsAcceptedInsertRelationType(*this->rel)) { + if (this->rel->type != RelationType::TABLE_RELATION) { throw InvalidInputException("'DuckDBPyRelation.insert' can only be used on a table relation"); } vector> values {DuckDBPyConnection::TransformPythonParamList(params)}; D_ASSERT(py::gil_check()); py::gil_scoped_release release; - rel->Insert(values); + // Grab table info + auto table_relation = static_cast(this->rel.get()); + auto catalog = table_relation->description->database; + auto schema = table_relation->description->schema; + auto table = table_relation->description->table; + // Create a value relation + vector column_names; + auto value_rel = + make_shared_ptr(this->rel->context->GetContext(), values, std::move(column_names), "values"); + // Now insert + value_rel->Insert(catalog, schema, table); } void DuckDBPyRelation::Create(const string &table) { From 20bfd52a0932327fafd94fa16a25c6acc38f5dcb Mon Sep 17 00:00:00 2001 From: Evert Lammerts Date: Thu, 6 Nov 2025 11:54:51 +0100 Subject: [PATCH 2/2] review feedback --- external/duckdb | 2 +- .../include/duckdb_python/pyrelation.hpp | 2 +- src/duckdb_py/pyrelation.cpp | 20 ++----------------- tests/fast/test_insert.py | 4 +--- 4 files changed, 5 insertions(+), 23 deletions(-) diff --git a/external/duckdb b/external/duckdb index 7ce99bc0..95fcb8f1 160000 --- a/external/duckdb +++ b/external/duckdb @@ -1 +1 @@ -Subproject commit 7ce99bc04130615dfc3a39dfb79177a8942fefba +Subproject commit 95fcb8f18819b1a77df079a7fcb753a8c2f52844 diff --git a/src/duckdb_py/include/duckdb_python/pyrelation.hpp b/src/duckdb_py/include/duckdb_python/pyrelation.hpp index e1f78b5a..e272ca41 100644 --- a/src/duckdb_py/include/duckdb_python/pyrelation.hpp +++ b/src/duckdb_py/include/duckdb_python/pyrelation.hpp @@ -235,7 +235,7 @@ struct DuckDBPyRelation { void InsertInto(const string &table); - void Insert(const py::object ¶ms = py::list()); + void Insert(const py::object ¶ms = py::list()) const; void Update(const py::object &set, const py::object &where = py::none()); void Create(const string &table); diff --git a/src/duckdb_py/pyrelation.cpp b/src/duckdb_py/pyrelation.cpp index 5d77dc9f..08b001be 100644 --- a/src/duckdb_py/pyrelation.cpp +++ b/src/duckdb_py/pyrelation.cpp @@ -23,8 +23,6 @@ #include "duckdb/common/arrow/physical_arrow_collector.hpp" #include "duckdb_python/arrow/arrow_export_utils.hpp" -#include - namespace duckdb { DuckDBPyRelation::DuckDBPyRelation(shared_ptr rel_p) : rel(std::move(rel_p)) { @@ -1517,10 +1515,6 @@ void DuckDBPyRelation::InsertInto(const string &table) { PyExecuteRelation(insert); } -static bool IsAcceptedInsertRelationType(const Relation &relation) { - return relation.type == RelationType::TABLE_RELATION; -} - void DuckDBPyRelation::Update(const py::object &set_p, const py::object &where) { AssertRelation(); unique_ptr condition; @@ -1565,7 +1559,7 @@ void DuckDBPyRelation::Update(const py::object &set_p, const py::object &where) return rel->Update(std::move(names), std::move(expressions), std::move(condition)); } -void DuckDBPyRelation::Insert(const py::object ¶ms) { +void DuckDBPyRelation::Insert(const py::object ¶ms) const { AssertRelation(); if (this->rel->type != RelationType::TABLE_RELATION) { throw InvalidInputException("'DuckDBPyRelation.insert' can only be used on a table relation"); @@ -1574,17 +1568,7 @@ void DuckDBPyRelation::Insert(const py::object ¶ms) { D_ASSERT(py::gil_check()); py::gil_scoped_release release; - // Grab table info - auto table_relation = static_cast(this->rel.get()); - auto catalog = table_relation->description->database; - auto schema = table_relation->description->schema; - auto table = table_relation->description->table; - // Create a value relation - vector column_names; - auto value_rel = - make_shared_ptr(this->rel->context->GetContext(), values, std::move(column_names), "values"); - // Now insert - value_rel->Insert(catalog, schema, table); + rel->Insert(values); } void DuckDBPyRelation::Create(const string &table) { diff --git a/tests/fast/test_insert.py b/tests/fast/test_insert.py index a61efd2e..455e6e48 100644 --- a/tests/fast/test_insert.py +++ b/tests/fast/test_insert.py @@ -27,6 +27,4 @@ def test_insert_with_schema(self, duckdb_cursor): res = duckdb_cursor.table("not_main.tbl").fetchall() assert len(res) == 10 - # TODO: This is not currently supported # noqa: TD002, TD003 - with pytest.raises(duckdb.CatalogException, match="Table with name tbl does not exist"): - duckdb_cursor.table("not_main.tbl").insert([42, 21, 1337]) + duckdb_cursor.table("not_main.tbl").insert((42,))