如何在自定义的编译表达式中使用bindparam()? [英] How to make use of bindparam() in a custom Compiled expression?
问题描述
我的代码基于@zzzeeek对此问题的回答。
我将其扩展了一点,因此它考虑了NULL和Postgresql的ARRAY。
I based my code on the @zzzeeek's answer to this question . I extended it a little so it takes into account NULLs and ARRAY for Postgresql.
class values(FromClause):
named_with_column = True
def __init__(self, columns, *args, **kw):
self._column_args = columns
self.list = args
self.alias_name = self.name = kw.pop('alias_name', None)
def _populate_column_collection(self):
# self._columns.update((col.name, col) for col in self._column_args)
for c in self._column_args:
c._make_proxy(self, c.name)
@compiles(values)
def compile_values(element, compiler, asfrom=False, **kw):
columns = element.columns
v = "VALUES %s" % ", ".join(
"(%s)" % ", ".join(
((compiler.visit_array(elem)+'::'+str(column.type)) if isinstance(column.type, ARRAY) else
compiler.render_literal_value(elem, column.type))
if elem is not None else compiler.render_literal_value(elem, NULLTYPE)
for elem, column in zip(tup, columns))
for tup in element.list
)
if asfrom:
if element.alias_name:
v = "(%s) AS %s (%s)" % (v, element.alias_name, (", ".join(c.name for c in element.columns)))
else:
v = "(%s)" % v
return v
一切正常,直到发现我无法使用%插入值-签到此VALUES子句-它们插入到结果语句中,这似乎会引起绑定问题
Everything worked fine until it turned out I couldn't insert values with "%"-sign to this VALUES clause - they get inlined in a resulting statement and this seems to cause binding problems
我猜是否代替 render_literal_value()
我们使用 bindparam()
可以避免这样的错误。但是 @compiles
下的所有内容都应返回纯文本,对吗?我该如何修改它以获得基于参数的查询?
I guess if instead of render_literal_value()
we used bindparam()
we could avoid such an error. But Everything under @compiles
should return plain text, am I right? How could I amend this to get parameter-based query?
推荐答案
我明白了。 bindparams的实际值保存在名为 SQLCompiler
的对象中,该对象通常是特定于方言的。
此处(链接到GitHub)是在查询编译过程中将bindparams存储在 SQLCompiler
实例中的地方
I got it. The actual values of bindparams are kept in an object called SQLCompiler
which is generally dialect-specific.
Here(link to GitHub) is where bindparams get stored in a SQLCompiler
instance during the query compilation process
因此,我的代码段的最终版本如下所示:
So the final version of my code snippet looks like this:
class values(FromClause):
named_with_column = True
def __init__(self, columns, *args, **kw):
self._column_args = columns
self.list = args
self.alias_name = self.name = kw.pop('alias_name', None)
def _populate_column_collection(self):
# self._columns.update((col.name, col) for col in self._column_args)
for c in self._column_args:
c._make_proxy(self, c.name)
@compiles(values)
def compile_values(clause, compiler, asfrom=False, **kw):
def decide(value, column):
add_type_hint = False
if isinstance(value, array) and not value.clauses: # for empty array literals
add_type_hint = True
if isinstance(value, ClauseElement):
intermediate = compiler.process(value)
if add_type_hint:
intermediate += '::' + str(column.type)
return intermediate
elif value is None:
return compiler.render_literal_value(
value,
NULLTYPE
) + '::' + str(column.type)
else:
return compiler.process(
bindparam(
None,
value=compiler.render_literal_value(
value,
column.type
).strip("'")
)
) + '::' + str(column.type)
columns = clause.columns
v = "VALUES %s" % ", ".join(
"(%s)" % ", ".join(
decide(elem, column)
for elem, column in zip(tup, columns))
for tup in clause.list
)
if asfrom:
if clause.alias_name:
v = "(%s) AS %s (%s)" % (v, clause.alias_name, (", ".join(c.name for c in clause.columns)))
else:
v = "(%s)" % v
return v
这篇关于如何在自定义的编译表达式中使用bindparam()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!