Skip to content

Commit 00988d4

Browse files
committed
WIP: Oracle named params.
1 parent 15e37ad commit 00988d4

10 files changed

+1063
-181
lines changed

sqlparams/__init__.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ def __init__(
111111
*out_style*:
112112
113113
- For all named styles the parameter keys must be valid `Python identifiers`_.
114-
They cannot start with a digit. This is to help preven incorrectly
114+
They cannot start with a digit. This is to help prevent incorrectly
115115
matching common strings such as date-times.
116116
117117
Named styles:
@@ -127,6 +127,14 @@ def __init__(
127127
128128
.. NOTE:: This is not defined by `PEP 249`_.
129129
130+
- "named_oracle" indicates parameters will use the named style supported
131+
by Oracle which allows for case-insensitive unquoted parameters and
132+
case-sensitive quoted parameters::
133+
134+
... WHERE name = :name OR name = :"name"
135+
136+
.. NOTE:: This is not defined by `PEP 249`_.
137+
130138
- "pyformat" indicates parameters will use the named Python extended
131139
format style::
132140

sqlparams/_converting.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def __init__(
7575

7676
self._out_quotes: bool = out_style.param_quotes and allow_out_quotes
7777
"""
78-
*_out_quotes* (:class:`bool`) whether enclosing out parameters in double
78+
*_out_quotes* (:class:`bool`) whether to enclose out parameters in double
7979
quotes.
8080
"""
8181

@@ -1120,6 +1120,9 @@ def __regex_replace(
11201120
out_replacements = []
11211121
for i, sub_value in enumerate(value):
11221122
out_name = f"_{in_num_str}_{i}"
1123+
if self._out_quotes:
1124+
out_name = _quote_oracle_param(out_name)
1125+
11231126
out_repl = self._out_format.format(param=out_name)
11241127
out_names.append(out_name)
11251128
out_replacements.append(out_repl)
@@ -1130,6 +1133,9 @@ def __regex_replace(
11301133
else:
11311134
# Convert numeric parameter.
11321135
out_name = "_" + in_num_str
1136+
if self._out_quotes:
1137+
out_name = _quote_oracle_param(out_name)
1138+
11331139
out_repl = self._out_format.format(param=out_name)
11341140
param_conversions.append((False, in_index, out_name))
11351141
return out_repl
@@ -1882,6 +1888,9 @@ def __regex_replace(
18821888
out_replacements = []
18831889
for i, sub_value in enumerate(value):
18841890
out_name = f"_{in_index}_{i}"
1891+
if self._out_quotes:
1892+
out_name = _quote_oracle_param(out_name)
1893+
18851894
out_repl = self._out_format.format(param=out_name)
18861895
out_names.append(out_name)
18871896
out_replacements.append(out_repl)
@@ -1892,6 +1901,9 @@ def __regex_replace(
18921901
else:
18931902
# Convert ordinal parameter.
18941903
out_name = f"_{in_index}"
1904+
if self._out_quotes:
1905+
out_name = _quote_oracle_param(out_name)
1906+
18951907
out_repl = self._out_format.format(param=out_name)
18961908
param_conversions.append((False, in_index, out_name))
18971909
return out_repl

tests/test_1_general.py

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,46 @@ class Test(unittest.TestCase):
1313
the :class:`~sqlparams.SQLParams` class.
1414
"""
1515

16-
# 1: Test assumptions about byte encoding.
17-
1816
def test_1_decode_bytes(self):
1917
"""
2018
Test decoding bytes.
2119
"""
22-
decoded = bytes(bytearray(range(0,256))).decode(sqlparams._BYTES_ENCODING)
23-
expected = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
20+
decoded = bytes(bytearray(range(0, 256))).decode(sqlparams._BYTES_ENCODING)
21+
expected = (
22+
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12"
23+
"\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
24+
" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcde"
25+
"fghijklmnopqrstuvwxyz{|}~"
26+
"\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
27+
"\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2"
28+
"\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4"
29+
"\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6"
30+
"\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8"
31+
"\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea"
32+
"\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc"
33+
"\xfd\xfe\xff"
34+
)
2435
self.assertEqual(decoded, expected)
2536

2637
def test_1_encode_bytes(self):
2738
"""
2839
Test encoding bytes.
2940
"""
3041
encoded = "".join(map(chr, range(0,256))).encode(sqlparams._BYTES_ENCODING)
31-
expected = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
42+
expected = (
43+
b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12"
44+
b"\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
45+
b" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcd"
46+
b"efghijklmnopqrstuvwxyz{|}~"
47+
b"\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
48+
b"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
49+
b"\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1"
50+
b"\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2"
51+
b"\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3"
52+
b"\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4"
53+
b"\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5"
54+
b"\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
55+
)
3256
self.assertEqual(encoded, expected)
3357

3458
def test_2_format_bytes(self):
@@ -342,8 +366,7 @@ def test_5_strip_comments_multi_last(self) -> None:
342366

343367
def test_5_strip_comments_multi_trailing(self) -> None:
344368
"""
345-
Test to make sure multiline comments do not consume trailing
346-
comments.
369+
Test to make sure multiline comments do not consume trailing comments.
347370
"""
348371
# Create instance.
349372
query = sqlparams.SQLParams('named', 'qmark', strip_comments=True)
@@ -398,8 +421,8 @@ def test_5_strip_comments_single(self) -> None:
398421

399422
def test_5_strip_comments_single_last(self) -> None:
400423
"""
401-
Test to make sure single line comment at the end of the string is
402-
handled properly.
424+
Test to make sure single line comment at the end of the string is handled
425+
properly.
403426
"""
404427
# Create instance.
405428
query = sqlparams.SQLParams('named', 'qmark', strip_comments=True)
@@ -426,8 +449,7 @@ def test_5_strip_comments_single_last(self) -> None:
426449

427450
def test_5_strip_comments_single_trailing(self) -> None:
428451
"""
429-
Test to make sure single line comments do not consume trailing
430-
comments.
452+
Test to make sure single line comments do not consume trailing comments.
431453
"""
432454
# Create instance.
433455
query = sqlparams.SQLParams('named', 'qmark', strip_comments=True)

tests/test_2_named_to_ordinal.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -622,7 +622,12 @@ def test_3_multiple(self):
622622
FROM users
623623
WHERE id = ? OR name = ? OR altid = ? OR altname = ?;
624624
"""
625-
dest_params = [src_params['id'], src_params['name'], src_params['id'], src_params['name']]
625+
dest_params = [
626+
src_params['id'],
627+
src_params['name'],
628+
src_params['id'],
629+
src_params['name'],
630+
]
626631

627632
# Format SQL with params.
628633
sql, params = query.format(src_sql, src_params)
@@ -656,7 +661,10 @@ def test_3_multiple_many(self):
656661
FROM users
657662
WHERE id = ? OR name = ? OR altid = ? OR altname = ?;
658663
"""
659-
dest_params = [[__row['id'], __row['name'], __row['id'], __row['name']] for __row in src_params]
664+
dest_params = [
665+
[__row['id'], __row['name'], __row['id'], __row['name']]
666+
for __row in src_params
667+
]
660668

661669
# Format SQL with params.
662670
sql, many_params = query.formatmany(src_sql, src_params)

0 commit comments

Comments
 (0)