Skip to content

Commit 4e0e2ad

Browse files
committed
workload/schemachanger: handle foreign key mutations
Previously, the insert operation could fail on foreign key violation errors, if the foreign key constraint was enforce using a mutation. This patch detects those scenarios and turns these errors into potential errors. Fixes: #148070 Release note: None
1 parent c6dedb3 commit 4e0e2ad

File tree

2 files changed

+40
-3
lines changed

2 files changed

+40
-3
lines changed

pkg/workload/schemachange/error_screening.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,3 +1726,32 @@ func (og *operationGenerator) tableHasUniqueConstraintMutation(
17261726
AND (m->'index'->>'unique')::BOOL IS TRUE
17271727
);`, tableName)
17281728
}
1729+
1730+
// tableHasForeignKeyMutation determines if a table has any foreign key constraint
1731+
// mutation ongoing. This means either being added or dropped.
1732+
func (og *operationGenerator) tableHasForeignKeyMutation(
1733+
ctx context.Context, tx pgx.Tx, tableName *tree.TableName,
1734+
) (bool, error) {
1735+
return og.scanBool(ctx, tx, `
1736+
WITH table_desc AS (
1737+
SELECT crdb_internal.pb_to_json(
1738+
'desc',
1739+
descriptor,
1740+
false
1741+
)->'table' as d
1742+
FROM system.descriptor
1743+
WHERE id = $1::REGCLASS
1744+
)
1745+
SELECT EXISTS (
1746+
SELECT * FROM (
1747+
SELECT jsonb_array_elements(
1748+
CASE WHEN d->'mutations' IS NULL
1749+
THEN '[]'::JSONB
1750+
ELSE d->'mutations'
1751+
END
1752+
) as m
1753+
FROM table_desc)
1754+
WHERE (m->>'direction')::STRING IN ('ADD', 'DROP')
1755+
AND (m->'constraint'->>'foreign_key') IS NOT NULL
1756+
);`, tableName)
1757+
}

pkg/workload/schemachange/operation_generator.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3082,6 +3082,7 @@ func (og *operationGenerator) insertRow(ctx context.Context, tx pgx.Tx) (stmt *o
30823082
// we will need to evaluate generated expressions below.
30833083
hasUniqueConstraints := false
30843084
hasUniqueConstraintsMutations := false
3085+
hasForeignKeyMutations := false
30853086
fkViolation := false
30863087
if !anyInvalidInserts {
30873088
// Verify if the new row may violate unique constraints by checking the
@@ -3103,18 +3104,25 @@ func (og *operationGenerator) insertRow(ctx context.Context, tx pgx.Tx) (stmt *o
31033104
if err != nil {
31043105
return nil, err
31053106
}
3106-
3107+
// Determine if a foreign key mutation exists.
3108+
hasForeignKeyMutations, err = og.tableHasForeignKeyMutation(ctx, tx, tableName)
3109+
if err != nil {
3110+
return nil, err
3111+
}
31073112
}
31083113

31093114
stmt.potentialExecErrors.addAll(codesWithConditions{
31103115
{code: pgcode.UniqueViolation, condition: hasUniqueConstraints || hasUniqueConstraintsMutations},
3111-
{code: pgcode.ForeignKeyViolation, condition: fkViolation},
3116+
{code: pgcode.ForeignKeyViolation, condition: fkViolation || hasForeignKeyMutations},
31123117
{code: pgcode.NotNullViolation, condition: true},
31133118
{code: pgcode.CheckViolation, condition: true},
31143119
{code: pgcode.InsufficientPrivilege, condition: true}, // For RLS violations
31153120
})
31163121
og.expectedCommitErrors.addAll(codesWithConditions{
3117-
{code: pgcode.ForeignKeyViolation, condition: fkViolation},
3122+
{code: pgcode.ForeignKeyViolation, condition: fkViolation && !hasForeignKeyMutations},
3123+
})
3124+
og.potentialCommitErrors.addAll(codesWithConditions{
3125+
{code: pgcode.ForeignKeyViolation, condition: hasForeignKeyMutations},
31183126
})
31193127

31203128
var formattedRows []string

0 commit comments

Comments
 (0)