e6data-python-connector 2.3.11rc2__tar.gz → 2.3.12rc1__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.
Files changed (87) hide show
  1. {e6data_python_connector-2.3.11rc2/e6data_python_connector.egg-info → e6data_python_connector-2.3.12rc1}/PKG-INFO +57 -2
  2. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/README.md +56 -1
  3. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/datainputstream.py +31 -19
  4. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/e6data_grpc.py +61 -5
  5. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1/e6data_python_connector.egg-info}/PKG-INFO +57 -2
  6. {e6data_python_connector-2.3.11rc2/e6data_python_connector → e6data_python_connector-2.3.12rc1/gen-py}/e6x_vector/ttypes.py +26 -2
  7. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/setup.py +1 -1
  8. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/LICENSE +0 -0
  9. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/MANIFEST.in +0 -0
  10. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/__init__.py +0 -0
  11. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/cluster_manager.py +0 -0
  12. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/cluster_server/__init__.py +0 -0
  13. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/cluster_server/cluster_pb2.py +0 -0
  14. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/cluster_server/cluster_pb2_grpc.py +0 -0
  15. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/common.py +0 -0
  16. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/connection_pool.py +0 -0
  17. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/constants.py +0 -0
  18. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/date_time_utils.py +0 -0
  19. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/dialect.py +0 -0
  20. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/e6x_vector/__init__.py +0 -0
  21. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/e6x_vector/constants.py +0 -0
  22. {e6data_python_connector-2.3.11rc2/gen-py → e6data_python_connector-2.3.12rc1/e6data_python_connector}/e6x_vector/ttypes.py +0 -0
  23. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/exceptions.py +0 -0
  24. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/server/QueryEngineService.py +0 -0
  25. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/server/__init__.py +0 -0
  26. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/server/constants.py +0 -0
  27. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/server/e6x_engine_pb2.py +0 -0
  28. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/server/e6x_engine_pb2.pyi +0 -0
  29. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/server/e6x_engine_pb2_grpc.py +0 -0
  30. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/server/ttypes.py +0 -0
  31. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/strategy.py +0 -0
  32. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector/typeId.py +0 -0
  33. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector.egg-info/SOURCES.txt +0 -0
  34. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector.egg-info/dependency_links.txt +0 -0
  35. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector.egg-info/entry_points.txt +0 -0
  36. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector.egg-info/requires.txt +0 -0
  37. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/e6data_python_connector.egg-info/top_level.txt +0 -0
  38. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/gen-py/__init__.py +0 -0
  39. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/gen-py/e6x_vector/__init__.py +0 -0
  40. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/gen-py/e6x_vector/constants.py +0 -0
  41. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/pyproject.toml +0 -0
  42. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/setup.cfg +0 -0
  43. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/__init__.py +0 -0
  44. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/analyze_38_nines.py +0 -0
  45. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/analyze_all_cases.py +0 -0
  46. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/analyze_binary.py +0 -0
  47. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/analyze_correct_value.py +0 -0
  48. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/analyze_fields.py +0 -0
  49. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/check_decimal_errors.py +0 -0
  50. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/cleanup_test_files.py +0 -0
  51. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/debug_38_nines.py +0 -0
  52. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/debug_binary.py +0 -0
  53. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/final_test.py +0 -0
  54. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/move_tests.py +0 -0
  55. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/quick_test.py +0 -0
  56. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_38_nines.py +0 -0
  57. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_all_decimal128_cases.py +0 -0
  58. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_cluster_manager_efficiency.py +0 -0
  59. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_cluster_manager_none_strategy.py +0 -0
  60. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_cluster_manager_strategy.py +0 -0
  61. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_comprehensive.py +0 -0
  62. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_connection_pool.py +0 -0
  63. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_connection_pool_e2e.py +0 -0
  64. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_current_implementation.py +0 -0
  65. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_decimal128_binary_parsing.py +0 -0
  66. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_decimal128_parsing.py +0 -0
  67. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_fix.py +0 -0
  68. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_improved_parsing.py +0 -0
  69. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_known_case.py +0 -0
  70. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_manual_analysis.py +0 -0
  71. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_mock_server.py +0 -0
  72. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_multiprocessing_fix.py +0 -0
  73. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_new_implementation.py +0 -0
  74. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_pool_concurrency_simple.py +0 -0
  75. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_pool_threading_multiprocessing.py +0 -0
  76. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_simple_connection_pool.py +0 -0
  77. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_specific_binary.py +0 -0
  78. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_strategy.py +0 -0
  79. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_strategy_logic.py +0 -0
  80. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_strategy_persistence_fix.py +0 -0
  81. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_strategy_sharing_fix.py +0 -0
  82. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/test_user_binary_value.py +0 -0
  83. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/tests.py +0 -0
  84. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/tests_grpc.py +0 -0
  85. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/validate_decimal128.py +0 -0
  86. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/test/validate_implementation.py +0 -0
  87. {e6data_python_connector-2.3.11rc2 → e6data_python_connector-2.3.12rc1}/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.11rc2
3
+ Version: 2.3.12rc1
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.
@@ -39,7 +39,7 @@ Dynamic: summary
39
39
 
40
40
  # e6data Python Connector
41
41
 
42
- ![version](https://img.shields.io/badge/version-2.3.11rc2-blue.svg)
42
+ ![version](https://img.shields.io/badge/version-2.3.12rc1-blue.svg)
43
43
 
44
44
  ## Introduction
45
45
 
@@ -124,6 +124,7 @@ The `Connection` class supports the following parameters:
124
124
  | `secure` | bool | No | False | Enable SSL/TLS for secure connections |
125
125
  | `auto_resume` | bool | No | True | Automatically resume cluster if suspended |
126
126
  | `grpc_options` | dict | No | None | Additional gRPC configuration options |
127
+ | `debug` | bool | No | False | Enable debug logging for troubleshooting |
127
128
 
128
129
  #### Secure Connection Example
129
130
 
@@ -637,4 +638,58 @@ conn.close()
637
638
  - Graceful connection recovery and retry logic
638
639
  - Blue-green deployment support with automatic failover
639
640
 
641
+ ## Debugging and Troubleshooting
642
+
643
+ ### Enable Debug Mode
644
+
645
+ Enable comprehensive debugging to troubleshoot connection and query issues:
646
+
647
+ ```python
648
+ from e6data_python_connector import Connection
649
+
650
+ conn = Connection(
651
+ host=host,
652
+ port=port,
653
+ username=username,
654
+ password=password,
655
+ database=database,
656
+ debug=True # Enable debug logging
657
+ )
658
+ ```
659
+
660
+ When `debug=True`, the following features are enabled:
661
+ - Python logging at DEBUG level for all operations
662
+ - Blue-green strategy transition logging
663
+ - Connection lifecycle logging
664
+ - Query execution detailed logging
665
+
666
+ ### gRPC Network Tracing
667
+
668
+ For low-level gRPC network debugging (HTTP/2 frames, TCP events), set environment variables **before** running your Python script:
669
+
670
+ ```bash
671
+ # Enable gRPC network tracing
672
+ export GRPC_VERBOSITY=DEBUG
673
+ export GRPC_TRACE=client_channel,http2
674
+
675
+ # For comprehensive tracing
676
+ export GRPC_TRACE=api,call_error,channel,client_channel,connectivity_state,http,http2_stream,tcp,transport_security
677
+
678
+ # Run your script
679
+ python your_script.py
680
+ ```
681
+
682
+ **Note**: These environment variables must be set before Python starts, as the gRPC C++ core reads them at module import time.
683
+
684
+ ### Common Issues and Solutions
685
+
686
+ | Issue | Solution |
687
+ |-------|----------|
688
+ | Connection timeout | Check network connectivity, firewall rules, and ensure port 80/443 is open |
689
+ | Authentication failure | Verify username (email) and access token are correct |
690
+ | 503 Service Unavailable | Cluster may be suspended; enable `auto_resume=True` |
691
+ | 456 Strategy Error | Automatic blue-green failover will handle this |
692
+ | Memory issues with large results | Use `fetchall_buffer()` instead of `fetchall()` |
693
+ | gRPC message size errors | Configure `grpc_options` with appropriate message size limits |
694
+
640
695
  See [TECH_DOC.md](TECH_DOC.md) for detailed technical documentation.
@@ -1,6 +1,6 @@
1
1
  # e6data Python Connector
2
2
 
3
- ![version](https://img.shields.io/badge/version-2.3.11rc2-blue.svg)
3
+ ![version](https://img.shields.io/badge/version-2.3.12rc1-blue.svg)
4
4
 
5
5
  ## Introduction
6
6
 
@@ -85,6 +85,7 @@ The `Connection` class supports the following parameters:
85
85
  | `secure` | bool | No | False | Enable SSL/TLS for secure connections |
86
86
  | `auto_resume` | bool | No | True | Automatically resume cluster if suspended |
87
87
  | `grpc_options` | dict | No | None | Additional gRPC configuration options |
88
+ | `debug` | bool | No | False | Enable debug logging for troubleshooting |
88
89
 
89
90
  #### Secure Connection Example
90
91
 
@@ -598,4 +599,58 @@ conn.close()
598
599
  - Graceful connection recovery and retry logic
599
600
  - Blue-green deployment support with automatic failover
600
601
 
602
+ ## Debugging and Troubleshooting
603
+
604
+ ### Enable Debug Mode
605
+
606
+ Enable comprehensive debugging to troubleshoot connection and query issues:
607
+
608
+ ```python
609
+ from e6data_python_connector import Connection
610
+
611
+ conn = Connection(
612
+ host=host,
613
+ port=port,
614
+ username=username,
615
+ password=password,
616
+ database=database,
617
+ debug=True # Enable debug logging
618
+ )
619
+ ```
620
+
621
+ When `debug=True`, the following features are enabled:
622
+ - Python logging at DEBUG level for all operations
623
+ - Blue-green strategy transition logging
624
+ - Connection lifecycle logging
625
+ - Query execution detailed logging
626
+
627
+ ### gRPC Network Tracing
628
+
629
+ For low-level gRPC network debugging (HTTP/2 frames, TCP events), set environment variables **before** running your Python script:
630
+
631
+ ```bash
632
+ # Enable gRPC network tracing
633
+ export GRPC_VERBOSITY=DEBUG
634
+ export GRPC_TRACE=client_channel,http2
635
+
636
+ # For comprehensive tracing
637
+ export GRPC_TRACE=api,call_error,channel,client_channel,connectivity_state,http,http2_stream,tcp,transport_security
638
+
639
+ # Run your script
640
+ python your_script.py
641
+ ```
642
+
643
+ **Note**: These environment variables must be set before Python starts, as the gRPC C++ core reads them at module import time.
644
+
645
+ ### Common Issues and Solutions
646
+
647
+ | Issue | Solution |
648
+ |-------|----------|
649
+ | Connection timeout | Check network connectivity, firewall rules, and ensure port 80/443 is open |
650
+ | Authentication failure | Verify username (email) and access token are correct |
651
+ | 503 Service Unavailable | Cluster may be suspended; enable `auto_resume=True` |
652
+ | 456 Strategy Error | Automatic blue-green failover will handle this |
653
+ | Memory issues with large results | Use `fetchall_buffer()` instead of `fetchall()` |
654
+ | gRPC message size errors | Configure `grpc_options` with appropriate message size limits |
655
+
601
656
  See [TECH_DOC.md](TECH_DOC.md) for detailed technical documentation.
@@ -26,16 +26,18 @@ except ImportError:
26
26
  _logger = logging.getLogger(__name__)
27
27
 
28
28
 
29
- def _binary_to_decimal128(binary_data):
29
+ def _binary_to_decimal128(binary_data, scale=None):
30
30
  """
31
31
  Convert binary data to Decimal128.
32
-
32
+
33
33
  The binary data represents a 128-bit decimal number in IEEE 754-2008 Decimal128 format.
34
34
  Based on the Java implementation from e6data's JDBC driver.
35
-
35
+
36
36
  Args:
37
37
  binary_data (bytes): Binary representation of Decimal128
38
-
38
+ scale (int, optional): Scale parameter for decimal precision. If None,
39
+ attempts to decode from IEEE format or defaults to 0.
40
+
39
41
  Returns:
40
42
  Decimal: Python Decimal object
41
43
  """
@@ -59,7 +61,7 @@ def _binary_to_decimal128(binary_data):
59
61
 
60
62
  # Handle IEEE 754-2008 Decimal128 binary format
61
63
  if len(binary_data) == 16: # Decimal128 should be exactly 16 bytes
62
- return _decode_decimal128_binary_java_style(binary_data)
64
+ return _decode_decimal128_binary_java_style(binary_data, scale)
63
65
  else:
64
66
  _logger.warning(f"Invalid Decimal128 binary length: {len(binary_data)} bytes, expected 16")
65
67
  return Decimal('0')
@@ -73,16 +75,17 @@ def _binary_to_decimal128(binary_data):
73
75
  return Decimal('0')
74
76
 
75
77
 
76
- def _decode_decimal128_binary_java_style(binary_data):
78
+ def _decode_decimal128_binary_java_style(binary_data, scale=None):
77
79
  """
78
80
  Decode IEEE 754-2008 Decimal128 binary format following Java implementation.
79
-
81
+
80
82
  Based on the Java implementation from e6data's JDBC driver getFieldDataFromChunk method.
81
83
  This method follows the same logic as the Java BigDecimal creation from ByteBuffer.
82
-
84
+
83
85
  Args:
84
86
  binary_data (bytes): 16-byte binary representation
85
-
87
+ scale (int, optional): Scale parameter for decimal precision
88
+
86
89
  Returns:
87
90
  Decimal: Python Decimal object
88
91
  """
@@ -103,17 +106,21 @@ def _decode_decimal128_binary_java_style(binary_data):
103
106
  if big_int_value == 0:
104
107
  return Decimal('0')
105
108
 
106
- # The Java code creates BigDecimal from BigInteger with scale 0
107
- # This means we treat the integer value as the unscaled value
108
- # However, for Decimal128, we need to handle the scaling properly
109
-
110
- # Try to create decimal directly from the integer value
111
- decimal_value = Decimal(big_int_value)
109
+ # The Java code creates BigDecimal from BigInteger with the provided scale
110
+ # If scale is provided, use it to create the properly scaled decimal
111
+ if scale is not None:
112
+ # Create decimal with the specified scale (like Java's BigDecimal constructor)
113
+ # This treats big_int_value as the unscaled value
114
+ decimal_value = Decimal(big_int_value) / (Decimal(10) ** scale)
115
+ else:
116
+ # Fallback: try to create decimal directly from the integer value
117
+ decimal_value = Decimal(big_int_value)
112
118
 
113
119
  # Check if this produces a reasonable decimal value
114
120
  # Decimal128 should represent normal decimal numbers
115
- if abs(decimal_value) < Decimal('1E-6143') or abs(decimal_value) > Decimal(
116
- '9.999999999999999999999999999999999E+6144'):
121
+ # Only check range if scale was not provided (backward compatibility)
122
+ if scale is None and (abs(decimal_value) < Decimal('1E-6143') or abs(decimal_value) > Decimal(
123
+ '9.999999999999999999999999999999999E+6144')):
117
124
  # Value is outside normal Decimal128 range, try alternative interpretation
118
125
  return _decode_decimal128_alternative(binary_data)
119
126
 
@@ -624,10 +631,12 @@ def get_column_from_chunk(vector: Vector) -> list:
624
631
  if vector.isConstantVector:
625
632
  # For constant vectors, get the binary data and convert it once
626
633
  binary_data = vector.data.numericDecimal128ConstantData.data
634
+ # Get scale with backward compatibility for older engines
635
+ scale = getattr(vector.data.numericDecimal128ConstantData, 'scale', None)
627
636
 
628
637
  # Convert binary data to BigDecimal equivalent
629
638
  if binary_data:
630
- decimal_value = _binary_to_decimal128(binary_data)
639
+ decimal_value = _binary_to_decimal128(binary_data, scale)
631
640
  else:
632
641
  decimal_value = Decimal('0')
633
642
 
@@ -639,13 +648,16 @@ def get_column_from_chunk(vector: Vector) -> list:
639
648
  value_array.append(decimal_value)
640
649
  else:
641
650
  # For non-constant vectors, process each row individually
651
+ # Get scale from decimal128Data (with backward compatibility)
652
+ scale = getattr(vector.data.decimal128Data, 'scale', None)
653
+
642
654
  for row in range(vector.size):
643
655
  if get_null(vector, row):
644
656
  value_array.append(None)
645
657
  continue
646
658
  # Get binary data for this row
647
659
  binary_data = vector.data.decimal128Data.data[row]
648
- decimal_value = _binary_to_decimal128(binary_data)
660
+ decimal_value = _binary_to_decimal128(binary_data, scale)
649
661
  value_array.append(decimal_value)
650
662
  else:
651
663
  value_array.append(None)
@@ -8,6 +8,8 @@ from __future__ import unicode_literals
8
8
 
9
9
  import datetime
10
10
  import logging
11
+ import os
12
+
11
13
  import re
12
14
  import sys
13
15
  import time
@@ -386,6 +388,7 @@ class Connection(object):
386
388
  self._auto_resume = auto_resume
387
389
 
388
390
  self._grpc_options = grpc_options
391
+
389
392
  if self._grpc_options is None:
390
393
  self._grpc_options = dict()
391
394
  self.grpc_prepare_timeout = self._grpc_options.get('grpc_prepare_timeout') or 10 * 60 # 10 minutes
@@ -395,13 +398,64 @@ class Connection(object):
395
398
  The default maximum time on client side to wait for the cluster to resume is 5 minutes.
396
399
  """
397
400
  self.grpc_auto_resume_timeout_seconds = self._grpc_options.pop('grpc_auto_resume_timeout_seconds')
398
-
401
+
402
+ self.timeout = 500
403
+ if 'timeout' in self._grpc_options:
404
+ """
405
+ The default maximum time on client side to wait for the cluster to resume is 5 minutes.
406
+ """
407
+ self.timeout = self._grpc_options.pop('timeout')
408
+
409
+
399
410
  # Store debug flag and register with debug connections
400
411
  self._debug = debug
401
412
  if self._debug:
402
413
  _debug_connections.add(id(self))
414
+
415
+ # Enable comprehensive debugging if debug flag is set
416
+ if self._debug:
417
+ # Configure root logger for DEBUG level
418
+ logging.basicConfig(
419
+ level=logging.DEBUG,
420
+ format='[%(name)s] %(asctime)s - %(levelname)s - %(message)s',
421
+ datefmt='%Y-%m-%d %H:%M:%S',
422
+ force=True # Force reconfiguration even if logging is already configured
423
+ )
424
+
425
+ # Note: gRPC C++ core tracing (GRPC_VERBOSITY and GRPC_TRACE) must be set
426
+ # BEFORE the gRPC module is imported to take effect. Setting them at runtime
427
+ # will not enable HTTP/2 frame logs or low-level tracing.
428
+ #
429
+ # To enable full gRPC network tracing, set these environment variables
430
+ # before starting your Python script:
431
+ # export GRPC_VERBOSITY=DEBUG
432
+ # export GRPC_TRACE=client_channel,http2
433
+ #
434
+ # The following runtime settings only affect Python-level logging:
435
+
436
+ # Enable gRPC Python logging (this works at runtime)
437
+ os.environ['GRPC_PYTHON_LOG_LEVEL'] = 'DEBUG'
438
+ os.environ['GRPC_PYTHON_LOG_STDERR'] = '1'
439
+
440
+ # Ensure gRPC logger is at DEBUG level
441
+ grpc_logger = logging.getLogger('grpc')
442
+ grpc_logger.setLevel(logging.DEBUG)
443
+
444
+ # Enable gRPC transport logger
445
+ grpc_transport_logger = logging.getLogger('grpc._channel')
446
+ grpc_transport_logger.setLevel(logging.DEBUG)
447
+
448
+ # Enable gRPC server logger
449
+ grpc_server_logger = logging.getLogger('grpc._server')
450
+ grpc_server_logger.setLevel(logging.DEBUG)
451
+
452
+ # Set e6data connector logger to DEBUG
453
+ e6data_logger = logging.getLogger('e6data_python_connector')
454
+ e6data_logger.setLevel(logging.DEBUG)
455
+
403
456
  _strategy_debug_log(f"Debug mode enabled for connection {id(self)}")
404
-
457
+ _strategy_debug_log(f"GRPC_TRACE={os.environ.get('GRPC_TRACE')}")
458
+
405
459
  self._create_client()
406
460
 
407
461
  @property
@@ -453,6 +507,7 @@ class Connection(object):
453
507
  Raises:
454
508
  grpc.RpcError: If there is an error in creating the gRPC channel or client stub.
455
509
  """
510
+
456
511
  if self._secure_channel:
457
512
  self._channel = grpc.secure_channel(
458
513
  target='{}:{}'.format(self._host, self._port),
@@ -577,7 +632,7 @@ class Connection(object):
577
632
  _strategy_debug_log(f"No cached strategy, will try strategies in order: {strategies}")
578
633
  last_error = None
579
634
  for strategy in strategies:
580
- _strategy_debug_log(f"1Attempting authentication with strategy: {strategy}")
635
+ _strategy_debug_log(f"Attempting authentication with strategy: {strategy}.")
581
636
  try:
582
637
  authenticate_response = self._client.authenticate(
583
638
  authenticate_request,
@@ -1397,13 +1452,14 @@ class Cursor(DBAPICursor):
1397
1452
  get_next_result_batch_request = e6x_engine_pb2.GetNextResultBatchRequest(
1398
1453
  engineIP=self._engine_ip,
1399
1454
  sessionId=self.connection.get_session_id,
1400
- queryId=self._query_id
1455
+ queryId=self._query_id,
1401
1456
  )
1402
1457
  # Get fresh client after session access (may have been invalidated)
1403
1458
  client = self.connection.client
1404
1459
  get_next_result_batch_response = client.getNextResultBatch(
1405
1460
  get_next_result_batch_request,
1406
- metadata=self.metadata
1461
+ metadata=self.metadata,
1462
+ timeout=self.connection.timeout
1407
1463
  )
1408
1464
 
1409
1465
  # Check for new strategy in batch response
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: e6data-python-connector
3
- Version: 2.3.11rc2
3
+ Version: 2.3.12rc1
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.
@@ -39,7 +39,7 @@ Dynamic: summary
39
39
 
40
40
  # e6data Python Connector
41
41
 
42
- ![version](https://img.shields.io/badge/version-2.3.11rc2-blue.svg)
42
+ ![version](https://img.shields.io/badge/version-2.3.12rc1-blue.svg)
43
43
 
44
44
  ## Introduction
45
45
 
@@ -124,6 +124,7 @@ The `Connection` class supports the following parameters:
124
124
  | `secure` | bool | No | False | Enable SSL/TLS for secure connections |
125
125
  | `auto_resume` | bool | No | True | Automatically resume cluster if suspended |
126
126
  | `grpc_options` | dict | No | None | Additional gRPC configuration options |
127
+ | `debug` | bool | No | False | Enable debug logging for troubleshooting |
127
128
 
128
129
  #### Secure Connection Example
129
130
 
@@ -637,4 +638,58 @@ conn.close()
637
638
  - Graceful connection recovery and retry logic
638
639
  - Blue-green deployment support with automatic failover
639
640
 
641
+ ## Debugging and Troubleshooting
642
+
643
+ ### Enable Debug Mode
644
+
645
+ Enable comprehensive debugging to troubleshoot connection and query issues:
646
+
647
+ ```python
648
+ from e6data_python_connector import Connection
649
+
650
+ conn = Connection(
651
+ host=host,
652
+ port=port,
653
+ username=username,
654
+ password=password,
655
+ database=database,
656
+ debug=True # Enable debug logging
657
+ )
658
+ ```
659
+
660
+ When `debug=True`, the following features are enabled:
661
+ - Python logging at DEBUG level for all operations
662
+ - Blue-green strategy transition logging
663
+ - Connection lifecycle logging
664
+ - Query execution detailed logging
665
+
666
+ ### gRPC Network Tracing
667
+
668
+ For low-level gRPC network debugging (HTTP/2 frames, TCP events), set environment variables **before** running your Python script:
669
+
670
+ ```bash
671
+ # Enable gRPC network tracing
672
+ export GRPC_VERBOSITY=DEBUG
673
+ export GRPC_TRACE=client_channel,http2
674
+
675
+ # For comprehensive tracing
676
+ export GRPC_TRACE=api,call_error,channel,client_channel,connectivity_state,http,http2_stream,tcp,transport_security
677
+
678
+ # Run your script
679
+ python your_script.py
680
+ ```
681
+
682
+ **Note**: These environment variables must be set before Python starts, as the gRPC C++ core reads them at module import time.
683
+
684
+ ### Common Issues and Solutions
685
+
686
+ | Issue | Solution |
687
+ |-------|----------|
688
+ | Connection timeout | Check network connectivity, firewall rules, and ensure port 80/443 is open |
689
+ | Authentication failure | Verify username (email) and access token are correct |
690
+ | 503 Service Unavailable | Cluster may be suspended; enable `auto_resume=True` |
691
+ | 456 Strategy Error | Automatic blue-green failover will handle this |
692
+ | Memory issues with large results | Use `fetchall_buffer()` instead of `fetchall()` |
693
+ | gRPC message size errors | Configure `grpc_options` with appropriate message size limits |
694
+
640
695
  See [TECH_DOC.md](TECH_DOC.md) for detailed technical documentation.
@@ -881,13 +881,15 @@ class Decimal128Data(object):
881
881
  """
882
882
  Attributes:
883
883
  - data
884
+ - scale
884
885
 
885
886
  """
886
887
  thrift_spec = None
887
888
 
888
889
 
889
- def __init__(self, data = None,):
890
+ def __init__(self, data = None, scale = None,):
890
891
  self.data = data
892
+ self.scale = scale
891
893
 
892
894
  def read(self, iprot):
893
895
  if iprot._fast_decode is not None and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None:
@@ -908,6 +910,11 @@ class Decimal128Data(object):
908
910
  iprot.readListEnd()
909
911
  else:
910
912
  iprot.skip(ftype)
913
+ elif fid == 2:
914
+ if ftype == TType.I32:
915
+ self.scale = iprot.readI32()
916
+ else:
917
+ iprot.skip(ftype)
911
918
  else:
912
919
  iprot.skip(ftype)
913
920
  iprot.readFieldEnd()
@@ -926,6 +933,10 @@ class Decimal128Data(object):
926
933
  oprot.writeBinary(iter55)
927
934
  oprot.writeListEnd()
928
935
  oprot.writeFieldEnd()
936
+ if self.scale is not None:
937
+ oprot.writeFieldBegin('scale', TType.I32, 2)
938
+ oprot.writeI32(self.scale)
939
+ oprot.writeFieldEnd()
929
940
  oprot.writeFieldStop()
930
941
  oprot.writeStructEnd()
931
942
 
@@ -1310,13 +1321,15 @@ class NumericDecimal128ConstantData(object):
1310
1321
  """
1311
1322
  Attributes:
1312
1323
  - data
1324
+ - scale
1313
1325
 
1314
1326
  """
1315
1327
  thrift_spec = None
1316
1328
 
1317
1329
 
1318
- def __init__(self, data = None,):
1330
+ def __init__(self, data = None, scale = None,):
1319
1331
  self.data = data
1332
+ self.scale = scale
1320
1333
 
1321
1334
  def read(self, iprot):
1322
1335
  if iprot._fast_decode is not None and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None:
@@ -1332,6 +1345,11 @@ class NumericDecimal128ConstantData(object):
1332
1345
  self.data = iprot.readBinary()
1333
1346
  else:
1334
1347
  iprot.skip(ftype)
1348
+ elif fid == 2:
1349
+ if ftype == TType.I32:
1350
+ self.scale = iprot.readI32()
1351
+ else:
1352
+ iprot.skip(ftype)
1335
1353
  else:
1336
1354
  iprot.skip(ftype)
1337
1355
  iprot.readFieldEnd()
@@ -1347,6 +1365,10 @@ class NumericDecimal128ConstantData(object):
1347
1365
  oprot.writeFieldBegin('data', TType.STRING, 1)
1348
1366
  oprot.writeBinary(self.data)
1349
1367
  oprot.writeFieldEnd()
1368
+ if self.scale is not None:
1369
+ oprot.writeFieldBegin('scale', TType.I32, 2)
1370
+ oprot.writeI32(self.scale)
1371
+ oprot.writeFieldEnd()
1350
1372
  oprot.writeFieldStop()
1351
1373
  oprot.writeStructEnd()
1352
1374
 
@@ -1783,6 +1805,7 @@ all_structs.append(Decimal128Data)
1783
1805
  Decimal128Data.thrift_spec = (
1784
1806
  None, # 0
1785
1807
  (1, TType.LIST, 'data', (TType.STRING, 'BINARY', False), None, ), # 1
1808
+ (2, TType.I32, 'scale', None, None, ), # 2
1786
1809
  )
1787
1810
  all_structs.append(VarcharData)
1788
1811
  VarcharData.thrift_spec = (
@@ -1818,6 +1841,7 @@ all_structs.append(NumericDecimal128ConstantData)
1818
1841
  NumericDecimal128ConstantData.thrift_spec = (
1819
1842
  None, # 0
1820
1843
  (1, TType.STRING, 'data', 'BINARY', None, ), # 1
1844
+ (2, TType.I32, 'scale', None, None, ), # 2
1821
1845
  )
1822
1846
  all_structs.append(TemporalIntervalConstantData)
1823
1847
  TemporalIntervalConstantData.thrift_spec = (
@@ -12,7 +12,7 @@
12
12
 
13
13
  import setuptools
14
14
 
15
- VERSION = (2, 3, 11, 'rc2')
15
+ VERSION = (2, 3, 12, 'rc1',)
16
16
 
17
17
 
18
18
  def get_long_desc():