Skip to content

Commit 6e67e13

Browse files
craig[bot]fqazi
andcommitted
Merge #153181
153181: workload/schemachanger: check for duplicate trigger functions r=fqazi a=fqazi Previously, it was possible for trigger function names to collide if the workload was run mutliple times against a CRDB server. Certain tests like the mixed version tests will intentionally do this. So, before creating triggers or trigger functions we need to validate that function names do not collide. Fixes: #152716 Release note: None Co-authored-by: Faizan Qazi <[email protected]>
2 parents 308bd8a + 2e0221c commit 6e67e13

File tree

2 files changed

+27
-5
lines changed

2 files changed

+27
-5
lines changed

pkg/workload/schemachange/error_screening.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,17 @@ func (og *operationGenerator) columnExistsOnTable(
6666
)`, tableName.Schema(), tableName.Object(), columnName)
6767
}
6868

69+
func (og *operationGenerator) fnExistsByName(
70+
ctx context.Context, tx pgx.Tx, schemaName string, routineName string,
71+
) (bool, error) {
72+
return og.scanBool(ctx, tx, `SELECT EXISTS (
73+
SELECT routine_name
74+
FROM information_schema.routines
75+
WHERE routine_schema = $1
76+
AND routine_name = $2
77+
)`, schemaName, routineName)
78+
}
79+
6980
func (og *operationGenerator) tableHasRows(
7081
ctx context.Context, tx pgx.Tx, tableName *tree.TableName,
7182
) (bool, error) {

pkg/workload/schemachange/operation_generator.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5434,18 +5434,29 @@ func (og *operationGenerator) createTrigger(ctx context.Context, tx pgx.Tx) (*op
54345434
return nil, err
54355435
}
54365436

5437+
schemaName, err := og.randSchema(ctx, tx, og.alwaysExisting())
5438+
if err != nil {
5439+
return nil, err
5440+
}
54375441
triggerFunctionName := fmt.Sprintf("trigger_function_%s", og.newUniqueSeqNumSuffix())
5442+
resolvedTriggerFunctionName := fmt.Sprintf("%s.%s", schemaName, triggerFunctionName)
54385443

5439-
// Try to generate a random SELECT statement for more complex dependencies
5444+
// Try to generate a random SELECT statement for more coamplex dependencies
54405445
selectStmt, err := og.selectStmt(ctx, tx)
54415446
if err != nil {
54425447
return nil, err
54435448
}
54445449
// Our trigger function will always return the original value to avoid
54455450
// breaking inserts.
5446-
triggerFunction := fmt.Sprintf(`CREATE FUNCTION %s() RETURNS TRIGGER AS $FUNC_BODY$ BEGIN %s;RETURN NEW;END; $FUNC_BODY$ LANGUAGE PLpgSQL`, triggerFunctionName, selectStmt.sql)
5451+
triggerFunction := fmt.Sprintf(`CREATE FUNCTION %s() RETURNS TRIGGER AS $FUNC_BODY$ BEGIN %s;RETURN NEW;END; $FUNC_BODY$ LANGUAGE PLpgSQL`, resolvedTriggerFunctionName, selectStmt.sql)
5452+
5453+
// Check if the routine already exists.
5454+
routineAlreadyExists, err := og.fnExistsByName(ctx, tx, schemaName, triggerFunctionName)
5455+
if err != nil {
5456+
return nil, err
5457+
}
54475458

5448-
og.LogMessage(fmt.Sprintf("Created trigger function %s", triggerFunction))
5459+
og.LogMessage(fmt.Sprintf("Created trigger function %s", resolvedTriggerFunctionName))
54495460

54505461
// Create TRIGGER statement components
54515462
triggerActionTime := "BEFORE"
@@ -5474,8 +5485,7 @@ func (og *operationGenerator) createTrigger(ctx context.Context, tx pgx.Tx) (*op
54745485

54755486
// Build the SQL statement
54765487
sqlStatement := fmt.Sprintf("%s;CREATE TRIGGER %s %s %s ON %s FOR EACH ROW EXECUTE FUNCTION %s()",
5477-
triggerFunction, triggerName, triggerActionTime, eventClause, tableName, triggerFunctionName)
5478-
5488+
triggerFunction, triggerName, triggerActionTime, eventClause, tableName, resolvedTriggerFunctionName)
54795489
og.LogMessage(fmt.Sprintf("createTrigger: %s", sqlStatement))
54805490

54815491
opStmt := makeOpStmt(OpStmtDDL)
@@ -5487,6 +5497,7 @@ func (og *operationGenerator) createTrigger(ctx context.Context, tx pgx.Tx) (*op
54875497
// It does not catch cases where the select statement in the trigger function
54885498
// has a select query on a table that doesn't exist.
54895499
{code: pgcode.UndefinedTable, condition: !triggerTableExists},
5500+
{code: pgcode.DuplicateFunction, condition: routineAlreadyExists},
54905501
})
54915502

54925503
opStmt.potentialExecErrors.addAll(codesWithConditions{

0 commit comments

Comments
 (0)