Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix drizzle-kit push crash on compound indexes with expression members #3888

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 14 additions & 25 deletions drizzle-kit/src/serializer/pgSerializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1531,37 +1531,26 @@ WHERE
}

const dbIndexes = await db.query(
`SELECT DISTINCT ON (t.relname, ic.relname, k.i) t.relname as table_name, ic.relname AS indexname,
`SELECT DISTINCT ON (t.relname, ic.relname, k.i) t.relname as table_name, ic.relname AS indexname,
k.i AS index_order,
i.indisunique as is_unique,
am.amname as method,
ic.reloptions as with,
coalesce(a.attname,
(('{' || pg_get_expr(
i.indexprs,
i.indrelid
)
|| '}')::text[]
)[k.i]
) AS column_name,
CASE
WHEN pg_get_expr(i.indexprs, i.indrelid) IS NOT NULL THEN 1
ELSE 0
END AS is_expression,
CASE
WHEN i.indkey[k.i-1] != 0 THEN a.attname
ELSE pg_get_indexdef(i.indexrelid, k.i, true)
END AS column_name,
Comment on lines +1539 to +1542
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any cases when a.attname and the returned value from pg_get_indexref are different for simple columns? pg_get_indexref returns the same values that the index was created with, couldn't this be simplified to just pg_get_indexdef(i.indexrelid, k.i, true) as column_name?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly— I have no idea!

This SQL was generated by Claude and seems to work for my use case. I can happily debug through the Typescript but my knowledge of PG introspection/internals is weak.

I'm hoping a reviewer with knowledge of pg details can make a proper assessment of the Claude-generated SQL changes— entirely possible your simplification is valid.

for simple columns

this is a fix for compound indexes where at least one component is an expression (ie not a simple column). Not sure if that affects your answer or not.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By "simple columns" I meant references to columns (without expressions), such as source_language in your example. Both the original and your refactored solution work for those cases, I was just wondering if we could make it cleaner and easier to read without the conditional and array indexing 😄 Other than that, it's essentially the same patch as I made on our project and hadn't had any issues so far, hope a maintainer can review it soon!

CASE WHEN pg_get_expr(i.indexprs, i.indrelid) IS NOT NULL THEN 1 ELSE 0 END AS is_expression,
i.indoption[k.i-1] & 1 = 1 AS descending,
i.indoption[k.i-1] & 2 = 2 AS nulls_first,
pg_get_expr(
i.indpred,
i.indrelid
) as where,
opc.opcname
FROM pg_class t
LEFT JOIN pg_index i ON t.oid = i.indrelid
LEFT JOIN pg_class ic ON ic.oid = i.indexrelid
CROSS JOIN LATERAL (SELECT unnest(i.indkey), generate_subscripts(i.indkey, 1) + 1) AS k(attnum, i)
LEFT JOIN pg_attribute AS a
ON i.indrelid = a.attrelid AND k.attnum = a.attnum
JOIN pg_namespace c on c.oid = t.relnamespace
pg_get_expr(i.indpred, i.indrelid) as where,
opc.opcname
FROM pg_class t
LEFT JOIN pg_index i ON t.oid = i.indrelid
LEFT JOIN pg_class ic ON ic.oid = i.indexrelid
CROSS JOIN LATERAL generate_series(1, array_length(i.indkey, 1)) AS k(i)
LEFT JOIN pg_attribute AS a ON i.indrelid = a.attrelid AND i.indkey[k.i-1] = a.attnum
JOIN pg_namespace c on c.oid = t.relnamespace
LEFT JOIN pg_am AS am ON ic.relam = am.oid
JOIN pg_opclass opc ON opc.oid = ANY(i.indclass)
WHERE
Expand Down