Summary
When the connection uses the native SEA backend (databricks.sql.connect(..., use_sea=True)), the metadata methods Cursor.catalogs(), .schemas(), .tables(), and .columns() return result sets whose column names are the raw SHOW … output columns (e.g. catalog, databaseName, namespace/tableName, col_name) instead of the JDBC / DB-API metadata column names (TABLE_CAT, TABLE_SCHEM, TABLE_NAME, COLUMN_NAME, …).
The Thrift backend (default) and the Rust kernel backend (use_kernel=True) both return the JDBC-standard column names for these same calls. So the native SEA path is inconsistent with the other two backends, and any code that reads metadata results by the documented JDBC column names breaks under use_sea=True.
Affected API
Cursor.catalogs(), Cursor.schemas(), Cursor.tables(), Cursor.columns() — via the SEA backend only.
Expected vs. actual cursor.description column names
| Call |
Expected (Thrift & kernel, JDBC/DB-API) |
Actual (native SEA) |
catalogs() |
TABLE_CAT |
catalog |
schemas() |
TABLE_SCHEM (+ TABLE_CATALOG) |
databaseName |
tables() |
TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE, REMARKS |
namespace, tableName, isTemporary, information, catalogName, tableType, remarks |
columns() |
TABLE_CAT, TABLE_SCHEM, TABLE_NAME, COLUMN_NAME, DATA_TYPE, … |
col_name, catalogName, namespace, tableName, columnType, columnSize, decimalDigits, radix, isNullable, remarks, ordinalPosition, isAutoIncrement, isGenerated |
Root cause
In src/databricks/sql/backend/sea/backend.py, the metadata methods execute raw SQL and return the SHOW command's result set as-is, with no projection/rename to the JDBC metadata schema:
get_catalogs() → SHOW CATALOGS
get_schemas() → SHOW SCHEMAS IN <catalog> [LIKE …]
get_tables() → SHOW TABLES IN … [LIKE …]
get_columns() → SHOW COLUMNS …
The columns of those SHOW … result sets differ from the GetCatalogs/GetSchemas/GetTables/GetColumns Thrift RPC schemas (which follow the JDBC DatabaseMetaData contract). The SEA backend needs to map/rename these to the same column names the Thrift and kernel backends expose so metadata results are backend-agnostic.
Impact
Any consumer that reads metadata results positionally-by-name against the documented JDBC contract (e.g. row["TABLE_NAME"], or indexing cursor.description by TABLE_CAT/TABLE_SCHEM/COLUMN_NAME) silently breaks when use_sea=True, while working on Thrift and the Rust kernel. This makes the backend non-substitutable for metadata use cases.
Reproduction
from databricks import sql
conn = sql.connect(
server_hostname="<host>",
http_path="<warehouse-http-path>",
access_token="<token>",
use_sea=True, # native SEA backend
)
with conn.cursor() as cur:
cur.catalogs()
print([c[0] for c in cur.description]) # SEA: ['catalog'] — expected: ['TABLE_CAT', ...]
cur.tables()
print([c[0] for c in cur.description]) # SEA: ['namespace','tableName',...] — expected: [...,'TABLE_NAME',...]
Run the same with the default (Thrift) connection or use_kernel=True and the column names follow the JDBC contract.
Environment
databricks-sql-connector installed from main (git+https://github.com/databricks/databricks-sql-python@main), connector main HEAD d303706497c3 (2026-07-03).
- Python 3.11, against a SQL warehouse.
- Observed via a cross-backend conformance suite that runs the identical tests over Thrift, native SEA, and the Rust kernel: Thrift and kernel pass all metadata assertions (23 passed / 0 failed on kernel); native SEA fails ~18 of them purely on the column-name mismatch.
Other native-SEA divergences surfaced by the same run (may warrant separate issues)
- Statement cancel returns HTTP 501 (Not Implemented).
Cursor.cancel() on the SEA backend fails with RequestError: SEA HTTP request failed with status 501 (seen for cancel of a running statement and for concurrent-cancel). Thrift supports CancelOperation.
schemas(catalog_name=<nonexistent>) raises instead of returning an empty result. Native SEA raises ServerOperationError: [NO_SUCH_CATALOG_EXCEPTION] Catalog '<x>' was not found where the JDBC/DB-API convention (and Thrift) is an empty result set for a non-matching filter.
Summary
When the connection uses the native SEA backend (
databricks.sql.connect(..., use_sea=True)), the metadata methodsCursor.catalogs(),.schemas(),.tables(), and.columns()return result sets whose column names are the rawSHOW …output columns (e.g.catalog,databaseName,namespace/tableName,col_name) instead of the JDBC / DB-API metadata column names (TABLE_CAT,TABLE_SCHEM,TABLE_NAME,COLUMN_NAME, …).The Thrift backend (default) and the Rust kernel backend (
use_kernel=True) both return the JDBC-standard column names for these same calls. So the native SEA path is inconsistent with the other two backends, and any code that reads metadata results by the documented JDBC column names breaks underuse_sea=True.Affected API
Cursor.catalogs(),Cursor.schemas(),Cursor.tables(),Cursor.columns()— via the SEA backend only.Expected vs. actual
cursor.descriptioncolumn namescatalogs()TABLE_CATcatalogschemas()TABLE_SCHEM(+TABLE_CATALOG)databaseNametables()TABLE_CAT,TABLE_SCHEM,TABLE_NAME,TABLE_TYPE,REMARKSnamespace,tableName,isTemporary,information,catalogName,tableType,remarkscolumns()TABLE_CAT,TABLE_SCHEM,TABLE_NAME,COLUMN_NAME,DATA_TYPE, …col_name,catalogName,namespace,tableName,columnType,columnSize,decimalDigits,radix,isNullable,remarks,ordinalPosition,isAutoIncrement,isGeneratedRoot cause
In
src/databricks/sql/backend/sea/backend.py, the metadata methods execute raw SQL and return the SHOW command's result set as-is, with no projection/rename to the JDBC metadata schema:get_catalogs()→SHOW CATALOGSget_schemas()→SHOW SCHEMAS IN <catalog> [LIKE …]get_tables()→SHOW TABLES IN … [LIKE …]get_columns()→SHOW COLUMNS …The columns of those
SHOW …result sets differ from theGetCatalogs/GetSchemas/GetTables/GetColumnsThrift RPC schemas (which follow the JDBCDatabaseMetaDatacontract). The SEA backend needs to map/rename these to the same column names the Thrift and kernel backends expose so metadata results are backend-agnostic.Impact
Any consumer that reads metadata results positionally-by-name against the documented JDBC contract (e.g.
row["TABLE_NAME"], or indexingcursor.descriptionbyTABLE_CAT/TABLE_SCHEM/COLUMN_NAME) silently breaks whenuse_sea=True, while working on Thrift and the Rust kernel. This makes the backend non-substitutable for metadata use cases.Reproduction
Run the same with the default (Thrift) connection or
use_kernel=Trueand the column names follow the JDBC contract.Environment
databricks-sql-connectorinstalled frommain(git+https://github.com/databricks/databricks-sql-python@main), connectormainHEADd303706497c3(2026-07-03).Other native-SEA divergences surfaced by the same run (may warrant separate issues)
Cursor.cancel()on the SEA backend fails withRequestError: SEA HTTP request failed with status 501(seen for cancel of a running statement and for concurrent-cancel). Thrift supportsCancelOperation.schemas(catalog_name=<nonexistent>)raises instead of returning an empty result. Native SEA raisesServerOperationError: [NO_SUCH_CATALOG_EXCEPTION] Catalog '<x>' was not foundwhere the JDBC/DB-API convention (and Thrift) is an empty result set for a non-matching filter.