Skip to content

Commit bbd8ee0

Browse files
committed
Fix parameter passing, SQLUser casing, and DDL case sensitivity (v1.0.9)
1 parent dbb3d03 commit bbd8ee0

File tree

5 files changed

+46
-17
lines changed

5 files changed

+46
-17
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.0.9] - 2026-01-17
9+
10+
### Fixed
11+
- **Parameter Passing Bug**: Fixed `iris_executor.py` to correctly pass parameters to `iris.sql.exec(*params)`, enabling parameterized queries in embedded mode.
12+
- **Schema Case Sensitivity**: Fixed normalizer to preserve `SQLUser` casing (instead of `SQLUSER`), satisfying case-sensitive package requirements in IRIS.
13+
- **DDL Case Sensitivity**: Fixed `IdentifierNormalizer` to respect quoted identifier casing in `CREATE TABLE` statements, preventing "Class not found" errors during subsequent queries.
14+
815
## [1.0.8] - 2026-01-17
916

1017
### Added

src/iris_pgwire/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
caretdev/sqlalchemy-iris.
77
"""
88

9-
__version__ = "1.0.8"
9+
__version__ = "1.0.9"
1010
__author__ = "IRIS PGWire Team"
1111

1212
# Don't import server/protocol in __init__ to avoid sys.modules conflicts

src/iris_pgwire/iris_executor.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,9 +1223,7 @@ def _split_multi_row_insert(self, sql: str) -> list[str]:
12231223

12241224
return statements
12251225

1226-
def _safe_execute(
1227-
self, sql: str, params: list | None = None, is_embedded: bool = True
1228-
) -> Any:
1226+
def _safe_execute(self, sql: str, params: list | None = None, is_embedded: bool = True) -> Any:
12291227
"""Execute SQL with DDL idempotency handling."""
12301228
import iris
12311229

@@ -1266,7 +1264,10 @@ def __iter__(self):
12661264
try:
12671265
if is_embedded:
12681266
# Embedded mode - return cursor-like object
1267+
if params is not None and len(params) > 0:
1268+
return iris.sql.exec(sql, *params)
12691269
return iris.sql.exec(sql)
1270+
12701271
else:
12711272
# External mode - use DBAPI cursor
12721273
connection = self._get_pooled_connection()
@@ -2917,7 +2918,7 @@ def _sync_execute():
29172918
optimized_params = tuple(self._normalize_parameters(optimized_params))
29182919

29192920
# Replace "public"."tablename" with SQLUser."tablename" (preserve quotes on tablename)
2920-
# Replace "public"."tablename" with SQLUser."tablename" (preserve quotes on tablename)
2921+
# Ensure we use the correct SQLUser casing
29212922
optimized_sql = re.sub(
29222923
r'"public"\s*\.\s*"(\w+)"', r'SQLUser."\1"', optimized_sql, flags=re.IGNORECASE
29232924
)

src/iris_pgwire/schema_mapper.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,20 +68,31 @@ def translate_input_schema(sql: str) -> str:
6868
flags=re.IGNORECASE,
6969
)
7070

71-
# Pattern 2: Schema-qualified table names (e.g., public.tablename)
72-
# Match public. followed by identifier (word chars) but not inside single quotes
73-
# This is a simplified approach - we process the SQL outside of string literals
71+
# Pattern 2: Schema-qualified table names (e.g., public.tablename or public."tablename")
72+
# Match public. followed by identifier (word chars) or quoted identifier
7473
result = re.sub(
75-
r'\bpublic\.(\w+)',
76-
rf'{IRIS_SCHEMA}.\1',
74+
r'\bpublic\s*\.\s*"(\w+)"',
75+
rf'{IRIS_SCHEMA}."\1"',
76+
result,
77+
flags=re.IGNORECASE,
78+
)
79+
result = re.sub(
80+
r"\bpublic\s*\.\s*(\w+)",
81+
rf"{IRIS_SCHEMA}.\1",
7782
result,
7883
flags=re.IGNORECASE,
7984
)
8085

81-
# Pattern 3: Double-quoted schema (e.g., "public".tablename)
86+
# Pattern 3: Double-quoted schema (e.g., "public".tablename or "public"."tablename")
87+
result = re.sub(
88+
r'"public"\s*\.\s*"(\w+)"',
89+
rf'{IRIS_SCHEMA}."\1"',
90+
result,
91+
flags=re.IGNORECASE,
92+
)
8293
result = re.sub(
83-
r'"public"\.(\w+)',
84-
rf'{IRIS_SCHEMA}.\1',
94+
r'"public"\s*\.\s*(\w+)',
95+
rf"{IRIS_SCHEMA}.\1",
8596
result,
8697
flags=re.IGNORECASE,
8798
)

src/iris_pgwire/sql_translator/identifier_normalizer.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,12 @@ def _normalize_chunk(self, chunk: str, current_count: int) -> tuple[str, int]:
275275
# Process CREATE TABLE specially to preserve column name case
276276
before_create = chunk[: create_match.start()]
277277
create_prefix = create_match.group(1).upper() # CREATE TABLE keywords
278-
table_name = create_match.group(2).upper() # Uppercase table name
278+
# Fix: Respect quoted identifier case for table name
279+
table_name_raw = create_match.group(2)
280+
if table_name_raw.startswith('"') and table_name_raw.endswith('"'):
281+
table_name = table_name_raw # Quoted: preserve exact case
282+
else:
283+
table_name = table_name_raw.upper() # Unquoted: uppercase for IRIS
279284
opening_paren = create_match.group(3)
280285

281286
# CRITICAL FIX: Find the matching closing paren for the table definition
@@ -387,13 +392,18 @@ def replace_identifier(match):
387392
return f'"{quoted}"' # Return as-is
388393
elif unquoted is not None:
389394
# Unquoted identifier - check if it's a keyword
390-
if unquoted.upper() in self._sql_keywords:
395+
upper_unquoted = unquoted.upper()
396+
if upper_unquoted in self._sql_keywords:
391397
# SQL keyword - uppercase but don't count as user identifier
392-
return unquoted.upper()
398+
return upper_unquoted
399+
elif upper_unquoted == "SQLUSER":
400+
# Feature 036 Fix: Preserve SQLUser case (IRIS is case-sensitive for schema names)
401+
identifier_count += 1
402+
return "SQLUser"
393403
else:
394404
# User identifier - uppercase and count
395405
identifier_count += 1
396-
return unquoted.upper()
406+
return upper_unquoted
397407

398408
return match.group(0) # Shouldn't reach here
399409

0 commit comments

Comments
 (0)