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.
@@ -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"