diff --git a/pkg/cmd/roachtest/tests/mixed_version_schemachange.go b/pkg/cmd/roachtest/tests/mixed_version_schemachange.go index d67433fae2c2..63ba5cb8fae7 100644 --- a/pkg/cmd/roachtest/tests/mixed_version_schemachange.go +++ b/pkg/cmd/roachtest/tests/mixed_version_schemachange.go @@ -27,7 +27,8 @@ func registerSchemaChangeMixedVersions(r registry.Registry) { // This tests the work done for 20.1 that made schema changes jobs and in // addition prevented making any new schema changes on a mixed cluster in // order to prevent bugs during upgrades. - Cluster: r.MakeClusterSpec(4), + Cluster: r.MakeClusterSpec(4), + NativeLibs: registry.LibGEOS, Run: func(ctx context.Context, t test.Test, c cluster.Cluster) { maxOps := 100 concurrency := 5 @@ -56,12 +57,6 @@ func runSchemaChangeWorkloadStep(loadNode, maxOps, concurrency int) versionStep t.L().Printf("Workload step run: %d", numFeatureRuns) runCmd := []string{ "./workload run schemachange --verbose=1", - // The workload is still in development and occasionally discovers schema - // change errors so for now we don't fail on them but only on panics, server - // crashes, deadlocks, etc. - // TODO(spaskob): remove when https://github.com/cockroachdb/cockroach/issues/47430 - // is closed. - "--tolerate-errors=true", fmt.Sprintf("--max-ops %d", maxOps), fmt.Sprintf("--concurrency %d", concurrency), fmt.Sprintf("{pgurl:1-%d}", u.c.Spec().NodeCount), diff --git a/pkg/workload/schemachange/operation_generator.go b/pkg/workload/schemachange/operation_generator.go index c447fee36163..779b2d519a2a 100644 --- a/pkg/workload/schemachange/operation_generator.go +++ b/pkg/workload/schemachange/operation_generator.go @@ -931,13 +931,22 @@ func (og *operationGenerator) createIndex(ctx context.Context, tx pgx.Tx) (*opSt return nil, err } + // Only generate invisible indexes when they are supported. + invisibleIndexesIsNotSupported, err := isClusterVersionLessThan( + ctx, + tx, + clusterversion.ByKey(clusterversion.Start22_2)) + if err != nil { + return nil, err + } + def := &tree.CreateIndex{ Name: tree.Name(indexName), Table: *tableName, - Unique: og.randIntn(4) == 0, // 25% UNIQUE - Inverted: og.randIntn(10) == 0, // 10% INVERTED - IfNotExists: og.randIntn(2) == 0, // 50% IF NOT EXISTS - NotVisible: og.randIntn(20) == 0, // 5% NOT VISIBLE + Unique: og.randIntn(4) == 0, // 25% UNIQUE + Inverted: og.randIntn(10) == 0, // 10% INVERTED + IfNotExists: og.randIntn(2) == 0, // 50% IF NOT EXISTS + NotVisible: og.randIntn(20) == 0 && !invisibleIndexesIsNotSupported, // 5% NOT VISIBLE } regionColumn := "" @@ -1180,6 +1189,49 @@ func (og *operationGenerator) createTable(ctx context.Context, tx pgx.Tx) (*opSt stmt := randgen.RandCreateTableWithColumnIndexNumberGenerator(og.params.rng, "table", tableIdx, databaseHasMultiRegion, og.newUniqueSeqNum) stmt.Table = *tableName stmt.IfNotExists = og.randIntn(2) == 0 + trigramIsNotSupported, err := isClusterVersionLessThan( + ctx, + tx, + clusterversion.ByKey(clusterversion.TrigramInvertedIndexes)) + if err != nil { + return nil, err + } + hasTrigramIdxUnsupported := func() bool { + if !trigramIsNotSupported { + return false + } + // Check if any of the indexes have trigrams involved. + for _, def := range stmt.Defs { + if idx, ok := def.(*tree.IndexTableDef); ok && idx.Inverted { + lastColumn := idx.Columns[len(idx.Columns)-1] + switch lastColumn.OpClass { + case "gin_trgm_ops", "gist_trgm_ops": + return true + } + } + } + return false + }() + + invisibleIndexesIsNotSupported, err := isClusterVersionLessThan( + ctx, + tx, + clusterversion.ByKey(clusterversion.Start22_2)) + if err != nil { + return nil, err + } + hasInvisibleIndexesUnsupported := func() bool { + if !invisibleIndexesIsNotSupported { + return false + } + // Check if any of the indexes have trigrams involved. + for _, def := range stmt.Defs { + if idx, ok := def.(*tree.IndexTableDef); ok && idx.NotVisible { + return true + } + } + return false + }() tableExists, err := og.tableExists(ctx, tx, tableName) if err != nil { @@ -1194,6 +1246,12 @@ func (og *operationGenerator) createTable(ctx context.Context, tx pgx.Tx) (*opSt {code: pgcode.DuplicateRelation, condition: tableExists && !stmt.IfNotExists}, {code: pgcode.UndefinedSchema, condition: !schemaExists}, }.add(opStmt.expectedExecErrors) + // Compatibility errors aren't guaranteed since the cluster version update is not + // fully transaction aware. + codesWithConditions{ + {code: pgcode.FeatureNotSupported, condition: hasTrigramIdxUnsupported}, + {code: pgcode.Syntax, condition: hasInvisibleIndexesUnsupported}, + }.add(opStmt.potentialExecErrors) opStmt.sql = tree.Serialize(stmt) return opStmt, nil } @@ -2350,6 +2408,18 @@ func (og *operationGenerator) insertRow(ctx context.Context, tx pgx.Tx) (stmt *o if err != nil { return nil, err } + // If we aren't on 22.2 then disable the insert plugin, since 21.X + // can have schema instrospection queries fail due to an optimizer bug. + skipInserts, err := isClusterVersionLessThan(ctx, tx, clusterversion.ByKey(clusterversion.Start22_2)) + if err != nil { + return nil, err + } + // If inserts are to be skipped, we will intentionally, target the insert towards + // a non-existent table, so that they become no-ops. + if skipInserts { + tableExists = false + tableName.SchemaName = "InvalidObjectName" + } if !tableExists { return makeOpStmtForSingleError(OpStmtDML, fmt.Sprintf(