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
Split out of #10997 (SQLite composite-key truncation). #10997 repaired the SQLite arm — completeness and key ordering. The PG and MySQL arms of the same method do not carry that completeness defect, but neither orders its result by key position, so the composite key they return is in unspecified row order.
SELECTa.attnameas column_name
FROM pg_index i
JOIN pg_attribute a ONa.attrelid=i.indrelidANDa.attnum= ANY(i.indkey)
WHEREi.indrelid= ?::regclass
ANDi.indisprimary
i.indkey is an int2vector holding the key's attnums in key order. a.attnum = ANY(i.indkey) is a membership test — it reads the vector as a set and discards the position. With no ORDER BY, the row order is whatever the plan yields (in practice pg_attribute scan order, i.e. column order). So the set is right and the order is not the declared key order whenever the key is declared out of column sequence.
MySQL arm:
SELECT COLUMN_NAME as column_name
FROMinformation_schema.KEY_COLUMN_USAGEWHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = ?
AND CONSTRAINT_NAME ='PRIMARY'
KEY_COLUMN_USAGE.ORDINAL_POSITION is exactly the key ordinal and is selected by neither the projection nor an ORDER BY. InnoDB tends to return ordinal order in practice, but nothing in the query requires it.
Why it matters
Same reason the ordering half of #10997 mattered: primaryKeys is consumed as an addressing / upsert-conflict-target key (federated-object codegen, the persisted external_catalog under ADR-0015, and schema-drift comparison against a declared key). For those consumers a key in the wrong order is a different key. After #10997 the SQLite arm reports declared key order and these two do not, so the same table introspected through different dialects can disagree.
Likely shape of the fix
MySQL: add ORDER BY ORDINAL_POSITION.
Postgres: join against the ordinality of indkey rather than testing membership — e.g. unnest(i.indkey) WITH ORDINALITY (or generate_subscripts) joined to pg_attribute, with ORDER BY on the ordinal.
The whole method body is wrapped in catch { /* silently ignore */ } and returns [] on error. A rewritten query that is syntactically invalid on some PG version does not fail loudly — it degrades to no primary key at all, with no diagnostic. That turns a cosmetic ordering gap into total, invisible loss of the key. Unexecuted SQL behind a silent catch is the wrong risk to take for an ordering improvement.
So this needs a seat with a reachable Postgres and MySQL. Worth pairing with a look at whether that silent catch should stay swallowing, which is arguably the more serious finding here and is deliberately not folded in.
Not measured here
Both arms were read, not run. No claim is made about what a live server actually returns for either query — only about what the SQL as written does and does not guarantee.
Split out of #10997 (SQLite composite-key truncation). #10997 repaired the SQLite arm — completeness and key ordering. The PG and MySQL arms of the same method do not carry that completeness defect, but neither orders its result by key position, so the composite key they return is in unspecified row order.
packages/drivers/driver-sql/src/sql-driver.ts,SqlDriver.introspectPrimaryKeys.What
Postgres arm:
i.indkeyis anint2vectorholding the key's attnums in key order.a.attnum = ANY(i.indkey)is a membership test — it reads the vector as a set and discards the position. With noORDER BY, the row order is whatever the plan yields (in practicepg_attributescan order, i.e. column order). So the set is right and the order is not the declared key order whenever the key is declared out of column sequence.MySQL arm:
KEY_COLUMN_USAGE.ORDINAL_POSITIONis exactly the key ordinal and is selected by neither the projection nor anORDER BY. InnoDB tends to return ordinal order in practice, but nothing in the query requires it.Why it matters
Same reason the ordering half of #10997 mattered:
primaryKeysis consumed as an addressing / upsert-conflict-target key (federated-object codegen, the persistedexternal_catalogunder ADR-0015, and schema-drift comparison against a declared key). For those consumers a key in the wrong order is a different key. After #10997 the SQLite arm reports declared key order and these two do not, so the same table introspected through different dialects can disagree.Likely shape of the fix
ORDER BY ORDINAL_POSITION.indkeyrather than testing membership — e.g.unnest(i.indkey) WITH ORDINALITY(orgenerate_subscripts) joined topg_attribute, withORDER BYon the ordinal.Why this was NOT fixed in #10997's PR
Two reasons, both about verification rather than difficulty:
mysqlclient, and the Docker CLI is present but has no daemon socket (/var/run/docker.sockabsent). The original filer of driver-sql: SQLite introspection reports only the FIRST column of a composite primary key (pk === 1vs SQLite's 1,2,3… numbering) #10997 hit the same limit. Landing a rewrittenpg_indexquery that has never been parsed by a real server is a guess, not a fix.catch { /* silently ignore */ }and returns[]on error. A rewritten query that is syntactically invalid on some PG version does not fail loudly — it degrades to no primary key at all, with no diagnostic. That turns a cosmetic ordering gap into total, invisible loss of the key. Unexecuted SQL behind a silent catch is the wrong risk to take for an ordering improvement.So this needs a seat with a reachable Postgres and MySQL. Worth pairing with a look at whether that silent
catchshould stay swallowing, which is arguably the more serious finding here and is deliberately not folded in.Not measured here
Both arms were read, not run. No claim is made about what a live server actually returns for either query — only about what the SQL as written does and does not guarantee.