Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

string: Change string.quote_ident to always quote, add quote_ident_if…

…_needed

string.quote_ident() and string.qname() will now always returned a
quoted string.  Introduce string.quote_ident_if_needed() and
string.qname_if_needed() for old behavior quoting only when unsafe characters
are present.
  • Loading branch information...
commit 99b00578dc2d421c38be071eb5d35ea6d1e6fc49 1 parent 61c5a9a
@elprans authored
View
20 postgresql/string.py
@@ -27,16 +27,19 @@ def escape_ident(text):
'Replace every instance of " with ""'
return text.replace('"', '""')
+def needs_quoting(text):
+ return not (text and not text[0].isdecimal() and text.replace('_', 'a').isalnum())
+
def quote_ident(text):
+ "Replace every instance of '"' with '""' *and* place '"' on each end"
+ return '"' + text.replace('"', '""') + '"'
+
+def quote_ident_if_needed(text):
"""
- If needed, replace every instance of '"' with '""' *and* place '"' on each
- end. Otherwise, just return the text.
+ If needed, replace every instance of '"' with '""' *and* place '"' on each end.
+ Otherwise, just return the text.
"""
- if not text or text[0].isdecimal() or (
- not text.replace('_', 'a').isalnum()
- ):
- return '"' + text.replace('"', '""') + '"'
- return text
+ return quote_ident(text) if needs_quoting(text) else text
quote_re = re.compile(r"""(?xu)
E'(?:''|\\.|[^'])*(?:'|$) (?# Backslash escapes E'str')
@@ -214,6 +217,9 @@ def qname(*args):
"Quote the identifiers and join them using '.'"
return '.'.join([quote_ident(x) for x in args])
+def qname_if_needed(*args):
+ return '.'.join([quote_ident_if_needed(x) for x in args])
+
def split_sql(sql, sep = ';'):
"""
Given SQL, safely split using the given separator.
View
6 postgresql/test/test_driver.py
@@ -520,8 +520,8 @@ def testStatementAndCursorMetadata(self):
myudt_oid = db.prepare("select oid from pg_type WHERE typname='myudt'").first()
ps = db.prepare("SELECT $1::text AS my_column1, $2::varchar AS my_column2, $3::public.myudt AS my_column3")
self.assertEqual(tuple(ps.column_names), ('my_column1','my_column2', 'my_column3'))
- self.assertEqual(tuple(ps.sql_column_types), ('pg_catalog.text', 'CHARACTER VARYING', 'public.myudt'))
- self.assertEqual(tuple(ps.sql_parameter_types), ('pg_catalog.text', 'CHARACTER VARYING', 'public.myudt'))
+ self.assertEqual(tuple(ps.sql_column_types), ('pg_catalog.text', 'CHARACTER VARYING', '"public"."myudt"'))
+ self.assertEqual(tuple(ps.sql_parameter_types), ('pg_catalog.text', 'CHARACTER VARYING', '"public"."myudt"'))
self.assertEqual(tuple(ps.pg_column_types), (
pg_types.TEXTOID, pg_types.VARCHAROID, myudt_oid)
)
@@ -532,7 +532,7 @@ def testStatementAndCursorMetadata(self):
self.assertEqual(tuple(ps.column_types), (str,str,tuple))
c = ps.declare('textdata', 'varchardata', (123,))
self.assertEqual(tuple(c.column_names), ('my_column1','my_column2', 'my_column3'))
- self.assertEqual(tuple(c.sql_column_types), ('pg_catalog.text', 'CHARACTER VARYING', 'public.myudt'))
+ self.assertEqual(tuple(c.sql_column_types), ('pg_catalog.text', 'CHARACTER VARYING', '"public"."myudt"'))
self.assertEqual(tuple(c.pg_column_types), (
pg_types.TEXTOID, pg_types.VARCHAROID, myudt_oid
))
View
30 postgresql/test/test_string.py
@@ -197,7 +197,7 @@ def test_qname(self):
for unsplit, split, norm in split_qname_samples:
xsplit = pg_str.split_qname(unsplit)
self.assertEqual(xsplit, split)
- self.assertEqual(pg_str.qname(*split), norm)
+ self.assertEqual(pg_str.qname_if_needed(*split), norm)
self.assertRaises(
ValueError,
@@ -215,6 +215,14 @@ def test_qname(self):
ValueError,
pg_str.split_qname, 'bar".foo"'
)
+ self.assertRaises(
+ ValueError,
+ pg_str.split_qname, '0bar.foo'
+ )
+ self.assertRaises(
+ ValueError,
+ pg_str.split_qname, 'bar.fo@'
+ )
def test_quotes(self):
self.assertEqual(
@@ -226,30 +234,38 @@ def test_quotes(self):
"""'\\foo''bar\\'"""
)
self.assertEqual(
- pg_str.quote_ident("foo"),
+ pg_str.quote_ident_if_needed("foo"),
"foo"
)
self.assertEqual(
- pg_str.quote_ident("0foo"),
+ pg_str.quote_ident_if_needed("0foo"),
'"0foo"'
)
self.assertEqual(
- pg_str.quote_ident("foo0"),
+ pg_str.quote_ident_if_needed("foo0"),
'foo0'
)
self.assertEqual(
- pg_str.quote_ident("_"),
+ pg_str.quote_ident_if_needed("_"),
'_'
)
self.assertEqual(
- pg_str.quote_ident("_9"),
+ pg_str.quote_ident_if_needed("_9"),
'_9'
)
self.assertEqual(
- pg_str.quote_ident('''\\foo'bar\\'''),
+ pg_str.quote_ident_if_needed('''\\foo'bar\\'''),
'''"\\foo'bar\\"'''
)
self.assertEqual(
+ pg_str.quote_ident("spam"),
+ '"spam"'
+ )
+ self.assertEqual(
+ pg_str.qname("spam", "ham"),
+ '"spam"."ham"'
+ )
+ self.assertEqual(
pg_str.escape_ident('"'),
'""',
)
Please sign in to comment.
Something went wrong with that request. Please try again.