--- /dev/null
+.. change::
+ :tags: usecase, sql
+ :tickets: 8800
+
+ An informative re-raise is now thrown in the case where any "literal
+ bindparam" render operation fails, indicating the value itself and
+ the datatype in use, to assist in debugging when literal params
+ are being rendered in a statement.
from . import schema
from . import selectable
from . import sqltypes
+from . import util as sql_util
from .base import NO_ARG
from .base import prefix_anon_map
from .elements import quoted_name
replacement_expressions[
escaped_name
] = self.render_literal_bindparam(
- parameter, render_literal_value=value
+ parameter,
+ render_literal_value=value,
)
continue
processor = type_._cached_literal_processor(self.dialect)
if processor:
- return processor(value)
+ try:
+ return processor(value)
+ except Exception as e:
+ util.raise_(
+ exc.CompileError(
+ "Could not render literal value "
+ '"%s" '
+ "with datatype "
+ "%s; see parent stack trace for "
+ "more detail."
+ % (
+ sql_util._repr_single_value(value),
+ type_,
+ )
+ ),
+ from_=e,
+ )
+
else:
- raise NotImplementedError(
- "Don't know how to literal-quote value %r" % value
+ raise exc.CompileError(
+ "No literal value renderer is available for literal value "
+ '"%s" with datatype %s'
+ % (sql_util._repr_single_value(value), type_)
)
def _truncate_bindparam(self, bindparam):
_isnull = True
def literal_processor(self, dialect):
- def process(value):
- raise exc.CompileError(
- "Don't know how to render literal SQL value: %r" % (value,)
- )
-
- return process
+ return None
class Comparator(TypeEngine.Comparator):
def _adapt_expression(self, op, other_comparator):
return rep
+def _repr_single_value(value):
+ rp = _repr_base()
+ rp.max_chars = 300
+ return rp.trunc(value)
+
+
class _repr_row(_repr_base):
"""Provide a string view of a row."""
from sqlalchemy.testing import mock
from sqlalchemy.testing import ne_
from sqlalchemy.testing.schema import pep435_enum
+from sqlalchemy.types import UserDefinedType
from sqlalchemy.util import u
table1 = table(
"OR mytable.myid = :myid_2 OR mytable.myid = :myid_3",
)
+ @testing.combinations("plain", "expanding", argnames="exprtype")
+ def test_literal_bind_typeerror(self, exprtype):
+ """test #8800"""
+
+ if exprtype == "expanding":
+ stmt = select(table1).where(
+ table1.c.myid.in_([("tuple",), ("tuple",)])
+ )
+ elif exprtype == "plain":
+ stmt = select(table1).where(table1.c.myid == ("tuple",))
+ else:
+ assert False
+
+ with expect_raises_message(
+ exc.CompileError,
+ r"Could not render literal value \"\(\'tuple\',\)\" "
+ r"with datatype INTEGER; see parent "
+ r"stack trace for more detail.",
+ ):
+ stmt.compile(compile_kwargs={"literal_binds": True})
+
+ @testing.combinations("plain", "expanding", argnames="exprtype")
+ def test_literal_bind_dont_know_how_to_quote(self, exprtype):
+ """test #8800"""
+
+ class MyType(UserDefinedType):
+ def get_col_spec(self, **kw):
+ return "MYTYPE"
+
+ col = column("x", MyType())
+
+ if exprtype == "expanding":
+ stmt = select(table1).where(col.in_([("tuple",), ("tuple",)]))
+ elif exprtype == "plain":
+ stmt = select(table1).where(col == ("tuple",))
+ else:
+ assert False
+
+ with expect_raises_message(
+ exc.CompileError,
+ r"No literal value renderer is available for literal "
+ r"value \"\('tuple',\)\" with datatype MYTYPE",
+ ):
+ stmt.compile(compile_kwargs={"literal_binds": True})
+
@testing.fixture
def ansi_compiler_fixture(self):
dialect = default.DefaultDialect()
def test_compile_err_formatting(self):
with expect_raises_message(
exc.CompileError,
- r"Don't know how to render literal SQL value: \(1, 2, 3\)",
+ r"No literal value renderer is available for literal "
+ r"value \"\(1, 2, 3\)\" with datatype NULL",
):
func.foo((1, 2, 3)).compile(compile_kwargs={"literal_binds": True})
lit = literal(value)
assert_raises_message(
- NotImplementedError,
- "Don't know how to literal-quote value.*",
+ exc.CompileError,
+ r"No literal value renderer is available for literal value.*",
lit.compile,
dialect=testing.db.dialect,
compile_kwargs={"literal_binds": True},
with expect_raises_message(
exc.CompileError,
- "Don't know how to render literal SQL value: 'textA'",
+ r"No literal value renderer is available for literal "
+ r"value \"'textA'\" with datatype NULL",
):
str(stmt)