sqlalchemy-cubrid 0.7.1__py3-none-any.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.
- sqlalchemy_cubrid/__init__.py +85 -0
- sqlalchemy_cubrid/alembic_impl.py +145 -0
- sqlalchemy_cubrid/base.py +428 -0
- sqlalchemy_cubrid/compiler.py +515 -0
- sqlalchemy_cubrid/dialect.py +700 -0
- sqlalchemy_cubrid/dml.py +318 -0
- sqlalchemy_cubrid/py.typed +0 -0
- sqlalchemy_cubrid/pycubrid_dialect.py +124 -0
- sqlalchemy_cubrid/requirements.py +270 -0
- sqlalchemy_cubrid/trace.py +92 -0
- sqlalchemy_cubrid/types.py +349 -0
- sqlalchemy_cubrid-0.7.1.dist-info/METADATA +281 -0
- sqlalchemy_cubrid-0.7.1.dist-info/RECORD +18 -0
- sqlalchemy_cubrid-0.7.1.dist-info/WHEEL +5 -0
- sqlalchemy_cubrid-0.7.1.dist-info/entry_points.txt +7 -0
- sqlalchemy_cubrid-0.7.1.dist-info/licenses/AUTHORS +2 -0
- sqlalchemy_cubrid-0.7.1.dist-info/licenses/LICENSE +21 -0
- sqlalchemy_cubrid-0.7.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# sqlalchemy_cubrid/trace.py
|
|
2
|
+
# Copyright (C) 2021-2026 by sqlalchemy-cubrid authors and contributors
|
|
3
|
+
# <see AUTHORS file>
|
|
4
|
+
#
|
|
5
|
+
# This module is part of sqlalchemy-cubrid and is released under
|
|
6
|
+
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
|
7
|
+
|
|
8
|
+
"""CUBRID query trace utility.
|
|
9
|
+
|
|
10
|
+
CUBRID does not support standard ``EXPLAIN`` syntax. Instead, it provides
|
|
11
|
+
a trace facility via ``SET TRACE ON`` / ``SHOW TRACE`` session commands.
|
|
12
|
+
|
|
13
|
+
Usage::
|
|
14
|
+
|
|
15
|
+
from sqlalchemy import create_engine, text
|
|
16
|
+
from sqlalchemy_cubrid.trace import trace_query
|
|
17
|
+
|
|
18
|
+
engine = create_engine("cubrid://dba@localhost:33000/demodb")
|
|
19
|
+
with engine.connect() as conn:
|
|
20
|
+
result = trace_query(conn, text("SELECT * FROM users WHERE id = 1"))
|
|
21
|
+
print(result)
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from typing import Any, List, Optional, Sequence, Tuple
|
|
27
|
+
|
|
28
|
+
from sqlalchemy import text
|
|
29
|
+
from sqlalchemy.engine import Connection
|
|
30
|
+
from sqlalchemy.sql.expression import ClauseElement
|
|
31
|
+
|
|
32
|
+
__all__ = ("trace_query",)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def trace_query(
|
|
36
|
+
connection: Connection,
|
|
37
|
+
statement: ClauseElement,
|
|
38
|
+
*,
|
|
39
|
+
parameters: Optional[Any] = None,
|
|
40
|
+
) -> List[str]:
|
|
41
|
+
"""Execute a statement with CUBRID's trace facility and return trace output.
|
|
42
|
+
|
|
43
|
+
CUBRID uses ``SET TRACE ON`` / ``SHOW TRACE`` instead of ``EXPLAIN``.
|
|
44
|
+
This function wraps that workflow:
|
|
45
|
+
|
|
46
|
+
1. ``SET TRACE ON`` — enables trace collection for the session
|
|
47
|
+
2. Executes the provided statement
|
|
48
|
+
3. ``SHOW TRACE`` — retrieves trace statistics
|
|
49
|
+
4. ``SET TRACE OFF`` — disables trace collection
|
|
50
|
+
|
|
51
|
+
:param connection: An active SQLAlchemy connection to a CUBRID database.
|
|
52
|
+
:param statement: The SQL statement (text or ORM construct) to trace.
|
|
53
|
+
:param parameters: Optional parameters for the statement.
|
|
54
|
+
:returns: A list of trace output strings. Each string contains trace
|
|
55
|
+
statistics for the executed query.
|
|
56
|
+
|
|
57
|
+
Usage::
|
|
58
|
+
|
|
59
|
+
from sqlalchemy import create_engine, text
|
|
60
|
+
from sqlalchemy_cubrid.trace import trace_query
|
|
61
|
+
|
|
62
|
+
engine = create_engine("cubrid://dba@localhost:33000/demodb")
|
|
63
|
+
with engine.connect() as conn:
|
|
64
|
+
traces = trace_query(conn, text("SELECT * FROM users WHERE id = 1"))
|
|
65
|
+
for line in traces:
|
|
66
|
+
print(line)
|
|
67
|
+
|
|
68
|
+
.. note::
|
|
69
|
+
|
|
70
|
+
This function requires a live CUBRID connection. It cannot be used
|
|
71
|
+
in offline (compilation-only) mode. The trace facility is session-scoped
|
|
72
|
+
and does not affect other connections.
|
|
73
|
+
"""
|
|
74
|
+
try:
|
|
75
|
+
connection.execute(text("SET TRACE ON"))
|
|
76
|
+
|
|
77
|
+
if parameters is not None:
|
|
78
|
+
connection.execute(statement, parameters)
|
|
79
|
+
else:
|
|
80
|
+
connection.execute(statement)
|
|
81
|
+
|
|
82
|
+
result = connection.execute(text("SHOW TRACE"))
|
|
83
|
+
rows: Sequence[Tuple[Any, ...]] = result.fetchall()
|
|
84
|
+
|
|
85
|
+
trace_output: List[str] = []
|
|
86
|
+
for row in rows:
|
|
87
|
+
if row and row[0] is not None:
|
|
88
|
+
trace_output.append(str(row[0]))
|
|
89
|
+
|
|
90
|
+
return trace_output
|
|
91
|
+
finally:
|
|
92
|
+
connection.execute(text("SET TRACE OFF"))
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
# sqlalchemy_cubrid/types.py
|
|
2
|
+
# Copyright (C) 2021-2026 by sqlalchemy-cubrid authors and contributors
|
|
3
|
+
# <see AUTHORS file>
|
|
4
|
+
#
|
|
5
|
+
# This module is part of sqlalchemy-cubrid and is released under
|
|
6
|
+
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
|
7
|
+
|
|
8
|
+
"""CUBRID-specific SQLAlchemy type definitions.
|
|
9
|
+
|
|
10
|
+
See: https://www.cubrid.org/manual/en/11.0/sql/datatype.html
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import inspect
|
|
16
|
+
|
|
17
|
+
from sqlalchemy.sql import sqltypes
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# ---------------------------------------------------------------------------
|
|
21
|
+
# Base Mixins
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class _NumericType:
|
|
26
|
+
"""Base for CUBRID numeric types."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, **kw):
|
|
29
|
+
super().__init__(**kw)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class _FloatType(_NumericType, sqltypes.Float):
|
|
33
|
+
def __init__(self, precision=None, **kw):
|
|
34
|
+
super().__init__(precision=precision, **kw)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class _IntegerType(_NumericType, sqltypes.Integer):
|
|
38
|
+
def __init__(self, display_width=None, **kw):
|
|
39
|
+
self.display_width = display_width
|
|
40
|
+
super().__init__(**kw)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class _StringType(sqltypes.String):
|
|
44
|
+
"""Base for CUBRID string types."""
|
|
45
|
+
|
|
46
|
+
def __init__(self, national=False, values=None, **kw):
|
|
47
|
+
self.national = national
|
|
48
|
+
self.values = values
|
|
49
|
+
super().__init__(**kw)
|
|
50
|
+
|
|
51
|
+
def __repr__(self):
|
|
52
|
+
try:
|
|
53
|
+
sig = inspect.signature(self.__class__.__init__)
|
|
54
|
+
attributes = [p.name for p in sig.parameters.values() if p.name != "self"]
|
|
55
|
+
except (ValueError, TypeError):
|
|
56
|
+
attributes = []
|
|
57
|
+
|
|
58
|
+
params = {}
|
|
59
|
+
for attr in attributes:
|
|
60
|
+
val = getattr(self, attr, None)
|
|
61
|
+
if val is not None and val is not False:
|
|
62
|
+
params[attr] = val
|
|
63
|
+
|
|
64
|
+
return "{}({})".format(
|
|
65
|
+
self.__class__.__name__,
|
|
66
|
+
", ".join(f"{k}={v!r}" for k, v in params.items()),
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# ---------------------------------------------------------------------------
|
|
71
|
+
# Numeric Types
|
|
72
|
+
# ---------------------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class SMALLINT(_IntegerType, sqltypes.SMALLINT):
|
|
76
|
+
"""CUBRID SMALLINT type."""
|
|
77
|
+
|
|
78
|
+
__visit_name__ = "SMALLINT"
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class BIGINT(_IntegerType, sqltypes.BIGINT):
|
|
82
|
+
"""CUBRID BIGINT type."""
|
|
83
|
+
|
|
84
|
+
__visit_name__ = "BIGINT"
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class NUMERIC(_NumericType, sqltypes.NUMERIC):
|
|
88
|
+
"""CUBRID NUMERIC type."""
|
|
89
|
+
|
|
90
|
+
__visit_name__ = "NUMERIC"
|
|
91
|
+
|
|
92
|
+
def __init__(self, precision=None, scale=None, **kw):
|
|
93
|
+
"""Construct a NUMERIC.
|
|
94
|
+
|
|
95
|
+
:param precision: Total digits in this number. If scale and precision
|
|
96
|
+
are both None, values are stored to limits allowed by the server.
|
|
97
|
+
:param scale: The number of digits after the decimal point.
|
|
98
|
+
"""
|
|
99
|
+
super().__init__(precision=precision, scale=scale, **kw)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class DECIMAL(_NumericType, sqltypes.DECIMAL):
|
|
103
|
+
"""CUBRID DECIMAL type."""
|
|
104
|
+
|
|
105
|
+
__visit_name__ = "DECIMAL"
|
|
106
|
+
|
|
107
|
+
def __init__(self, precision=None, scale=None, **kw):
|
|
108
|
+
"""Construct a DECIMAL.
|
|
109
|
+
|
|
110
|
+
:param precision: Total digits in this number. If scale and precision
|
|
111
|
+
are both None, values are stored to limits allowed by the server.
|
|
112
|
+
(range from 1 thru 38)
|
|
113
|
+
:param scale: The number of digits following the decimal point.
|
|
114
|
+
"""
|
|
115
|
+
super().__init__(precision=precision, scale=scale, **kw)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class FLOAT(_FloatType, sqltypes.FLOAT):
|
|
119
|
+
"""CUBRID FLOAT type."""
|
|
120
|
+
|
|
121
|
+
__visit_name__ = "FLOAT"
|
|
122
|
+
|
|
123
|
+
def __init__(self, precision=7, **kw):
|
|
124
|
+
"""Construct a FLOAT.
|
|
125
|
+
|
|
126
|
+
:param precision: Defaults to 7. Total digits in this number.
|
|
127
|
+
(range from 1 thru 38)
|
|
128
|
+
"""
|
|
129
|
+
super().__init__(precision=precision, **kw)
|
|
130
|
+
|
|
131
|
+
def bind_processor(self, dialect):
|
|
132
|
+
return None
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class REAL(_FloatType, sqltypes.FLOAT):
|
|
136
|
+
"""CUBRID REAL type."""
|
|
137
|
+
|
|
138
|
+
__visit_name__ = "REAL"
|
|
139
|
+
|
|
140
|
+
def __init__(self, precision=None, **kw):
|
|
141
|
+
"""Construct a REAL.
|
|
142
|
+
|
|
143
|
+
:param precision: Total digits in this number.
|
|
144
|
+
"""
|
|
145
|
+
super().__init__(precision=precision, **kw)
|
|
146
|
+
|
|
147
|
+
def bind_processor(self, dialect):
|
|
148
|
+
return None
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class DOUBLE(_FloatType):
|
|
152
|
+
"""CUBRID DOUBLE type."""
|
|
153
|
+
|
|
154
|
+
__visit_name__ = "DOUBLE"
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class DOUBLE_PRECISION(_FloatType):
|
|
158
|
+
"""CUBRID DOUBLE PRECISION type."""
|
|
159
|
+
|
|
160
|
+
__visit_name__ = "DOUBLE_PRECISION"
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
# ---------------------------------------------------------------------------
|
|
164
|
+
# Bit String Types
|
|
165
|
+
# ---------------------------------------------------------------------------
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class BIT(sqltypes.TypeEngine):
|
|
169
|
+
"""CUBRID BIT type."""
|
|
170
|
+
|
|
171
|
+
__visit_name__ = "BIT"
|
|
172
|
+
|
|
173
|
+
def __init__(self, length=1, varying=False):
|
|
174
|
+
"""Construct a BIT.
|
|
175
|
+
|
|
176
|
+
:param length: Defaults to 1. Optional, number of bits.
|
|
177
|
+
:param varying: If True, use BIT VARYING.
|
|
178
|
+
"""
|
|
179
|
+
if not varying:
|
|
180
|
+
self.length = length or 1
|
|
181
|
+
else:
|
|
182
|
+
self.length = length # BIT VARYING can be unlimited-length
|
|
183
|
+
self.varying = varying
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
# ---------------------------------------------------------------------------
|
|
187
|
+
# Character String Types
|
|
188
|
+
# ---------------------------------------------------------------------------
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class CHAR(_StringType, sqltypes.CHAR):
|
|
192
|
+
"""CUBRID CHAR type, for fixed-length character data."""
|
|
193
|
+
|
|
194
|
+
__visit_name__ = "CHAR"
|
|
195
|
+
|
|
196
|
+
def __init__(self, length=None, **kwargs):
|
|
197
|
+
"""Construct a CHAR.
|
|
198
|
+
|
|
199
|
+
:param length: The number of characters.
|
|
200
|
+
"""
|
|
201
|
+
super().__init__(length=length, **kwargs)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class VARCHAR(_StringType, sqltypes.VARCHAR):
|
|
205
|
+
"""CUBRID VARCHAR type, for variable-length character data."""
|
|
206
|
+
|
|
207
|
+
__visit_name__ = "VARCHAR"
|
|
208
|
+
|
|
209
|
+
def __init__(self, length=None, **kwargs):
|
|
210
|
+
"""Construct a VARCHAR.
|
|
211
|
+
|
|
212
|
+
:param length: The number of characters.
|
|
213
|
+
"""
|
|
214
|
+
super().__init__(length=length, **kwargs)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class NCHAR(_StringType, sqltypes.NCHAR):
|
|
218
|
+
"""CUBRID NCHAR type.
|
|
219
|
+
|
|
220
|
+
For fixed-length character data in the server's configured national
|
|
221
|
+
character set.
|
|
222
|
+
"""
|
|
223
|
+
|
|
224
|
+
__visit_name__ = "NCHAR"
|
|
225
|
+
|
|
226
|
+
def __init__(self, length=None, **kwargs):
|
|
227
|
+
"""Construct a NCHAR.
|
|
228
|
+
|
|
229
|
+
:param length: The number of characters.
|
|
230
|
+
"""
|
|
231
|
+
kwargs["national"] = True
|
|
232
|
+
super().__init__(length=length, **kwargs)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class NVARCHAR(_StringType, sqltypes.NVARCHAR):
|
|
236
|
+
"""CUBRID NVARCHAR type.
|
|
237
|
+
|
|
238
|
+
For variable-length character data in the server's configured national
|
|
239
|
+
character set.
|
|
240
|
+
"""
|
|
241
|
+
|
|
242
|
+
__visit_name__ = "NVARCHAR"
|
|
243
|
+
|
|
244
|
+
def __init__(self, length=None, **kwargs):
|
|
245
|
+
"""Construct a NVARCHAR.
|
|
246
|
+
|
|
247
|
+
:param length: The number of characters.
|
|
248
|
+
"""
|
|
249
|
+
kwargs["national"] = True
|
|
250
|
+
super().__init__(length=length, **kwargs)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class STRING(_StringType):
|
|
254
|
+
"""CUBRID STRING type.
|
|
255
|
+
|
|
256
|
+
STRING is a variable-length character string data type.
|
|
257
|
+
STRING is the same as the VARCHAR with the length specified to the maximum value.
|
|
258
|
+
That is, STRING and VARCHAR(1,073,741,823) have the same value.
|
|
259
|
+
"""
|
|
260
|
+
|
|
261
|
+
__visit_name__ = "STRING"
|
|
262
|
+
|
|
263
|
+
def __init__(self, length=None, national=False, **kwargs):
|
|
264
|
+
super().__init__(length=length, **kwargs)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
# ---------------------------------------------------------------------------
|
|
268
|
+
# LOB Types
|
|
269
|
+
# ---------------------------------------------------------------------------
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
class BLOB(sqltypes.LargeBinary):
|
|
273
|
+
"""CUBRID BLOB type."""
|
|
274
|
+
|
|
275
|
+
__visit_name__ = "BLOB"
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
class CLOB(sqltypes.Text):
|
|
279
|
+
"""CUBRID CLOB type."""
|
|
280
|
+
|
|
281
|
+
__visit_name__ = "CLOB"
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
# ---------------------------------------------------------------------------
|
|
285
|
+
# Collection Types
|
|
286
|
+
# ---------------------------------------------------------------------------
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
class SET(_StringType):
|
|
290
|
+
"""CUBRID SET type."""
|
|
291
|
+
|
|
292
|
+
__visit_name__ = "SET"
|
|
293
|
+
|
|
294
|
+
def __init__(self, *values, **kw):
|
|
295
|
+
"""Construct a SET."""
|
|
296
|
+
self._ddl_values = values
|
|
297
|
+
super().__init__(**kw)
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
class MULTISET(_StringType):
|
|
301
|
+
"""CUBRID MULTISET type."""
|
|
302
|
+
|
|
303
|
+
__visit_name__ = "MULTISET"
|
|
304
|
+
|
|
305
|
+
def __init__(self, *values, **kw):
|
|
306
|
+
"""Construct a MULTISET."""
|
|
307
|
+
self._ddl_values = values
|
|
308
|
+
super().__init__(**kw)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
class SEQUENCE(_StringType):
|
|
312
|
+
"""CUBRID SEQUENCE type."""
|
|
313
|
+
|
|
314
|
+
__visit_name__ = "SEQUENCE"
|
|
315
|
+
|
|
316
|
+
def __init__(self, *values, **kw):
|
|
317
|
+
"""Construct a SEQUENCE."""
|
|
318
|
+
self._ddl_values = values
|
|
319
|
+
super().__init__(**kw)
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
# ---------------------------------------------------------------------------
|
|
323
|
+
# Monetary Type
|
|
324
|
+
# ---------------------------------------------------------------------------
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
class MONETARY(sqltypes.TypeEngine):
|
|
328
|
+
"""CUBRID MONETARY type.
|
|
329
|
+
|
|
330
|
+
Stores monetary values with currency. Internally represented as a
|
|
331
|
+
DOUBLE with an associated currency code.
|
|
332
|
+
"""
|
|
333
|
+
|
|
334
|
+
__visit_name__ = "MONETARY"
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
# ---------------------------------------------------------------------------
|
|
338
|
+
# Object Type
|
|
339
|
+
# ---------------------------------------------------------------------------
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
class OBJECT(sqltypes.TypeEngine):
|
|
343
|
+
"""CUBRID OBJECT type.
|
|
344
|
+
|
|
345
|
+
Represents a reference to another CUBRID class instance (OID).
|
|
346
|
+
This is a CUBRID-specific type with no direct equivalent in other databases.
|
|
347
|
+
"""
|
|
348
|
+
|
|
349
|
+
__visit_name__ = "OBJECT"
|