Skip to content

Commit 03e9fbb

Browse files
authored
Merge pull request #152907 from spilchen/blathers/backport-release-25.3-152879
release-25.3: workload/schemachange: handle triggers in NULL constraint validation
2 parents ebcf35e + b13e228 commit 03e9fbb

File tree

1 file changed

+36
-1
lines changed

1 file changed

+36
-1
lines changed

pkg/workload/schemachange/error_screening.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,28 @@ func isValidGenerationError(code string) bool {
494494
return getValidGenerationErrors().contains(pgCode)
495495
}
496496

497+
// tableHasBeforeInsertTrigger checks if the table has any BEFORE INSERT triggers
498+
// that could affect the insertion behavior.
499+
func (og *operationGenerator) tableHasBeforeInsertTrigger(
500+
ctx context.Context, tx pgx.Tx, tableName *tree.TableName,
501+
) (bool, error) {
502+
query := `
503+
SELECT EXISTS (
504+
SELECT 1 FROM pg_trigger t
505+
JOIN pg_class c ON t.tgrelid = c.oid
506+
JOIN pg_namespace n ON c.relnamespace = n.oid
507+
WHERE n.nspname = $1
508+
AND c.relname = $2
509+
AND t.tgenabled != 'D'
510+
AND (t.tgtype & 2) = 2 -- BEFORE trigger
511+
AND (t.tgtype & 4) = 4 -- INSERT trigger
512+
)`
513+
514+
var hasTrigger bool
515+
err := tx.QueryRow(ctx, query, tableName.Schema(), tableName.Object()).Scan(&hasTrigger)
516+
return hasTrigger, err
517+
}
518+
497519
// validateGeneratedExpressionsForInsert goes through generated expressions and
498520
// detects if a valid value can be generated with a given insert row.
499521
func (og *operationGenerator) validateGeneratedExpressionsForInsert(
@@ -514,6 +536,12 @@ func (og *operationGenerator) validateGeneratedExpressionsForInsert(
514536
isInvalidInsert = true
515537
}
516538
}()
539+
540+
hasBeforeInsertTrigger, err := og.tableHasBeforeInsertTrigger(ctx, tx, tableName)
541+
if err != nil {
542+
return false, nil, nil, err
543+
}
544+
517545
// Put values to be inserted into a column name to value map to simplify lookups.
518546
columnsToValues := map[tree.Name]string{}
519547
for i := 0; i < len(nonGeneratedColNames); i++ {
@@ -601,7 +629,14 @@ func (og *operationGenerator) validateGeneratedExpressionsForInsert(
601629
}
602630
if isNull && !isNullable && !nullViolationAdded {
603631
nullViolationAdded = true
604-
expectedErrCodes = expectedErrCodes.append(pgcode.NotNullViolation)
632+
// If there is a trigger, then we cannot be sure if the NULL value
633+
// will actually be inserted. It may be replaced or the row itself could
634+
// be cleared.
635+
if hasBeforeInsertTrigger {
636+
potentialErrCodes = potentialErrCodes.append(pgcode.NotNullViolation)
637+
} else {
638+
expectedErrCodes = expectedErrCodes.append(pgcode.NotNullViolation)
639+
}
605640
}
606641
// Re-run the another variant in case we have NULL values in arithmetic
607642
// of expression, the evaluation order can differ depending on how variables

0 commit comments

Comments
 (0)