From e107fa418de25a077433dc531fa88fec47961353 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Wed, 11 Nov 2026 21:06:53 +0400 Subject: [PATCH] =?UTF-8?q?perf(formulas):=20=D1=80=D0=B0=D0=B2=D0=B5?= =?UTF-8?q?=D0=BD=D1=81=D1=82=D0=B2=D0=BE=20=D0=BF=D0=BE=20=D0=B2=D0=BB?= =?UTF-8?q?=D0=B0=D0=B4=D0=B5=D0=BB=D1=8C=D1=86=D1=83=20=D0=B2=D0=BC=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=BE=20IS=20NOT=20DISTINCT=20FROM,=20=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0=D0=B7=20=D0=BD=D0=B0=20Infinity=20(AURORA-1896,=20?= =?UTF-8?q?M-1,=20M-2,=20M-3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- .../versions/sql/0060_cell_formula.sql | 80 ++++++++++++------- .../integration/test_cell_formula_sql.py | 2 +- 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/api/alembic/versions/sql/0060_cell_formula.sql b/api/alembic/versions/sql/0060_cell_formula.sql index 6cac185..c10f4af 100644 --- a/api/alembic/versions/sql/0060_cell_formula.sql +++ b/api/alembic/versions/sql/0060_cell_formula.sql @@ -85,12 +85,20 @@ BEGIN END IF; IF v_expr = '' THEN - DELETE FROM v3.cell_formula cf - WHERE cf.sheet = p_sheet - AND cf.line_id = v_line - AND cf.column_key = v_column - AND cf.budget_form_id IS NOT DISTINCT FROM p_budget_form_id - AND cf.rf_project_report_id IS NOT DISTINCT FROM p_report_id; + -- равенство по владельцу в отдельных ветках: так планировщик берёт частичные уникальные индексы + IF p_budget_form_id IS NOT NULL THEN + DELETE FROM v3.cell_formula cf + WHERE cf.budget_form_id = p_budget_form_id + AND cf.sheet = p_sheet + AND cf.line_id = v_line + AND cf.column_key = v_column; + ELSE + DELETE FROM v3.cell_formula cf + WHERE cf.rf_project_report_id = p_report_id + AND cf.sheet = p_sheet + AND cf.line_id = v_line + AND cf.column_key = v_column; + END IF; CONTINUE; END IF; @@ -106,7 +114,7 @@ BEGIN EXCEPTION WHEN others THEN RAISE EXCEPTION 'invalid_formula: value'; END; - IF v_value IS NULL OR v_value = 'NaN'::numeric THEN + IF v_value IS NULL OR v_value::text IN ('NaN', 'Infinity', '-Infinity') THEN RAISE EXCEPTION 'invalid_formula: value'; END IF; @@ -117,6 +125,16 @@ BEGIN ON CONFLICT (budget_form_id, sheet, line_id, column_key) WHERE budget_form_id IS NOT NULL DO UPDATE SET expression = EXCLUDED.expression, value = EXCLUDED.value, updated_by = EXCLUDED.updated_by, updated_at = EXCLUDED.updated_at; + + RETURN QUERY + SELECT cf.line_id, cf.column_key, cf.expression, cf.value, cf.updated_by, + u.full_name::text, cf.updated_at + FROM v3.cell_formula cf + LEFT JOIN v3.app_user u ON u.id = cf.updated_by + WHERE cf.budget_form_id = p_budget_form_id + AND cf.sheet = p_sheet + AND cf.line_id = v_line + AND cf.column_key = v_column; ELSE INSERT INTO v3.cell_formula AS cf (rf_project_report_id, sheet, line_id, column_key, expression, value, updated_by, updated_at) @@ -124,18 +142,16 @@ BEGIN ON CONFLICT (rf_project_report_id, sheet, line_id, column_key) WHERE rf_project_report_id IS NOT NULL DO UPDATE SET expression = EXCLUDED.expression, value = EXCLUDED.value, updated_by = EXCLUDED.updated_by, updated_at = EXCLUDED.updated_at; + RETURN QUERY + SELECT cf.line_id, cf.column_key, cf.expression, cf.value, cf.updated_by, + u.full_name::text, cf.updated_at + FROM v3.cell_formula cf + LEFT JOIN v3.app_user u ON u.id = cf.updated_by + WHERE cf.rf_project_report_id = p_report_id + AND cf.sheet = p_sheet + AND cf.line_id = v_line + AND cf.column_key = v_column; END IF; - - RETURN QUERY - SELECT cf.line_id, cf.column_key, cf.expression, cf.value, cf.updated_by, - u.full_name::text, cf.updated_at - FROM v3.cell_formula cf - LEFT JOIN v3.app_user u ON u.id = cf.updated_by - WHERE cf.sheet = p_sheet - AND cf.line_id = v_line - AND cf.column_key = v_column - AND cf.budget_form_id IS NOT DISTINCT FROM p_budget_form_id - AND cf.rf_project_report_id IS NOT DISTINCT FROM p_report_id; END LOOP; END; $function$; @@ -163,15 +179,25 @@ BEGIN RAISE EXCEPTION 'invalid_formula: owner'; END IF; - RETURN QUERY - SELECT cf.line_id, cf.column_key, cf.expression, cf.value, cf.updated_by, - u.full_name::text, cf.updated_at - FROM v3.cell_formula cf - LEFT JOIN v3.app_user u ON u.id = cf.updated_by - WHERE cf.sheet = p_sheet - AND cf.budget_form_id IS NOT DISTINCT FROM p_budget_form_id - AND cf.rf_project_report_id IS NOT DISTINCT FROM p_report_id - ORDER BY cf.line_id, cf.column_key; + IF p_budget_form_id IS NOT NULL THEN + RETURN QUERY + SELECT cf.line_id, cf.column_key, cf.expression, cf.value, cf.updated_by, + u.full_name::text, cf.updated_at + FROM v3.cell_formula cf + LEFT JOIN v3.app_user u ON u.id = cf.updated_by + WHERE cf.budget_form_id = p_budget_form_id + AND cf.sheet = p_sheet + ORDER BY cf.line_id, cf.column_key; + ELSE + RETURN QUERY + SELECT cf.line_id, cf.column_key, cf.expression, cf.value, cf.updated_by, + u.full_name::text, cf.updated_at + FROM v3.cell_formula cf + LEFT JOIN v3.app_user u ON u.id = cf.updated_by + WHERE cf.rf_project_report_id = p_report_id + AND cf.sheet = p_sheet + ORDER BY cf.line_id, cf.column_key; + END IF; END; $function$; diff --git a/api/tests/integration/test_cell_formula_sql.py b/api/tests/integration/test_cell_formula_sql.py index 08d01da..d333497 100644 --- a/api/tests/integration/test_cell_formula_sql.py +++ b/api/tests/integration/test_cell_formula_sql.py @@ -87,7 +87,7 @@ def test_empty_after_normalization_is_no_formula(svod2_sql): @pytest.mark.parametrize( "formula,value", - [("drop table", 1), ("1" * 501, 1), ("1+1", None), ("1+1", "abc"), ("1+1", "NaN")], + [("drop table", 1), ("1" * 501, 1), ("1+1", None), ("1+1", "abc"), ("1+1", "NaN"), ("1+1", "Infinity"), ("1+1", "-Infinity")], ) def test_invalid_formula_raises(svod2_sql, formula, value): admin, line = _admin(svod2_sql), _line(svod2_sql)