You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
driver-sql (PG): introspectPrimaryKeys reports a covering primary key's INCLUDE'd columns as key members — indkey is read whole, indnkeyatts is ignored #11162
Found while working #11101 (which repaired the ordering of the PG/MySQL key). This is a membership defect in the same method — a different defect class, so it was deliberately not folded in. Measured on a live PostgreSQL 16.13.
What
packages/drivers/driver-sql/src/sql-driver.ts, SqlDriver.introspectPrimaryKeys, Postgres arm. The query reads all of pg_index.indkey. For a covering primary key, indkey holds the key columns and the INCLUDEd payload columns; indnkeyatts is the count of the leading entries that are actually key columns, and it is not consulted.
Postgres reaches this via CREATE UNIQUE INDEX … INCLUDE (…) promoted with ALTER TABLE … ADD CONSTRAINT … PRIMARY KEY USING INDEX.
Measured (PostgreSQL 16.13)
CREATETABLEcovered (k1 textNOT NULL, k2 textNOT NULL, payload text);
CREATEUNIQUE INDEXcovered_pkON covered (k2, k1) INCLUDE (payload);
ALTERTABLE covered ADD CONSTRAINT covered_pkey PRIMARY KEY USING INDEX covered_pk;
The declared key is (k2, k1). payload (attnum 3) is a payload column, not a key column — indnkeyatts = 2 says so.
Both the pre-#11101 query and the post-#11101 query report it as a key member:
--- OLD query (membership test, a.attnum = ANY(i.indkey)) ---
k1
k2
payload
--- NEW query (#11101, joins the ordinality of indkey) ---
k2
k1
payload
#11101 neither introduced nor worsened this — the two arms agree on membership and differ only in order, which is why it was left alone there. The payload entry is wrong in both.
Why it matters
primaryKeys is consumed as an addressing / upsert-conflict-target key (federated-object codegen, the persisted external_catalog under ADR-0015, schema-drift comparison). A key with an extra member is a different key: an upsert conflict target naming a non-key column does not match the constraint, and drift comparison against a correctly-declared (k2, k1) reports a phantom unexpected_key_member:payload.
Likely shape of the fix
Bound the join to the key attributes: WHERE k.ord <= i.indnkeyatts (or unnest(i.indkey[0:i.indnkeyatts-1]) — note int2vector is 0-based). indnkeyatts exists in PG 11+; below that it equals indnatts and the bound is a no-op.
Worth checking the MySQL and SQLite arms for the analogous question before fixing, so all three dialects keep the single answer #11101 just established. MySQL has no covering-index concept for a PRIMARY KEY, so it is likely PG-only.
Not measured here
Whether any in-tree consumer currently introspects a covering primary key. The repo's own schema sync does not create them; this reaches a remote table under federation (ADR-0015), where the DDL is not ours.
Triage: pm:queue, domain:engine, Bug — see the family-anchor comment on #11161 (driver-sql introspection trio; prefer one claim covering all three, region-declared against in-flight #11067/#11176).
This card was dispatched as part of the introspection trio (#11161 / #11162 / #11163, one file region in packages/drivers/driver-sql/src/sql-driver.ts, one commit per issue). The work is in PR #11203, which carries Fixes #11162.
The label pair was not written at dispatch time: the card stayed pm:queue + unassigned for the duration of the run, which advertised it to the lane as dispatchable while an open PR already covered it. Corrected now to pm:dispatched + assignee. No work state changed — only the card's honesty about it.
For the record of what the PR measured on this card specifically (live PG 16.13, fixture (k1, k2, payload) with CREATE UNIQUE INDEX ... (k2, k1) INCLUDE (payload) promoted via ADD CONSTRAINT ... PRIMARY KEY USING INDEX): catalog reports indkey = '2 1 3', indnatts = 3, indnkeyatts = 2; before the fix the introspected key was k2, k1, payload, after it is k2, k1. Reverse verification took 2 reds on this card's legs.
Activity
os-zhuang commentedon Aug 23, 2026
Triage:
pm:queue,domain:engine, Bug — see the family-anchor comment on #11161 (driver-sql introspection trio; prefer one claim covering all three, region-declared against in-flight #11067/#11176).Generated by Claude Code
fix(driver-sql): bound the PG primary-key join to indnkeyatts so INCL…
os-zhuang commentedon Aug 23, 2026
Claim (late — PM bookkeeping correction) · session
session_01RfyXxZ2WPjcjhuXpiQQc3y· branchclaude/issue-11161-introspection-trioThis card was dispatched as part of the introspection trio (#11161 / #11162 / #11163, one file region in
packages/drivers/driver-sql/src/sql-driver.ts, one commit per issue). The work is in PR #11203, which carriesFixes #11162.The label pair was not written at dispatch time: the card stayed
pm:queue+ unassigned for the duration of the run, which advertised it to the lane as dispatchable while an open PR already covered it. Corrected now topm:dispatched+ assignee. No work state changed — only the card's honesty about it.For the record of what the PR measured on this card specifically (live PG 16.13, fixture
(k1, k2, payload)withCREATE UNIQUE INDEX ... (k2, k1) INCLUDE (payload)promoted viaADD CONSTRAINT ... PRIMARY KEY USING INDEX): catalog reportsindkey = '2 1 3',indnatts = 3,indnkeyatts = 2; before the fix the introspected key wask2, k1, payload, after it isk2, k1. Reverse verification took 2 reds on this card's legs.Generated by Claude Code
fix(driver-sql): introspection trio — error contract (objectstack-ai#…