From 087ba2d88d079b361e30e698e251c022b5780a3d Mon Sep 17 00:00:00 2001 From: Carlos Sousa Date: Tue, 3 Oct 2023 00:06:10 -0300 Subject: [PATCH] Fixes: #9647 - Raise exception for execute when parameter is an empty list --- lib/sqlalchemy/engine/base.py | 4 ++++ lib/sqlalchemy/orm/session.py | 2 +- test/engine/test_execute.py | 28 +++++++++++++++++++++++----- test/orm/test_session.py | 18 ++++++++++++++++++ 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py index 72012ff9d9..bfbe472cb0 100644 --- a/lib/sqlalchemy/engine/base.py +++ b/lib/sqlalchemy/engine/base.py @@ -1403,6 +1403,10 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]): :return: a :class:`_engine.Result` object. """ + if isinstance(parameters, list) and not parameters: + raise exc.ArgumentError( + "Empty list of parameters passed; no statement to execute" + ) distilled_parameters = _distill_params_20(parameters) try: meth = statement._execute_on_connection diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index e5eb5036dd..032b2ba97c 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -2151,7 +2151,7 @@ class Session(_SessionClassMethods, EventTarget): ) else: result = conn.execute( - statement, params or {}, execution_options=execution_options + statement, params, execution_options=execution_options ) if _scalar_result: diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py index 6080f3dc6d..5d9d47d90c 100644 --- a/test/engine/test_execute.py +++ b/test/engine/test_execute.py @@ -272,6 +272,17 @@ class ExecuteTest(fixtures.TablesTest): (4, "sally"), ] + @testing.requires.named_paramstyle + def test_raw_insert_with_empty_list(self, connection): + conn = connection + assert_raises_message( + tsa.exc.ProgrammingError, + "Incorrect number of bindings supplied. The current statement uses 2, and there are 0 supplied", + conn.exec_driver_sql, + "insert into users (user_id, user_name) values (:id, :name)", + [], + ) + def test_raw_tuple_params(self, connection): """test #7820 @@ -639,11 +650,18 @@ class ExecuteTest(fixtures.TablesTest): """test that execute() interprets [] as a list with no params""" users_autoinc = self.tables.users_autoinc - connection.execute( - users_autoinc.insert().values(user_name=bindparam("name", None)), - [], - ) - eq_(connection.execute(users_autoinc.select()).fetchall(), [(1, None)]) + with expect_raises_message( + tsa.exc.ArgumentError, + "Empty list of parameters passed; no statement to execute", + ): + connection.execute( + users_autoinc.insert().values( + user_name=bindparam("name", None) + ), + [], + ) + + eq_(connection.execute(users_autoinc.select()).fetchall(), []) @testing.only_on("sqlite") def test_execute_compiled_favors_compiled_paramstyle(self): diff --git a/test/orm/test_session.py b/test/orm/test_session.py index b304ac5745..dff7f3f7df 100644 --- a/test/orm/test_session.py +++ b/test/orm/test_session.py @@ -128,6 +128,24 @@ class ExecutionTest(_fixtures.FixtureTest): ): sess.scalar("select id from users where id=:id", {"id": 7}) + def test_empty_list_execute(self, connection): + users = self.tables.users + sess = Session(bind=testing.db) + sess.execute(users.insert(), {"id": 10, "name": "u10"}) + + with expect_raises_message( + sa.exc.ArgumentError, + "Empty list of parameters passed; no statement to execute", + ): + sess.execute(users.insert(), []) + + eq_( + sess.execute( + sa.select(users.c.id).order_by(users.c.id) + ).fetchall(), + [(10,)], + ) + class TransScopingTest(_fixtures.FixtureTest): run_inserts = None -- 2.47.2