Skip to content

fix: handle PostgreSQL identifier quoting in partial index predicate comparison#5788

Merged
jacek-prisma merged 2 commits intoprisma:mainfrom
jay-l-e-e:fix/partial-index-pg-identifier-quoting
Mar 9, 2026
Merged

fix: handle PostgreSQL identifier quoting in partial index predicate comparison#5788
jacek-prisma merged 2 commits intoprisma:mainfrom
jay-l-e-e:fix/partial-index-pg-identifier-quoting

Conversation

@jay-l-e-e
Copy link
Copy Markdown
Contributor

@jay-l-e-e jay-l-e-e commented Mar 7, 2026

Description

Closes #5787

Problem

After #5780, partial indexes with object literal where clauses are still recreated on every migration when predicates contain multiple conditions. PostgreSQL's pg_get_expr() returns unquoted identifiers for lowercase column names (postcode), while Prisma generates quoted identifiers ("postcode"). The AST comparison treats these as different, causing needless drop+recreate cycles.

-- Prisma generates:
("deletedAt" IS NULL AND "postcode" IS NOT NULL)

-- pg_get_expr() returns:
((("deletedAt" IS NULL) AND (postcode IS NOT NULL)))

Solution

Extend exprs_semantically_eq to treat quoted and unquoted identifiers as equivalent when the unquoted form is a valid PostgreSQL identifier. Uses sqlparser with PostgreSqlDialect to verify that the identifier value can be safely used without quotes (i.e., it's not a reserved keyword and follows identifier rules).

Changes

  • PG schema_differ.rs — Added identifier quoting comparison in exprs_semantically_eq; checks if "foo" and foo refer to the same column by re-parsing with sqlparser
  • partial.rs — Regression test for object literal predicates with null and not: null conditions

Summary by CodeRabbit

  • Bug Fixes
    • Improved PostgreSQL schema comparison to more robustly treat identifiers as equivalent across quote styles and within expressions.
  • Tests
    • Added an idempotency test for Postgres partial indexes using object-literal filters with null and not-null conditions.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 7, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c8234276-4ff1-4b63-8174-916d36d63080

📥 Commits

Reviewing files that changed from the base of the PR and between 0953f51 and c75b823.

📒 Files selected for processing (1)
  • schema-engine/connectors/sql-schema-connector/src/flavour/postgres/schema_differ.rs

Walkthrough

Adds semantic identifier comparison to the Postgres schema differ to treat quoted and unquoted identifiers as equivalent in predicate ASTs, and adds a Postgres test ensuring a partial index with an object-literal where clause is idempotent across repeated pushes.

Changes

Cohort / File(s) Summary
Postgres Schema Differ Enhancement
schema-engine/connectors/sql-schema-connector/src/flavour/postgres/schema_differ.rs
Adds private fn idents_semantically_eq(a: &Ident, b: &Ident) -> bool; extends exprs_semantically_eq to handle Identifier and CompoundIdentifier by delegating to the new helper; refactors pg_predicates_semantically_equal imports and comparison paths to use the identifier-aware logic.
Partial Index Tests
schema-engine/sql-migration-tests/tests/migrations/indexes/partial.rs
Adds test partial_index_object_literal_null_and_not_null_is_idempotent_postgres (Postgres-only, excludes CockroachDB, enables partialIndexes) verifying idempotence of partial index with object-literal where clause across consecutive pushes.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title accurately describes the main change: adding PostgreSQL identifier quoting handling in partial index predicate comparison, matching the core objective.
Linked Issues check ✅ Passed Code changes directly address issue #5787: new idents_semantically_eq function handles quoted vs unquoted identifier comparison [#5787], and regression test validates the fix [#5787].
Out of Scope Changes check ✅ Passed All changes are directly scoped to the linked issue: identifier comparison logic in schema_differ.rs and a regression test in partial.rs.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jay-l-e-e
Copy link
Copy Markdown
Contributor Author

Hi @jacek-prisma, Please review these changes! Thank you.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 9, 2026

Merging this PR will not alter performance

✅ 11 untouched benchmarks
⏩ 11 skipped benchmarks1


Comparing jay-l-e-e:fix/partial-index-pg-identifier-quoting (c75b823) with main (ab73dcf)

Open in CodSpeed

Footnotes

  1. 11 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@jacek-prisma jacek-prisma merged commit 0f1690a into prisma:main Mar 9, 2026
94 of 99 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Partial index with object literal where clause still recreated on every migration (PostgreSQL identifier quoting)

2 participants