Skip to content

Commit

Permalink
Merge pull request #9394 from Tishj/python_execute_multi_statements
Browse files Browse the repository at this point in the history
[Python] Throw explicit error for misuse of `execute`
  • Loading branch information
Mytherin committed Oct 20, 2023
2 parents 739da94 + 1507777 commit 39820ba
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
7 changes: 6 additions & 1 deletion tools/pythonpkg/src/pyconnection.cpp
Expand Up @@ -47,6 +47,7 @@
#include "duckdb_python/pybind11/conversions/exception_handling_enum.hpp"
#include "duckdb/parser/parsed_data/drop_info.hpp"
#include "duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp"
#include "duckdb/main/pending_query_result.hpp"

#include <random>

Expand Down Expand Up @@ -448,7 +449,11 @@ unique_ptr<QueryResult> DuckDBPyConnection::ExecuteInternal(const string &query,
// if there are multiple statements, we directly execute the statements besides the last one
// we only return the result of the last statement to the user, unless one of the previous statements fails
for (idx_t i = 0; i + 1 < statements.size(); i++) {
// TODO: this doesn't take in any prepared parameters?
if (statements[i]->n_param != 0) {
throw NotImplementedException(
"Prepared parameters are only supported for the last statement, please split your query up into "
"separate 'execute' calls if you want to use prepared parameters");
}
auto pending_query = connection->PendingQuery(std::move(statements[i]), false);
auto res = CompletePendingQuery(*pending_query);

Expand Down
38 changes: 38 additions & 0 deletions tools/pythonpkg/tests/fast/api/test_duckdb_execute.py
@@ -0,0 +1,38 @@
import duckdb
import pytest


class TestDuckDBExecute(object):
def test_execute_basic(self, duckdb_cursor):
duckdb_cursor.execute('create table t as select 5')
res = duckdb_cursor.table('t').fetchall()
assert res == [(5,)]

def test_execute_many_basic(self, duckdb_cursor):
duckdb_cursor.execute("create table t(x int);")

# This works because prepared parameter is only present in the last statement
duckdb_cursor.execute(
"""
delete from t where x=5;
insert into t(x) values($1);
""",
(99,),
)
res = duckdb_cursor.table('t').fetchall()
assert res == [(99,)]

def test_execute_many_error(self, duckdb_cursor):
duckdb_cursor.execute("create table t(x int);")

# Prepared parameter used in a statement that is not the last
with pytest.raises(
duckdb.NotImplementedException, match='Prepared parameters are only supported for the last statement'
):
duckdb_cursor.execute(
"""
delete from t where x=$1;
insert into t(x) values($1);
""",
(99,),
)

0 comments on commit 39820ba

Please sign in to comment.