e6data-python-connector 2.2.6__tar.gz → 2.3.6__tar.gz
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-2.2.6/e6data_python_connector.egg-info → e6data_python_connector-2.3.6}/PKG-INFO +2 -2
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/README.md +1 -1
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/cluster_manager.py +22 -41
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/e6data_grpc.py +45 -47
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6/e6data_python_connector.egg-info}/PKG-INFO +2 -2
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/setup.py +1 -1
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/LICENSE +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/MANIFEST.in +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/__init__.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/cluster_server/__init__.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/cluster_server/cluster_pb2.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/cluster_server/cluster_pb2_grpc.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/common.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/constants.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/datainputstream.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/date_time_utils.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/dialect.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/e6x_vector/__init__.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/e6x_vector/constants.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/e6x_vector/ttypes.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/exceptions.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/server/QueryEngineService.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/server/__init__.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/server/constants.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/server/e6x_engine_pb2.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/server/e6x_engine_pb2.pyi +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/server/e6x_engine_pb2_grpc.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/server/ttypes.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/strategy.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/typeId.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector.egg-info/SOURCES.txt +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector.egg-info/dependency_links.txt +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector.egg-info/entry_points.txt +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector.egg-info/requires.txt +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector.egg-info/top_level.txt +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/pyproject.toml +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/setup.cfg +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/__init__.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/analyze_38_nines.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/analyze_all_cases.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/analyze_binary.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/analyze_correct_value.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/analyze_fields.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/check_decimal_errors.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/cleanup_test_files.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/debug_38_nines.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/debug_binary.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/final_test.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/move_tests.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/quick_test.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_38_nines.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_all_decimal128_cases.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_cluster_manager_efficiency.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_cluster_manager_none_strategy.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_cluster_manager_strategy.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_comprehensive.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_current_implementation.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_decimal128_binary_parsing.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_decimal128_parsing.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_fix.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_improved_parsing.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_known_case.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_manual_analysis.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_mock_server.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_multiprocessing_fix.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_new_implementation.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_specific_binary.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_strategy.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_strategy_logic.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_strategy_persistence_fix.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_strategy_sharing_fix.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_user_binary_value.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/tests.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/tests_grpc.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/validate_decimal128.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/validate_implementation.py +0 -0
- {e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/verify_decimal_fix.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: e6data-python-connector
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.6
|
|
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
|
|
|
@@ -5,13 +5,9 @@ import e6data_python_connector.cluster_server.cluster_pb2_grpc as cluster_pb2_gr
|
|
|
5
5
|
import grpc
|
|
6
6
|
from grpc._channel import _InactiveRpcError
|
|
7
7
|
import multiprocessing
|
|
8
|
-
import logging
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
# Set up logging
|
|
14
|
-
_logger = logging.getLogger(__name__)
|
|
9
|
+
from e6data_python_connector.strategy import _get_active_strategy, _set_active_strategy, _set_pending_strategy, \
|
|
10
|
+
_get_grpc_header as _get_strategy_header
|
|
15
11
|
|
|
16
12
|
|
|
17
13
|
def _get_grpc_header(engine_ip=None, cluster=None, strategy=None):
|
|
@@ -140,7 +136,8 @@ class ClusterManager:
|
|
|
140
136
|
cluster_uuid (str): The unique identifier for the target cluster.
|
|
141
137
|
"""
|
|
142
138
|
|
|
143
|
-
def __init__(self, host: str, port: int, user: str, password: str, secure_channel: bool = False, timeout=60 * 5,
|
|
139
|
+
def __init__(self, host: str, port: int, user: str, password: str, secure_channel: bool = False, timeout=60 * 5,
|
|
140
|
+
cluster_uuid=None, grpc_options=None):
|
|
144
141
|
"""
|
|
145
142
|
Initializes a new instance of the ClusterManager class.
|
|
146
143
|
|
|
@@ -208,7 +205,7 @@ class ClusterManager:
|
|
|
208
205
|
The response from the successful request
|
|
209
206
|
"""
|
|
210
207
|
current_strategy = _get_active_strategy()
|
|
211
|
-
|
|
208
|
+
|
|
212
209
|
# Create payload if not provided
|
|
213
210
|
if payload is None:
|
|
214
211
|
if request_type == "status":
|
|
@@ -221,12 +218,10 @@ class ClusterManager:
|
|
|
221
218
|
user=self._user,
|
|
222
219
|
password=self._password
|
|
223
220
|
)
|
|
224
|
-
|
|
221
|
+
|
|
225
222
|
# If we have an active strategy, use it first
|
|
226
223
|
if current_strategy is not None:
|
|
227
224
|
try:
|
|
228
|
-
_logger.info(f"ClusterManager: Trying {request_type} with established strategy: {current_strategy}")
|
|
229
|
-
|
|
230
225
|
if request_type == "status":
|
|
231
226
|
response = self._get_connection.status(
|
|
232
227
|
payload,
|
|
@@ -239,22 +234,20 @@ class ClusterManager:
|
|
|
239
234
|
)
|
|
240
235
|
else:
|
|
241
236
|
raise ValueError(f"Unknown request type: {request_type}")
|
|
242
|
-
|
|
237
|
+
|
|
243
238
|
# Check for new strategy in response
|
|
244
239
|
if hasattr(response, 'new_strategy') and response.new_strategy:
|
|
245
240
|
new_strategy = response.new_strategy.lower()
|
|
246
241
|
if new_strategy != current_strategy:
|
|
247
|
-
_logger.info(f"ClusterManager: Server indicated new strategy during {request_type}: {new_strategy}")
|
|
248
242
|
_set_pending_strategy(new_strategy)
|
|
249
|
-
|
|
243
|
+
|
|
250
244
|
return response
|
|
251
|
-
|
|
245
|
+
|
|
252
246
|
except _InactiveRpcError as e:
|
|
253
247
|
if e.code() == grpc.StatusCode.UNKNOWN and 'status: 456' in e.details():
|
|
254
248
|
# 456 error - switch to alternative strategy
|
|
255
249
|
alternative_strategy = 'green' if current_strategy == 'blue' else 'blue'
|
|
256
|
-
|
|
257
|
-
|
|
250
|
+
|
|
258
251
|
try:
|
|
259
252
|
if request_type == "status":
|
|
260
253
|
response = self._get_connection.status(
|
|
@@ -266,36 +259,30 @@ class ClusterManager:
|
|
|
266
259
|
payload,
|
|
267
260
|
metadata=_get_grpc_header(cluster=self.cluster_uuid, strategy=alternative_strategy)
|
|
268
261
|
)
|
|
269
|
-
|
|
262
|
+
|
|
270
263
|
# Update active strategy since the alternative worked
|
|
271
264
|
_set_active_strategy(alternative_strategy)
|
|
272
|
-
|
|
273
|
-
|
|
265
|
+
|
|
274
266
|
# Check for new strategy in response
|
|
275
267
|
if hasattr(response, 'new_strategy') and response.new_strategy:
|
|
276
268
|
new_strategy = response.new_strategy.lower()
|
|
277
269
|
if new_strategy != alternative_strategy:
|
|
278
|
-
_logger.info(f"ClusterManager: Server indicated new strategy during {request_type}: {new_strategy}")
|
|
279
270
|
_set_pending_strategy(new_strategy)
|
|
280
|
-
|
|
271
|
+
|
|
281
272
|
return response
|
|
282
|
-
|
|
273
|
+
|
|
283
274
|
except _InactiveRpcError as e2:
|
|
284
|
-
_logger.error(f"ClusterManager: Both strategies failed for {request_type}. Original error: {e}, Alternative error: {e2}")
|
|
285
275
|
raise e # Raise the original error
|
|
286
276
|
else:
|
|
287
277
|
# Non-456 error - don't retry
|
|
288
|
-
_logger.error(f"ClusterManager: {request_type} failed with non-456 error: {e}")
|
|
289
278
|
raise e
|
|
290
|
-
|
|
279
|
+
|
|
291
280
|
# No active strategy - start with authentication logic (blue first, then green)
|
|
292
|
-
_logger.info(f"ClusterManager: No active strategy, starting authentication sequence for {request_type}")
|
|
293
281
|
strategies_to_try = ['blue', 'green']
|
|
294
|
-
|
|
282
|
+
|
|
295
283
|
for i, strategy in enumerate(strategies_to_try):
|
|
296
284
|
try:
|
|
297
|
-
|
|
298
|
-
|
|
285
|
+
|
|
299
286
|
if request_type == "status":
|
|
300
287
|
response = self._get_connection.status(
|
|
301
288
|
payload,
|
|
@@ -308,36 +295,30 @@ class ClusterManager:
|
|
|
308
295
|
)
|
|
309
296
|
else:
|
|
310
297
|
raise ValueError(f"Unknown request type: {request_type}")
|
|
311
|
-
|
|
298
|
+
|
|
312
299
|
# Set the working strategy as active
|
|
313
300
|
_set_active_strategy(strategy)
|
|
314
|
-
|
|
315
|
-
|
|
301
|
+
|
|
316
302
|
# Check for new strategy in response
|
|
317
303
|
if hasattr(response, 'new_strategy') and response.new_strategy:
|
|
318
304
|
new_strategy = response.new_strategy.lower()
|
|
319
305
|
if new_strategy != strategy:
|
|
320
|
-
_logger.info(f"ClusterManager: Server indicated new strategy during {request_type}: {new_strategy}")
|
|
321
306
|
_set_pending_strategy(new_strategy)
|
|
322
|
-
|
|
307
|
+
|
|
323
308
|
return response
|
|
324
|
-
|
|
309
|
+
|
|
325
310
|
except _InactiveRpcError as e:
|
|
326
311
|
if e.code() == grpc.StatusCode.UNKNOWN and 'status: 456' in e.details():
|
|
327
312
|
# 456 error - try next strategy
|
|
328
313
|
if i < len(strategies_to_try) - 1:
|
|
329
|
-
_logger.info(f"ClusterManager: {request_type} failed with 456 error on {strategy}, trying next strategy: {strategies_to_try[i + 1]}")
|
|
330
314
|
continue
|
|
331
315
|
else:
|
|
332
|
-
_logger.error(f"ClusterManager: {request_type} failed with 456 error on all strategies")
|
|
333
316
|
raise e
|
|
334
317
|
else:
|
|
335
318
|
# Non-456 error - don't retry
|
|
336
|
-
_logger.error(f"ClusterManager: {request_type} failed with non-456 error: {e}")
|
|
337
319
|
raise e
|
|
338
|
-
|
|
320
|
+
|
|
339
321
|
# If we get here, all strategies failed
|
|
340
|
-
_logger.error(f"ClusterManager: All strategies failed for {request_type}")
|
|
341
322
|
raise e
|
|
342
323
|
|
|
343
324
|
def _check_cluster_status(self):
|
|
@@ -7,7 +7,6 @@ from __future__ import absolute_import
|
|
|
7
7
|
from __future__ import unicode_literals
|
|
8
8
|
|
|
9
9
|
import datetime
|
|
10
|
-
import logging
|
|
11
10
|
import re
|
|
12
11
|
import sys
|
|
13
12
|
import time
|
|
@@ -32,9 +31,6 @@ apilevel = '2.0'
|
|
|
32
31
|
threadsafety = 2 # Threads may share the e6xdb and connections.
|
|
33
32
|
paramstyle = 'pyformat' # Python extended format codes, e.g. ...WHERE name=%(name)s
|
|
34
33
|
|
|
35
|
-
logging.basicConfig(level=logging.DEBUG)
|
|
36
|
-
_logger = logging.getLogger(__name__)
|
|
37
|
-
|
|
38
34
|
_TIMESTAMP_PATTERN = re.compile(r'(\d+-\d+-\d+ \d+:\d+:\d+(\.\d{,6})?)')
|
|
39
35
|
|
|
40
36
|
ssl_cert_parameter_map = {
|
|
@@ -121,10 +117,10 @@ _strategy_lock = threading.Lock()
|
|
|
121
117
|
_strategy_manager = None
|
|
122
118
|
_shared_strategy = None
|
|
123
119
|
_local_strategy_cache = {
|
|
124
|
-
'active_strategy': None,
|
|
120
|
+
'active_strategy': None,
|
|
125
121
|
'last_check_time': 0,
|
|
126
122
|
'pending_strategy': None, # Strategy to use for next query
|
|
127
|
-
'query_strategy_map': {},
|
|
123
|
+
'query_strategy_map': {}, # Map of query_id to strategy used
|
|
128
124
|
'last_transition_time': 0, # Timestamp of last strategy transition
|
|
129
125
|
'session_invalidated': False # Flag to invalidate all sessions
|
|
130
126
|
}
|
|
@@ -132,10 +128,11 @@ _local_strategy_cache = {
|
|
|
132
128
|
# Strategy cache timeout in seconds (5 minutes)
|
|
133
129
|
STRATEGY_CACHE_TIMEOUT = 300
|
|
134
130
|
|
|
131
|
+
|
|
135
132
|
def _get_shared_strategy():
|
|
136
133
|
"""Get or create the shared strategy storage."""
|
|
137
134
|
global _strategy_manager, _shared_strategy
|
|
138
|
-
|
|
135
|
+
|
|
139
136
|
# Try to use multiprocessing.Manager for process-safe storage
|
|
140
137
|
try:
|
|
141
138
|
if _strategy_manager is None:
|
|
@@ -174,15 +171,15 @@ def _set_active_strategy(strategy):
|
|
|
174
171
|
normalized_strategy = strategy.lower()
|
|
175
172
|
if normalized_strategy not in ['blue', 'green']:
|
|
176
173
|
return
|
|
177
|
-
|
|
174
|
+
|
|
178
175
|
with _strategy_lock:
|
|
179
176
|
shared_strategy = _get_shared_strategy()
|
|
180
177
|
current_time = time.time()
|
|
181
|
-
|
|
178
|
+
|
|
182
179
|
# Only update transition time if strategy actually changed
|
|
183
180
|
if shared_strategy['active_strategy'] != normalized_strategy:
|
|
184
181
|
shared_strategy['last_transition_time'] = current_time
|
|
185
|
-
|
|
182
|
+
|
|
186
183
|
shared_strategy['active_strategy'] = normalized_strategy
|
|
187
184
|
shared_strategy['last_check_time'] = current_time
|
|
188
185
|
|
|
@@ -204,11 +201,11 @@ def _set_pending_strategy(strategy):
|
|
|
204
201
|
normalized_strategy = strategy.lower()
|
|
205
202
|
if normalized_strategy not in ['blue', 'green']:
|
|
206
203
|
return
|
|
207
|
-
|
|
204
|
+
|
|
208
205
|
with _strategy_lock:
|
|
209
206
|
shared_strategy = _get_shared_strategy()
|
|
210
207
|
current_active = shared_strategy['active_strategy']
|
|
211
|
-
|
|
208
|
+
|
|
212
209
|
if normalized_strategy != current_active:
|
|
213
210
|
shared_strategy['pending_strategy'] = normalized_strategy
|
|
214
211
|
|
|
@@ -221,13 +218,13 @@ def _apply_pending_strategy():
|
|
|
221
218
|
old_strategy = shared_strategy['active_strategy']
|
|
222
219
|
new_strategy = shared_strategy['pending_strategy']
|
|
223
220
|
current_time = time.time()
|
|
224
|
-
|
|
221
|
+
|
|
225
222
|
shared_strategy['active_strategy'] = new_strategy
|
|
226
223
|
shared_strategy['pending_strategy'] = None
|
|
227
224
|
shared_strategy['last_check_time'] = current_time
|
|
228
225
|
shared_strategy['last_transition_time'] = current_time
|
|
229
226
|
shared_strategy['session_invalidated'] = True # Invalidate all sessions
|
|
230
|
-
|
|
227
|
+
|
|
231
228
|
return new_strategy
|
|
232
229
|
return None
|
|
233
230
|
|
|
@@ -247,7 +244,7 @@ def _register_query_strategy(query_id, strategy):
|
|
|
247
244
|
normalized_strategy = strategy.lower()
|
|
248
245
|
if normalized_strategy not in ['blue', 'green']:
|
|
249
246
|
return
|
|
250
|
-
|
|
247
|
+
|
|
251
248
|
with _strategy_lock:
|
|
252
249
|
shared_strategy = _get_shared_strategy()
|
|
253
250
|
query_map = shared_strategy.get('query_strategy_map', {})
|
|
@@ -407,7 +404,8 @@ class Connection(object):
|
|
|
407
404
|
"keepalive_permit_without_calls": 1, # Allow keep-alives with no active RPCs.
|
|
408
405
|
"http2.max_pings_without_data": 0, # Unlimited pings without data.
|
|
409
406
|
"http2.min_time_between_pings_ms": 15000, # Minimum time between pings (15 seconds).
|
|
410
|
-
"http2.min_ping_interval_without_data_ms": 15000,
|
|
407
|
+
"http2.min_ping_interval_without_data_ms": 15000,
|
|
408
|
+
# Minimum interval between pings without data (15 seconds).
|
|
411
409
|
}
|
|
412
410
|
if grpc_options:
|
|
413
411
|
for key, value in grpc_options.items():
|
|
@@ -481,7 +479,7 @@ class Connection(object):
|
|
|
481
479
|
self._create_client()
|
|
482
480
|
# Clear the invalidation flag
|
|
483
481
|
shared_strategy['session_invalidated'] = False
|
|
484
|
-
|
|
482
|
+
|
|
485
483
|
# Only create fresh connection if we have no active queries
|
|
486
484
|
elif self._session_id and pending_strategy and pending_strategy != active_strategy:
|
|
487
485
|
query_map = shared_strategy.get('query_strategy_map', {})
|
|
@@ -531,7 +529,7 @@ class Connection(object):
|
|
|
531
529
|
elif pending_strategy:
|
|
532
530
|
# If there's a pending strategy, force re-authentication with new strategy
|
|
533
531
|
active_strategy = None
|
|
534
|
-
|
|
532
|
+
|
|
535
533
|
if not active_strategy:
|
|
536
534
|
# Check if we have a pending strategy to use
|
|
537
535
|
if pending_strategy:
|
|
@@ -555,7 +553,8 @@ class Connection(object):
|
|
|
555
553
|
_set_active_strategy(strategy)
|
|
556
554
|
|
|
557
555
|
# Check for new strategy in authenticate response
|
|
558
|
-
if hasattr(authenticate_response,
|
|
556
|
+
if hasattr(authenticate_response,
|
|
557
|
+
'new_strategy') and authenticate_response.new_strategy:
|
|
559
558
|
new_strategy = authenticate_response.new_strategy.lower()
|
|
560
559
|
if new_strategy != strategy:
|
|
561
560
|
_set_pending_strategy(new_strategy)
|
|
@@ -569,11 +568,11 @@ class Connection(object):
|
|
|
569
568
|
else:
|
|
570
569
|
# Different error, handle it normally
|
|
571
570
|
raise e
|
|
572
|
-
|
|
571
|
+
|
|
573
572
|
if not self._session_id and last_error:
|
|
574
573
|
# Neither strategy worked
|
|
575
574
|
raise last_error
|
|
576
|
-
|
|
575
|
+
|
|
577
576
|
if not self._session_id:
|
|
578
577
|
raise ValueError("Invalid credentials.")
|
|
579
578
|
except _InactiveRpcError as e:
|
|
@@ -671,7 +670,7 @@ class Connection(object):
|
|
|
671
670
|
pending_strategy = shared_strategy.get('pending_strategy')
|
|
672
671
|
active_strategy = shared_strategy.get('active_strategy')
|
|
673
672
|
query_map = shared_strategy.get('query_strategy_map', {})
|
|
674
|
-
|
|
673
|
+
|
|
675
674
|
if pending_strategy and pending_strategy != active_strategy and len(query_map) == 0:
|
|
676
675
|
_apply_pending_strategy()
|
|
677
676
|
# Force new authentication with new strategy
|
|
@@ -690,11 +689,11 @@ class Connection(object):
|
|
|
690
689
|
pending_strategy = shared_strategy.get('pending_strategy')
|
|
691
690
|
active_strategy = shared_strategy.get('active_strategy')
|
|
692
691
|
query_map = shared_strategy.get('query_strategy_map', {})
|
|
693
|
-
|
|
692
|
+
|
|
694
693
|
# Create new connection if:
|
|
695
694
|
# 1. No session exists
|
|
696
695
|
# 2. There's a pending strategy change and no active queries
|
|
697
|
-
return (not self._session_id or
|
|
696
|
+
return (not self._session_id or
|
|
698
697
|
(pending_strategy and pending_strategy != active_strategy and len(query_map) == 0))
|
|
699
698
|
|
|
700
699
|
def clear(self, query_id, engine_ip=None):
|
|
@@ -714,7 +713,7 @@ class Connection(object):
|
|
|
714
713
|
clear_request,
|
|
715
714
|
metadata=_get_grpc_header(engine_ip=engine_ip, cluster=self.cluster_uuid, strategy=_get_active_strategy())
|
|
716
715
|
)
|
|
717
|
-
|
|
716
|
+
|
|
718
717
|
# Check for new strategy in clear response
|
|
719
718
|
if hasattr(clear_response, 'new_strategy') and clear_response.new_strategy:
|
|
720
719
|
_set_pending_strategy(clear_response.new_strategy)
|
|
@@ -745,7 +744,7 @@ class Connection(object):
|
|
|
745
744
|
cancel_query_request,
|
|
746
745
|
metadata=_get_grpc_header(engine_ip=engine_ip, cluster=self.cluster_uuid, strategy=_get_active_strategy())
|
|
747
746
|
)
|
|
748
|
-
|
|
747
|
+
|
|
749
748
|
# Check for new strategy in cancel response
|
|
750
749
|
if hasattr(cancel_response, 'new_strategy') and cancel_response.new_strategy:
|
|
751
750
|
_set_pending_strategy(cancel_response.new_strategy)
|
|
@@ -791,7 +790,7 @@ class Connection(object):
|
|
|
791
790
|
get_table_request,
|
|
792
791
|
metadata=_get_grpc_header(cluster=self.cluster_uuid, strategy=_get_active_strategy())
|
|
793
792
|
)
|
|
794
|
-
|
|
793
|
+
|
|
795
794
|
# Check for new strategy in get tables response
|
|
796
795
|
if hasattr(get_table_response, 'new_strategy') and get_table_response.new_strategy:
|
|
797
796
|
_set_pending_strategy(get_table_response.new_strategy)
|
|
@@ -819,7 +818,7 @@ class Connection(object):
|
|
|
819
818
|
get_columns_request,
|
|
820
819
|
metadata=_get_grpc_header(cluster=self.cluster_uuid, strategy=_get_active_strategy())
|
|
821
820
|
)
|
|
822
|
-
|
|
821
|
+
|
|
823
822
|
# Check for new strategy in get columns response
|
|
824
823
|
if hasattr(get_columns_response, 'new_strategy') and get_columns_response.new_strategy:
|
|
825
824
|
_set_pending_strategy(get_columns_response.new_strategy)
|
|
@@ -843,11 +842,11 @@ class Connection(object):
|
|
|
843
842
|
get_schema_request,
|
|
844
843
|
metadata=_get_grpc_header(cluster=self.cluster_uuid, strategy=_get_active_strategy())
|
|
845
844
|
)
|
|
846
|
-
|
|
845
|
+
|
|
847
846
|
# Check for new strategy in get schema names response
|
|
848
847
|
if hasattr(get_schema_response, 'new_strategy') and get_schema_response.new_strategy:
|
|
849
848
|
_set_pending_strategy(get_schema_response.new_strategy)
|
|
850
|
-
|
|
849
|
+
|
|
851
850
|
return list(get_schema_response.schemas)
|
|
852
851
|
|
|
853
852
|
def commit(self):
|
|
@@ -1072,7 +1071,7 @@ class Cursor(DBAPICursor):
|
|
|
1072
1071
|
"""
|
|
1073
1072
|
if not query_id:
|
|
1074
1073
|
query_id = self._query_id
|
|
1075
|
-
|
|
1074
|
+
|
|
1076
1075
|
clear_request = e6x_engine_pb2.ClearOrCancelQueryRequest(
|
|
1077
1076
|
sessionId=self.connection.get_session_id,
|
|
1078
1077
|
queryId=query_id,
|
|
@@ -1081,7 +1080,7 @@ class Cursor(DBAPICursor):
|
|
|
1081
1080
|
# Get fresh client after session access (may have been invalidated)
|
|
1082
1081
|
client = self.connection.client
|
|
1083
1082
|
clear_response = client.clearOrCancelQuery(clear_request, metadata=self.metadata)
|
|
1084
|
-
|
|
1083
|
+
|
|
1085
1084
|
# Check for new strategy in clear response
|
|
1086
1085
|
if hasattr(clear_response, 'new_strategy') and clear_response.new_strategy:
|
|
1087
1086
|
_set_pending_strategy(clear_response.new_strategy)
|
|
@@ -1094,7 +1093,7 @@ class Cursor(DBAPICursor):
|
|
|
1094
1093
|
shared_strategy = _get_shared_strategy()
|
|
1095
1094
|
pending_strategy = shared_strategy.get('pending_strategy')
|
|
1096
1095
|
query_map = shared_strategy.get('query_strategy_map', {})
|
|
1097
|
-
|
|
1096
|
+
|
|
1098
1097
|
if pending_strategy and len(query_map) == 0:
|
|
1099
1098
|
_apply_pending_strategy()
|
|
1100
1099
|
|
|
@@ -1117,7 +1116,7 @@ class Cursor(DBAPICursor):
|
|
|
1117
1116
|
shared_strategy = _get_shared_strategy()
|
|
1118
1117
|
pending_strategy = shared_strategy.get('pending_strategy')
|
|
1119
1118
|
query_map = shared_strategy.get('query_strategy_map', {})
|
|
1120
|
-
|
|
1119
|
+
|
|
1121
1120
|
if pending_strategy and len(query_map) == 0:
|
|
1122
1121
|
_apply_pending_strategy()
|
|
1123
1122
|
|
|
@@ -1137,11 +1136,11 @@ class Cursor(DBAPICursor):
|
|
|
1137
1136
|
engineIP=self._engine_ip
|
|
1138
1137
|
)
|
|
1139
1138
|
status_response = self.connection.client.status(status_request, metadata=self.metadata)
|
|
1140
|
-
|
|
1139
|
+
|
|
1141
1140
|
# Check for new strategy in status response
|
|
1142
1141
|
if hasattr(status_response, 'new_strategy') and status_response.new_strategy:
|
|
1143
1142
|
_set_pending_strategy(status_response.new_strategy)
|
|
1144
|
-
|
|
1143
|
+
|
|
1145
1144
|
return status_response
|
|
1146
1145
|
|
|
1147
1146
|
@re_auth
|
|
@@ -1183,18 +1182,17 @@ class Cursor(DBAPICursor):
|
|
|
1183
1182
|
self._query_id = prepare_statement_response.queryId
|
|
1184
1183
|
self._engine_ip = prepare_statement_response.engineIP
|
|
1185
1184
|
|
|
1186
|
-
|
|
1187
1185
|
# Check for new strategy in prepare response
|
|
1188
1186
|
if hasattr(prepare_statement_response, 'new_strategy') and prepare_statement_response.new_strategy:
|
|
1189
1187
|
new_strategy = prepare_statement_response.new_strategy.lower()
|
|
1190
1188
|
if new_strategy != _get_active_strategy():
|
|
1191
1189
|
_set_pending_strategy(new_strategy)
|
|
1192
|
-
|
|
1190
|
+
|
|
1193
1191
|
# Register this query with the current strategy
|
|
1194
1192
|
current_strategy = _get_active_strategy()
|
|
1195
1193
|
if current_strategy:
|
|
1196
1194
|
_register_query_strategy(self._query_id, current_strategy)
|
|
1197
|
-
|
|
1195
|
+
|
|
1198
1196
|
execute_statement_request = e6x_engine_pb2.ExecuteStatementRequest(
|
|
1199
1197
|
engineIP=self._engine_ip,
|
|
1200
1198
|
sessionId=self.connection.get_session_id,
|
|
@@ -1206,7 +1204,7 @@ class Cursor(DBAPICursor):
|
|
|
1206
1204
|
execute_statement_request,
|
|
1207
1205
|
metadata=self.metadata
|
|
1208
1206
|
)
|
|
1209
|
-
|
|
1207
|
+
|
|
1210
1208
|
# Check for new strategy in execute response
|
|
1211
1209
|
if hasattr(execute_response, 'new_strategy') and execute_response.new_strategy:
|
|
1212
1210
|
new_strategy = execute_response.new_strategy.lower()
|
|
@@ -1235,7 +1233,7 @@ class Cursor(DBAPICursor):
|
|
|
1235
1233
|
new_strategy = prepare_statement_response.new_strategy.lower()
|
|
1236
1234
|
if new_strategy != _get_active_strategy():
|
|
1237
1235
|
_set_pending_strategy(new_strategy)
|
|
1238
|
-
|
|
1236
|
+
|
|
1239
1237
|
# Register this query with the current strategy
|
|
1240
1238
|
current_strategy = _get_active_strategy()
|
|
1241
1239
|
|
|
@@ -1288,13 +1286,13 @@ class Cursor(DBAPICursor):
|
|
|
1288
1286
|
result_meta_data_request,
|
|
1289
1287
|
metadata=self.metadata
|
|
1290
1288
|
)
|
|
1291
|
-
|
|
1289
|
+
|
|
1292
1290
|
# Check for new strategy in metadata response
|
|
1293
1291
|
if hasattr(get_result_metadata_response, 'new_strategy') and get_result_metadata_response.new_strategy:
|
|
1294
1292
|
new_strategy = get_result_metadata_response.new_strategy.lower()
|
|
1295
1293
|
if new_strategy != _get_active_strategy():
|
|
1296
1294
|
_set_pending_strategy(new_strategy)
|
|
1297
|
-
|
|
1295
|
+
|
|
1298
1296
|
buffer = BytesIO(get_result_metadata_response.resultMetaData)
|
|
1299
1297
|
self._rowcount, self._query_columns_description = get_query_columns_info(buffer)
|
|
1300
1298
|
self._is_metadata_updated = True
|
|
@@ -1368,13 +1366,13 @@ class Cursor(DBAPICursor):
|
|
|
1368
1366
|
get_next_result_batch_request,
|
|
1369
1367
|
metadata=self.metadata
|
|
1370
1368
|
)
|
|
1371
|
-
|
|
1369
|
+
|
|
1372
1370
|
# Check for new strategy in batch response
|
|
1373
1371
|
if hasattr(get_next_result_batch_response, 'new_strategy') and get_next_result_batch_response.new_strategy:
|
|
1374
1372
|
new_strategy = get_next_result_batch_response.new_strategy.lower()
|
|
1375
1373
|
if new_strategy != _get_active_strategy():
|
|
1376
1374
|
_set_pending_strategy(new_strategy)
|
|
1377
|
-
|
|
1375
|
+
|
|
1378
1376
|
buffer = get_next_result_batch_response.resultBatch
|
|
1379
1377
|
if not self._is_metadata_updated:
|
|
1380
1378
|
self.update_mete_data()
|
|
@@ -1467,11 +1465,11 @@ class Cursor(DBAPICursor):
|
|
|
1467
1465
|
explain_analyze_request,
|
|
1468
1466
|
metadata=self.metadata
|
|
1469
1467
|
)
|
|
1470
|
-
|
|
1468
|
+
|
|
1471
1469
|
# Check for new strategy in explain analyze response
|
|
1472
1470
|
if hasattr(explain_analyze_response, 'new_strategy') and explain_analyze_response.new_strategy:
|
|
1473
1471
|
_set_pending_strategy(explain_analyze_response.new_strategy)
|
|
1474
|
-
|
|
1472
|
+
|
|
1475
1473
|
return dict(
|
|
1476
1474
|
is_cached=explain_analyze_response.isCached,
|
|
1477
1475
|
parsing_time=explain_analyze_response.parsingTime,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: e6data-python-connector
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.6
|
|
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
|
|
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/common.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/constants.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/dialect.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/strategy.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/e6data_python_connector/typeId.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/analyze_correct_value.py
RENAMED
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/check_decimal_errors.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_all_decimal128_cases.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_current_implementation.py
RENAMED
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_decimal128_parsing.py
RENAMED
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_improved_parsing.py
RENAMED
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_manual_analysis.py
RENAMED
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_multiprocessing_fix.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_new_implementation.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_specific_binary.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_strategy_sharing_fix.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/test_user_binary_value.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.2.6 → e6data_python_connector-2.3.6}/test/validate_implementation.py
RENAMED
|
File without changes
|
|
File without changes
|