From 32165f50209036a98959553e1c5e81537a091a15 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Wed, 30 Jul 2014 16:08:33 -0400 Subject: [PATCH] - update the literal binds section --- doc/build/faq.rst | 67 +++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 43 deletions(-) diff --git a/doc/build/faq.rst b/doc/build/faq.rst index 0c8314cb5d..3dc81026b1 100644 --- a/doc/build/faq.rst +++ b/doc/build/faq.rst @@ -251,19 +251,19 @@ How do I render SQL expressions as strings, possibly with bound parameters inlin The "stringification" of a SQLAlchemy statement or Query in the vast majority of cases is as simple as:: - print str(statement) + print(str(statement)) this applies both to an ORM :class:`~.orm.query.Query` as well as any :func:`.select` or other statement. Additionally, to get the statement as compiled to a specific dialect or engine, if the statement itself is not already bound to one you can pass this in to :meth:`.ClauseElement.compile`:: - print statement.compile(someengine) + print(statement.compile(someengine)) or without an :class:`.Engine`:: from sqlalchemy.dialects import postgresql - print statement.compile(dialect=postgresql.dialect()) + print(statement.compile(dialect=postgresql.dialect())) When given an ORM :class:`~.orm.query.Query` object, in order to get at the :meth:`.ClauseElement.compile` @@ -271,7 +271,7 @@ method we only need access the :attr:`~.orm.query.Query.statement` accessor first:: statement = query.statement - print statement.compile(someengine) + print(statement.compile(someengine)) The above forms will render the SQL statement as it is passed to the Python :term:`DBAPI`, which includes that bound parameters are not rendered inline. @@ -289,60 +289,41 @@ flag, passed to ``compile_kwargs``:: s = select([t]).where(t.c.x == 5) - print s.compile(compile_kwargs={"literal_binds": True}) + print(s.compile(compile_kwargs={"literal_binds": True})) the above approach has the caveats that it is only supported for basic types, such as ints and strings, and furthermore if a :func:`.bindparam` without a pre-set value is used directly, it won't be able to -stringify that either. Additionally, the ``compile_kwargs`` argument -itself is only available as of SQLAlchemy 0.9; and there are slightly -more verbose ways of getting ``literal_binds`` injected with 0.8. +stringify that either. -.. topic:: Applying compiler kw arguments prior to 0.9 +To support inline literal rendering for types not supported, implement +a :class:`.TypeDecorator` for the target type which includes a +:meth:`.TypeDecorator.process_literal_param` method:: - We can provide a fixed set of ``**kw`` by calling upon ``process()`` - directly:: + from sqlalchemy import TypeDecorator, Integer - compiled = s.compile() - print compiled.process(s, literal_binds=True) - Note that in this approach the statement is actually being stringified - twice, hence using ``compile_kwargs`` in 0.9 should be preferred. + class MyFancyType(TypeDecorator): + impl = Integer + def process_literal_param(self, value, dialect): + return "my_fancy_formatting(%s)" % value -If we want to skip using ``literal_binds`` altogether due to the above -caveats, we can take the approach of replacing them out ahead of time -with whatever we want:: + from sqlalchemy import Table, Column, MetaData - from sqlalchemy.sql import visitors, text + tab = Table('mytable', MetaData(), Column('x', MyFancyType())) - def replace_bindparam(element): - if hasattr(element, 'effective_value'): - return text(str(element.effective_value)) - - s = visitors.replacement_traverse(s, {}, replace_bindparam) - print s - -Still another approach to injecting functionality where bound -parameters are concerned is to use the :doc:`Compilation Extension -API `:: - - from sqlalchemy.ext.compiler import compiles - from sqlalchemy.sql.expression import BindParameter - - s = select([t]).where(t.c.x == 5) + print( + tab.select().where(tab.c.x > 5).compile( + compile_kwargs={"literal_binds": True}) + ) - @compiles(BindParameter) - def as_str(element, compiler, **kw): - if 'binds_as_str' in kw: - return str(element.effective_value) - else: - return compiler.visit_bindparam(element, **kw) +producing output like:: - print s.compile(compile_kwargs={"binds_as_str": True}) + SELECT mytable.x + FROM mytable + WHERE mytable.x > my_fancy_formatting(5) -Above, we pass a self-defined flag ``binds_as_str`` through the compiler, -which we then intercept within our custom render method for :class:`.BindParameter`. Why does ``.col.in_([])`` Produce ``col != col``? Why not ``1=0``? ------------------------------------------------------------------- -- 2.47.3