Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
singlestore-labs
GitHub Repository: singlestore-labs/singlestoredb-python
Path: blob/main/singlestoredb/utils/mogrify.py
801 views
1
#!/usr/bin/env python3
2
from collections.abc import Sequence
3
from typing import Any
4
from typing import Dict
5
from typing import Optional
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
interpolate_query_with_empty_args: bool = False,
127
) -> Union[str, bytes]:
128
"""
129
Returns the exact string sent to the database by calling the execute() method.
130
131
This method follows the extension to the DB API 2.0 followed by Psycopg.
132
133
Parameters
134
----------
135
query : str
136
Query to mogrify.
137
args : Sequence[Any] or Dict[str, Any] or Any, optional
138
Parameters used with query. (optional)
139
interpolate_query_with_empty_args : bool, optional
140
If True, apply string interpolation even when args is an empty tuple/list.
141
If False, only apply when args is truthy. Defaults to False.
142
143
Returns
144
-------
145
str : The query with argument binding applied.
146
147
"""
148
if should_interpolate_query(interpolate_query_with_empty_args, args):
149
query = query % _escape_args(
150
args, charset=charset,
151
encoders=encoders,
152
server_status=server_status,
153
binary_prefix=binary_prefix,
154
)
155
return query
156
157
158
def should_interpolate_query(
159
interpolate_query_with_empty_args: bool,
160
args: Union[Sequence[Any], Dict[str, Any], None],
161
) -> bool:
162
if interpolate_query_with_empty_args:
163
return args is not None
164
return bool(args)
165
166