singlestoredb 0.9.1__cp36-abi3-win32.whl → 0.9.3__cp36-abi3-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of singlestoredb might be problematic. Click here for more details.
- _singlestoredb_accel.pyd +0 -0
- singlestoredb/__init__.py +1 -1
- singlestoredb/fusion/__init__.py +11 -0
- singlestoredb/fusion/handler.py +555 -0
- singlestoredb/fusion/handlers/__init__.py +0 -0
- singlestoredb/fusion/handlers/workspace.py +361 -0
- singlestoredb/fusion/registry.py +167 -0
- singlestoredb/fusion/result.py +120 -0
- singlestoredb/http/connection.py +69 -13
- singlestoredb/management/workspace.py +1 -1
- singlestoredb/mysql/connection.py +10 -4
- singlestoredb/mysql/constants/FIELD_TYPE.py +1 -0
- singlestoredb/tests/test_fusion.py +83 -0
- singlestoredb/tests/test_management.py +1 -1
- singlestoredb/tests/test_results.py +6 -6
- singlestoredb/utils/mogrify.py +151 -0
- {singlestoredb-0.9.1.dist-info → singlestoredb-0.9.3.dist-info}/METADATA +2 -1
- {singlestoredb-0.9.1.dist-info → singlestoredb-0.9.3.dist-info}/RECORD +21 -13
- {singlestoredb-0.9.1.dist-info → singlestoredb-0.9.3.dist-info}/LICENSE +0 -0
- {singlestoredb-0.9.1.dist-info → singlestoredb-0.9.3.dist-info}/WHEEL +0 -0
- {singlestoredb-0.9.1.dist-info → singlestoredb-0.9.3.dist-info}/top_level.txt +0 -0
singlestoredb/http/connection.py
CHANGED
|
@@ -41,6 +41,7 @@ except ImportError:
|
|
|
41
41
|
has_shapely = False
|
|
42
42
|
|
|
43
43
|
from .. import connection
|
|
44
|
+
from .. import fusion
|
|
44
45
|
from .. import types
|
|
45
46
|
from ..config import get_option
|
|
46
47
|
from ..converters import converters
|
|
@@ -56,6 +57,7 @@ from ..exceptions import ProgrammingError
|
|
|
56
57
|
from ..exceptions import Warning # noqa: F401
|
|
57
58
|
from ..utils.convert_rows import convert_rows
|
|
58
59
|
from ..utils.debug import log_query
|
|
60
|
+
from ..utils.mogrify import mogrify
|
|
59
61
|
from ..utils.results import Description
|
|
60
62
|
from ..utils.results import format_results
|
|
61
63
|
from ..utils.results import Result
|
|
@@ -431,16 +433,79 @@ class Cursor(connection.Cursor):
|
|
|
431
433
|
else:
|
|
432
434
|
query = query % args
|
|
433
435
|
|
|
436
|
+
def _execute_fusion_query(
|
|
437
|
+
self,
|
|
438
|
+
oper: Union[str, bytes],
|
|
439
|
+
params: Optional[Union[Sequence[Any], Dict[str, Any]]] = None,
|
|
440
|
+
handler: Any = None,
|
|
441
|
+
) -> int:
|
|
442
|
+
oper = mogrify(oper, params)
|
|
443
|
+
|
|
444
|
+
if isinstance(oper, bytes):
|
|
445
|
+
oper = oper.decode('utf-8')
|
|
446
|
+
|
|
447
|
+
log_query(oper, None)
|
|
448
|
+
|
|
449
|
+
results_type = self._results_type
|
|
450
|
+
self._results_type = 'tuples'
|
|
451
|
+
try:
|
|
452
|
+
mgmt_res = fusion.execute(
|
|
453
|
+
self._connection, # type: ignore
|
|
454
|
+
oper,
|
|
455
|
+
handler=handler,
|
|
456
|
+
)
|
|
457
|
+
finally:
|
|
458
|
+
self._results_type = results_type
|
|
459
|
+
|
|
460
|
+
self._descriptions.append(list(mgmt_res.description))
|
|
461
|
+
self._results.append(list(mgmt_res.rows))
|
|
462
|
+
self.rowcount = len(self._results[-1])
|
|
463
|
+
|
|
464
|
+
pymy_res = PyMyResult()
|
|
465
|
+
for field in mgmt_res.fields:
|
|
466
|
+
pymy_res.append(
|
|
467
|
+
PyMyField(
|
|
468
|
+
field.name,
|
|
469
|
+
field.flags,
|
|
470
|
+
field.charsetnr,
|
|
471
|
+
),
|
|
472
|
+
)
|
|
473
|
+
|
|
474
|
+
self._pymy_results.append(pymy_res)
|
|
475
|
+
|
|
476
|
+
if self._results and self._results[0]:
|
|
477
|
+
self._row_idx = 0
|
|
478
|
+
self._result_idx = 0
|
|
479
|
+
|
|
480
|
+
return self.rowcount
|
|
481
|
+
|
|
434
482
|
def _execute(
|
|
435
483
|
self, oper: str,
|
|
436
484
|
params: Optional[Union[Sequence[Any], Dict[str, Any]]] = None,
|
|
437
485
|
is_callproc: bool = False,
|
|
438
486
|
) -> int:
|
|
487
|
+
self._descriptions = []
|
|
488
|
+
self._results = []
|
|
489
|
+
self._pymy_results = []
|
|
490
|
+
self._row_idx = -1
|
|
491
|
+
self._result_idx = -1
|
|
492
|
+
self.rowcount = 0
|
|
493
|
+
self._expect_results = False
|
|
494
|
+
|
|
439
495
|
if self._connection is None:
|
|
440
496
|
raise ProgrammingError(errno=2048, msg='Connection is closed.')
|
|
441
497
|
|
|
498
|
+
sql_type = 'exec'
|
|
499
|
+
if re.match(r'^\s*(select|show|call|echo|describe|with)\s+', oper, flags=re.I):
|
|
500
|
+
self._expect_results = True
|
|
501
|
+
sql_type = 'query'
|
|
502
|
+
|
|
442
503
|
self._validate_param_subs(oper, params)
|
|
443
504
|
|
|
505
|
+
handler = fusion.get_handler(oper)
|
|
506
|
+
if handler is not None:
|
|
507
|
+
return self._execute_fusion_query(oper, params, handler=handler)
|
|
508
|
+
|
|
444
509
|
oper, params = self._connection._convert_params(oper, params)
|
|
445
510
|
|
|
446
511
|
log_query(oper, params)
|
|
@@ -455,12 +520,6 @@ class Cursor(connection.Cursor):
|
|
|
455
520
|
if self._connection._database:
|
|
456
521
|
data['database'] = self._connection._database
|
|
457
522
|
|
|
458
|
-
self._expect_results = False
|
|
459
|
-
sql_type = 'exec'
|
|
460
|
-
if re.match(r'^\s*(select|show|call|echo|describe|with)\s+', oper, flags=re.I):
|
|
461
|
-
self._expect_results = True
|
|
462
|
-
sql_type = 'query'
|
|
463
|
-
|
|
464
523
|
if sql_type == 'query':
|
|
465
524
|
res = self._post('query/tuples', json=data)
|
|
466
525
|
else:
|
|
@@ -479,18 +538,12 @@ class Cursor(connection.Cursor):
|
|
|
479
538
|
|
|
480
539
|
out = json.loads(res.text)
|
|
481
540
|
|
|
482
|
-
self._descriptions = []
|
|
483
|
-
self._results = []
|
|
484
|
-
self._row_idx = -1
|
|
485
|
-
self._result_idx = -1
|
|
486
|
-
self.rowcount = 0
|
|
487
|
-
|
|
488
541
|
if sql_type == 'query':
|
|
489
542
|
# description: (name, type_code, display_size, internal_size,
|
|
490
543
|
# precision, scale, null_ok, column_flags, charset)
|
|
491
544
|
|
|
492
545
|
# Remove converters for things the JSON parser already converted
|
|
493
|
-
http_converters = dict(
|
|
546
|
+
http_converters = dict(self._connection.decoders)
|
|
494
547
|
http_converters.pop(4, None)
|
|
495
548
|
http_converters.pop(5, None)
|
|
496
549
|
http_converters.pop(6, None)
|
|
@@ -902,6 +955,9 @@ class Connection(connection.Connection):
|
|
|
902
955
|
version = kwargs.get('version', 'v2')
|
|
903
956
|
self.driver = kwargs.get('driver', 'https')
|
|
904
957
|
|
|
958
|
+
self.encoders = {k: v for (k, v) in converters.items() if type(k) is not int}
|
|
959
|
+
self.decoders = {k: v for (k, v) in converters.items() if type(k) is int}
|
|
960
|
+
|
|
905
961
|
self._database = kwargs.get('database', get_option('database'))
|
|
906
962
|
self._url = f'{self.driver}://{host}:{port}/api/{version}/'
|
|
907
963
|
self._messages: List[Tuple[int, str]] = []
|
|
@@ -1389,7 +1389,7 @@ class WorkspaceManager(Manager):
|
|
|
1389
1389
|
'workspaceGroups', json=dict(
|
|
1390
1390
|
name=name, regionID=region,
|
|
1391
1391
|
adminPassword=admin_password,
|
|
1392
|
-
firewallRanges=firewall_ranges,
|
|
1392
|
+
firewallRanges=firewall_ranges or [],
|
|
1393
1393
|
expiresAt=expires_at,
|
|
1394
1394
|
allowAllTraffic=allow_all_traffic,
|
|
1395
1395
|
updateWindow=update_window,
|
|
@@ -47,6 +47,7 @@ from .protocol import (
|
|
|
47
47
|
)
|
|
48
48
|
from . import err
|
|
49
49
|
from ..config import get_option
|
|
50
|
+
from .. import fusion
|
|
50
51
|
from ..connection import Connection as BaseConnection
|
|
51
52
|
|
|
52
53
|
try:
|
|
@@ -758,10 +759,15 @@ class Connection(BaseConnection):
|
|
|
758
759
|
"""
|
|
759
760
|
# if DEBUG:
|
|
760
761
|
# print("DEBUG: sending query:", sql)
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
762
|
+
handler = fusion.get_handler(sql)
|
|
763
|
+
if handler is not None:
|
|
764
|
+
self._result = fusion.execute(self, sql, handler=handler)
|
|
765
|
+
self._affected_rows = self._result.affected_rows
|
|
766
|
+
else:
|
|
767
|
+
if isinstance(sql, str):
|
|
768
|
+
sql = sql.encode(self.encoding, 'surrogateescape')
|
|
769
|
+
self._execute_command(COMMAND.COM_QUERY, sql)
|
|
770
|
+
self._affected_rows = self._read_query_result(unbuffered=unbuffered)
|
|
765
771
|
return self._affected_rows
|
|
766
772
|
|
|
767
773
|
def next_result(self, unbuffered=False):
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# type: ignore
|
|
3
|
+
"""SingleStoreDB Fusion testing."""
|
|
4
|
+
import os
|
|
5
|
+
import unittest
|
|
6
|
+
|
|
7
|
+
import singlestoredb as s2
|
|
8
|
+
from singlestoredb.tests import utils
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TestFusion(unittest.TestCase):
|
|
12
|
+
|
|
13
|
+
dbname: str = ''
|
|
14
|
+
dbexisted: bool = False
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
def setUpClass(cls):
|
|
18
|
+
sql_file = os.path.join(os.path.dirname(__file__), 'test.sql')
|
|
19
|
+
cls.dbname, cls.dbexisted = utils.load_sql(sql_file)
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
def tearDownClass(cls):
|
|
23
|
+
if not cls.dbexisted:
|
|
24
|
+
utils.drop_database(cls.dbname)
|
|
25
|
+
|
|
26
|
+
def setUp(self):
|
|
27
|
+
self.enabled = os.environ.get('SINGLESTOREDB_ENABLE_FUSION')
|
|
28
|
+
os.environ['SINGLESTOREDB_ENABLE_FUSION'] = '1'
|
|
29
|
+
self.conn = s2.connect(database=type(self).dbname, local_infile=True)
|
|
30
|
+
self.cur = self.conn.cursor()
|
|
31
|
+
|
|
32
|
+
def tearDown(self):
|
|
33
|
+
if self.enabled:
|
|
34
|
+
os.environ['SINGLESTOREDB_ENABLE_FUSION'] = self.enabled
|
|
35
|
+
else:
|
|
36
|
+
del os.environ['SINGLESTOREDB_ENABLE_FUSION']
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
if self.cur is not None:
|
|
40
|
+
self.cur.close()
|
|
41
|
+
except Exception:
|
|
42
|
+
# traceback.print_exc()
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
if self.conn is not None:
|
|
47
|
+
self.conn.close()
|
|
48
|
+
except Exception:
|
|
49
|
+
# traceback.print_exc()
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
def test_env_var(self):
|
|
53
|
+
os.environ['SINGLESTOREDB_ENABLE_FUSION'] = '0'
|
|
54
|
+
|
|
55
|
+
with self.assertRaises(s2.ProgrammingError):
|
|
56
|
+
self.cur.execute('show fusion commands')
|
|
57
|
+
|
|
58
|
+
del os.environ['SINGLESTOREDB_ENABLE_FUSION']
|
|
59
|
+
|
|
60
|
+
with self.assertRaises(s2.ProgrammingError):
|
|
61
|
+
self.cur.execute('show fusion commands')
|
|
62
|
+
|
|
63
|
+
os.environ['SINGLESTOREDB_ENABLE_FUSION'] = 'yes'
|
|
64
|
+
|
|
65
|
+
self.cur.execute('show fusion commands')
|
|
66
|
+
assert list(self.cur)
|
|
67
|
+
|
|
68
|
+
def test_show_commands(self):
|
|
69
|
+
self.cur.execute('show fusion commands')
|
|
70
|
+
cmds = [x[0] for x in self.cur.fetchall()]
|
|
71
|
+
assert cmds
|
|
72
|
+
assert [x for x in cmds if x.strip().startswith('SHOW FUSION GRAMMAR')], cmds
|
|
73
|
+
|
|
74
|
+
self.cur.execute('show fusion commands like "create%"')
|
|
75
|
+
cmds = [x[0] for x in self.cur.fetchall()]
|
|
76
|
+
assert cmds
|
|
77
|
+
assert [x for x in cmds if x.strip().startswith('CREATE')] == cmds, cmds
|
|
78
|
+
|
|
79
|
+
def test_show_grammar(self):
|
|
80
|
+
self.cur.execute('show fusion grammar for "create workspace"')
|
|
81
|
+
cmds = [x[0] for x in self.cur.fetchall()]
|
|
82
|
+
assert cmds
|
|
83
|
+
assert [x for x in cmds if x.strip().startswith('CREATE WORKSPACE')], cmds
|
|
@@ -51,7 +51,7 @@ class TestResults(unittest.TestCase):
|
|
|
51
51
|
with conn.cursor() as cur:
|
|
52
52
|
cur.execute('select * from data')
|
|
53
53
|
out = cur.fetchone()
|
|
54
|
-
assert type(out)
|
|
54
|
+
assert type(out) is tuple, type(out)
|
|
55
55
|
assert len(out) == 3, len(out)
|
|
56
56
|
cur.fetchall()
|
|
57
57
|
|
|
@@ -59,7 +59,7 @@ class TestResults(unittest.TestCase):
|
|
|
59
59
|
out = cur.fetchall()
|
|
60
60
|
assert len(out) == 5, len(out)
|
|
61
61
|
assert len(out[0]) == 3, len(out[0])
|
|
62
|
-
assert type(out[0])
|
|
62
|
+
assert type(out[0]) is tuple, type(out[0])
|
|
63
63
|
assert sorted(out) == sorted([
|
|
64
64
|
('a', 'antelopes', 2),
|
|
65
65
|
('b', 'bears', 2),
|
|
@@ -111,13 +111,13 @@ class TestResults(unittest.TestCase):
|
|
|
111
111
|
with conn.cursor() as cur:
|
|
112
112
|
cur.execute('select * from data')
|
|
113
113
|
out = cur.fetchone()
|
|
114
|
-
assert type(out)
|
|
114
|
+
assert type(out) is dict, type(out)
|
|
115
115
|
assert len(out) == 3, len(out)
|
|
116
116
|
cur.fetchall()
|
|
117
117
|
|
|
118
118
|
cur.execute('select * from data')
|
|
119
119
|
out = cur.fetchall()
|
|
120
|
-
assert type(out[0])
|
|
120
|
+
assert type(out[0]) is dict, type(out[0])
|
|
121
121
|
assert len(out) == 5, len(out)
|
|
122
122
|
assert len(out[0]) == 3, len(out[0])
|
|
123
123
|
assert sorted(out, key=lambda x: x['id']) == sorted(
|
|
@@ -139,13 +139,13 @@ class TestResults(unittest.TestCase):
|
|
|
139
139
|
with conn.cursor() as cur:
|
|
140
140
|
cur.execute('select * from data')
|
|
141
141
|
out = cur.fetchone()
|
|
142
|
-
assert type(out)
|
|
142
|
+
assert type(out) is pd.DataFrame, type(out)
|
|
143
143
|
assert len(out) == 1, len(out)
|
|
144
144
|
cur.fetchall()
|
|
145
145
|
|
|
146
146
|
cur.execute('select * from data')
|
|
147
147
|
out = cur.fetchall()
|
|
148
|
-
assert type(out)
|
|
148
|
+
assert type(out) is pd.DataFrame, type(out)
|
|
149
149
|
assert len(out) == 5, len(out)
|
|
150
150
|
out = out.sort_values('id').reset_index(drop=True)
|
|
151
151
|
exp = pd.DataFrame(
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from typing import Any
|
|
3
|
+
from typing import Dict
|
|
4
|
+
from typing import Optional
|
|
5
|
+
from typing import Sequence
|
|
6
|
+
from typing import Union
|
|
7
|
+
|
|
8
|
+
from ..mysql import converters
|
|
9
|
+
from ..mysql.constants import SERVER_STATUS
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
Encoders = converters.Encoders
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def escape(
|
|
16
|
+
obj: Any,
|
|
17
|
+
charset: str = 'utf8',
|
|
18
|
+
mapping: Optional[Encoders] = None,
|
|
19
|
+
server_status: int = 0,
|
|
20
|
+
binary_prefix: bool = False,
|
|
21
|
+
) -> str:
|
|
22
|
+
"""
|
|
23
|
+
Escape whatever value is passed.
|
|
24
|
+
|
|
25
|
+
Non-standard, for internal use; do not use this in your applications.
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
dtype = type(obj)
|
|
29
|
+
if dtype is str or isinstance(obj, str):
|
|
30
|
+
return "'{}'".format(escape_string(obj, server_status=server_status))
|
|
31
|
+
if dtype is bytes or dtype is bytearray or isinstance(obj, (bytes, bytearray)):
|
|
32
|
+
return _quote_bytes(
|
|
33
|
+
obj,
|
|
34
|
+
server_status=server_status,
|
|
35
|
+
binary_prefix=binary_prefix,
|
|
36
|
+
)
|
|
37
|
+
if mapping is None:
|
|
38
|
+
mapping = converters.encoders
|
|
39
|
+
return converters.escape_item(obj, charset, mapping=mapping)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def literal(
|
|
43
|
+
obj: Any,
|
|
44
|
+
charset: str = 'utf8',
|
|
45
|
+
encoders: Optional[Encoders] = None,
|
|
46
|
+
server_status: int = 0,
|
|
47
|
+
binary_prefix: bool = False,
|
|
48
|
+
) -> str:
|
|
49
|
+
"""
|
|
50
|
+
Alias for escape().
|
|
51
|
+
|
|
52
|
+
Non-standard, for internal use; do not use this in your applications.
|
|
53
|
+
|
|
54
|
+
"""
|
|
55
|
+
return escape(
|
|
56
|
+
obj, charset=charset, mapping=encoders,
|
|
57
|
+
server_status=server_status, binary_prefix=binary_prefix,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def escape_string(
|
|
62
|
+
s: str,
|
|
63
|
+
server_status: int = 0,
|
|
64
|
+
) -> str:
|
|
65
|
+
"""Escape a string value."""
|
|
66
|
+
if server_status & SERVER_STATUS.SERVER_STATUS_NO_BACKSLASH_ESCAPES:
|
|
67
|
+
return s.replace("'", "''")
|
|
68
|
+
return converters.escape_string(s)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _quote_bytes(
|
|
72
|
+
s: bytes,
|
|
73
|
+
server_status: int = 0,
|
|
74
|
+
binary_prefix: bool = False,
|
|
75
|
+
) -> str:
|
|
76
|
+
if server_status & SERVER_STATUS.SERVER_STATUS_NO_BACKSLASH_ESCAPES:
|
|
77
|
+
if binary_prefix:
|
|
78
|
+
return "_binary X'{}'".format(s.hex())
|
|
79
|
+
return "X'{}'".format(s.hex())
|
|
80
|
+
return converters.escape_bytes(s)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _escape_args(
|
|
84
|
+
args: Union[Sequence[Any], Dict[str, Any], None],
|
|
85
|
+
charset: str = 'utf8',
|
|
86
|
+
encoders: Optional[Encoders] = None,
|
|
87
|
+
server_status: int = 0,
|
|
88
|
+
binary_prefix: bool = False,
|
|
89
|
+
) -> Any:
|
|
90
|
+
if encoders is None:
|
|
91
|
+
encoders = converters.encoders
|
|
92
|
+
|
|
93
|
+
if isinstance(args, (tuple, list)):
|
|
94
|
+
return tuple(
|
|
95
|
+
literal(
|
|
96
|
+
arg, charset=charset, encoders=encoders,
|
|
97
|
+
server_status=server_status,
|
|
98
|
+
binary_prefix=binary_prefix,
|
|
99
|
+
) for arg in args
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
elif isinstance(args, dict):
|
|
103
|
+
return {
|
|
104
|
+
key: literal(
|
|
105
|
+
val, charset=charset, encoders=encoders,
|
|
106
|
+
server_status=server_status,
|
|
107
|
+
binary_prefix=binary_prefix,
|
|
108
|
+
) for (key, val) in args.items()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# If it's not a dictionary let's try escaping it anyways.
|
|
112
|
+
# Worst case it will throw a Value error
|
|
113
|
+
return escape(
|
|
114
|
+
args, charset=charset, mapping=encoders,
|
|
115
|
+
server_status=server_status, binary_prefix=binary_prefix,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def mogrify(
|
|
120
|
+
query: Union[str, bytes],
|
|
121
|
+
args: Union[Sequence[Any], Dict[str, Any], None] = None,
|
|
122
|
+
charset: str = 'utf8',
|
|
123
|
+
encoders: Optional[Encoders] = None,
|
|
124
|
+
server_status: int = 0,
|
|
125
|
+
binary_prefix: bool = False,
|
|
126
|
+
) -> Union[str, bytes]:
|
|
127
|
+
"""
|
|
128
|
+
Returns the exact string sent to the database by calling the execute() method.
|
|
129
|
+
|
|
130
|
+
This method follows the extension to the DB API 2.0 followed by Psycopg.
|
|
131
|
+
|
|
132
|
+
Parameters
|
|
133
|
+
----------
|
|
134
|
+
query : str
|
|
135
|
+
Query to mogrify.
|
|
136
|
+
args : Sequence[Any] or Dict[str, Any] or Any, optional
|
|
137
|
+
Parameters used with query. (optional)
|
|
138
|
+
|
|
139
|
+
Returns
|
|
140
|
+
-------
|
|
141
|
+
str : The query with argument binding applied.
|
|
142
|
+
|
|
143
|
+
"""
|
|
144
|
+
if args:
|
|
145
|
+
query = query % _escape_args(
|
|
146
|
+
args, charset=charset,
|
|
147
|
+
encoders=encoders,
|
|
148
|
+
server_status=server_status,
|
|
149
|
+
binary_prefix=binary_prefix,
|
|
150
|
+
)
|
|
151
|
+
return query
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: singlestoredb
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.3
|
|
4
4
|
Summary: Interface to the SingleStoreDB database and workspace management APIs
|
|
5
5
|
Home-page: https://github.com/singlestore-labs/singlestoredb-python
|
|
6
6
|
Author: SingleStore
|
|
@@ -16,6 +16,7 @@ Description-Content-Type: text/markdown
|
|
|
16
16
|
License-File: LICENSE
|
|
17
17
|
Requires-Dist: PyJWT
|
|
18
18
|
Requires-Dist: build
|
|
19
|
+
Requires-Dist: parsimonious
|
|
19
20
|
Requires-Dist: requests
|
|
20
21
|
Requires-Dist: sqlparams
|
|
21
22
|
Requires-Dist: wheel
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
_singlestoredb_accel.pyd,sha256=
|
|
2
|
-
singlestoredb/__init__.py,sha256=
|
|
1
|
+
_singlestoredb_accel.pyd,sha256=A4Heg5r20M6TzP78CzPbnPHIz4jONkKoSGKtcBKxis4,34816
|
|
2
|
+
singlestoredb/__init__.py,sha256=uPSaY4xDxpO0orU6aqssT93B24ItTyVzGvhv4tgZSOc,909
|
|
3
3
|
singlestoredb/auth.py,sha256=RmYiH0Wlc2RXc4pTlRMysxtBI445ggCIwojWKC_eDLE,7844
|
|
4
4
|
singlestoredb/config.py,sha256=-n8HA5_KlwFxcOnfqnLobDbIA43sMlLiVr-YmvtG3a0,7397
|
|
5
5
|
singlestoredb/connection.py,sha256=XeuKeM0ihbF1QIlDn2AxnJfT5d-RNCch56q0z3dn9g8,45409
|
|
@@ -15,8 +15,14 @@ singlestoredb/functions/ext/__init__.py,sha256=NrwbyL86NeG_Kv1N23R4VwL1Ap-pY9Z1B
|
|
|
15
15
|
singlestoredb/functions/ext/asgi.py,sha256=LFrcZL2R7sgXflWqx-wcCYRIlivywqBg1joDrGUplSg,11319
|
|
16
16
|
singlestoredb/functions/ext/json.py,sha256=7dncClZrC1X42GbKzVgV5jgExdbI7GQq0BGSDB9NuTM,1107
|
|
17
17
|
singlestoredb/functions/ext/rowdat_1.py,sha256=70KSVL7E2842uMWOa-pygbLFd8GyZqOviEFwFacadDs,3296
|
|
18
|
+
singlestoredb/fusion/__init__.py,sha256=FHWtrg6OJFTf6Ye197V5sU6ssryr2h6FBcDIgXP7-H4,367
|
|
19
|
+
singlestoredb/fusion/handler.py,sha256=bJRJFX-j70J3aSfAaeX38AkfV_WlwL-wWU--T5JBYjc,16725
|
|
20
|
+
singlestoredb/fusion/registry.py,sha256=0suBgQ87A85sCZWGWlzBoIIZxbcL18wnrt280w01qJU,4433
|
|
21
|
+
singlestoredb/fusion/result.py,sha256=K5WOm4_COuWXo-YxL0wjodfLhjO_X5Fdp34TrX9_FZI,4019
|
|
22
|
+
singlestoredb/fusion/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
+
singlestoredb/fusion/handlers/workspace.py,sha256=PLxIM0747WN7tbQ_QMxQG_YvSSL_UqCoijMFwH2xfuA,10893
|
|
18
24
|
singlestoredb/http/__init__.py,sha256=4cEDvLloGc3LSpU-PnIwacyu0n5oIIIE6xk2SPyWD_w,939
|
|
19
|
-
singlestoredb/http/connection.py,sha256=
|
|
25
|
+
singlestoredb/http/connection.py,sha256=uVbHgjcU28uHf4sMpJD8UIqzcFVPmJQAcE_ikDTr_GQ,35259
|
|
20
26
|
singlestoredb/management/__init__.py,sha256=pRxBjzZxNjnuAtBlv4WwYZF-2Z3dbrKoy5XilJRXT2w,102
|
|
21
27
|
singlestoredb/management/billing_usage.py,sha256=0UHFSPCrN0nyeGFFM-HXS3NP8pYmYo2BCCahDEPXvzg,3883
|
|
22
28
|
singlestoredb/management/cluster.py,sha256=dqozXaM8kneKTFlUg92gjw6oIT6sPsoYWwJ8aefsVCo,14611
|
|
@@ -24,11 +30,11 @@ singlestoredb/management/manager.py,sha256=6-fKCB-3biMFQqk1fQtI5ZiYcX2pKMs0jD0sB
|
|
|
24
30
|
singlestoredb/management/organization.py,sha256=iz5Mde0lat3EYLpwNDbnS0ytI33O6tG6-wYDL4-TGdM,2200
|
|
25
31
|
singlestoredb/management/region.py,sha256=oGoLLS88dE1GmY7GCc0BV7X3f7bWwKQyeXOVBFmK9Pk,1678
|
|
26
32
|
singlestoredb/management/utils.py,sha256=wAJaLRm7B7urG6MDkALZXxVa-kKmidXQk_-ezuppv5U,6270
|
|
27
|
-
singlestoredb/management/workspace.py,sha256=
|
|
33
|
+
singlestoredb/management/workspace.py,sha256=yEI0epRCBLtWTnHLDO8WhHnsYrLpC4CLjHvwf-z9gNs,47138
|
|
28
34
|
singlestoredb/mysql/__init__.py,sha256=CbpwzNUJPAmKPpIobC0-ugBta_RgHCMq7X7N75QLReY,4669
|
|
29
35
|
singlestoredb/mysql/_auth.py,sha256=YaqqyvAHmeraBv3BM207rNveUVPM-mPnW20ts_ynVWg,8341
|
|
30
36
|
singlestoredb/mysql/charset.py,sha256=mnCdMpvdub1S2mm2PSk2j5JddgsWRjsVLtGx-y9TskE,10724
|
|
31
|
-
singlestoredb/mysql/connection.py,sha256=
|
|
37
|
+
singlestoredb/mysql/connection.py,sha256=KD7edphkdSy5Ijj0hbpCe4Mmu4MudC2wKtCnRVrlA4A,64129
|
|
32
38
|
singlestoredb/mysql/converters.py,sha256=vebFFm6IrC0WgY-5Eh-esaPizY5cq3vDOUlEKGaYM-U,7771
|
|
33
39
|
singlestoredb/mysql/cursors.py,sha256=t3t5-Iq5lOwyh-Qj3jVimEUIrljewHkOPaK01Dl5xsk,21959
|
|
34
40
|
singlestoredb/mysql/err.py,sha256=aDbmfq08gWVmfgIea735wSeiFdvYbB5wusgd3qTVq1s,2480
|
|
@@ -39,7 +45,7 @@ singlestoredb/mysql/constants/CLIENT.py,sha256=hAo5tQqhc1V7t7tdNd4s6TINwYoDHldys
|
|
|
39
45
|
singlestoredb/mysql/constants/COMMAND.py,sha256=T81MAx6Vkxf5-86PTk2OtENoXtaFSlEckBzzwrI9uXQ,711
|
|
40
46
|
singlestoredb/mysql/constants/CR.py,sha256=qCE-3R28NHhkyVwhgwgxQK0XX_bZyGtTlvNa3UWaXv0,2383
|
|
41
47
|
singlestoredb/mysql/constants/ER.py,sha256=FuZGMUaHPJzXNxcEsQUfQNtVEMYzYUXRvPDJnVOxXyQ,12770
|
|
42
|
-
singlestoredb/mysql/constants/FIELD_TYPE.py,sha256=
|
|
48
|
+
singlestoredb/mysql/constants/FIELD_TYPE.py,sha256=MWFwixlGMvI3tBq0dTknwvoza9krqVS3aZa7EMivZIU,414
|
|
43
49
|
singlestoredb/mysql/constants/FLAG.py,sha256=CbdDkHclXsvS-NdAvrFhFzby4BAVpvq0tIPOszHAqgA,229
|
|
44
50
|
singlestoredb/mysql/constants/SERVER_STATUS.py,sha256=W4UYyw1AW0brlgywTBaE6cm6eGq6NBvHK8iCAh2mQhM,343
|
|
45
51
|
singlestoredb/mysql/constants/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -74,9 +80,10 @@ singlestoredb/tests/test_config.py,sha256=Ad0PDmCnJMOyy9f7WTKiRasSR_3mYRByUlSb7k
|
|
|
74
80
|
singlestoredb/tests/test_connection.py,sha256=0GRvsvUz8G2I5ah0lHI97XUVv6UI13A1D5UNHk7RRmc,52215
|
|
75
81
|
singlestoredb/tests/test_dbapi.py,sha256=cNJoTEZvYG7ckcwT7xqlkJX-2TDEYGTDDU1Igucp48k,679
|
|
76
82
|
singlestoredb/tests/test_exceptions.py,sha256=vscMYmdOJr0JmkTAJrNI2w0Q96Nfugjkrt5_lYnw8i0,1176
|
|
83
|
+
singlestoredb/tests/test_fusion.py,sha256=g7sLQUJgHRDe48SWDfFPrx0onbh4qAVjQ_sEp8-VGBs,2624
|
|
77
84
|
singlestoredb/tests/test_http.py,sha256=7hwXe61hlUes3nji0MTTZweo94tJAlJ-vA5ct9geXFQ,8868
|
|
78
|
-
singlestoredb/tests/test_management.py,sha256=
|
|
79
|
-
singlestoredb/tests/test_results.py,sha256=
|
|
85
|
+
singlestoredb/tests/test_management.py,sha256=jvT38o-nYGmzk260NS8j9Bit2kBv24CSloG3CJmcQVs,26512
|
|
86
|
+
singlestoredb/tests/test_results.py,sha256=Zg1ynZFRZqalAMfNLOU5C6BDXaox6JxrKm_XZwVNFcg,6753
|
|
80
87
|
singlestoredb/tests/test_types.py,sha256=YeVE6KPqlqzJke-4hbRmc8ko1E7RLHu5S8qLg04Bl5Y,4632
|
|
81
88
|
singlestoredb/tests/test_udf.py,sha256=6fGNQELY6KKvUUUmi6StTGw-jZUMGrVXTpfZf61bwFw,29562
|
|
82
89
|
singlestoredb/tests/test_xdict.py,sha256=5ArRJqd5aNXkPK7Y6sFeRbqZ59MZ1YaGBpSlDAbBrjM,10741
|
|
@@ -85,10 +92,11 @@ singlestoredb/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
|
|
|
85
92
|
singlestoredb/utils/config.py,sha256=WVQ567ZzqzlTGueQH5fEpm5tPZuz8y7qvpEQUB-vPjk,25453
|
|
86
93
|
singlestoredb/utils/convert_rows.py,sha256=gkZeZazeJvimCYEQ1FdAC-AmMDwmFGCuP6mi653bpns,1885
|
|
87
94
|
singlestoredb/utils/debug.py,sha256=y7dnJeJGt3U_BWXz9pLt1qNQREpPtumYX_sk1DiqG6Y,362
|
|
95
|
+
singlestoredb/utils/mogrify.py,sha256=gCcn99-vgsGVjTUV7RHJ6hH4vCNrsGB_Xo4z8kiSPDQ,4201
|
|
88
96
|
singlestoredb/utils/results.py,sha256=ely2XVAHHejObjLibS3UcrPOuCO2g5aRtA3PxAMtE-g,5432
|
|
89
97
|
singlestoredb/utils/xdict.py,sha256=-wi1lSPTnY99fhVMBhPKJ8cCsQhNG4GMUfkEBDKYgCw,13321
|
|
90
|
-
singlestoredb-0.9.
|
|
91
|
-
singlestoredb-0.9.
|
|
92
|
-
singlestoredb-0.9.
|
|
93
|
-
singlestoredb-0.9.
|
|
94
|
-
singlestoredb-0.9.
|
|
98
|
+
singlestoredb-0.9.3.dist-info/LICENSE,sha256=Bojenzui8aPNjlF3w4ojguDP7sTf8vFV_9Gc2UAG1sg,11542
|
|
99
|
+
singlestoredb-0.9.3.dist-info/METADATA,sha256=3Kv3yUR-JCqYGCvlmCsSX5MJdhG4lvh8tGpnfetigXI,7793
|
|
100
|
+
singlestoredb-0.9.3.dist-info/WHEEL,sha256=_QnT23Vv5YRa4iRimE-BlP6ILVeuwvhs3ULTMOeMgOs,96
|
|
101
|
+
singlestoredb-0.9.3.dist-info/top_level.txt,sha256=SDtemIXf-Kp-_F2f_S6x0db33cHGOILdAEsIQZe2LZc,35
|
|
102
|
+
singlestoredb-0.9.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|