diff --git a/csharp/src/StatementExecution/StatementExecutionStatement.cs b/csharp/src/StatementExecution/StatementExecutionStatement.cs index b910097af..36b308b09 100644 --- a/csharp/src/StatementExecution/StatementExecutionStatement.cs +++ b/csharp/src/StatementExecution/StatementExecutionStatement.cs @@ -1492,8 +1492,17 @@ private async Task GetPrimaryKeysAsync(CancellationToken cancellati var keys = new List<(string, string, string, string, int, string)>(); int seq = 0; + // PECO-3045: prefer canonical identifiers from the SHOW KEYS server response over the + // (possibly non-canonical) user input. JDBC spec calls for canonical names in the + // result columns; Thrift returns them natively, so SEA must match. + string fallbackCatalog = _metadataCatalogName!.ToLowerInvariant(); + string fallbackSchema = _metadataSchemaName!.ToLowerInvariant(); + string fallbackTable = _metadataTableName!.ToLowerInvariant(); foreach (var batch in batches) { + var catalogArray = TryGetColumn(batch, "catalogName"); + var schemaArray = TryGetColumn(batch, "namespace"); + var tableNameArray = TryGetColumn(batch, "tableName"); var colNameArray = TryGetColumn(batch, "col_name"); var keyNameArray = TryGetColumn(batch, "constraintName"); var keySeqArray = TryGetColumn(batch, "keySeq"); @@ -1503,7 +1512,10 @@ private async Task GetPrimaryKeysAsync(CancellationToken cancellati if (colNameArray.IsNull(i)) continue; int keySeq = keySeqArray != null && !keySeqArray.IsNull(i) ? keySeqArray.GetValue(i)!.Value : ++seq; string pkName = keyNameArray != null && !keyNameArray.IsNull(i) ? keyNameArray.GetString(i) : ""; - keys.Add((_metadataCatalogName!, _metadataSchemaName!, _metadataTableName!, + string catalog = catalogArray != null && !catalogArray.IsNull(i) ? catalogArray.GetString(i) : fallbackCatalog; + string schemaName = schemaArray != null && !schemaArray.IsNull(i) ? schemaArray.GetString(i) : fallbackSchema; + string tableName = tableNameArray != null && !tableNameArray.IsNull(i) ? tableNameArray.GetString(i) : fallbackTable; + keys.Add((catalog, schemaName, tableName, colNameArray.GetString(i), keySeq, pkName)); } } diff --git a/csharp/test/E2E/StatementExecution/SeaMetadataE2ETests.cs b/csharp/test/E2E/StatementExecution/SeaMetadataE2ETests.cs index a7405ff2b..b9d775ed4 100644 --- a/csharp/test/E2E/StatementExecution/SeaMetadataE2ETests.cs +++ b/csharp/test/E2E/StatementExecution/SeaMetadataE2ETests.cs @@ -330,6 +330,31 @@ public async Task SEA_GetPrimaryKeys_ReturnsPKColumns() Assert.Equal("c_int", rows[1]["COLUMN_NAME"]); } + // PECO-3045 — SEA echoed input case in result columns; JDBC spec says columns + // should be canonical (lowercase). Call get_primary_keys with uppercase + // catalog/schema/table and assert the returned TABLE_CAT / TABLE_SCHEM / TABLE_NAME + // columns are the canonical lowercase form. + [SkippableFact] + public async Task SEA_GetPrimaryKeys_ReturnsCanonicalCase_InResultColumns() + { + SkipIfNotConfigured(); + using var conn = CreateSeaConnection(); + // Pass non-canonical (uppercase) input — server-side identifiers are lowercase. + var rows = await ReadMetadata( + conn, + "GetPrimaryKeys", + TestCatalog.ToUpperInvariant(), + TestSchema.ToUpperInvariant(), + TestTable.ToUpperInvariant()); + Assert.Equal(2, rows.Count); + foreach (var row in rows) + { + Assert.Equal(TestCatalog, row["TABLE_CAT"]); + Assert.Equal(TestSchema, row["TABLE_SCHEM"]); + Assert.Equal(TestTable, row["TABLE_NAME"]); + } + } + // --- GetTableSchema --- [SkippableFact]