Skip to content

fix(api): skip uuidv7() creation when PostgreSQL 18 provides it natively#36998

Open
zeeshan56656 wants to merge 1 commit into
langgenius:mainfrom
zeeshan56656:fix/36907-pg18-uuidv7-migration
Open

fix(api): skip uuidv7() creation when PostgreSQL 18 provides it natively#36998
zeeshan56656 wants to merge 1 commit into
langgenius:mainfrom
zeeshan56656:fix/36907-pg18-uuidv7-migration

Conversation

@zeeshan56656
Copy link
Copy Markdown

Summary

On PostgreSQL 18 a fresh start fails during database migration. Revision 1c9ba48be8e4 runs CREATE FUNCTION uuidv7(), but PostgreSQL 18 already ships a native pg_catalog.uuidv7(). Our create collides with the built-in, and the unqualified COMMENT ON FUNCTION uuidv7 that follows becomes ambiguous, so the migration aborts and the API container never finishes booting. Reported against PostgreSQL 18.3 in #36907.

This PR guards the create. In upgrade() we look up pg_proc/pg_namespace for a uuidv7 function in the pg_catalog schema before creating our own. When the server already provides one (PostgreSQL 18), we skip both the CREATE FUNCTION uuidv7() and its COMMENT, and call sites that use uuidv7() then resolve to the native implementation, which has a compatible zero-argument signature. The uuidv7_boundary(timestamptz) helper is still created unconditionally because PostgreSQL 18 does not provide it. This reuses the same _is_pg(conn) dialect-guard style that #28188 added to this file.

downgrade() now uses DROP FUNCTION IF EXISTS public.uuidv7() and DROP FUNCTION IF EXISTS public.uuidv7_boundary(timestamptz). The IF EXISTS plus the explicit public schema make a rollback a no-op on PostgreSQL 18 (where the public copy was never created) and keep it from ever touching the built-in.

Behavior on PostgreSQL 13 to 17 is unchanged: there is no native uuidv7, so both functions are created exactly as before. The change is scoped to this one migration file.

Fixes #36907

Tests

Added api/tests/unit_tests/migrations/test_uuidv7_pg18_migration.py. It mocks the Alembic bind and covers each branch separately:

  • native uuidv7 absent (PostgreSQL 13 to 17): both uuidv7() and uuidv7_boundary() are created
  • native uuidv7 present (PostgreSQL 18): uuidv7() is skipped, uuidv7_boundary() is still created, and the probe queries the pg_catalog schema
  • downgrade() emits the IF EXISTS public-scoped drops
  • non-PostgreSQL dialects stay a no-op for both upgrade() and downgrade()
python -m pytest api/tests/unit_tests/migrations/test_uuidv7_pg18_migration.py -v

5 passed.

Checklist

  • This change requires a documentation update, included: Dify Document
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.
  • I ran make lint && make type-check (backend) and cd web && pnpm exec vp staged (frontend) to appease the lint gods

Lint note: .ruff.toml excludes migrations/*, so the migration file is not linted. The new test file passes ruff check and ruff format --check cleanly. There are no frontend changes.

PostgreSQL 18 ships a native pg_catalog.uuidv7(), so the migration's
CREATE FUNCTION uuidv7() collided with the built-in and the unqualified
COMMENT became ambiguous, aborting the migration on a fresh start.

Probe pg_catalog before creating our own uuidv7() and skip it when the
server already provides one. uuidv7_boundary(timestamptz) is still
created unconditionally since PostgreSQL 18 does not provide it. The
downgrade now uses IF EXISTS public-scoped drops so a rollback is a
no-op on PostgreSQL 18 and never touches the built-in.

Fixes langgenius#36907
@zeeshan56656 zeeshan56656 requested a review from a team June 3, 2026 08:22
@dosubot dosubot Bot added the size:S This PR changes 10-29 lines, ignoring generated files. label Jun 3, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 3, 2026

Pyrefly Type Coverage

Metric Base PR Delta
Type coverage 46.10% 46.09% -0.01%
Strict coverage 45.59% 45.58% -0.01%
Typed symbols 25,079 25,079 0
Untyped symbols 29,648 29,659 +11
Modules 2788 2789 +1

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 3, 2026

Pyrefly Diff

base → PR
--- /tmp/pyrefly_base.txt	2026-06-03 08:57:36.151536845 +0000
+++ /tmp/pyrefly_pr.txt	2026-06-03 08:57:22.276500510 +0000
@@ -6103,6 +6103,10 @@
   --> tests/unit_tests/libs/test_time_parser.py:54:38
 ERROR Argument `SimpleNamespace` is not assignable to parameter `account` with type `Account | None` in function `libs.helper.TokenManager.generate_token` [bad-argument-type]
   --> tests/unit_tests/libs/test_token_manager.py:76:17
+ERROR Argument `ModuleSpec | None` is not assignable to parameter `spec` with type `ModuleSpec` in function `_frozen_importlib.module_from_spec` [bad-argument-type]
+  --> tests/unit_tests/migrations/test_uuidv7_pg18_migration.py:31:46
+ERROR Object of class `NoneType` has no attribute `loader` [missing-attribute]
+  --> tests/unit_tests/migrations/test_uuidv7_pg18_migration.py:32:5
 ERROR TypedDict `TenantCustomConfigDict` does not have key `feature1` [bad-typed-dict-key]
    --> tests/unit_tests/models/test_account_models.py:551:23
 ERROR TypedDict `TenantCustomConfigDict` does not have key `feature2` [bad-typed-dict-key]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PostgreSQL 18 compatibility issue: migration fails because uuidv7() already exists in pg_catalog

1 participant