Skip to content

Commit 618566f

Browse files
authored
Fix SQLPrimaryKeys to exclude INCLUDE columns from results (#171)
* Fix SQLPrimaryKeys to exclude INCLUDE columns from results When a PRIMARY KEY is created with an INCLUDE clause (PostgreSQL 11+), SQLPrimaryKeys incorrectly returned both the key columns and the included columns. For example, given PRIMARY KEY (a, b) INCLUDE (c, d), all four columns were returned instead of just a and b. The root cause was that the pg_attribute join on the index relation iterated over all index attributes without distinguishing key columns from included columns. Fix by adding a filter on i.indnkeyatts when connected to PostgreSQL >= 11, which limits results to only the actual key attributes. Both query paths in PGAPI_PrimaryKeys are fixed. Add a regression test that creates a table with a composite primary key using INCLUDE and verifies only the key columns are returned. * use openssl 3.5.6
1 parent 863a0e9 commit 618566f

5 files changed

Lines changed: 86 additions & 6 deletions

File tree

.github/workflows/main.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ env:
1616

1717
# PostgreSQL build from source.
1818
POSTGRESQL_SOURCE_TAG: 'REL_18_STABLE'
19-
OPENSSL_VERSION: '3_5_5'
19+
OPENSSL_VERSION: '3_5_6'
2020
PKGCONFIGLITE_VERSION: '0.28-1'
2121
WINFLEXBISON_VERSION: '2.5.24'
2222
WORKFLOW_VERSION_POSTGRESQL: '1' # increment to invalidate cache
@@ -322,7 +322,7 @@ jobs:
322322
- name: Install WiX
323323
shell: cmd
324324
run: |
325-
dotnet tool install --global wix
325+
dotnet tool install --global wix --version "6.*"
326326
wix extension add --global WixToolset.UI.wixext/6.0.0
327327
328328
- name: Build psqlodbc ${{matrix.variant}}

info.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4055,7 +4055,11 @@ PGAPI_PrimaryKeys(HSTMT hstmt,
40554055
" AND ta.attnum operator(pg_catalog.=) i.indkey[ia.attnum-1]"
40564056
" AND (NOT ta.attisdropped)"
40574057
" AND (NOT ia.attisdropped)"
4058-
" AND ic.oid operator(pg_catalog.=) i.indexrelid"
4058+
" AND ic.oid operator(pg_catalog.=) i.indexrelid");
4059+
if (PG_VERSION_GE(conn, 11.0))
4060+
appendPQExpBufferStr(&tables_query,
4061+
" AND ia.attnum operator(pg_catalog.<=) i.indnkeyatts");
4062+
appendPQExpBufferStr(&tables_query,
40594063
" order by ia.attnum");
40604064
break;
40614065
case 2:
@@ -4075,8 +4079,12 @@ PGAPI_PrimaryKeys(HSTMT hstmt,
40754079
" AND ta.attrelid operator(pg_catalog.=) i.indrelid"
40764080
" AND ta.attnum operator(pg_catalog.=) i.indkey[ia.attnum-1]"
40774081
" AND (NOT ta.attisdropped)"
4078-
" AND (NOT ia.attisdropped)"
4079-
" order by ia.attnum", eq_string, escTableName, eq_string, pkscm);
4082+
" AND (NOT ia.attisdropped)", eq_string, escTableName, eq_string, pkscm);
4083+
if (PG_VERSION_GE(conn, 11.0))
4084+
appendPQExpBufferStr(&tables_query,
4085+
" AND ia.attnum operator(pg_catalog.<=) i.indnkeyatts");
4086+
appendPQExpBufferStr(&tables_query,
4087+
" order by ia.attnum");
40804088
break;
40814089
}
40824090
if (PQExpBufferDataBroken(tables_query))
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
connected
2+
Check SQLPrimaryKeys with INCLUDE columns
3+
Result set:
4+
contrib_regression public pk_include_test a 1 pk_include_test_pkey
5+
contrib_regression public pk_include_test b 2 pk_include_test_pkey
6+
disconnecting
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Test that SQLPrimaryKeys excludes INCLUDE columns.
3+
*
4+
* A PRIMARY KEY with INCLUDE (PG 11+) should only return the actual
5+
* key columns, not the included columns.
6+
*/
7+
#include <stdio.h>
8+
#include <stdlib.h>
9+
10+
#include "common.h"
11+
12+
int
13+
main(int argc, char **argv)
14+
{
15+
SQLRETURN rc;
16+
HSTMT hstmt = SQL_NULL_HSTMT;
17+
18+
test_connect();
19+
20+
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn, &hstmt);
21+
CHECK_CONN_RESULT(rc, "failed to allocate stmt handle", conn);
22+
23+
/* INCLUDE clause requires PG >= 11 */
24+
if (server_version_lt(conn, 11, 0))
25+
{
26+
printf("Server version < 11, skipping INCLUDE test\n");
27+
test_disconnect();
28+
return 0;
29+
}
30+
31+
/* Create table with PK that has INCLUDE columns */
32+
rc = SQLExecDirect(hstmt,
33+
(SQLCHAR *) "DROP TABLE IF EXISTS pk_include_test", SQL_NTS);
34+
CHECK_STMT_RESULT(rc, "DROP TABLE failed", hstmt);
35+
36+
rc = SQLExecDirect(hstmt,
37+
(SQLCHAR *) "CREATE TABLE pk_include_test (a int, b int, c int, d int,"
38+
" CONSTRAINT pk_include_test_pkey PRIMARY KEY (a, b) INCLUDE (c, d))",
39+
SQL_NTS);
40+
CHECK_STMT_RESULT(rc, "CREATE TABLE failed", hstmt);
41+
42+
rc = SQLFreeStmt(hstmt, SQL_CLOSE);
43+
CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt);
44+
45+
/* Call SQLPrimaryKeys - should return only a and b, not c or d */
46+
printf("Check SQLPrimaryKeys with INCLUDE columns\n");
47+
rc = SQLPrimaryKeys(hstmt,
48+
NULL, 0,
49+
(SQLCHAR *) "public", SQL_NTS,
50+
(SQLCHAR *) "pk_include_test", SQL_NTS);
51+
CHECK_STMT_RESULT(rc, "SQLPrimaryKeys failed", hstmt);
52+
print_result(hstmt);
53+
54+
rc = SQLFreeStmt(hstmt, SQL_CLOSE);
55+
CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt);
56+
57+
/* Clean up */
58+
rc = SQLExecDirect(hstmt,
59+
(SQLCHAR *) "DROP TABLE pk_include_test", SQL_NTS);
60+
CHECK_STMT_RESULT(rc, "DROP TABLE failed", hstmt);
61+
62+
test_disconnect();
63+
64+
return 0;
65+
}

test/tests

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,5 @@ TESTBINS = exe/connect-test \
5757
exe/wchar-char-test \
5858
exe/params-batch-exec-test \
5959
exe/fetch-refcursors-test \
60-
exe/descrec-test
60+
exe/descrec-test \
61+
exe/primarykeys-include-test

0 commit comments

Comments
 (0)