e6data-python-connector 2.2.2.3rc2__py3-none-any.whl → 2.2.3__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.
- e6data_python_connector/cluster_manager.py +46 -22
- e6data_python_connector/e6data_grpc.py +352 -48
- {e6data_python_connector-2.2.2.3rc2.dist-info → e6data_python_connector-2.2.3.dist-info}/METADATA +2 -2
- {e6data_python_connector-2.2.2.3rc2.dist-info → e6data_python_connector-2.2.3.dist-info}/RECORD +8 -8
- {e6data_python_connector-2.2.2.3rc2.dist-info → e6data_python_connector-2.2.3.dist-info}/LICENSE +0 -0
- {e6data_python_connector-2.2.2.3rc2.dist-info → e6data_python_connector-2.2.3.dist-info}/WHEEL +0 -0
- {e6data_python_connector-2.2.2.3rc2.dist-info → e6data_python_connector-2.2.3.dist-info}/entry_points.txt +0 -0
- {e6data_python_connector-2.2.2.3rc2.dist-info → e6data_python_connector-2.2.3.dist-info}/top_level.txt +0 -0
|
@@ -8,6 +8,19 @@ import multiprocessing
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def _get_grpc_header(engine_ip=None, cluster=None):
|
|
11
|
+
"""
|
|
12
|
+
Generate gRPC metadata headers for the request.
|
|
13
|
+
|
|
14
|
+
This function creates a list of metadata headers to be used in gRPC requests.
|
|
15
|
+
It includes optional headers for the engine IP and cluster UUID.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
engine_ip (str, optional): The IP address of the engine. Defaults to None.
|
|
19
|
+
cluster (str, optional): The UUID of the cluster. Defaults to None.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
list: A list of tuples representing the gRPC metadata headers.
|
|
23
|
+
"""
|
|
11
24
|
metadata = []
|
|
12
25
|
if engine_ip:
|
|
13
26
|
metadata.append(('plannerip', engine_ip))
|
|
@@ -123,7 +136,7 @@ class ClusterManager:
|
|
|
123
136
|
cluster_uuid (str): The unique identifier for the target cluster.
|
|
124
137
|
"""
|
|
125
138
|
|
|
126
|
-
def __init__(self, host: str, port: int, user: str, password: str, secure_channel: bool = False, timeout=60 * 3, cluster_uuid=None):
|
|
139
|
+
def __init__(self, host: str, port: int, user: str, password: str, secure_channel: bool = False, timeout=60 * 3, cluster_uuid=None, grpc_options=None):
|
|
127
140
|
"""
|
|
128
141
|
Initializes a new instance of the ClusterManager class.
|
|
129
142
|
|
|
@@ -147,6 +160,9 @@ class ClusterManager:
|
|
|
147
160
|
self._timeout = time.time() + timeout
|
|
148
161
|
self._secure_channel = secure_channel
|
|
149
162
|
self.cluster_uuid = cluster_uuid
|
|
163
|
+
self._grpc_options = grpc_options
|
|
164
|
+
if grpc_options is None:
|
|
165
|
+
self._grpc_options = dict()
|
|
150
166
|
|
|
151
167
|
@property
|
|
152
168
|
def _get_connection(self):
|
|
@@ -161,14 +177,34 @@ class ClusterManager:
|
|
|
161
177
|
if self._secure_channel:
|
|
162
178
|
self._channel = grpc.secure_channel(
|
|
163
179
|
target='{}:{}'.format(self._host, self._port),
|
|
180
|
+
options=self._grpc_options,
|
|
164
181
|
credentials=grpc.ssl_channel_credentials()
|
|
165
182
|
)
|
|
166
183
|
else:
|
|
167
184
|
self._channel = grpc.insecure_channel(
|
|
168
|
-
target='{}:{}'.format(self._host, self._port)
|
|
185
|
+
target='{}:{}'.format(self._host, self._port),
|
|
186
|
+
options=self._grpc_options
|
|
169
187
|
)
|
|
170
188
|
return cluster_pb2_grpc.ClusterServiceStub(self._channel)
|
|
171
189
|
|
|
190
|
+
def _check_cluster_status(self):
|
|
191
|
+
while True:
|
|
192
|
+
try:
|
|
193
|
+
# Create a status request payload with user credentials
|
|
194
|
+
status_payload = cluster_pb2.ClusterStatusRequest(
|
|
195
|
+
user=self._user,
|
|
196
|
+
password=self._password
|
|
197
|
+
)
|
|
198
|
+
# Send the status request to the cluster service
|
|
199
|
+
response = self._get_connection.status(
|
|
200
|
+
status_payload,
|
|
201
|
+
metadata=_get_grpc_header(cluster=self.cluster_uuid)
|
|
202
|
+
)
|
|
203
|
+
# Yield the current status
|
|
204
|
+
yield response.status
|
|
205
|
+
except _InactiveRpcError as e:
|
|
206
|
+
yield None
|
|
207
|
+
|
|
172
208
|
def resume(self) -> bool:
|
|
173
209
|
"""
|
|
174
210
|
Resumes the cluster if it is currently suspended or not in the 'active' state.
|
|
@@ -229,27 +265,15 @@ class ClusterManager:
|
|
|
229
265
|
"""
|
|
230
266
|
return False
|
|
231
267
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
response = self._get_connection.status(
|
|
240
|
-
status_payload,
|
|
241
|
-
metadata=_get_grpc_header(cluster=self.cluster_uuid)
|
|
242
|
-
)
|
|
243
|
-
if response.status == 'active':
|
|
244
|
-
lock.set_active()
|
|
245
|
-
return True
|
|
246
|
-
if response.status in ['suspended', 'failed']:
|
|
247
|
-
return False
|
|
248
|
-
if time.time() > self._timeout:
|
|
249
|
-
return False
|
|
250
|
-
except _InactiveRpcError as e:
|
|
251
|
-
pass
|
|
268
|
+
for status in self._check_cluster_status():
|
|
269
|
+
if status == 'active':
|
|
270
|
+
lock.set_active()
|
|
271
|
+
return True
|
|
272
|
+
elif status == 'failed' or time.time() > self._timeout:
|
|
273
|
+
return False
|
|
274
|
+
# Wait for 5 seconds before the next status check
|
|
252
275
|
time.sleep(5)
|
|
276
|
+
return False
|
|
253
277
|
|
|
254
278
|
def suspend(self):
|
|
255
279
|
"""
|
|
@@ -80,8 +80,9 @@ def re_auth(func):
|
|
|
80
80
|
raise e
|
|
81
81
|
if e.code() == grpc.StatusCode.INTERNAL and 'Access denied' in e.details():
|
|
82
82
|
time.sleep(0.2)
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
_logger.info(f'RE_AUTH: Function Name: {func}')
|
|
84
|
+
_logger.info(f'RE_AUTH: Error Found {e}')
|
|
85
|
+
self.connection.get_re_authenticate_session_id()
|
|
85
86
|
else:
|
|
86
87
|
raise e
|
|
87
88
|
|
|
@@ -173,6 +174,7 @@ class Connection(object):
|
|
|
173
174
|
- max_receive_message_length: This parameter sets the maximum allowed size (in bytes) for incoming messages on the gRPC server.
|
|
174
175
|
- max_send_message_length: Similar to max_receive_message_length, this parameter sets the maximum allowed size (in bytes) for outgoing messages from the gRPC client
|
|
175
176
|
- grpc_prepare_timeout: Timeout for prepare statement API call (default to 10 minutes).
|
|
177
|
+
- keepalive_time_ms: This parameter defines the time, in milliseconds, Default to 30 seconds
|
|
176
178
|
"""
|
|
177
179
|
if not username or not password:
|
|
178
180
|
raise ValueError("username or password cannot be empty.")
|
|
@@ -192,43 +194,88 @@ class Connection(object):
|
|
|
192
194
|
|
|
193
195
|
self._auto_resume = auto_resume
|
|
194
196
|
|
|
195
|
-
self.
|
|
196
|
-
self.
|
|
197
|
-
|
|
198
|
-
self.grpc_prepare_timeout = 10 * 60 # 10 minutes
|
|
199
|
-
|
|
200
|
-
if isinstance(grpc_options, dict):
|
|
201
|
-
self._keepalive_timeout_ms = grpc_options.get('keepalive_timeout_ms') or self._keepalive_timeout_ms
|
|
202
|
-
self._max_receive_message_length = grpc_options.get(
|
|
203
|
-
'max_receive_message_length') or self._max_receive_message_length
|
|
204
|
-
self._max_send_message_length = grpc_options.get('max_send_message_length') or self._max_send_message_length
|
|
205
|
-
self.grpc_prepare_timeout = grpc_options.get('grpc_prepare_timeout') or self.grpc_prepare_timeout
|
|
197
|
+
self._grpc_options = grpc_options
|
|
198
|
+
if self._grpc_options is None:
|
|
199
|
+
self._grpc_options = dict()
|
|
200
|
+
self.grpc_prepare_timeout = self._grpc_options.get('grpc_prepare_timeout') or 10 * 60 # 10 minutes
|
|
206
201
|
self._create_client()
|
|
207
202
|
|
|
203
|
+
@property
|
|
204
|
+
def _get_grpc_options(self):
|
|
205
|
+
"""
|
|
206
|
+
Property to get gRPC options for the connection.
|
|
207
|
+
|
|
208
|
+
This method checks if the gRPC options are already cached. If not, it creates a copy of the
|
|
209
|
+
provided gRPC options and merges them with the default options. The merged options are then
|
|
210
|
+
cached for future use.
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
list: A list of tuples containing gRPC options.
|
|
214
|
+
"""
|
|
215
|
+
if not hasattr(self, '_cached_grpc_options'):
|
|
216
|
+
grpc_options = self._grpc_options.copy()
|
|
217
|
+
default_options = {
|
|
218
|
+
"keepalive_timeout_ms": 900000, # Time in milliseconds to keep the connection alive.
|
|
219
|
+
"max_receive_message_length": -1, # Maximum size of received messages.
|
|
220
|
+
"max_send_message_length": 300 * 1024 * 1024, # Maximum size of sent messages (300 MB).
|
|
221
|
+
"grpc_prepare_timeout": self.grpc_prepare_timeout, # Timeout for prepare statement API call.
|
|
222
|
+
"keepalive_time_ms": 30000, # Time in milliseconds between keep-alive pings.
|
|
223
|
+
"keepalive_permit_without_calls": 1, # Allow keep-alives with no active RPCs.
|
|
224
|
+
"http2.max_pings_without_data": 0, # Unlimited pings without data.
|
|
225
|
+
"http2.min_time_between_pings_ms": 15000, # Minimum time between pings (15 seconds).
|
|
226
|
+
"http2.min_ping_interval_without_data_ms": 15000, # Minimum interval between pings without data (15 seconds).
|
|
227
|
+
}
|
|
228
|
+
if grpc_options:
|
|
229
|
+
for key, value in grpc_options.items():
|
|
230
|
+
default_options[key] = value
|
|
231
|
+
|
|
232
|
+
self._cached_grpc_options = [(f'grpc.{key}', value) for key, value in default_options.items()]
|
|
233
|
+
|
|
234
|
+
return self._cached_grpc_options
|
|
235
|
+
|
|
208
236
|
def _create_client(self):
|
|
237
|
+
"""
|
|
238
|
+
Creates a gRPC client for the connection.
|
|
239
|
+
|
|
240
|
+
This method initializes a gRPC channel based on whether a secure channel is required or not.
|
|
241
|
+
It then creates a client stub for the QueryEngineService.
|
|
242
|
+
|
|
243
|
+
If the secure channel is enabled, it uses `grpc.secure_channel` with SSL credentials.
|
|
244
|
+
Otherwise, it uses `grpc.insecure_channel`.
|
|
245
|
+
|
|
246
|
+
The gRPC options are retrieved from the `_get_grpc_options` property.
|
|
247
|
+
|
|
248
|
+
Raises:
|
|
249
|
+
grpc.RpcError: If there is an error in creating the gRPC channel or client stub.
|
|
250
|
+
"""
|
|
209
251
|
if self._secure_channel:
|
|
210
252
|
self._channel = grpc.secure_channel(
|
|
211
253
|
target='{}:{}'.format(self._host, self._port),
|
|
212
|
-
options=
|
|
213
|
-
("grpc.keepalive_timeout_ms", self._keepalive_timeout_ms),
|
|
214
|
-
('grpc.max_send_message_length', self._max_send_message_length),
|
|
215
|
-
('grpc.max_receive_message_length', self._max_receive_message_length)
|
|
216
|
-
],
|
|
254
|
+
options=self._get_grpc_options,
|
|
217
255
|
credentials=grpc.ssl_channel_credentials()
|
|
218
256
|
)
|
|
219
257
|
else:
|
|
220
258
|
self._channel = grpc.insecure_channel(
|
|
221
259
|
target='{}:{}'.format(self._host, self._port),
|
|
222
|
-
options=
|
|
223
|
-
("grpc.keepalive_timeout_ms", self._keepalive_timeout_ms),
|
|
224
|
-
('grpc.max_send_message_length', self._max_send_message_length),
|
|
225
|
-
('grpc.max_receive_message_length', self._max_receive_message_length)
|
|
226
|
-
]
|
|
260
|
+
options=self._get_grpc_options
|
|
227
261
|
)
|
|
228
262
|
self._client = e6x_engine_pb2_grpc.QueryEngineServiceStub(self._channel)
|
|
229
263
|
|
|
230
264
|
def get_re_authenticate_session_id(self):
|
|
231
|
-
|
|
265
|
+
"""
|
|
266
|
+
Re-authenticates the session by closing the current connection and creating a new client.
|
|
267
|
+
|
|
268
|
+
This method is used to re-establish the session ID by closing the existing gRPC channel,
|
|
269
|
+
creating a new client, and then retrieving a new session ID.
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
str: The new session ID after re-authentication.
|
|
273
|
+
|
|
274
|
+
Raises:
|
|
275
|
+
Exception: If there is an error during the re-authentication process.
|
|
276
|
+
"""
|
|
277
|
+
self.close()
|
|
278
|
+
self._create_client()
|
|
232
279
|
return self.get_session_id
|
|
233
280
|
|
|
234
281
|
@property
|
|
@@ -281,35 +328,58 @@ class Connection(object):
|
|
|
281
328
|
raise e
|
|
282
329
|
return self._session_id
|
|
283
330
|
|
|
284
|
-
def
|
|
285
|
-
self.client.updateUsers(userInfo=user_info)
|
|
286
|
-
|
|
287
|
-
def set_prop_map(self, prop_map: str):
|
|
288
|
-
"""
|
|
289
|
-
To enable to disable the caches.
|
|
290
|
-
:param prop_map: To set engine props
|
|
331
|
+
def __enter__(self):
|
|
291
332
|
"""
|
|
292
|
-
|
|
293
|
-
self._client.setProps(set_props_request)
|
|
333
|
+
Enters the runtime context related to this object.
|
|
294
334
|
|
|
295
|
-
|
|
296
|
-
|
|
335
|
+
This method is called when the execution flow enters the context of the `with` statement.
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
Connection: The current instance of the connection.
|
|
339
|
+
"""
|
|
297
340
|
return self
|
|
298
341
|
|
|
299
342
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
300
|
-
"""
|
|
343
|
+
"""
|
|
344
|
+
Exits the runtime context related to this object.
|
|
345
|
+
|
|
346
|
+
This method is called when the execution flow exits the context of the `with` statement.
|
|
347
|
+
|
|
348
|
+
Args:
|
|
349
|
+
exc_type (Type[BaseException]): The type of exception raised (if any).
|
|
350
|
+
exc_val (BaseException): The exception instance raised (if any).
|
|
351
|
+
exc_tb (Traceback): The traceback object of the exception (if any).
|
|
352
|
+
"""
|
|
301
353
|
self.close()
|
|
302
354
|
|
|
303
355
|
def close(self):
|
|
356
|
+
"""
|
|
357
|
+
Closes the gRPC channel and resets the session ID.
|
|
358
|
+
|
|
359
|
+
This method ensures that the gRPC channel is properly closed and the session ID is reset to None.
|
|
360
|
+
"""
|
|
304
361
|
if self._channel is not None:
|
|
305
362
|
self._channel.close()
|
|
306
363
|
self._channel = None
|
|
307
364
|
self._session_id = None
|
|
308
365
|
|
|
309
366
|
def check_connection(self):
|
|
367
|
+
"""
|
|
368
|
+
Checks if the gRPC channel is still open.
|
|
369
|
+
|
|
370
|
+
Returns:
|
|
371
|
+
bool: True if the gRPC channel is open, False otherwise.
|
|
372
|
+
"""
|
|
310
373
|
return self._channel is not None
|
|
311
374
|
|
|
312
375
|
def clear(self, query_id, engine_ip=None):
|
|
376
|
+
"""
|
|
377
|
+
Clears the query results from the server.
|
|
378
|
+
|
|
379
|
+
Args:
|
|
380
|
+
query_id (str): The ID of the query to be cleared.
|
|
381
|
+
engine_ip (str, optional): The IP address of the engine. Defaults to None.
|
|
382
|
+
"""
|
|
313
383
|
clear_request = e6x_engine_pb2.ClearRequest(
|
|
314
384
|
sessionId=self.get_session_id,
|
|
315
385
|
queryId=query_id,
|
|
@@ -321,10 +391,22 @@ class Connection(object):
|
|
|
321
391
|
)
|
|
322
392
|
|
|
323
393
|
def reopen(self):
|
|
394
|
+
"""
|
|
395
|
+
Reopens the gRPC channel by closing the current channel and creating a new client.
|
|
396
|
+
|
|
397
|
+
This method is useful for re-establishing the connection if it was previously closed.
|
|
398
|
+
"""
|
|
324
399
|
self._channel.close()
|
|
325
400
|
self._create_client()
|
|
326
401
|
|
|
327
402
|
def query_cancel(self, engine_ip, query_id):
|
|
403
|
+
"""
|
|
404
|
+
Cancels the execution of a query on the server.
|
|
405
|
+
|
|
406
|
+
Args:
|
|
407
|
+
engine_ip (str): The IP address of the engine.
|
|
408
|
+
query_id (str): The ID of the query to be canceled.
|
|
409
|
+
"""
|
|
328
410
|
cancel_query_request = e6x_engine_pb2.CancelQueryRequest(
|
|
329
411
|
engineIP=engine_ip,
|
|
330
412
|
sessionId=self.get_session_id,
|
|
@@ -336,6 +418,15 @@ class Connection(object):
|
|
|
336
418
|
)
|
|
337
419
|
|
|
338
420
|
def dry_run(self, query):
|
|
421
|
+
"""
|
|
422
|
+
Performs a dry run of the query to validate its syntax and structure.
|
|
423
|
+
|
|
424
|
+
Args:
|
|
425
|
+
query (str): The SQL query to be validated.
|
|
426
|
+
|
|
427
|
+
Returns:
|
|
428
|
+
str: The result of the dry run validation.
|
|
429
|
+
"""
|
|
339
430
|
dry_run_request = e6x_engine_pb2.DryRunRequest(
|
|
340
431
|
sessionId=self.get_session_id,
|
|
341
432
|
schema=self.database,
|
|
@@ -348,6 +439,16 @@ class Connection(object):
|
|
|
348
439
|
return dry_run_response.dryrunValue
|
|
349
440
|
|
|
350
441
|
def get_tables(self, catalog, database):
|
|
442
|
+
"""
|
|
443
|
+
Retrieves the list of tables from the specified catalog and database.
|
|
444
|
+
|
|
445
|
+
Args:
|
|
446
|
+
catalog (str): The catalog name.
|
|
447
|
+
database (str): The database name.
|
|
448
|
+
|
|
449
|
+
Returns:
|
|
450
|
+
list: A list of table names.
|
|
451
|
+
"""
|
|
351
452
|
get_table_request = e6x_engine_pb2.GetTablesV2Request(
|
|
352
453
|
sessionId=self.get_session_id,
|
|
353
454
|
schema=database,
|
|
@@ -360,6 +461,17 @@ class Connection(object):
|
|
|
360
461
|
return list(get_table_response.tables)
|
|
361
462
|
|
|
362
463
|
def get_columns(self, catalog, database, table):
|
|
464
|
+
"""
|
|
465
|
+
Retrieves the list of columns for the specified table in the given catalog and database.
|
|
466
|
+
|
|
467
|
+
Args:
|
|
468
|
+
catalog (str): The catalog name.
|
|
469
|
+
database (str): The database name.
|
|
470
|
+
table (str): The table name.
|
|
471
|
+
|
|
472
|
+
Returns:
|
|
473
|
+
list: A list of dictionaries containing column information.
|
|
474
|
+
"""
|
|
363
475
|
get_columns_request = e6x_engine_pb2.GetColumnsV2Request(
|
|
364
476
|
sessionId=self.get_session_id,
|
|
365
477
|
schema=database,
|
|
@@ -373,6 +485,15 @@ class Connection(object):
|
|
|
373
485
|
return [{'fieldName': row.fieldName, 'fieldType': row.fieldType} for row in get_columns_response.fieldInfo]
|
|
374
486
|
|
|
375
487
|
def get_schema_names(self, catalog):
|
|
488
|
+
"""
|
|
489
|
+
Retrieves the list of schema names from the specified catalog.
|
|
490
|
+
|
|
491
|
+
Args:
|
|
492
|
+
catalog (str): The catalog name.
|
|
493
|
+
|
|
494
|
+
Returns:
|
|
495
|
+
list: A list of schema names.
|
|
496
|
+
"""
|
|
376
497
|
get_schema_request = e6x_engine_pb2.GetSchemaNamesV2Request(
|
|
377
498
|
sessionId=self.get_session_id,
|
|
378
499
|
catalog=catalog
|
|
@@ -384,29 +505,65 @@ class Connection(object):
|
|
|
384
505
|
return list(get_schema_response.schemas)
|
|
385
506
|
|
|
386
507
|
def commit(self):
|
|
387
|
-
"""
|
|
508
|
+
"""
|
|
509
|
+
Commits the current transaction.
|
|
510
|
+
|
|
511
|
+
Note:
|
|
512
|
+
This method does nothing as transactions are not supported.
|
|
513
|
+
"""
|
|
388
514
|
pass
|
|
389
515
|
|
|
390
516
|
def cursor(self, catalog_name=None, db_name=None):
|
|
391
|
-
"""
|
|
517
|
+
"""
|
|
518
|
+
Creates a new cursor object for executing queries.
|
|
519
|
+
|
|
520
|
+
Args:
|
|
521
|
+
catalog_name (str, optional): The catalog name. Defaults to None.
|
|
522
|
+
db_name (str, optional): The database name. Defaults to None.
|
|
523
|
+
|
|
524
|
+
Returns:
|
|
525
|
+
Cursor: A new cursor object.
|
|
526
|
+
"""
|
|
392
527
|
return Cursor(self, database=db_name, catalog_name=catalog_name)
|
|
393
528
|
|
|
394
529
|
def rollback(self):
|
|
395
|
-
|
|
530
|
+
"""
|
|
531
|
+
Rolls back the current transaction.
|
|
532
|
+
|
|
533
|
+
Raises:
|
|
534
|
+
Exception: Always raises an exception as transactions are not supported.
|
|
535
|
+
"""
|
|
536
|
+
raise Exception("e6data does not support transactions") # pragma: no cover
|
|
396
537
|
|
|
397
538
|
@property
|
|
398
539
|
def client(self):
|
|
540
|
+
"""
|
|
541
|
+
Returns the gRPC client stub for interacting with the server.
|
|
542
|
+
|
|
543
|
+
Returns:
|
|
544
|
+
e6x_engine_pb2_grpc.QueryEngineServiceStub: The gRPC client stub.
|
|
545
|
+
"""
|
|
399
546
|
return self._client
|
|
400
547
|
|
|
401
548
|
|
|
402
549
|
class Cursor(DBAPICursor):
|
|
403
|
-
"""
|
|
550
|
+
"""
|
|
551
|
+
These objects represent a database cursor, which is used to manage the context of a fetch
|
|
404
552
|
operation.
|
|
405
553
|
Cursors are not isolated, i.e., any changes done to the database by a cursor are immediately
|
|
406
554
|
visible by other cursors or connections.
|
|
407
555
|
"""
|
|
408
556
|
|
|
409
557
|
def __init__(self, connection: Connection, array_size=1000, database=None, catalog_name=None):
|
|
558
|
+
"""
|
|
559
|
+
Initialize a new Cursor object.
|
|
560
|
+
|
|
561
|
+
Args:
|
|
562
|
+
connection (Connection): The connection object to the database.
|
|
563
|
+
array_size (int, optional): The number of rows to fetch at a time. Defaults to 1000.
|
|
564
|
+
database (str, optional): The database name. Defaults to None.
|
|
565
|
+
catalog_name (str, optional): The catalog name. Defaults to None.
|
|
566
|
+
"""
|
|
410
567
|
super(Cursor, self).__init__()
|
|
411
568
|
self._array_size = array_size
|
|
412
569
|
self.connection = connection
|
|
@@ -427,15 +584,32 @@ class Cursor(DBAPICursor):
|
|
|
427
584
|
|
|
428
585
|
@property
|
|
429
586
|
def metadata(self):
|
|
587
|
+
"""
|
|
588
|
+
Get the gRPC metadata for the current query.
|
|
589
|
+
|
|
590
|
+
Returns:
|
|
591
|
+
list: A list of tuples containing gRPC metadata.
|
|
592
|
+
"""
|
|
430
593
|
return _get_grpc_header(engine_ip=self._engine_ip, cluster=self.connection.cluster_uuid)
|
|
431
594
|
|
|
432
595
|
@property
|
|
433
596
|
def arraysize(self):
|
|
597
|
+
"""
|
|
598
|
+
Get the array size for fetching rows.
|
|
599
|
+
|
|
600
|
+
Returns:
|
|
601
|
+
int: The number of rows to fetch at a time.
|
|
602
|
+
"""
|
|
434
603
|
return self._arraysize
|
|
435
604
|
|
|
436
605
|
@arraysize.setter
|
|
437
606
|
def arraysize(self, value):
|
|
438
|
-
"""
|
|
607
|
+
"""
|
|
608
|
+
Set the array size for fetching rows.
|
|
609
|
+
|
|
610
|
+
Args:
|
|
611
|
+
value (int): The number of rows to fetch at a time.
|
|
612
|
+
"""
|
|
439
613
|
default_arraysize = 1000
|
|
440
614
|
try:
|
|
441
615
|
self._arraysize = int(value) or default_arraysize
|
|
@@ -471,14 +645,29 @@ class Cursor(DBAPICursor):
|
|
|
471
645
|
return self._description
|
|
472
646
|
|
|
473
647
|
def __enter__(self):
|
|
648
|
+
"""
|
|
649
|
+
Enter the runtime context related to this object.
|
|
650
|
+
|
|
651
|
+
Returns:
|
|
652
|
+
Cursor: The current instance of the cursor.
|
|
653
|
+
"""
|
|
474
654
|
return self
|
|
475
655
|
|
|
476
656
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
657
|
+
"""
|
|
658
|
+
Exit the runtime context related to this object.
|
|
659
|
+
|
|
660
|
+
Args:
|
|
661
|
+
exc_type (Type[BaseException]): The type of exception raised (if any).
|
|
662
|
+
exc_val (BaseException): The exception instance raised (if any).
|
|
663
|
+
exc_tb (Traceback): The traceback object of the exception (if any).
|
|
664
|
+
"""
|
|
477
665
|
self.close()
|
|
478
666
|
|
|
479
667
|
def close(self):
|
|
480
|
-
"""
|
|
481
|
-
|
|
668
|
+
"""
|
|
669
|
+
Close the operation handle and reset the cursor state.
|
|
670
|
+
"""
|
|
482
671
|
try:
|
|
483
672
|
self.clear()
|
|
484
673
|
except:
|
|
@@ -495,17 +684,44 @@ class Cursor(DBAPICursor):
|
|
|
495
684
|
self._database = None
|
|
496
685
|
|
|
497
686
|
def get_tables(self):
|
|
687
|
+
"""
|
|
688
|
+
Retrieve the list of tables from the current database.
|
|
689
|
+
|
|
690
|
+
Returns:
|
|
691
|
+
list: A list of table names.
|
|
692
|
+
"""
|
|
498
693
|
schema = self.connection.database
|
|
499
694
|
return self.connection.get_tables(catalog=self._catalog_name, database=schema)
|
|
500
695
|
|
|
501
696
|
def get_columns(self, table):
|
|
697
|
+
"""
|
|
698
|
+
Retrieve the list of columns for the specified table.
|
|
699
|
+
|
|
700
|
+
Args:
|
|
701
|
+
table (str): The table name.
|
|
702
|
+
|
|
703
|
+
Returns:
|
|
704
|
+
list: A list of dictionaries containing column information.
|
|
705
|
+
"""
|
|
502
706
|
schema = self.connection.database
|
|
503
707
|
return self.connection.get_columns(catalog=self._catalog_name, database=schema, table=table)
|
|
504
708
|
|
|
505
709
|
def get_schema_names(self):
|
|
710
|
+
"""
|
|
711
|
+
Retrieve the list of schema names from the current catalog.
|
|
712
|
+
|
|
713
|
+
Returns:
|
|
714
|
+
list: A list of schema names.
|
|
715
|
+
"""
|
|
506
716
|
return self.connection.get_schema_names(catalog=self._catalog_name)
|
|
507
717
|
|
|
508
718
|
def clear(self, query_id=None):
|
|
719
|
+
"""
|
|
720
|
+
Clear the query results from the server.
|
|
721
|
+
|
|
722
|
+
Args:
|
|
723
|
+
query_id (str, optional): The ID of the query to be cleared. Defaults to None.
|
|
724
|
+
"""
|
|
509
725
|
if not query_id:
|
|
510
726
|
query_id = self._query_id
|
|
511
727
|
clear_request = e6x_engine_pb2.ClearOrCancelQueryRequest(
|
|
@@ -516,9 +732,24 @@ class Cursor(DBAPICursor):
|
|
|
516
732
|
return self.connection.client.clearOrCancelQuery(clear_request, metadata=self.metadata)
|
|
517
733
|
|
|
518
734
|
def cancel(self, query_id):
|
|
735
|
+
"""
|
|
736
|
+
Cancel the execution of a query on the server.
|
|
737
|
+
|
|
738
|
+
Args:
|
|
739
|
+
query_id (str): The ID of the query to be canceled.
|
|
740
|
+
"""
|
|
519
741
|
self.connection.query_cancel(engine_ip=self._engine_ip, query_id=query_id)
|
|
520
742
|
|
|
521
743
|
def status(self, query_id):
|
|
744
|
+
"""
|
|
745
|
+
Get the status of the specified query.
|
|
746
|
+
|
|
747
|
+
Args:
|
|
748
|
+
query_id (str): The ID of the query.
|
|
749
|
+
|
|
750
|
+
Returns:
|
|
751
|
+
StatusResponse: The status response of the query.
|
|
752
|
+
"""
|
|
522
753
|
status_request = e6x_engine_pb2.StatusRequest(
|
|
523
754
|
sessionId=self.connection.get_session_id,
|
|
524
755
|
queryId=query_id,
|
|
@@ -528,12 +759,17 @@ class Cursor(DBAPICursor):
|
|
|
528
759
|
|
|
529
760
|
@re_auth
|
|
530
761
|
def execute(self, operation, parameters=None, **kwargs):
|
|
531
|
-
"""Prepare and execute a database operation (query or command).
|
|
532
|
-
Return values are not defined.
|
|
533
|
-
"""
|
|
534
762
|
"""
|
|
535
|
-
|
|
763
|
+
Prepare and execute a database operation (query or command).
|
|
764
|
+
|
|
765
|
+
Args:
|
|
766
|
+
operation (str): The SQL query or command to execute.
|
|
767
|
+
parameters (dict, optional): The parameters to bind to the query. Defaults to None.
|
|
768
|
+
|
|
769
|
+
Returns:
|
|
770
|
+
str: The query ID of the executed query.
|
|
536
771
|
"""
|
|
772
|
+
# Semicolon is now not supported. So removing it from query end.
|
|
537
773
|
operation = operation.strip() # Remove leading and trailing whitespaces.
|
|
538
774
|
if operation.endswith(';'):
|
|
539
775
|
operation = operation[:-1]
|
|
@@ -597,10 +833,19 @@ class Cursor(DBAPICursor):
|
|
|
597
833
|
|
|
598
834
|
@property
|
|
599
835
|
def rowcount(self):
|
|
836
|
+
"""
|
|
837
|
+
Get the number of rows affected by the last execute operation.
|
|
838
|
+
|
|
839
|
+
Returns:
|
|
840
|
+
int: The number of rows affected.
|
|
841
|
+
"""
|
|
600
842
|
self.update_mete_data()
|
|
601
843
|
return self._rowcount
|
|
602
844
|
|
|
603
845
|
def update_mete_data(self):
|
|
846
|
+
"""
|
|
847
|
+
Update the metadata for the current query.
|
|
848
|
+
"""
|
|
604
849
|
result_meta_data_request = e6x_engine_pb2.GetResultMetadataRequest(
|
|
605
850
|
engineIP=self._engine_ip,
|
|
606
851
|
sessionId=self.connection.get_session_id,
|
|
@@ -615,6 +860,12 @@ class Cursor(DBAPICursor):
|
|
|
615
860
|
self._is_metadata_updated = True
|
|
616
861
|
|
|
617
862
|
def _fetch_more(self):
|
|
863
|
+
"""
|
|
864
|
+
Fetch more rows from the server.
|
|
865
|
+
|
|
866
|
+
Returns:
|
|
867
|
+
list: A list of rows fetched from the server.
|
|
868
|
+
"""
|
|
618
869
|
batch_size = self._arraysize
|
|
619
870
|
self._data = list()
|
|
620
871
|
for i in range(batch_size):
|
|
@@ -625,6 +876,12 @@ class Cursor(DBAPICursor):
|
|
|
625
876
|
return self._data
|
|
626
877
|
|
|
627
878
|
def _fetch_all(self):
|
|
879
|
+
"""
|
|
880
|
+
Fetch all rows from the server.
|
|
881
|
+
|
|
882
|
+
Returns:
|
|
883
|
+
list: A list of all rows fetched from the server.
|
|
884
|
+
"""
|
|
628
885
|
self._data = list()
|
|
629
886
|
while True:
|
|
630
887
|
rows = self.fetch_batch()
|
|
@@ -636,6 +893,15 @@ class Cursor(DBAPICursor):
|
|
|
636
893
|
return rows
|
|
637
894
|
|
|
638
895
|
def fetchall_buffer(self, query_id=None):
|
|
896
|
+
"""
|
|
897
|
+
Fetch all rows from the server in a buffered manner.
|
|
898
|
+
|
|
899
|
+
Args:
|
|
900
|
+
query_id (str, optional): The ID of the query. Defaults to None.
|
|
901
|
+
|
|
902
|
+
Yields:
|
|
903
|
+
list: A list of rows fetched from the server.
|
|
904
|
+
"""
|
|
639
905
|
if query_id:
|
|
640
906
|
self._query_id = query_id
|
|
641
907
|
while True:
|
|
@@ -645,6 +911,12 @@ class Cursor(DBAPICursor):
|
|
|
645
911
|
yield rows
|
|
646
912
|
|
|
647
913
|
def fetch_batch(self):
|
|
914
|
+
"""
|
|
915
|
+
Fetch a batch of rows from the server.
|
|
916
|
+
|
|
917
|
+
Returns:
|
|
918
|
+
list: A list of rows fetched from the server.
|
|
919
|
+
"""
|
|
648
920
|
client = self.connection.client
|
|
649
921
|
get_next_result_batch_request = e6x_engine_pb2.GetNextResultBatchRequest(
|
|
650
922
|
engineIP=self._engine_ip,
|
|
@@ -664,9 +936,24 @@ class Cursor(DBAPICursor):
|
|
|
664
936
|
return read_rows_from_chunk(self._query_columns_description, buffer)
|
|
665
937
|
|
|
666
938
|
def fetchall(self):
|
|
939
|
+
"""
|
|
940
|
+
Fetch all rows from the server.
|
|
941
|
+
|
|
942
|
+
Returns:
|
|
943
|
+
list: A list of all rows fetched from the server.
|
|
944
|
+
"""
|
|
667
945
|
return self._fetch_all()
|
|
668
946
|
|
|
669
947
|
def fetchmany(self, size: int = None):
|
|
948
|
+
"""
|
|
949
|
+
Fetch a specified number of rows from the server.
|
|
950
|
+
|
|
951
|
+
Args:
|
|
952
|
+
size (int, optional): The number of rows to fetch. Defaults to None.
|
|
953
|
+
|
|
954
|
+
Returns:
|
|
955
|
+
list: A list of rows fetched from the server.
|
|
956
|
+
"""
|
|
670
957
|
if size is None:
|
|
671
958
|
size = self.arraysize
|
|
672
959
|
if self._data is None:
|
|
@@ -685,13 +972,24 @@ class Cursor(DBAPICursor):
|
|
|
685
972
|
return rows
|
|
686
973
|
|
|
687
974
|
def fetchone(self):
|
|
688
|
-
|
|
975
|
+
"""
|
|
976
|
+
Fetch a single row from the server.
|
|
977
|
+
|
|
978
|
+
Returns:
|
|
979
|
+
list: A single row fetched from the server.
|
|
980
|
+
"""
|
|
689
981
|
rows = self.fetchmany(1)
|
|
690
982
|
if rows is None or len(rows) == 0:
|
|
691
983
|
return None
|
|
692
984
|
return rows
|
|
693
985
|
|
|
694
986
|
def explain(self):
|
|
987
|
+
"""
|
|
988
|
+
Get the execution plan for the current query.
|
|
989
|
+
|
|
990
|
+
Returns:
|
|
991
|
+
str: The execution plan of the query.
|
|
992
|
+
"""
|
|
695
993
|
explain_request = e6x_engine_pb2.ExplainRequest(
|
|
696
994
|
engineIP=self._engine_ip,
|
|
697
995
|
sessionId=self.connection.get_session_id,
|
|
@@ -704,6 +1002,12 @@ class Cursor(DBAPICursor):
|
|
|
704
1002
|
return explain_response.explain
|
|
705
1003
|
|
|
706
1004
|
def explain_analyse(self):
|
|
1005
|
+
"""
|
|
1006
|
+
Get the execution plan for the current query.
|
|
1007
|
+
|
|
1008
|
+
Returns:
|
|
1009
|
+
dict: The execution plan of the query.
|
|
1010
|
+
"""
|
|
707
1011
|
explain_analyze_request = e6x_engine_pb2.ExplainAnalyzeRequest(
|
|
708
1012
|
engineIP=self._engine_ip,
|
|
709
1013
|
sessionId=self.connection.get_session_id,
|
{e6data_python_connector-2.2.2.3rc2.dist-info → e6data_python_connector-2.2.3.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: e6data-python-connector
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.3
|
|
4
4
|
Summary: Client for the e6data distributed SQL Engine.
|
|
5
5
|
Home-page: https://github.com/e6x-labs/e6data-python-connector
|
|
6
6
|
Author: e6data, Inc.
|
|
@@ -38,7 +38,7 @@ Dynamic: summary
|
|
|
38
38
|
|
|
39
39
|
# e6data Python Connector
|
|
40
40
|
|
|
41
|
-

|
|
42
42
|
|
|
43
43
|
## Introduction
|
|
44
44
|
|
{e6data_python_connector-2.2.2.3rc2.dist-info → e6data_python_connector-2.2.3.dist-info}/RECORD
RENAMED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
e6data_python_connector/__init__.py,sha256=x_VwhPQ7XLlthR-NJL9Vl7lkLBRCG2pSjmyZSBHOBpM,103
|
|
2
|
-
e6data_python_connector/cluster_manager.py,sha256=
|
|
2
|
+
e6data_python_connector/cluster_manager.py,sha256=rg-eEYP-tQF4Yoj7w0fMORlO3nl2iqXThd168zqFGBs,11060
|
|
3
3
|
e6data_python_connector/common.py,sha256=nk0CDQ5j1iu8DctBOXX4QypPYmxSgIgoA-Cn1UZXLic,9976
|
|
4
4
|
e6data_python_connector/constants.py,sha256=h5w0lWiFsxz__zUZRlo1f72-8mT_vt9gcWvtWh0viFI,682
|
|
5
5
|
e6data_python_connector/datainputstream.py,sha256=2XKW__PCGfTQ55Puqgie2LZdk_WU-YKwpEIUOQEF-sY,12592
|
|
6
6
|
e6data_python_connector/date_time_utils.py,sha256=zmIwRhEGJwDvCOUjAl6VTDWGppluA-DPl_ioHTNpJKI,14413
|
|
7
7
|
e6data_python_connector/dialect.py,sha256=hkVRjXxx9DhS8-aHpSoyMVhhHxVs3jdTE60x2aOAf5I,11312
|
|
8
|
-
e6data_python_connector/e6data_grpc.py,sha256=
|
|
8
|
+
e6data_python_connector/e6data_grpc.py,sha256=qFLpaG0cceY_HiuFxOgNON8IknHkSH1uZTDS02RR_KY,36279
|
|
9
9
|
e6data_python_connector/exceptions.py,sha256=vrUqdzMq3LjbCmvr5_TcRq9eKmdqGfe-uVjR0BJQf5U,382
|
|
10
10
|
e6data_python_connector/typeId.py,sha256=2EMNWK2SO5CBReNuJphma6xp-69r9GDwwys66t-kSk0,1777
|
|
11
11
|
e6data_python_connector/cluster_server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -21,9 +21,9 @@ e6data_python_connector/server/e6x_engine_pb2.py,sha256=BxJjbijNrEqXQTWEhzLm54Fq
|
|
|
21
21
|
e6data_python_connector/server/e6x_engine_pb2.pyi,sha256=_aQDLFbSCQ7ubK0Z5ZKh9_VAHFaXbMV55MXYXr85srg,18693
|
|
22
22
|
e6data_python_connector/server/e6x_engine_pb2_grpc.py,sha256=n-eTCsAjsmpgPA_bDansKZq_zMmqkK6TlQGn6IdT6L4,46671
|
|
23
23
|
e6data_python_connector/server/ttypes.py,sha256=uWxwSp4m6e-7SeSEckbZtSduGYmfzXWM09iy5eltBPA,21227
|
|
24
|
-
e6data_python_connector-2.2.
|
|
25
|
-
e6data_python_connector-2.2.
|
|
26
|
-
e6data_python_connector-2.2.
|
|
27
|
-
e6data_python_connector-2.2.
|
|
28
|
-
e6data_python_connector-2.2.
|
|
29
|
-
e6data_python_connector-2.2.
|
|
24
|
+
e6data_python_connector-2.2.3.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
|
|
25
|
+
e6data_python_connector-2.2.3.dist-info/METADATA,sha256=3YC7YniJCrZ2lIKHoRFVYe1PfDJpdFCz6hN9uJjN2Ok,7309
|
|
26
|
+
e6data_python_connector-2.2.3.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
|
27
|
+
e6data_python_connector-2.2.3.dist-info/entry_points.txt,sha256=MDK4cAOND0preLvq2Tlpnz00wXnP_Y_UopqJsAf3U7Y,77
|
|
28
|
+
e6data_python_connector-2.2.3.dist-info/top_level.txt,sha256=ChOS6qLf-SQycXr0uBiVxomIfYfbH2SgwrOWhW79ab0,24
|
|
29
|
+
e6data_python_connector-2.2.3.dist-info/RECORD,,
|
{e6data_python_connector-2.2.2.3rc2.dist-info → e6data_python_connector-2.2.3.dist-info}/LICENSE
RENAMED
|
File without changes
|
{e6data_python_connector-2.2.2.3rc2.dist-info → e6data_python_connector-2.2.3.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|