summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2022-01-18 17:19:24 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2022-01-18 17:21:59 -0500
commit692d05a5cc15cf3947055e9089b86ed99be3da46 (patch)
treea83174c129e50a2915e78db87ae4498dbad4d812
parent2bd622d27b44893a0dca5138e4acbff213771ddb (diff)
downloadsqlalchemy-692d05a5cc15cf3947055e9089b86ed99be3da46.tar.gz
reject methods as lambda SQL callables
Added an informative error message when a method object is passed to a SQL construct. Previously, when such a callable were passed, as is a common typographical error when dealing with method-chained SQL constructs, they were interpreted as "lambda SQL" targets to be invoked at compilation time, which would lead to silent failures. As this feature was not intended to be used with methods, method objects are now rejected. Fixes: #7032 Change-Id: If714715bd8c11557ab769ee3b1a24264b0b06acc (cherry picked from commit e28ec27b599558b3e26ced106a972e8b4aa9e668)
-rw-r--r--doc/build/changelog/unreleased_14/7032.rst10
-rw-r--r--lib/sqlalchemy/sql/lambdas.py5
-rw-r--r--test/sql/test_lambdas.py21
3 files changed, 36 insertions, 0 deletions
diff --git a/doc/build/changelog/unreleased_14/7032.rst b/doc/build/changelog/unreleased_14/7032.rst
new file mode 100644
index 000000000..c837be494
--- /dev/null
+++ b/doc/build/changelog/unreleased_14/7032.rst
@@ -0,0 +1,10 @@
+.. change::
+ :tags: bug, sql
+ :tickets: 7032
+
+ Added an informative error message when a method object is passed to a SQL
+ construct. Previously, when such a callable were passed, as is a common
+ typographical error when dealing with method-chained SQL constructs, they
+ were interpreted as "lambda SQL" targets to be invoked at compilation time,
+ which would lead to silent failures. As this feature was not intended to be
+ used with methods, method objects are now rejected.
diff --git a/lib/sqlalchemy/sql/lambdas.py b/lib/sqlalchemy/sql/lambdas.py
index e22f87167..5f9155998 100644
--- a/lib/sqlalchemy/sql/lambdas.py
+++ b/lib/sqlalchemy/sql/lambdas.py
@@ -5,6 +5,7 @@
# This module is part of SQLAlchemy and is released under
# the MIT License: https://www.opensource.org/licenses/mit-license.php
+import inspect
import itertools
import operator
import sys
@@ -619,6 +620,10 @@ class AnalyzedCode(object):
return analyzed
def __init__(self, fn, lambda_element, opts):
+ if inspect.ismethod(fn):
+ raise exc.ArgumentError(
+ "Method %s may not be passed as a SQL expression" % fn
+ )
closure = fn.__closure__
self.track_bound_values = (
diff --git a/test/sql/test_lambdas.py b/test/sql/test_lambdas.py
index 76be0af3c..29e1258ef 100644
--- a/test/sql/test_lambdas.py
+++ b/test/sql/test_lambdas.py
@@ -8,6 +8,7 @@ from sqlalchemy.sql import and_
from sqlalchemy.sql import bindparam
from sqlalchemy.sql import coercions
from sqlalchemy.sql import column
+from sqlalchemy.sql import func
from sqlalchemy.sql import join
from sqlalchemy.sql import lambda_stmt
from sqlalchemy.sql import lambdas
@@ -38,6 +39,26 @@ class LambdaElementTest(
):
__dialect__ = "default"
+ def test_reject_methods(self):
+ """test #7032"""
+
+ t1 = table("t1", column("q"), column("p"))
+
+ subq = select(t1).subquery
+
+ with expect_raises_message(
+ exc.ArgumentError,
+ "Method <bound method Select.*.subquery .* may not be "
+ "passed as a SQL expression",
+ ):
+ select(func.count()).select_from(subq)
+
+ self.assert_compile(
+ select(func.count()).select_from(subq()),
+ "SELECT count(*) AS count_1 FROM "
+ "(SELECT t1.q AS q, t1.p AS p FROM t1) AS anon_1",
+ )
+
def test_select_whereclause(self):
t1 = table("t1", column("q"), column("p"))