summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndi Albrecht <albrecht.andi@gmail.com>2012-11-03 13:05:25 +0100
committerAndi Albrecht <albrecht.andi@gmail.com>2012-11-03 13:05:25 +0100
commit39ddba76709cc36dda0e9519efe7316d5ff5f12f (patch)
tree93a62f9a1626077ba4c558e442a67be7e7ea39e2
parent813782f5f842023c5dcc9658f27f957ca83955eb (diff)
downloadsqlparse-39ddba76709cc36dda0e9519efe7316d5ff5f12f.tar.gz
Improve handling of quoted indentifiers (fixes issue78).
-rw-r--r--CHANGES16
-rw-r--r--sqlparse/sql.py25
-rw-r--r--tests/test_parse.py7
-rw-r--r--tests/test_regressions.py28
4 files changed, 66 insertions, 10 deletions
diff --git a/CHANGES b/CHANGES
index f75da17..3e6e071 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,15 @@
+Development Version
+-------------------
+
+Bug Fixes
+ * Improve handling of quoted identifiers (issue78).
+
+Other
+ * Deprecated sqlparse.SQLParseError. Please use
+ sqlparse.exceptions.SQLParseError instead.
+
+
+
Release 0.1.4 (Apr 20, 2012)
----------------------------
@@ -14,10 +26,6 @@ Bug Fixes
* Pretty format comments in identifier lists (issue59).
* Several minor bug fixes and improvements.
-Other
- * Deprecated sqlparse.SQLParseError. Please use
- sqlparse.exceptions.SQLParseError instead.
-
Release 0.1.3 (Jul 29, 2011)
----------------------------
diff --git a/sqlparse/sql.py b/sqlparse/sql.py
index 02e46a3..92bf83e 100644
--- a/sqlparse/sql.py
+++ b/sqlparse/sql.py
@@ -169,6 +169,14 @@ class TokenList(Token):
if (token.is_group() and (max_depth is None or depth < max_depth)):
token._pprint_tree(max_depth, depth + 1)
+ def _remove_quotes(self, val):
+ """Helper that removes surrounding quotes from strings."""
+ if not val:
+ return val
+ if val[0] in ('"', '\'') and val[-1] == val[0]:
+ val = val[1:-1]
+ return val
+
def flatten(self):
"""Generator yielding ungrouped tokens.
@@ -362,11 +370,13 @@ class TokenList(Token):
else:
next_ = self.token_next_by_instance(0, Identifier)
if next_ is None:
- return None
+ next_ = self.token_next_by_type(0, T.String.Symbol)
+ if next_ is None:
+ return None
alias = next_
if isinstance(alias, Identifier):
return alias.get_name()
- return unicode(alias)
+ return self._remove_quotes(unicode(alias))
def get_name(self):
"""Returns the name of this identifier.
@@ -385,13 +395,16 @@ class TokenList(Token):
# a.b
dot = self.token_next_match(0, T.Punctuation, '.')
if dot is None:
- return self.token_next_by_type(0, T.Name).value
+ next_ = self.token_next_by_type(0, T.Name)
+ if next_ is not None:
+ return self._remove_quotes(next_.value)
+ return None
next_ = self.token_next_by_type(self.token_index(dot),
- (T.Name, T.Wildcard))
+ (T.Name, T.Wildcard, T.String.Symbol))
if next_ is None: # invalid identifier, e.g. "a."
return None
- return next_.value
+ return self._remove_quotes(next_.value)
class Statement(TokenList):
@@ -437,7 +450,7 @@ class Identifier(TokenList):
prev_ = self.token_prev(self.token_index(dot))
if prev_ is None: # something must be verry wrong here..
return None
- return prev_.value
+ return self._remove_quotes(prev_.value)
def is_wildcard(self):
"""Return ``True`` if this identifier contains a wildcard."""
diff --git a/tests/test_parse.py b/tests/test_parse.py
index e14c9e2..05141a4 100644
--- a/tests/test_parse.py
+++ b/tests/test_parse.py
@@ -106,3 +106,10 @@ class SQLParseTest(TestCaseBase):
t = sqlparse.parse('foo.key')[0].tokens
self.assertEqual(len(t), 1)
self.assert_(isinstance(t[0], sqlparse.sql.Identifier))
+
+
+def test_quoted_identifier():
+ t = sqlparse.parse('select x.y as "z" from foo')[0].tokens
+ assert isinstance(t[2], sqlparse.sql.Identifier)
+ assert t[2].get_name() == 'z'
+ assert t[2].get_real_name() == 'y'
diff --git a/tests/test_regressions.py b/tests/test_regressions.py
index 86b6292..e1c2c89 100644
--- a/tests/test_regressions.py
+++ b/tests/test_regressions.py
@@ -106,3 +106,31 @@ class RegressionTests(TestCaseBase):
' (SELECT id,\n'
' name\n'
' FROM bar) as foo'))
+
+
+def test_issue78():
+ # the bug author provided this nice examples, let's use them!
+ def _get_identifier(sql):
+ p = sqlparse.parse(sql)[0]
+ return p.tokens[2]
+ results = (('get_name', 'z'),
+ ('get_real_name', 'y'),
+ ('get_parent_name', 'x'),
+ ('get_alias', 'z'),
+ ('get_typecast', 'text'))
+ variants = (
+ 'select x.y::text as z from foo',
+ 'select x.y::text as "z" from foo',
+ 'select x."y"::text as z from foo',
+ 'select x."y"::text as "z" from foo',
+ 'select "x".y::text as z from foo',
+ 'select "x".y::text as "z" from foo',
+ 'select "x"."y"::text as z from foo',
+ 'select "x"."y"::text as "z" from foo',
+ )
+ for variant in variants:
+ i = _get_identifier(variant)
+ assert isinstance(i, sql.Identifier)
+ for func_name, result in results:
+ func = getattr(i, func_name)
+ assert func() == result