fix(postgres): keep expression index DDL text and key order in sync

This commit is contained in:
zipg authored and GitHub committed 2026-09-22 16:49:50 +08:00
1 parent 78d8076c53
commit 05d3bd0635
4 files changed
+213 -15

No files matched your search

@@ -542,10 +542,13 @@ public abstract class PostgresLikeAgent extends AbstractJdbcAgent {
// dropped; their text comes from pg_get_indexdef instead of a.attname, and
// is_expression records which case applied so Rust never has to guess from
// characters in the text (#6312 review).
// `a.attname::text` keeps the cast: a bare COALESCE(name, text) resolves to
// `name`, which truncates an expression key part to 63 bytes (NAMEDATALEN - 1)
// and makes the rebuilt CREATE INDEX invalid (#9988).
Map<String, IndexBuilder> byName = new LinkedHashMap<>();
String sql = "SELECT i.relname AS index_name, am.amname AS index_type, " +
"(ix.indisunique AND ix.indisvalid) AS is_unique, ix.indisprimary AS is_primary, " +
"COALESCE(a.attname, " + profile.catalogPrefixedFunction("get_indexdef") + "(ix.indexrelid, k.n, true)) AS column_text, " +
"COALESCE(a.attname::text, " + profile.catalogPrefixedFunction("get_indexdef") + "(ix.indexrelid, k.n, true)) AS column_text, " +
"(a.attname IS NULL) AS is_expression, " +
"array_length(ix.indoption, 1) AS nkeyatts, k.n AS key_position, " +
"ix.indoption[(k.n - 1)::int] AS key_option " +
@@ -201,6 +201,9 @@ class PostgresLikeAgentTest {
String sql = String.join("\n", MetadataSqlFake.statements);
assertTrue(sql.contains("LEFT JOIN pg_catalog.pg_attribute a ON a.attrelid = t.oid AND a.attnum = k.attnum AND k.attnum > 0"), sql);
assertTrue(sql.contains("pg_catalog.pg_get_indexdef(ix.indexrelid, k.n, true)"), sql);
// #9988: a bare COALESCE(name, text) resolves to `name`, so PostgreSQL truncated a
// long expression key part to 63 bytes and the rebuilt CREATE INDEX was invalid.
assertTrue(sql.contains("COALESCE(a.attname::text, pg_catalog.pg_get_indexdef(ix.indexrelid, k.n, true)) AS column_text"), sql);
assertTrue(sql.contains("ix.indisunique AND ix.indisvalid"), sql);
assertTrue(sql.contains("ix.indoption[(k.n - 1)::int]"), sql);
assertTrue(sql.contains("array_length(ix.indoption, 1) AS nkeyatts"), sql);