diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-06-24 12:19:15 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-06-24 12:19:15 -0400 |
| commit | 87664ce88ab8931ccaacbac3357f484069efe6e9 (patch) | |
| tree | 5635f38b27d3d6c489f9aeb41509a8dc890cb263 /lib/sqlalchemy | |
| parent | 0adf381d994b0f374d2b6394bff5f2c423942c78 (diff) | |
| download | sqlalchemy-87664ce88ab8931ccaacbac3357f484069efe6e9.tar.gz | |
- The argument to "ESCAPE" of a LIKE operator or similar
is passed through render_literal_value(), which may
implement escaping of backslashes. [ticket:1400]
- Postgresql render_literal_value() is overridden which escapes
backslashes, currently applies to the ESCAPE clause
of LIKE and similar expressions.
Ultimately this will have to detect the value of
"standard_conforming_strings" for full behavior.
[ticket:1400]
- MySQL render_literal_value() is overridden which escapes
backslashes, currently applies to the ESCAPE clause
of LIKE and similar expressions. This behavior
is derived from detecting the value of
NO_BACKSLASH_ESCAPES. [ticket:1400]
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/dialects/mysql/base.py | 21 | ||||
| -rw-r--r-- | lib/sqlalchemy/dialects/postgresql/base.py | 18 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/compiler.py | 16 | ||||
| -rw-r--r-- | lib/sqlalchemy/types.py | 1 |
4 files changed, 47 insertions, 9 deletions
diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py index c4af013fc..46e29694f 100644 --- a/lib/sqlalchemy/dialects/mysql/base.py +++ b/lib/sqlalchemy/dialects/mysql/base.py @@ -1196,6 +1196,12 @@ class MySQLCompiler(compiler.SQLCompiler): return 'CAST(%s AS %s)' % (self.process(cast.clause), type_) + def render_literal_value(self, value, type_): + value = super(MySQLCompiler, self).render_literal_value(value, type_) + if self.dialect._backslash_escapes: + value = value.replace('\\', '\\\\') + return value + def get_select_precolumns(self, select): if isinstance(select._distinct, basestring): return select._distinct.upper() + " " @@ -1639,6 +1645,12 @@ class MySQLDialect(default.DefaultDialect): ischema_names = ischema_names preparer = MySQLIdentifierPreparer + # default SQL compilation settings - + # these are modified upon initialize(), + # i.e. first connect + _backslash_escapes = True + _server_ansiquotes = False + def __init__(self, use_ansiquotes=None, **kwargs): default.DefaultDialect.__init__(self, **kwargs) @@ -1760,7 +1772,7 @@ class MySQLDialect(default.DefaultDialect): self._connection_charset = self._detect_charset(connection) self._server_casing = self._detect_casing(connection) self._server_collations = self._detect_collations(connection) - self._server_ansiquotes = self._detect_ansiquotes(connection) + self._detect_ansiquotes(connection) if self._server_ansiquotes: # if ansiquotes == True, build a new IdentifierPreparer # with the new setting @@ -2019,8 +2031,11 @@ class MySQLDialect(default.DefaultDialect): mode_no = int(mode) mode = (mode_no | 4 == mode_no) and 'ANSI_QUOTES' or '' - return 'ANSI_QUOTES' in mode - + self._server_ansiquotes = 'ANSI_QUOTES' in mode + + # as of MySQL 5.0.1 + self._backslash_escapes = 'NO_BACKSLASH_ESCAPES' not in mode + def _show_create_table(self, connection, table, charset=None, full_name=None): """Run SHOW CREATE TABLE for a ``Table``.""" diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py index 76d1122e8..8275aa1e7 100644 --- a/lib/sqlalchemy/dialects/postgresql/base.py +++ b/lib/sqlalchemy/dialects/postgresql/base.py @@ -324,12 +324,23 @@ class PGCompiler(compiler.SQLCompiler): def visit_ilike_op(self, binary, **kw): escape = binary.modifiers.get("escape", None) return '%s ILIKE %s' % (self.process(binary.left), self.process(binary.right)) \ - + (escape and ' ESCAPE \'%s\'' % escape or '') + + (escape and + (' ESCAPE ' + self.render_literal_value(escape, None)) + or '') def visit_notilike_op(self, binary, **kw): escape = binary.modifiers.get("escape", None) return '%s NOT ILIKE %s' % (self.process(binary.left), self.process(binary.right)) \ - + (escape and ' ESCAPE \'%s\'' % escape or '') + + (escape and + (' ESCAPE ' + self.render_literal_value(escape, None)) + or '') + + def render_literal_value(self, value, type_): + value = super(PGCompiler, self).render_literal_value(value, type_) + # TODO: need to inspect "standard_conforming_strings" + if self.dialect._backslash_escapes: + value = value.replace('\\', '\\\\') + return value def visit_sequence(self, seq): if seq.optional: @@ -625,6 +636,9 @@ class PGDialect(default.DefaultDialect): inspector = PGInspector isolation_level = None + # TODO: need to inspect "standard_conforming_strings" + _backslash_escapes = True + def __init__(self, isolation_level=None, **kwargs): default.DefaultDialect.__init__(self, **kwargs) self.isolation_level = isolation_level diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index b4992eec3..c54931b87 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -494,28 +494,36 @@ class SQLCompiler(engine.Compiled): return '%s LIKE %s' % ( self.process(binary.left, **kw), self.process(binary.right, **kw)) \ - + (escape and ' ESCAPE \'%s\'' % escape or '') + + (escape and + (' ESCAPE ' + self.render_literal_value(escape, None)) + or '') def visit_notlike_op(self, binary, **kw): escape = binary.modifiers.get("escape", None) return '%s NOT LIKE %s' % ( self.process(binary.left, **kw), self.process(binary.right, **kw)) \ - + (escape and ' ESCAPE \'%s\'' % escape or '') + + (escape and + (' ESCAPE ' + self.render_literal_value(escape, None)) + or '') def visit_ilike_op(self, binary, **kw): escape = binary.modifiers.get("escape", None) return 'lower(%s) LIKE lower(%s)' % ( self.process(binary.left, **kw), self.process(binary.right, **kw)) \ - + (escape and ' ESCAPE \'%s\'' % escape or '') + + (escape and + (' ESCAPE ' + self.render_literal_value(escape, None)) + or '') def visit_notilike_op(self, binary, **kw): escape = binary.modifiers.get("escape", None) return 'lower(%s) NOT LIKE lower(%s)' % ( self.process(binary.left, **kw), self.process(binary.right, **kw)) \ - + (escape and ' ESCAPE \'%s\'' % escape or '') + + (escape and + (' ESCAPE ' + self.render_literal_value(escape, None)) + or '') def _operator_dispatch(self, operator, element, fn, **kw): if util.callable(operator): diff --git a/lib/sqlalchemy/types.py b/lib/sqlalchemy/types.py index 84bd85ff2..d8a176f1f 100644 --- a/lib/sqlalchemy/types.py +++ b/lib/sqlalchemy/types.py @@ -1796,6 +1796,7 @@ class BOOLEAN(Boolean): NULLTYPE = NullType() BOOLEANTYPE = Boolean() +STRINGTYPE = String() # using VARCHAR/NCHAR so that we dont get the genericized "String" # type which usually resolves to TEXT/CLOB |
