iris-pgwire 1.7.2__tar.gz → 1.7.3__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 (133) hide show
  1. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/PKG-INFO +1 -1
  2. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/__init__.py +1 -1
  3. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/conversions/ddl_idempotency.py +4 -1
  4. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/conversions/vector_syntax.py +4 -2
  5. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/iris_executor.py +22 -7
  6. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/protocol.py +7 -1
  7. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/mappings/constructs.py +3 -2
  8. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/vector_optimizer.py +4 -1
  9. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/.gitignore +0 -0
  10. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/LICENSE +0 -0
  11. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/README.md +0 -0
  12. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/pyproject.toml +0 -0
  13. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/_column_naming.py +0 -0
  14. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/_noop_cursor.py +0 -0
  15. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/_result_processing.py +0 -0
  16. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/_type_mapping.py +0 -0
  17. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/auth/__init__.py +0 -0
  18. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/auth/auth_selector.py +0 -0
  19. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/auth/gssapi_auth.py +0 -0
  20. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/auth/oauth_bridge.py +0 -0
  21. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/auth/scram.py +0 -0
  22. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/auth/wallet_credentials.py +0 -0
  23. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/backend_selector.py +0 -0
  24. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/bulk_executor.py +0 -0
  25. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/catalog/__init__.py +0 -0
  26. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/catalog/_reentrancy.py +0 -0
  27. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/catalog/catalog_functions.py +0 -0
  28. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/catalog/catalog_router.py +0 -0
  29. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/catalog/function_installer.py +0 -0
  30. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/catalog/functions.py +0 -0
  31. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/catalog/oid_generator.py +0 -0
  32. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/catalog/pg_attrdef.py +0 -0
  33. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/catalog/pg_attribute.py +0 -0
  34. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/catalog/pg_class.py +0 -0
  35. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/catalog/pg_constraint.py +0 -0
  36. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/catalog/pg_index.py +0 -0
  37. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/catalog/pg_namespace.py +0 -0
  38. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/catalog/pg_type.py +0 -0
  39. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/catalog/views/__init__.py +0 -0
  40. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/catalog/views/definitions.py +0 -0
  41. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/catalog/views/installer.py +0 -0
  42. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/column_validator.py +0 -0
  43. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/config.py +0 -0
  44. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/config_schema.py +0 -0
  45. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/constitutional.py +0 -0
  46. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/conversions/__init__.py +0 -0
  47. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/conversions/bulk_insert.py +0 -0
  48. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/conversions/date_horolog.py +0 -0
  49. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/conversions/ddl_splitter.py +0 -0
  50. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/conversions/json_path.py +0 -0
  51. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/copy_handler.py +0 -0
  52. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/csv_processor.py +0 -0
  53. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/dbapi_connection_pool.py +0 -0
  54. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/dbapi_executor.py +0 -0
  55. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/debug_tracer.py +0 -0
  56. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/health_checker.py +0 -0
  57. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/integratedml.py +0 -0
  58. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/iris_constructs.py +0 -0
  59. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/iris_log_handler.py +0 -0
  60. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/iris_user_management.py +0 -0
  61. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/migrations/__init__.py +0 -0
  62. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/migrations/__main__.py +0 -0
  63. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/migrations/executor.py +0 -0
  64. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/models/__init__.py +0 -0
  65. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/models/backend_config.py +0 -0
  66. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/models/connection_pool_state.py +0 -0
  67. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/models/dbapi_connection.py +0 -0
  68. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/models/ipm_metadata.py +0 -0
  69. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/models/vector_query_request.py +0 -0
  70. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/observability.py +0 -0
  71. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/performance_monitor.py +0 -0
  72. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/quality/__init__.py +0 -0
  73. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/quality/__main__.py +0 -0
  74. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/quality/code_quality_validator.py +0 -0
  75. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/quality/documentation_validator.py +0 -0
  76. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/quality/package_metadata_validator.py +0 -0
  77. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/quality/security_validator.py +0 -0
  78. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/quality/validator.py +0 -0
  79. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/schema_mapper.py +0 -0
  80. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/server.py +0 -0
  81. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/__init__.py +0 -0
  82. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/alias_extractor.py +0 -0
  83. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/api.py +0 -0
  84. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/array_literal.py +0 -0
  85. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/array_params.py +0 -0
  86. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/boolean_expr.py +0 -0
  87. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/boolean_translator.py +0 -0
  88. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/cache.py +0 -0
  89. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/column_types.py +0 -0
  90. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/confidence_analyzer.py +0 -0
  91. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/config.py +0 -0
  92. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/constraint_translator.py +0 -0
  93. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/copy_parser.py +0 -0
  94. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/date_translator.py +0 -0
  95. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/ddl_parser.py +0 -0
  96. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/ddl_translator.py +0 -0
  97. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/debug.py +0 -0
  98. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/default_values.py +0 -0
  99. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/enum_registry.py +0 -0
  100. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/enum_translator.py +0 -0
  101. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/error_handler.py +0 -0
  102. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/identifier_normalizer.py +0 -0
  103. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/index_validator.py +0 -0
  104. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/interceptor.py +0 -0
  105. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/logging_config.py +0 -0
  106. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/mappings/__init__.py +0 -0
  107. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/mappings/datatypes.py +0 -0
  108. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/mappings/document_filters.py +0 -0
  109. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/mappings/functions.py +0 -0
  110. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/metadata_cache.py +0 -0
  111. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/metrics.py +0 -0
  112. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/models.py +0 -0
  113. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/normalizer.py +0 -0
  114. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/parser.py +0 -0
  115. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/performance_monitor.py +0 -0
  116. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/pg_array.py +0 -0
  117. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/pg_functions.py +0 -0
  118. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/pipeline.py +0 -0
  119. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/refiner.py +0 -0
  120. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/reserved_words.py +0 -0
  121. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/returning_plan.py +0 -0
  122. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/skipped_table_set.py +0 -0
  123. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/sqlstate.py +0 -0
  124. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/statement_filter.py +0 -0
  125. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/transaction_translator.py +0 -0
  126. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/translator.py +0 -0
  127. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/type_translator.py +0 -0
  128. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/validator.py +0 -0
  129. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/sql_translator/verbatim.py +0 -0
  130. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/testing/__init__.py +0 -0
  131. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/testing/base_fixture_builder.py +0 -0
  132. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/type_mapping.py +0 -0
  133. {iris_pgwire-1.7.2 → iris_pgwire-1.7.3}/src/iris_pgwire/vector_metrics.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: iris-pgwire
3
- Version: 1.7.2
3
+ Version: 1.7.3
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.7.2"
9
+ __version__ = "1.7.3"
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
@@ -44,8 +44,11 @@ class DdlErrorHandler:
44
44
  DdlResult indicating if the operation succeeded, was skipped, or failed
45
45
  """
46
46
  error_msg = str(error)
47
+ # iris.sql.exec raises SQLError with a .sqlcode attribute; -324 is the
48
+ # IRIS SQLCODE for "already has index named" (not always present in str(e)).
49
+ sqlcode = getattr(error, "sqlcode", None)
47
50
 
48
- if self._is_duplicate_error(error_msg):
51
+ if sqlcode == -324 or self._is_duplicate_error(error_msg):
49
52
  if self.has_if_not_exists(sql):
50
53
  obj_name = self.extract_object_name(sql)
51
54
  obj_type = self._extract_object_type(sql)
@@ -65,8 +65,10 @@ class HnswIndexSpec:
65
65
  Raises ValueError for unsupported operators (e.g. vector_l2_ops).
66
66
  """
67
67
  # Form 1: USING hnsw (col ops) [WITH (...)]
68
+ # (?P<ine>) matches "IF NOT EXISTS" or the /* IF_NOT_EXISTS */ comment marker
69
+ # that the construct translator inserts before HNSW translation runs.
68
70
  form1 = re.search(
69
- r"CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?P<ine>IF\s+NOT\s+EXISTS\s+)?"
71
+ r"CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?P<ine>IF\s+NOT\s+EXISTS|/\*\s*IF_NOT_EXISTS\s*\*/)?\s*"
70
72
  r"(?P<name>\w+)\s+ON\s+(?P<table>[\w.]+)\s+"
71
73
  r"USING\s+hnsw\s*\(\s*(?P<col>\w+)\s+(?P<op>\w+)\s*\)"
72
74
  r"(?:\s+WITH\s*\((?P<with>[^)]*)\))?",
@@ -99,7 +101,7 @@ class HnswIndexSpec:
99
101
 
100
102
  # Form 2: (col) USING HNSW [WITH (...)]
101
103
  form2 = re.search(
102
- r"CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?P<ine>IF\s+NOT\s+EXISTS\s+)?"
104
+ r"CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?P<ine>IF\s+NOT\s+EXISTS|/\*\s*IF_NOT_EXISTS\s*\*/)?\s*"
103
105
  r"(?P<name>\w+)\s+ON\s+(?P<table>[\w.]+)\s*"
104
106
  r"\(\s*(?P<col>\w+)\s*\)\s+"
105
107
  r"USING\s+HNSW"
@@ -1258,7 +1258,10 @@ class IRISExecutor:
1258
1258
  # Check both for raised exceptions and for success=False results
1259
1259
  if not result.get("success", True):
1260
1260
  error_msg = result.get("error", "")
1261
- ddl_result = self.ddl_handler.handle(sql, Exception(error_msg))
1261
+ # Use original_sql (pre-translation) so DdlErrorHandler can see
1262
+ # IF NOT EXISTS even when HNSW translation strips the marker.
1263
+ _sql_for_ddl = kwargs.get("original_sql") or sql
1264
+ ddl_result = self.ddl_handler.handle(_sql_for_ddl, Exception(error_msg))
1262
1265
  if ddl_result.success and ddl_result.skipped:
1263
1266
  logger.info(
1264
1267
  f"DDL idempotency: skipped '{ddl_result.object_name}' because it already exists",
@@ -1956,6 +1959,7 @@ class IRISExecutor:
1956
1959
  is_embedded: bool = True,
1957
1960
  session_id: str | None = None,
1958
1961
  connection: Any = None,
1962
+ original_sql: str | None = None,
1959
1963
  ) -> Any:
1960
1964
  """Execute SQL with DDL idempotency handling."""
1961
1965
  iris = self._import_iris()
@@ -2030,7 +2034,10 @@ class IRISExecutor:
2030
2034
  pass
2031
2035
  raise e
2032
2036
  except Exception as e:
2033
- result = self.ddl_handler.handle(sql, e)
2037
+ # Use original_sql (pre-translation) so DdlErrorHandler sees IF NOT EXISTS
2038
+ # even when HNSW translation strips the marker from the final SQL.
2039
+ _sql_for_ddl = original_sql or sql
2040
+ result = self.ddl_handler.handle(_sql_for_ddl, e)
2034
2041
  if result.success and result.skipped:
2035
2042
  return NoopCursor()
2036
2043
  raise e
@@ -2479,7 +2486,8 @@ class IRISExecutor:
2479
2486
  pass
2480
2487
 
2481
2488
  def _execute_embedded_statement_sequence(
2482
- self, statements: list[str], params: list | None, session_id: str | None
2489
+ self, statements: list[str], params: list | None, session_id: str | None,
2490
+ original_sql: str | None = None,
2483
2491
  ) -> Any:
2484
2492
  """Execute statement sequence for embedded mode and return the final cursor."""
2485
2493
  if not statements:
@@ -2493,10 +2501,15 @@ class IRISExecutor:
2493
2501
  )
2494
2502
 
2495
2503
  for stmt in statements[:-1]:
2496
- tmp_result = self._safe_execute(stmt, None, is_embedded=True, session_id=session_id)
2504
+ tmp_result = self._safe_execute(
2505
+ stmt, None, is_embedded=True, session_id=session_id, original_sql=original_sql
2506
+ )
2497
2507
  self._close_cursor_if_possible(tmp_result)
2498
2508
 
2499
- return self._safe_execute(statements[-1], params, is_embedded=True, session_id=session_id)
2509
+ return self._safe_execute(
2510
+ statements[-1], params, is_embedded=True, session_id=session_id,
2511
+ original_sql=original_sql,
2512
+ )
2500
2513
 
2501
2514
  def _resolve_embedded_returning_result(
2502
2515
  self,
@@ -2733,7 +2746,7 @@ class IRISExecutor:
2733
2746
 
2734
2747
  statements = self._split_sql_statements(optimized_sql)
2735
2748
  result = self._execute_embedded_statement_sequence(
2736
- statements, optimized_params, session_id
2749
+ statements, optimized_params, session_id, original_sql=original_sql
2737
2750
  )
2738
2751
 
2739
2752
  result = self._resolve_embedded_returning_result(
@@ -3314,7 +3327,8 @@ class IRISExecutor:
3314
3327
  # Execute all statements except the last
3315
3328
  for stmt in statements[:-1]:
3316
3329
  tmp_cursor = self._safe_execute(
3317
- stmt, None, is_embedded=False, session_id=session_id, connection=conn
3330
+ stmt, None, is_embedded=False, session_id=session_id, connection=conn,
3331
+ original_sql=original_sql,
3318
3332
  )
3319
3333
  if tmp_cursor:
3320
3334
  try:
@@ -3332,6 +3346,7 @@ class IRISExecutor:
3332
3346
  is_embedded=False,
3333
3347
  session_id=session_id,
3334
3348
  connection=conn,
3349
+ original_sql=original_sql,
3335
3350
  )
3336
3351
  except Exception as exc:
3337
3352
  if plan.conflict_action and self._is_unique_violation(exc):
@@ -1389,6 +1389,7 @@ class PGWireProtocol:
1389
1389
  session_id=self.connection_id,
1390
1390
  in_transaction=in_txn,
1391
1391
  autocommit=autocommit,
1392
+ original_sql=translation_result.get("original_sql", query),
1392
1393
  )
1393
1394
 
1394
1395
  # Add translation metadata to result for debugging/monitoring
@@ -1407,7 +1408,12 @@ class PGWireProtocol:
1407
1408
  else:
1408
1409
  error_msg = result.get("error", "Query execution failed")
1409
1410
  if (
1410
- VectorQueryOptimizer.sql_has_if_not_exists(final_sql)
1411
+ (
1412
+ VectorQueryOptimizer.sql_has_if_not_exists(final_sql)
1413
+ or VectorQueryOptimizer.sql_has_if_not_exists(
1414
+ translation_result.get("original_sql", "")
1415
+ )
1416
+ )
1411
1417
  and VectorQueryOptimizer.is_duplicate_object_error(error_msg)
1412
1418
  ):
1413
1419
  logger.info(
@@ -255,9 +255,10 @@ class IRISSQLConstructRegistry:
255
255
 
256
256
  # HNSW Index — Form 1: pgvector USING hnsw (col ops) [WITH (...)]
257
257
  # Handles schema-qualified table names (schema.table)
258
+ _HNSW_INE = r"(?:IF\s+NOT\s+EXISTS|/\*\s*IF_NOT_EXISTS\s*\*/)?\s*"
258
259
  self.add_construct(
259
260
  name="HNSW_INDEX",
260
- pattern=r"CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?\w+\s+ON\s+[\w.]+\s+USING\s+hnsw\s*\([^)]+\)(?:\s+WITH\s*\([^)]*\))?",
261
+ pattern=r"CREATE\s+(?:UNIQUE\s+)?INDEX\s+" + _HNSW_INE + r"\w+\s+ON\s+[\w.]+\s+USING\s+hnsw\s*\([^)]+\)(?:\s+WITH\s*\([^)]*\))?",
261
262
  replacement=None,
262
263
  post_process=self._translate_hnsw_index,
263
264
  confidence=0.95,
@@ -268,7 +269,7 @@ class IRISSQLConstructRegistry:
268
269
  # e.g. CREATE INDEX i ON t (emb) USING HNSW WITH (M=16, Distance='COSINE')
269
270
  self.add_construct(
270
271
  name="HNSW_INDEX_COL_FIRST",
271
- pattern=r"CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?\w+\s+ON\s+[\w.]+\s*\([^)]+\)\s+USING\s+HNSW(?:\s+WITH\s*\([^)]*\))?",
272
+ pattern=r"CREATE\s+(?:UNIQUE\s+)?INDEX\s+" + _HNSW_INE + r"\w+\s+ON\s+[\w.]+\s*\([^)]+\)\s+USING\s+HNSW(?:\s+WITH\s*\([^)]*\))?",
272
273
  replacement=None,
273
274
  post_process=self._translate_hnsw_index,
274
275
  confidence=0.95,
@@ -788,7 +788,10 @@ class VectorQueryOptimizer:
788
788
  @staticmethod
789
789
  def is_duplicate_object_error(error_msg: str) -> bool:
790
790
  """Return True if error_msg indicates an object-already-exists SQLCODE."""
791
- return any(code in error_msg for code in VectorQueryOptimizer._IRIS_DUPLICATE_CODES)
791
+ if any(code in error_msg for code in VectorQueryOptimizer._IRIS_DUPLICATE_CODES):
792
+ return True
793
+ # IRIS text message for duplicate index (no SQLCODE emitted)
794
+ return bool(re.search(r"already\s+has\s+index\s+named|already\s+exists", error_msg, re.IGNORECASE))
792
795
 
793
796
  @staticmethod
794
797
  def sql_has_if_not_exists(sql: str) -> bool:
File without changes
File without changes
File without changes
File without changes