Skip to content

Auto-quoting reserved word column names produces lowercase quoted identifiers — rejected by DB2 #195

@astral-alpaca

Description

@astral-alpaca

Summary

When a column is named after a SQL reserved word (e.g. table), SQLAlchemy's auto-quoting mechanism (quote=None, the default) wraps it in double quotes. Because ibm_db_sa provides the name in lowercase, the generated SQL contains "table" (lowercase, quoted). DB2 treats quoted identifiers as case-sensitive, but stores unquoted identifiers as UPPERCASE in the catalog. This mismatch causes SQL0206N:

sqlalchemy.exc.ProgrammingError: ibm_db_dbi::ProgrammingError: Binding Error:
[IBM][CLI Driver][DB2/LINUXX8664] SQL0206N  "FE_CODETABLE_1.table" is not valid
in the context where it is used.  SQLSTATE=42703 SQLCODE=-206

The same column works fine when accessed unquoted (quote=False), because DB2 folds it to TABLE automatically.

Environment

  • SQLAlchemy: 2.0.46
  • ibm_db_sa: 0.4.3
  • Database: IBM DB2 for Linux (DB2/LINUXX8664)

Steps to reproduce

import sqlalchemy as sa

metadata = sa.MetaData()

# Column named "table" — a SQL reserved word.
# quote is omitted, so SQLAlchemy should auto-detect and handle it.
codetable = sa.Table(
    "fe_codetable",
    metadata,
    sa.Column("oid", sa.BigInteger(), primary_key=True),
    sa.Column("table", sa.String()),
)

alias = codetable.alias()
stmt = sa.select(alias.c.table).where(alias.c.table == "SomeValue")

with engine.connect() as conn:
    conn.execute(stmt)  # → SQL0206N

Setting quote=True explicitly produces the same error, because the generated SQL is identical.

Generated SQL

Both quote=None (auto) and quote=True produce:

SELECT fe_codetable_1."table"
FROM fe_codetable AS fe_codetable_1
WHERE fe_codetable_1."table" = ?

DB2 sees "table" (lowercase, case-sensitive) and looks for a column literally named table. The catalog stores it as TABLE (uppercase), so the lookup fails.

Setting quote=False produces working SQL:

SELECT fe_codetable_1.table
FROM fe_codetable AS fe_codetable_1
WHERE fe_codetable_1.table = ?

DB2 folds the unquoted table to TABLE, matches the catalog, and the query succeeds.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions