summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2009-01-14 19:55:20 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2009-01-14 19:55:20 +0000
commit76a7818013b1803876da7f51ec1601a25cb1e78b (patch)
treeefe808502f9e9c9a4d5a35fe92c6df6bf5609ab3 /lib/sqlalchemy/sql
parent4fad095858e218c1c53de3c1ce64fc438688f826 (diff)
downloadsqlalchemy-76a7818013b1803876da7f51ec1601a25cb1e78b.tar.gz
- Improved the methodology to handling percent signs in column
names from [ticket:1256]. Added more tests. MySQL and Postgres dialects still do not issue correct CREATE TABLE statements for identifiers with percent signs in them.
Diffstat (limited to 'lib/sqlalchemy/sql')
-rw-r--r--lib/sqlalchemy/sql/compiler.py10
-rw-r--r--lib/sqlalchemy/sql/expression.py22
2 files changed, 20 insertions, 12 deletions
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index d5c85d71d..8622aeea4 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -277,7 +277,10 @@ class DefaultCompiler(engine.Compiled):
schema_prefix = self.preparer.quote(column.table.schema, column.table.quote_schema) + '.'
else:
schema_prefix = ''
- return schema_prefix + self.preparer.quote(column.table.name % self.anon_map, column.table.quote) + "." + name
+ tablename = column.table.name
+ if isinstance(tablename, sql._generated_label):
+ tablename = tablename % self.anon_map
+ return schema_prefix + self.preparer.quote(tablename, column.table.quote) + "." + name
def escape_literal_column(self, text):
"""provide escaping for the literal_column() construct."""
@@ -410,12 +413,11 @@ class DefaultCompiler(engine.Compiled):
return bind_name
- _trunc_re = re.compile(r'%\((-?\d+ \w+)\)s', re.U)
def _truncated_identifier(self, ident_class, name):
if (ident_class, name) in self.truncated_names:
return self.truncated_names[(ident_class, name)]
- anonname = self._trunc_re.sub(lambda m: self.anon_map[m.group(1)], name)
+ anonname = name % self.anon_map
if len(anonname) > self.label_length:
counter = self.truncated_names.get(ident_class, 1)
@@ -427,7 +429,7 @@ class DefaultCompiler(engine.Compiled):
return truncname
def _anonymize(self, name):
- return self._trunc_re.sub(lambda m: self.anon_map[m.group(1)], name)
+ return name % self.anon_map
def _process_anon(self, key):
(ident, derived) = key.split(' ')
diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py
index f527c6351..48b1d0687 100644
--- a/lib/sqlalchemy/sql/expression.py
+++ b/lib/sqlalchemy/sql/expression.py
@@ -869,6 +869,12 @@ modifier = _FunctionGenerator(group=False)
class _generated_label(unicode):
"""A unicode subclass used to identify dynamically generated names."""
+def _escape_for_generated(x):
+ if isinstance(x, _generated_label):
+ return x
+ else:
+ return x.replace('%', '%%')
+
def _clone(element):
return element._clone()
@@ -1637,7 +1643,7 @@ class ColumnElement(ClauseElement, _CompareMixin):
expressions and function calls.
"""
- return _generated_label("%%(%d %s)s" % (id(self), getattr(self, 'name', 'anon')))
+ return _generated_label("%%(%d %s)s" % (id(self), _escape_for_generated(getattr(self, 'name', 'anon'))))
class ColumnCollection(util.OrderedProperties):
"""An ordered dictionary that stores a list of ColumnElement
@@ -1969,7 +1975,7 @@ class _BindParamClause(ColumnElement):
"""
if unique:
- self.key = _generated_label("%%(%d %s)s" % (id(self), key or 'param'))
+ self.key = _generated_label("%%(%d %s)s" % (id(self), key and _escape_for_generated(key) or 'param'))
else:
self.key = key or _generated_label("%%(%d param)s" % id(self))
self._orig_key = key or 'param'
@@ -1988,13 +1994,13 @@ class _BindParamClause(ColumnElement):
def _clone(self):
c = ClauseElement._clone(self)
if self.unique:
- c.key = _generated_label("%%(%d %s)s" % (id(c), c._orig_key or 'param'))
+ c.key = _generated_label("%%(%d %s)s" % (id(c), c._orig_key and _escape_for_generated(c._orig_key) or 'param'))
return c
def _convert_to_unique(self):
if not self.unique:
self.unique = True
- self.key = _generated_label("%%(%d %s)s" % (id(self), self._orig_key or 'param'))
+ self.key = _generated_label("%%(%d %s)s" % (id(self), self._orig_key and _escape_for_generated(self._orig_key) or 'param'))
def bind_processor(self, dialect):
return self.type.dialect_impl(dialect).bind_processor(dialect)
@@ -2601,7 +2607,7 @@ class Alias(FromClause):
if alias is None:
if self.original.named_with_column:
alias = getattr(self.original, 'name', None)
- alias = _generated_label('%%(%d %s)s' % (id(self), alias or 'anon'))
+ alias = _generated_label('%%(%d %s)s' % (id(self), alias and _escape_for_generated(alias) or 'anon'))
self.name = alias
@property
@@ -2722,7 +2728,7 @@ class _Label(ColumnElement):
def __init__(self, name, element, type_=None):
while isinstance(element, _Label):
element = element.element
- self.name = self.key = self._label = name or _generated_label("%%(%d %s)s" % (id(self), getattr(element, 'name', 'anon')))
+ self.name = self.key = self._label = name or _generated_label("%%(%d %s)s" % (id(self), _escape_for_generated(getattr(element, 'name', 'anon'))))
self._element = element
self._type = type_
self.quote = element.quote
@@ -2811,9 +2817,9 @@ class ColumnClause(_Immutable, ColumnElement):
elif self.table and self.table.named_with_column:
if getattr(self.table, 'schema', None):
- label = self.table.schema + "_" + self.table.name + "_" + self.name
+ label = self.table.schema + "_" + _escape_for_generated(self.table.name) + "_" + _escape_for_generated(self.name)
else:
- label = self.table.name + "_" + self.name
+ label = _escape_for_generated(self.table.name) + "_" + _escape_for_generated(self.name)
if label in self.table.c:
# TODO: coverage does not seem to be present for this