iris-pgwire 1.2.31__tar.gz → 1.2.33__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 (111) hide show
  1. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/PKG-INFO +1 -1
  2. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/__init__.py +1 -1
  3. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/dbapi_connection_pool.py +2 -2
  4. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/dbapi_executor.py +38 -3
  5. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/iris_executor.py +35 -1
  6. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/models/dbapi_connection.py +19 -0
  7. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/.gitignore +0 -0
  8. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/CHANGELOG.md +0 -0
  9. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/LICENSE +0 -0
  10. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/README.md +0 -0
  11. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/docs/VECTOR_PARAMETER_BINDING.md +0 -0
  12. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/examples/BI_TOOLS_SETUP.md +0 -0
  13. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/examples/async_sqlalchemy_demo.py +0 -0
  14. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/examples/bi_tools_demo.py +0 -0
  15. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/examples/client_demonstrations.py +0 -0
  16. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/examples/client_demos.py +0 -0
  17. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/examples/translation_api_demo.py +0 -0
  18. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/pyproject.toml +0 -0
  19. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/auth/__init__.py +0 -0
  20. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/auth/auth_selector.py +0 -0
  21. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/auth/gssapi_auth.py +0 -0
  22. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/auth/oauth_bridge.py +0 -0
  23. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/auth/scram.py +0 -0
  24. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/auth/wallet_credentials.py +0 -0
  25. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/backend_selector.py +0 -0
  26. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/bulk_executor.py +0 -0
  27. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/catalog/__init__.py +0 -0
  28. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/catalog/catalog_functions.py +0 -0
  29. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/catalog/catalog_router.py +0 -0
  30. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/catalog/oid_generator.py +0 -0
  31. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/catalog/pg_attrdef.py +0 -0
  32. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/catalog/pg_attribute.py +0 -0
  33. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/catalog/pg_class.py +0 -0
  34. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/catalog/pg_constraint.py +0 -0
  35. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/catalog/pg_index.py +0 -0
  36. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/catalog/pg_namespace.py +0 -0
  37. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/catalog/pg_type.py +0 -0
  38. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/column_validator.py +0 -0
  39. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/config_schema.py +0 -0
  40. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/constitutional.py +0 -0
  41. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/conversions/__init__.py +0 -0
  42. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/conversions/bulk_insert.py +0 -0
  43. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/conversions/date_horolog.py +0 -0
  44. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/conversions/ddl_idempotency.py +0 -0
  45. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/conversions/ddl_splitter.py +0 -0
  46. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/conversions/json_path.py +0 -0
  47. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/conversions/vector_syntax.py +0 -0
  48. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/copy_handler.py +0 -0
  49. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/csv_processor.py +0 -0
  50. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/debug_tracer.py +0 -0
  51. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/health_checker.py +0 -0
  52. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/integratedml.py +0 -0
  53. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/iris_constructs.py +0 -0
  54. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/iris_log_handler.py +0 -0
  55. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/iris_user_management.py +0 -0
  56. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/models/__init__.py +0 -0
  57. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/models/backend_config.py +0 -0
  58. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/models/connection_pool_state.py +0 -0
  59. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/models/ipm_metadata.py +0 -0
  60. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/models/vector_query_request.py +0 -0
  61. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/observability.py +0 -0
  62. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/performance_monitor.py +0 -0
  63. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/protocol.py +0 -0
  64. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/quality/__init__.py +0 -0
  65. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/quality/__main__.py +0 -0
  66. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/quality/code_quality_validator.py +0 -0
  67. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/quality/documentation_validator.py +0 -0
  68. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/quality/package_metadata_validator.py +0 -0
  69. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/quality/security_validator.py +0 -0
  70. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/quality/validator.py +0 -0
  71. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/schema_mapper.py +0 -0
  72. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/server.py +0 -0
  73. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/__init__.py +0 -0
  74. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/alias_extractor.py +0 -0
  75. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/api.py +0 -0
  76. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/boolean_translator.py +0 -0
  77. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/cache.py +0 -0
  78. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/confidence_analyzer.py +0 -0
  79. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/config.py +0 -0
  80. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/copy_parser.py +0 -0
  81. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/date_translator.py +0 -0
  82. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/debug.py +0 -0
  83. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/default_values.py +0 -0
  84. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/enum_registry.py +0 -0
  85. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/enum_translator.py +0 -0
  86. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/error_handler.py +0 -0
  87. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/identifier_normalizer.py +0 -0
  88. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/interceptor.py +0 -0
  89. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/logging_config.py +0 -0
  90. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/mappings/__init__.py +0 -0
  91. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/mappings/constructs.py +0 -0
  92. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/mappings/datatypes.py +0 -0
  93. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/mappings/document_filters.py +0 -0
  94. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/mappings/functions.py +0 -0
  95. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/metrics.py +0 -0
  96. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/models.py +0 -0
  97. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/normalizer.py +0 -0
  98. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/parser.py +0 -0
  99. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/performance_monitor.py +0 -0
  100. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/pipeline.py +0 -0
  101. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/refiner.py +0 -0
  102. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/skipped_table_set.py +0 -0
  103. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/statement_filter.py +0 -0
  104. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/transaction_translator.py +0 -0
  105. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/translator.py +0 -0
  106. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/sql_translator/validator.py +0 -0
  107. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/testing/__init__.py +0 -0
  108. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/testing/base_fixture_builder.py +0 -0
  109. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/type_mapping.py +0 -0
  110. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/vector_metrics.py +0 -0
  111. {iris_pgwire-1.2.31 → iris_pgwire-1.2.33}/src/iris_pgwire/vector_optimizer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iris-pgwire
3
- Version: 1.2.31
3
+ Version: 1.2.33
4
4
  Summary: PostgreSQL Wire Protocol Server for InterSystems IRIS - Connect BI tools, Python frameworks, and PostgreSQL clients to IRIS databases
5
5
  Project-URL: Homepage, https://github.com/intersystems-community/iris-pgwire
6
6
  Project-URL: Documentation, https://github.com/intersystems-community/iris-pgwire#readme
@@ -6,7 +6,7 @@ Based on the specification from docs/iris_pgwire_plan.md and proven patterns fro
6
6
  caretdev/sqlalchemy-iris.
7
7
  """
8
8
 
9
- __version__ = "1.2.31"
9
+ __version__ = "1.2.33"
10
10
  __author__ = "Thomas Dyar <thomas.dyar@intersystems.com>"
11
11
 
12
12
  # Don't import server/protocol in __init__ to avoid sys.modules conflicts
@@ -339,9 +339,9 @@ class IRISConnectionPool:
339
339
  self._total_created += 1
340
340
 
341
341
  logger.info(
342
- "Removing idle overflow connection",
342
+ "Created new IRIS connection",
343
343
  connection_id=conn_wrapper.connection_id,
344
- idle_seconds=round(conn_wrapper.idle_seconds, 1),
344
+ idle_seconds=round(getattr(conn_wrapper, "idle_seconds", 0.0), 1),
345
345
  )
346
346
 
347
347
  return conn_wrapper
@@ -87,6 +87,35 @@ class DBAPIExecutor:
87
87
  """
88
88
  return re.sub(r"\$\d+", "?", sql)
89
89
 
90
+ def _convert_params_for_iris(self, params: Any) -> Any:
91
+ """
92
+ Convert parameters to IRIS-compatible formats.
93
+ Specifically handles ISO 8601 timestamps.
94
+ """
95
+ if params is None:
96
+ return None
97
+
98
+ if isinstance(params, (list, tuple)):
99
+ return [self._convert_value_for_iris(v) for v in params]
100
+
101
+ return self._convert_value_for_iris(params)
102
+
103
+ def _convert_value_for_iris(self, value: Any) -> Any:
104
+ """Helper to convert a single value."""
105
+ if isinstance(value, str):
106
+ # FR-004: Normalize ISO 8601 timestamp strings for IRIS
107
+ # Handles: YYYY-MM-DD[T ]HH:MM:SS[.fff][Z|[+-]HH:MM]
108
+ # IRIS rejects the 'T' and 'Z' or offset in %PosixTime/TIMESTAMP
109
+ import re
110
+
111
+ ts_match = re.match(
112
+ r"^(\d{4}-\d{2}-\d{2})[T ](\d{2}:\d{2}:\d{2}(?:\.\d+)?)(?:Z|[+-]\d{2}:?(\d{2})?)?$",
113
+ value,
114
+ )
115
+ if ts_match:
116
+ return f"{ts_match.group(1)} {ts_match.group(2)}"
117
+ return value
118
+
90
119
  async def execute_query(
91
120
  self, sql: str, params: tuple | None = None, session_id: str | None = None, **kwargs
92
121
  ) -> dict[str, Any]:
@@ -116,6 +145,9 @@ class DBAPIExecutor:
116
145
  # Translate placeholders ($1 -> ?)
117
146
  sql = self._translate_placeholders(sql)
118
147
 
148
+ # Convert parameters for IRIS (e.g., ISO 8601 timestamps)
149
+ converted_params = self._convert_params_for_iris(params)
150
+
119
151
  # Acquire connection from pool
120
152
  conn_wrapper = await self.pool.acquire()
121
153
 
@@ -134,8 +166,8 @@ class DBAPIExecutor:
134
166
  # For now, we log it.
135
167
  logger.debug(f"Session {session_id} using namespace {ns}")
136
168
 
137
- if params:
138
- cursor.execute(clean_sql, params)
169
+ if converted_params:
170
+ cursor.execute(clean_sql, converted_params)
139
171
  else:
140
172
  cursor.execute(clean_sql)
141
173
 
@@ -256,9 +288,12 @@ class DBAPIExecutor:
256
288
  # Pre-process parameters (e.g. convert lists to IRIS vector strings)
257
289
  final_params_list = []
258
290
  for p_set in params_list:
291
+ # Convert ISO 8601 timestamps and other formats
292
+ converted_p_set = self._convert_params_for_iris(p_set)
293
+
259
294
  processed_params = [
260
295
  "[" + ",".join(map(str, p)) + "]" if isinstance(p, list) else p
261
- for p in p_set
296
+ for p in converted_p_set
262
297
  ]
263
298
  final_params_list.append(tuple(processed_params))
264
299
 
@@ -1211,11 +1211,14 @@ class IRISExecutor:
1211
1211
 
1212
1212
  rows_affected = 0
1213
1213
  for row_params in params_list:
1214
+ # Normalize parameters for IRIS (e.g. ISO timestamps)
1215
+ normalized_row_params = self._normalize_parameters(row_params)
1216
+
1214
1217
  inline_sql = "N/A"
1215
1218
  try:
1216
1219
  # Build inline SQL by replacing ? placeholders with actual values
1217
1220
  inline_sql = normalized_sql
1218
- for param_value in row_params:
1221
+ for param_value in normalized_row_params:
1219
1222
  # Convert value to SQL literal
1220
1223
  if param_value is None:
1221
1224
  sql_literal = "NULL"
@@ -4384,3 +4387,34 @@ class IRISExecutor:
4384
4387
  except Exception as e:
4385
4388
  logger.warning("Vector query translation failed", error=str(e), sql=sql[:100])
4386
4389
  return sql # Return original if translation fails
4390
+
4391
+ def _convert_params_for_iris(self, params: Any) -> Any:
4392
+ """
4393
+ Convert parameters to IRIS-compatible formats.
4394
+ Specifically handles ISO 8601 timestamps.
4395
+ """
4396
+ if params is None:
4397
+ return None
4398
+
4399
+ if isinstance(params, (list, tuple)):
4400
+ return [self._convert_value_for_iris(v) for v in params]
4401
+
4402
+ return self._convert_value_for_iris(params)
4403
+
4404
+ def _convert_value_for_iris(self, value: Any) -> Any:
4405
+ """Helper to convert a single value."""
4406
+ if isinstance(value, str):
4407
+ # Check for ISO 8601 timestamp: 2026-01-29T21:27:38.111Z
4408
+ # or 2026-01-29T21:27:38.111+00:00
4409
+ # IRIS rejects the 'T' and 'Z' or offset in %PosixTime/TIMESTAMP
4410
+ if len(value) >= 19 and value[10] == "T":
4411
+ # Replace 'T' with space
4412
+ converted = value.replace("T", " ")
4413
+ # Remove 'Z' if present
4414
+ if converted.endswith("Z"):
4415
+ converted = converted[:-1]
4416
+ # Remove timezone offset if present (e.g., +00:00)
4417
+ if "+" in converted:
4418
+ converted = converted.split("+")[0]
4419
+ return converted
4420
+ return value
@@ -79,6 +79,7 @@ class DBAPIConnection(BaseModel):
79
79
  pool_recycle_seconds: int = Field(
80
80
  ge=60, description="Maximum connection lifetime before recycling"
81
81
  )
82
+ is_overflow: bool = Field(default=False, description="Whether this is an overflow connection")
82
83
 
83
84
  # Pydantic v2 configuration
84
85
  model_config = ConfigDict(
@@ -101,10 +102,28 @@ class DBAPIConnection(BaseModel):
101
102
  "iris_port": 1972,
102
103
  "iris_namespace": "USER",
103
104
  "pool_recycle_seconds": 3600,
105
+ "is_overflow": False,
104
106
  }
105
107
  },
106
108
  )
107
109
 
110
+ @property
111
+ def idle_seconds(self) -> float:
112
+ """
113
+ Calculate connection idle time in seconds.
114
+
115
+ Returns:
116
+ Seconds since last usage, or since creation if never used.
117
+ """
118
+ reference_time = self.last_used_at or self.created_at
119
+ now = datetime.now(UTC)
120
+
121
+ if now < reference_time:
122
+ # Handle potential clock skew
123
+ return 0.0
124
+
125
+ return (now - reference_time).total_seconds()
126
+
108
127
  def age_seconds(self) -> float:
109
128
  """
110
129
  Calculate connection age in seconds.
File without changes
File without changes
File without changes
File without changes