Subject: Does included columns part of the PK

From: Igor Korot <[email-masked]>
Date: Sat, 14 Mar 2026 02:09:04 -0500

Hi, ALL,
Have one weird question ;-)

When I connect with ODBC and call SQLPrimaryKey() the function returns
all fields including
"included" fields.

However running libpq and trying to get the table info with:

[quote]
    L"SELECT DISTINCT column_name, data_type,
character_maximum_length, character_octet_length, numeric_precision,
numeric_precision_radix, numeric_scale, is_nullable, column_default,
CASE WHEN column_name IN (SELECT ccu.column_name FROM
information_schema.constraint_column_usage ccu,
information_schema.table_constraints tc WHERE ccu.constraint_name =
tc.constraint_name AND tc.constraint_type = 'PRIMARY KEY' AND
ccu.table_name = $2) THEN 'YES' ELSE 'NO' END AS is_pk,
ordinal_position FROM information_schema.columns col,
information_schema.table_constraints tc WHERE tc.table_schema =
col.table_schema AND tc.table_name = col.table_name AND
col.table_schema = $1 AND col.table_name = $2 ORDER BY
ordinal_position;";
[/quote]

I'm getting only direct PK fields.

I presume that libpq is correct and the ODBC driver is the one that
needs to be fixed.

Just wanted to ask this list before going to complain to the ODBC list... ;-)

Thank you.

---

From: Igor Korot <[email-masked]>
Date: Sat, 14 Mar 2026 02:12:42 -0500

Below is the version info I use on this machine:

Calculating dependencies... done!
Dependency resolution took 53.38 s (backtrack: 0/20).

[ebuild   R    ] dev-db/postgresql-16.2:16::gentoo  USE="icu lz4 nls
pam readline ssl xml zlib zstd -debug -doc -kerberos -ldap -llvm -perl
-python (-selinux) -server* -static-libs -systemd -tcl -uuid"
PYTHON_SINGLE_TARGET="python3_11 -python3_10 -python3_12" 0 KiB
[ebuild   R    ] dev-db/psqlodbc-11.01.0000::gentoo  USE="ssl -doc
-iodbc -threads" 0 KiB

Total: 2 packages (2 reinstalls), Size of downloads: 0 KiB
WaylandGnome /home/igor/dbhandler/Debug #

Thank you.

---

From: "David G. Johnston" <[email-masked]>
Date: Sat, 14 Mar 2026 08:07:37 -0700

> I presume that libpq is correct and the ODBC driver is the one that

Odbc does seem to be in the wrong here, yes.

David J.

---

From: Adrian Klaver <[email-masked]>
Date: Sat, 14 Mar 2026 08:25:08 -0700

> When I connect with ODBC and call SQLPrimaryKey() the function returns

Are you actually using the SQLPrimaryKeys(), not SQLPrimaryKey()?

> "included" fields.

Define 'included' fields.

> I'm getting only direct PK fields.

Define direct PK fields.

> I presume that libpq is correct and the ODBC driver is the one that

Returning the actual results from each case would help.

Have you cranked up the logging on the Postgres server to see what query 
ODBC is using?

-- 
Adrian Klaver
[email-masked]

---

From: "David G. Johnston" <[email-masked]>
Date: Sat, 14 Mar 2026 08:51:24 -0700

> Define 'included' fields.

They are referring to the unique index that backs the PK constraint.

David J.

---

From: Igor Korot <[email-masked]>
Date: Sat, 14 Mar 2026 09:56:55 -0700

Hi,

> They are referring to the unique index that backs the PK constraint.

Not “they” - “He”. 😊

And yes - that’s what I’m referring to.

Thank you.

---

From: Adrian Klaver <[email-masked]>
Date: Sat, 14 Mar 2026 16:30:19 -0700

On 3/14/26 9:56 AM, Igor Korot wrote:
> Hi,
> 
> On Sat, Mar 14, 2026 at 8:51 AM David G. Johnston 
> <[email-masked] <mailto:[email-masked]>> wrote:
> 
>     On Saturday, March 14, 2026, Adrian Klaver
>     <[email-masked] <mailto:[email-masked]>> wrote:
> 

 From here:

https://www.ibm.com/docs/en/db2-for-zos/12.0.0?topic=functions-sqlprimarykeys-get-primary-key-columns-table:

1	TABLE_CAT	VARCHAR(128)	This is always null.
2	TABLE_SCHEM	VARCHAR(128)	The name of the schema containing TABLE_NAME.
3	TABLE_NAME	VARCHAR(128) NOT NULL	Name of the specified table.
4	COLUMN_NAME	VARCHAR(128) NOT NULL	Primary key column name.
5	KEY_SEQ	SMALLINT NOT NULL	Column sequence number in the primary key, 
starting with 1.
6	PK_NAME	VARCHAR(128)	Primary key identifier. Contains a null value if 
not applicable to the data

 From here:

https://github.com/postgresql-interfaces/psqlodbc/blob/main/info.c

At line 4035 in SQLPrimaryKeys()

For case 1

/*
				 * Simplified query to remove assumptions about number of
				 * possible index columns. Courtesy of Tom Lane - thomas
				 * 2000-03-21
				 */

[...]

"select ta.attname, ia.attnum, ic.relname, n.nspname, tc.relname"
					" from pg_catalog.pg_attribute ta ... "

case 2

select ta.attname, ia.attnum, ic.relname, n.nspname, NULL"
					" from pg_catalog.pg_attribute ta, ..."

If I am following correctly then:

attname = column_name
attnum = key_seq
ic.relname = pk_name
nspname = table_schem
tc.relname = table_name

So how are using it in your code and what are the actual results?

Also what is showing up in the Postgres logs?

---

From: Igor Korot <[email-masked]>
Date: Sun, 15 Mar 2026 01:24:38 -0500

Hi, Adrian,

> not applicable to the data

Lets start with the beginning:

draft=# CREATE TABLE leagues_new(id serial, name varchar(100),
drafttype smallint, scoringtype smallint, roundvalues smallint,
leaguetype char(5), salary integer, benchplayers smallint, primary
key(id) INCLUDE (drafttype, scoringtype) WITH( fillfactor = 50,
deduplicate_items = OFF ));
CREATE TABLE
draft=#

---

From: Adrian Klaver <[email-masked]>
Date: Sun, 15 Mar 2026 08:34:13 -0700

> deduplicate_items = OFF ));

I think the above is for this thread:

https://www.postgresql.org/message-id/CA%2BFnnTyGEM-1mwxKPbwFTOodf%2BYUX%3DTxTmBPY5S%3DYh1h%3DoVY9A%40mail.gmail.com

---

From: Igor Korot <[email-masked]>
Date: Sun, 15 Mar 2026 20:23:57 -0500

Hi, Adrian,

Here is the log file from running in ODBC mode: https://bpa.st/Z2DWG

Thank you.

---

From: Greg Sabino Mullane <[email-masked]>
Date: Mon, 16 Mar 2026 09:53:11 -0400

Please don't send links to external sites. Since I've already clicked on
it, I'll put it here for the archives as an attachment.

---

From: Adrian Klaver <[email-masked]>
Date: Mon, 16 Mar 2026 08:03:42 -0700

> Here is the log file from running in ODBC mode: https://bpa.st/Z2DWG

I have no idea what this is trying to show?

Is it referring to the thread  I linked to below:

"CREATE TABLE fails"

or this thread?

In any case what actions on the client action where done and how did 
they not match expectations?

If this was really about the "CREATE TABLE fails" thread it needs to go 
back there.

As to this thread go back to:

https://www.postgresql.org/message-id/3547f40b-08b9-4d0c-bba8-f1c26d0bf09d%40aklaver.com

and provide the information requested.

---

From: Igor Korot <[email-masked]>
Date: Mon, 16 Mar 2026 11:43:13 -0700

Thx, Greg.

---

From: Adrian Klaver <[email-masked]>
Date: Mon, 16 Mar 2026 14:27:05 -0700

On 3/16/26 11:44 AM, Igor Korot wrote:
Reply to list also
Ccing list
> Adrian,
> 
> On Mon, Mar 16, 2026, 8:03 AM Adrian Klaver <[email-masked] 
> <mailto:[email-masked]>> wrote:
> 
>      > Here is the log file from running in ODBC mode: https://bpa.st/
>     Z2DWG <https://bpa.st/Z2DWG>
> 
> Didn't you ask for a log file from running ODBC?

No.

 From here:

"

"

While you are it specify what ODBC driver you are using and what what 
version.

---

From: Adrian Klaver <[email-masked]>
Date: Mon, 16 Mar 2026 14:30:32 -0700

On 3/16/26 11:47 AM, Igor Korot wrote:

Reply to list also.
Ccing list.
> The log shows ODBC connection and then at the end - call to 
> SQLPrimaryKeys().

Where?

I don't see that in either the link you posted or the text file Greg 
sent to the list.

> 
> If you run it against the table I posted above, you will get 3 fields.  
> Whereas it should be just one.

Again, run it how?

---

From: Adrian Klaver <[email-masked]>
Date: Mon, 16 Mar 2026 14:40:20 -0700

On 3/16/26 2:30 PM, Adrian Klaver wrote:
>>      > Hi, Adrian,
>>      >
>>      > Here is the log file from running in ODBC mode: https://bpa.st/

Alright I see what you are talking about now. I'm not using the ODBC 
driver just it's query. In psql :

CREATE TABLE leagues_new (
     id serial,
     name varchar(100),
     drafttype smallint,
     scoringtype smallint,
     roundvalues smallint,
     leaguetype char(5),
     salary integer,
     benchplayers smallint,
     PRIMARY KEY (id) INCLUDE (drafttype, scoringtype
) WITH (fillfactor = 50, deduplicate_items = OFF)
);

SELECT
     ta.attname,
     ia.attnum,
     ic.relname,
     n.nspname,
     tc.relname
FROM
     pg_catalog.pg_attribute ta,
     pg_catalog.pg_attribute ia,
     pg_catalog.pg_class tc,
     pg_catalog.pg_index i,
     pg_catalog.pg_namespace n,
     pg_catalog.pg_class ic
WHERE
     tc.relname = 'leagues_new'
     AND n.nspname = 'public'
     AND tc.oid = i.indrelid
     AND n.oid = tc.relnamespace
     AND i.indisprimary = 't'
     AND ia.attrelid = i.indexrelid
     AND ta.attrelid = i.indrelid
     AND ta.attnum = i.indkey[ia.attnum - 1]
     AND (NOT ta.attisdropped)
     AND (NOT ia.attisdropped)
     AND ic.oid = i.indexrelid
ORDER BY
     ia.attnum;

yields

attname   | attnum |     relname      | nspname |   relname
-------------+--------+------------------+---------+-------------
  id          |      1 | leagues_new_pkey | public  | leagues_new
  drafttype   |      2 | leagues_new_pkey | public  | leagues_new
  scoringtype |      3 | leagues_new_pkey | public  | leagues_new

---

From: Igor Korot <[email-masked]>
Date: Mon, 16 Mar 2026 14:51:22 -0700

Adrian,

> attname   | attnum |     relname      | nspname |   relname

Correct.

And according to the second reply it should yeld just the first record.

I'm going to forward this to the ODBC list...

Thank you.

---

From: Igor Korot <[email-masked]>
Date: Mon, 16 Mar 2026 14:53:49 -0700

Hi, List.

This is what I found out.

Could someone please look into it?

Thank you.

---------- Forwarded message ---------
From: Igor Korot <[email-masked]>
Date: Mon, Mar 16, 2026 at 2:51 PM
Subject: Re: Does included columns part of the PK
To: Adrian Klaver <[email-masked]>
Cc: pgsql-general <[email-masked]>

Adrian,

Correct.

Thank you.

---

From: Adrian Klaver <[email-masked]>
Date: Mon, 16 Mar 2026 14:57:35 -0700

> I'm going to forward this to the ODBC list...

I have not worked it out yet but would start with:

per

www.postgresql.org/docs/current/catalog-pg-index.html

"
indkey int2vector (references pg_attribute.attnum)

...

This is an array of indnatts values that indicate which table columns 
this index indexes. For example, a value of 1 3 would mean that the 
first and the third table columns make up the index entries. Key columns 
come before non-key (included) columns.

...
"

Though there is the below from the same page:

"indnatts int2

The total number of columns in the index (duplicates pg_class.relnatts); 
this number includes both key and included attributes

indnkeyatts int2

The number of key columns in the index, not counting any included 
columns, which are merely stored and do not participate in the index 
semantics
"

---

From: Igor Korot <[email-masked]>
Date: Mon, 16 Mar 2026 16:38:22 -0700

Adrian,

Most important - do you agree that those fields should not be in this
recordset?

Thank you.

---

From: Adrian Klaver <[email-masked]>
Date: Mon, 16 Mar 2026 17:44:45 -0700

> Most important - do you agree that those fields should not be in this

I don't see anything here:

https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlprimarykeys-function?view=sql-server-ver17

that says they should be returned. Though the above also says:

" Additional columns beyond column 6 (PK_NAME) can be defined by the 
driver."

That is not the case here, where additional rows are used. However it 
does allow for more information to be supplied.

My purely un-expert analysis is, no the extra rows should not be there.

---

From: Igor Korot <[email-masked]>
Date: Mon, 16 Mar 2026 18:11:26 -0700

Adrian,,

> My purely un-expert analysis is, no the extra rows should not be there.

Thx for confirming.

I already forwarded the email with the query results over to ODBC list.

Hopefully someone can come back soon.

Are you reading that list as well? If not I will update this thread
with the results.

Thank you.

---

From: Igor Korot <[email-masked]>
Date: Mon, 20 Apr 2026 22:33:33 -0700

For all involved and interested:

The issue with ODBC driver has been fixed and will
be part of the next release.

Ref: https://github.com/postgresql-interfaces/psqlodbc/issues/170.

Thank you.