mirror of
https://github.com/zitadel/zitadel.git
synced 2026-11-03 12:47:09 -06:00
<!-- CURSOR_AGENT_PR_BODY_BEGIN --> - Setup 79 rewrites unique-constraint owners in one statement per file. On a large table that statement holds row locks for the whole update, and adding `LIMIT` does not help: the username statement bitmap-scans every empty `owners` value and then index-scans every user in the instance for each constraint. - The backfill joined projection tables before those tables were created and before event replay filled them. - The page cursor is a `text[]`. `database.TextArray.Value` joined elements with commas and never quoted them, so a project role key such as `a,b` became two array elements. The next page repeated the same row and the migration stopped. - Each setup 79 statement pages its projection by primary key and updates `eventstore.unique_constraints` with an equality lookup on `(instance_id, unique_type, unique_field)`. - The original field and `lower(...)` are separate `UNION` arms, so the lookup stays a primary-key probe. - Setup repeats a file until the projection page is empty. A page that matches no constraint still advances the cursor. - `BatchSize` is a `uint16`, configured like `ForceFinalize` (`cmd/setup/steps.yaml`, `ZITADEL_BACKFILLUNIQUECONSTRAINTOWNERS_BATCHSIZE`) and is not stored on lastRun. The default in `steps.yaml` is 5000. - Each page logs the file, the page index, and the number of rows updated. - The backfill runs after projection prefill. When `InitProjections` is disabled or setup is for mirror, it still runs against the projection rows already stored. - `TextArray.Value` quotes every element and backslash-escapes `"` and `\`. An empty array is still SQL `NULL`, so existing `ANY($1)` callers stay unchanged. The setup statements already cast `$1` to `text[]`. - Integration tests for the username and org-domain statements pass an empty cursor and a page size. - `TestTextArray_Value` expects quoted elements, and a round trip through `Scan` covers a comma, a quote, and a backslash. - initial fix https://github.com/zitadel/zitadel/pull/12740 - fix of the setup job, broken by the first fix https://github.com/zitadel/zitadel/pull/12785 - needs to be a `fix` tag because `perf` wouldn't bump the version - Based on `owner-app-fix`. - A setup process already running the old statement keeps that plan until it is restarted. <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-31bfb5c4-5888-43f0-85cf-af1af097ca30?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-31bfb5c4-5888-43f0-85cf-af1af097ca30&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Silvan <adlerhurst@users.noreply.github.com>
30 lines
1.2 KiB
SQL
30 lines
1.2 KiB
SQL
-- unique_field: aggregateID:mailTextType:language (policy.NewAddMailTextUniqueConstraint)
|
|
WITH page AS MATERIALIZED (
|
|
SELECT t.instance_id, t.aggregate_id, t.type, t.language
|
|
FROM {{.message_texts}} t
|
|
WHERE (t.instance_id, t.aggregate_id, t.type, t.language) > (COALESCE(($1::text[])[1], ''), COALESCE(($1::text[])[2], ''), COALESCE(($1::text[])[3], ''), COALESCE(($1::text[])[4], ''))
|
|
AND t.aggregate_id <> t.instance_id
|
|
ORDER BY t.instance_id, t.aggregate_id, t.type, t.language
|
|
LIMIT $2
|
|
),
|
|
keys AS (
|
|
SELECT t.instance_id, t.aggregate_id, t.aggregate_id || ':' || t.type || ':' || t.language AS unique_field
|
|
FROM page t
|
|
UNION
|
|
SELECT t.instance_id, t.aggregate_id, lower(t.aggregate_id || ':' || t.type || ':' || t.language)
|
|
FROM page t
|
|
),
|
|
upd AS (
|
|
UPDATE eventstore.unique_constraints uc
|
|
SET owners = ARRAY['org:' || k.aggregate_id]
|
|
FROM keys k
|
|
WHERE uc.instance_id = k.instance_id
|
|
AND uc.unique_type = 'mail_text'
|
|
AND uc.unique_field = k.unique_field
|
|
AND uc.owners = '{}'
|
|
RETURNING 1
|
|
)
|
|
SELECT
|
|
(SELECT ARRAY[instance_id, aggregate_id, type, language] FROM page ORDER BY instance_id DESC, aggregate_id DESC, type DESC, language DESC LIMIT 1),
|
|
(SELECT COUNT(*) FROM upd);
|