Skip to content

Commit fe69e9e

Browse files
committed
workload: remove FK dependency check in schemachanger drop column
The schemachanger previously attempted to predict whether a DROP COLUMN operation would fail due to a foreign key (FK) dependency. This logic has proven to be unreliable and difficult to maintain correctly. Rather than investing more effort into fixing the latest edge cases, we’ve decided to remove the FK dependency detection logic altogether. This simplifies the codebase. Resolves: #159034 Release note: none
1 parent 367d1b8 commit fe69e9e

File tree

3 files changed

+21
-508
lines changed

3 files changed

+21
-508
lines changed

pkg/sql/logictest/testdata/logic_test/fk

Lines changed: 0 additions & 366 deletions
Original file line numberDiff line numberDiff line change
@@ -4837,369 +4837,3 @@ DROP TABLE t2_fk;
48374837
DROP TABLE t1_fk;
48384838

48394839
subtest end
4840-
4841-
subtest drop_col_dep_non_self_fk_stored
4842-
4843-
# The logic in this UDF is equivalent to and originated from
4844-
# columnDropViolatesFKIndexRequirements() in pkg/workload/schemachange/error_screening.go.
4845-
statement ok
4846-
CREATE FUNCTION column_drop_violates_fk_index_requirements(table_name STRING, column_name STRING)
4847-
RETURNS BOOL
4848-
LANGUAGE SQL
4849-
AS $$
4850-
WITH fk AS (
4851-
SELECT oid,
4852-
(
4853-
SELECT r.relname
4854-
FROM pg_class AS r
4855-
WHERE r.oid = c.confrelid
4856-
) AS base_table,
4857-
a.attname AS base_col,
4858-
array_position(
4859-
c.confkey,
4860-
a.attnum
4861-
) AS base_ordinal,
4862-
(
4863-
SELECT r.relname
4864-
FROM pg_class AS r
4865-
WHERE r.oid = c.conrelid
4866-
) AS referencing_table,
4867-
unnest(
4868-
(
4869-
SELECT array_agg(attname)
4870-
FROM pg_attribute
4871-
WHERE attrelid = c.conrelid
4872-
AND ARRAY[attnum] <@ c.conkey
4873-
AND array_position(
4874-
c.confkey,
4875-
a.attnum
4876-
)
4877-
= array_position(
4878-
c.conkey,
4879-
attnum
4880-
)
4881-
)
4882-
) AS referencing_col
4883-
FROM pg_constraint AS c
4884-
JOIN pg_attribute AS a ON c.confrelid
4885-
= a.attrelid
4886-
AND ARRAY[
4887-
attnum
4888-
]
4889-
<@ c.conkey
4890-
WHERE c.confrelid = table_name::REGCLASS::OID
4891-
),
4892-
all_index_columns AS (
4893-
SELECT
4894-
i.indexrelid::REGCLASS::STRING
4895-
AS index_name,
4896-
a.attname AS col_name,
4897-
NOT
4898-
i.indisunique AS non_unique,
4899-
a.attnum
4900-
> i.indnkeyatts AS storing,
4901-
a.attnum AS index_ordinal
4902-
FROM
4903-
pg_index AS i
4904-
JOIN pg_attribute AS a ON
4905-
a.attrelid
4906-
= i.indexrelid
4907-
AND a.attnum > 0
4908-
WHERE
4909-
i.indrelid
4910-
= table_name::REGCLASS::OID
4911-
),
4912-
valid_indexes AS (
4913-
SELECT *
4914-
FROM all_index_columns
4915-
WHERE index_name
4916-
NOT IN (
4917-
SELECT DISTINCT
4918-
index_name
4919-
FROM all_index_columns
4920-
WHERE col_name = column_name
4921-
AND index_name
4922-
NOT LIKE '%_pkey'
4923-
)
4924-
),
4925-
fk_col_counts AS (
4926-
SELECT oid, count(*) AS num_cols
4927-
FROM fk
4928-
GROUP BY oid
4929-
),
4930-
index_column_counts AS (
4931-
SELECT index_name, count(*) as num_cols FROM valid_indexes WHERE storing='f' GROUP BY index_name
4932-
),
4933-
matching_fks AS (
4934-
SELECT fk.oid
4935-
FROM fk
4936-
JOIN valid_indexes ON
4937-
fk.base_col
4938-
= valid_indexes.col_name
4939-
JOIN index_column_counts ON
4940-
valid_indexes.index_name = index_column_counts.index_name
4941-
JOIN fk_col_counts ON
4942-
fk.oid
4943-
= fk_col_counts.oid
4944-
WHERE valid_indexes.storing
4945-
= false
4946-
AND valid_indexes.non_unique
4947-
= false
4948-
AND index_column_counts.num_cols = fk_col_counts.num_cols
4949-
GROUP BY fk.oid,
4950-
valid_indexes.index_name,
4951-
fk_col_counts.num_cols
4952-
HAVING count(DISTINCT fk.base_col)
4953-
= fk_col_counts.num_cols
4954-
)
4955-
SELECT EXISTS(
4956-
SELECT *
4957-
FROM fk
4958-
WHERE oid NOT IN (SELECT DISTINCT oid FROM matching_fks)
4959-
)
4960-
$$;
4961-
4962-
statement ok
4963-
CREATE TABLE parent_dep_store (
4964-
id INT PRIMARY KEY,
4965-
key_col INT UNIQUE,
4966-
stored STRING,
4967-
FAMILY f1 (id, key_col, stored)
4968-
) WITH (schema_locked = false);
4969-
4970-
statement ok
4971-
CREATE UNIQUE INDEX idx_parent_dep_store ON parent_dep_store (key_col) STORING (stored);
4972-
4973-
statement ok
4974-
CREATE TABLE child_dep_store (
4975-
id INT PRIMARY KEY,
4976-
parent_key INT REFERENCES parent_dep_store (key_col),
4977-
FAMILY f1 (id, parent_key)
4978-
) WITH (schema_locked = false);
4979-
4980-
query B
4981-
SELECT column_drop_violates_fk_index_requirements('parent_dep_store', 'stored');
4982-
----
4983-
false
4984-
4985-
statement ok
4986-
ALTER TABLE parent_dep_store DROP COLUMN stored;
4987-
4988-
query TT
4989-
SHOW CREATE TABLE parent_dep_store
4990-
----
4991-
parent_dep_store CREATE TABLE public.parent_dep_store (
4992-
id INT8 NOT NULL,
4993-
key_col INT8 NULL,
4994-
CONSTRAINT parent_dep_store_pkey PRIMARY KEY (id ASC),
4995-
UNIQUE INDEX parent_dep_store_key_col_key (key_col ASC),
4996-
FAMILY f1 (id, key_col)
4997-
);
4998-
4999-
statement ok
5000-
DROP TABLE child_dep_store;
5001-
5002-
statement ok
5003-
DROP TABLE parent_dep_store;
5004-
5005-
subtest end
5006-
5007-
subtest drop_col_dep_non_self_fk_key
5008-
5009-
statement ok
5010-
CREATE TABLE parent_dep_key (
5011-
id INT PRIMARY KEY,
5012-
key_col INT,
5013-
stored STRING,
5014-
FAMILY f1 (id, key_col, stored)
5015-
) WITH (schema_locked = false);
5016-
5017-
statement ok
5018-
CREATE UNIQUE INDEX idx_parent_dep_key ON parent_dep_key (key_col) STORING (stored);
5019-
5020-
statement ok
5021-
CREATE TABLE child_dep_key (
5022-
id INT PRIMARY KEY,
5023-
parent_key INT REFERENCES parent_dep_key (key_col),
5024-
FAMILY f1 (id, parent_key)
5025-
) WITH (schema_locked = false);
5026-
5027-
query B
5028-
SELECT column_drop_violates_fk_index_requirements('parent_dep_key', 'key_col');
5029-
----
5030-
true
5031-
5032-
statement error pq: "idx_parent_dep_key" is referenced by foreign key from table "child_dep_key"
5033-
ALTER TABLE parent_dep_key DROP COLUMN key_col;
5034-
5035-
query TT
5036-
SHOW CREATE TABLE parent_dep_key
5037-
----
5038-
parent_dep_key CREATE TABLE public.parent_dep_key (
5039-
id INT8 NOT NULL,
5040-
key_col INT8 NULL,
5041-
stored STRING NULL,
5042-
CONSTRAINT parent_dep_key_pkey PRIMARY KEY (id ASC),
5043-
UNIQUE INDEX idx_parent_dep_key (key_col ASC) STORING (stored),
5044-
FAMILY f1 (id, key_col, stored)
5045-
);
5046-
5047-
statement ok
5048-
DROP TABLE child_dep_key;
5049-
5050-
statement ok
5051-
DROP TABLE parent_dep_key;
5052-
5053-
subtest end
5054-
5055-
subtest drop_col_dep_self_ref_stored
5056-
5057-
statement ok
5058-
CREATE TABLE self_dep_store (
5059-
id INT PRIMARY KEY,
5060-
ref INT,
5061-
stored STRING,
5062-
FAMILY f1 (id, ref, stored)
5063-
) WITH (schema_locked = false);
5064-
5065-
statement ok
5066-
CREATE UNIQUE INDEX idx_self_dep_store ON self_dep_store (ref) STORING (stored);
5067-
5068-
statement ok
5069-
ALTER TABLE self_dep_store ADD CONSTRAINT fk_self_dep_store FOREIGN KEY (ref) REFERENCES self_dep_store (id);
5070-
5071-
query B
5072-
SELECT column_drop_violates_fk_index_requirements('self_dep_store', 'stored');
5073-
----
5074-
false
5075-
5076-
statement ok
5077-
ALTER TABLE self_dep_store DROP COLUMN stored;
5078-
5079-
query TT
5080-
SHOW CREATE TABLE self_dep_store
5081-
----
5082-
self_dep_store CREATE TABLE public.self_dep_store (
5083-
id INT8 NOT NULL,
5084-
ref INT8 NULL,
5085-
CONSTRAINT self_dep_store_pkey PRIMARY KEY (id ASC),
5086-
CONSTRAINT fk_self_dep_store FOREIGN KEY (ref) REFERENCES public.self_dep_store(id),
5087-
FAMILY f1 (id, ref)
5088-
);
5089-
5090-
statement ok
5091-
DROP TABLE self_dep_store;
5092-
5093-
subtest end
5094-
5095-
subtest drop_col_dep_self_ref_key
5096-
5097-
statement ok
5098-
CREATE TABLE self_dep_key (
5099-
id INT PRIMARY KEY,
5100-
ref INT,
5101-
stored STRING,
5102-
FAMILY f1 (id, ref, stored)
5103-
) WITH (schema_locked = false);
5104-
5105-
statement ok
5106-
CREATE UNIQUE INDEX idx_self_dep_key ON self_dep_key (ref) STORING (stored);
5107-
5108-
statement ok
5109-
ALTER TABLE self_dep_key ADD CONSTRAINT fk_self_dep_key FOREIGN KEY (ref) REFERENCES self_dep_key (id);
5110-
5111-
query B
5112-
SELECT column_drop_violates_fk_index_requirements('self_dep_key', 'ref');
5113-
----
5114-
false
5115-
5116-
statement ok
5117-
ALTER TABLE self_dep_key DROP COLUMN ref;
5118-
5119-
query TT
5120-
SHOW CREATE TABLE self_dep_key
5121-
----
5122-
self_dep_key CREATE TABLE public.self_dep_key (
5123-
id INT8 NOT NULL,
5124-
stored STRING NULL,
5125-
CONSTRAINT self_dep_key_pkey PRIMARY KEY (id ASC),
5126-
FAMILY f1 (id, stored)
5127-
);
5128-
5129-
statement ok
5130-
DROP TABLE self_dep_key;
5131-
5132-
# Alternative secondary index has more storing columns, but has the correct key column
5133-
# prefix to work.
5134-
statement ok
5135-
CREATE TABLE self_dep_key_2 (
5136-
col1_w4_6 INET NOT NULL,
5137-
col1_w4_7 DATE NOT NULL,
5138-
col1_w4_8 STRING COLLATE da_DK NOT NULL,
5139-
col1_w4_11 STRING NOT NULL,
5140-
col1_w4_13 INTERVAL NOT NULL,
5141-
col1_w4_14 UUID NOT NULL,
5142-
col1_w4_15 "char" NOT NULL,
5143-
CONSTRAINT table_w4_1_pkey PRIMARY KEY (col1_w4_6 ASC) USING HASH WITH (bucket_count=16),
5144-
CONSTRAINT table_w4_1_col1_w4_6_table_w4_1_col1_w4_6_fk FOREIGN KEY (col1_w4_6) REFERENCES self_dep_key_2 (col1_w4_6) ON DELETE CASCADE ON UPDATE CASCADE,
5145-
UNIQUE INDEX table_w4_1_col1_w4_6_key (col1_w4_6 ASC) STORING (col1_w4_7, col1_w4_11, col1_w4_13, col1_w4_14, col1_w4_15),
5146-
UNIQUE INDEX table_w4_1_col1_w4_6_col1_w4_8_key (col1_w4_6 ASC, col1_w4_8 DESC)
5147-
);
5148-
5149-
query B
5150-
SELECT column_drop_violates_fk_index_requirements('self_dep_key_2', 'col1_w4_8');
5151-
----
5152-
false
5153-
5154-
# Sanity this should work.
5155-
statement ok
5156-
ALTER TABLE self_dep_key_2 DROP COLUMN col1_w4_8;
5157-
5158-
5159-
# Self reference where dropping the stored column will be trouble.
5160-
statement ok
5161-
CREATE TABLE self_dep_key_3 (
5162-
id INT PRIMARY KEY,
5163-
indexed_col INT NOT NULL,
5164-
stored_col INT NOT NULL,
5165-
UNIQUE (indexed_col) STORING (stored_col)
5166-
);
5167-
5168-
statement ok
5169-
ALTER TABLE self_dep_key_3 ADD CONSTRAINT t_fk
5170-
FOREIGN KEY (indexed_col) REFERENCES self_dep_key_3 (indexed_col);
5171-
5172-
query B
5173-
SELECT column_drop_violates_fk_index_requirements('self_dep_key_3', 'stored_col');
5174-
----
5175-
true
5176-
5177-
# This should fail
5178-
statement error pq: "self_dep_key_3_indexed_col_key" is referenced by foreign key from table "self_dep_key_3"
5179-
ALTER TABLE self_dep_key_3 DROP COLUMN stored_col;
5180-
5181-
# Self reference where dropping the stored column will lead to the only other
5182-
# index not being usable (not the same prefix + length).
5183-
statement ok
5184-
CREATE TABLE self_dep_key_4 (
5185-
id INT PRIMARY KEY,
5186-
indexed_col INT NOT NULL,
5187-
stored_col INT NOT NULL,
5188-
UNIQUE (indexed_col) STORING (stored_col),
5189-
UNIQUE (indexed_col, id)
5190-
);
5191-
5192-
statement ok
5193-
ALTER TABLE self_dep_key_4 ADD CONSTRAINT t_fk
5194-
FOREIGN KEY (indexed_col) REFERENCES self_dep_key_4 (indexed_col);
5195-
5196-
query B
5197-
SELECT column_drop_violates_fk_index_requirements('self_dep_key_4', 'stored_col');
5198-
----
5199-
true
5200-
5201-
# This should fail
5202-
statement error pq: "self_dep_key_4_indexed_col_key" is referenced by foreign key from table "self_dep_key_4"
5203-
ALTER TABLE self_dep_key_4 DROP COLUMN stored_col;
5204-
5205-
subtest end

0 commit comments

Comments
 (0)