@@ -23,6 +23,7 @@ import (
23
23
"github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
24
24
"github.com/cockroachdb/cockroach/pkg/util/leaktest"
25
25
"github.com/cockroachdb/cockroach/pkg/util/log"
26
+ "github.com/cockroachdb/cockroach/pkg/util/randutil"
26
27
"github.com/cockroachdb/cockroach/pkg/workload"
27
28
"github.com/cockroachdb/cockroach/pkg/workload/histogram"
28
29
_ "github.com/cockroachdb/cockroach/pkg/workload/schemachange"
@@ -36,6 +37,7 @@ func TestWorkload(t *testing.T) {
36
37
skip .UnderDeadlock (t , "test connections can be too slow under expensive configs" )
37
38
skip .UnderRace (t , "test connections can be too slow under expensive configs" )
38
39
40
+ rng , _ := randutil .NewTestRand ()
39
41
scope := log .Scope (t )
40
42
defer scope .Close (t )
41
43
dir := scope .GetDirectory ()
@@ -70,31 +72,78 @@ func TestWorkload(t *testing.T) {
70
72
require .NoError (t , os .WriteFile (fmt .Sprintf ("%s/%s.rows" , dir , name ), []byte (sqlutils .MatrixToStr (mat )), 0666 ))
71
73
}
72
74
73
- // Grab a backup, dump the namespace and descriptor tables upon failure.
75
+ // Reusable validation function.
76
+ findInvalidObjects := func () {
77
+ t .Helper ()
78
+ var (
79
+ id int
80
+ databaseName string
81
+ schemaName string
82
+ objName string
83
+ objError string
84
+ )
85
+ numInvalidObjects := 0
86
+ rows , err := tdb .DB .QueryContext (ctx , `SELECT id, database_name, schema_name, obj_name, error FROM "".crdb_internal.invalid_objects` )
87
+ if err != nil {
88
+ t .Fatal (err )
89
+ }
90
+ for rows .Next () {
91
+ numInvalidObjects ++
92
+ if err := rows .Scan (& id , & databaseName , & schemaName , & objName , & objError ); err != nil {
93
+ t .Fatal (err )
94
+ }
95
+ t .Logf (
96
+ "invalid object found: id: %d, database_name: %s, schema_name: %s, obj_name: %s, error: %s" ,
97
+ id , databaseName , schemaName , objName , objError ,
98
+ )
99
+ }
100
+ if err := rows .Err (); err != nil {
101
+ t .Fatal (err )
102
+ }
103
+ if numInvalidObjects > 0 {
104
+ t .Errorf ("found %d invalid objects" , numInvalidObjects )
105
+ }
106
+ }
107
+
74
108
defer func () {
75
- if ! t .Failed () {
76
- return
109
+ // Run validation before dropping the database.
110
+ findInvalidObjects ()
111
+
112
+ // Only take a backup if the test failed.
113
+ if t .Failed () {
114
+ // Dump namespace and descriptor in their raw format. This is useful for
115
+ // processing results with some degree of scripting.
116
+ dumpRows ("namespace" , tdb .Query (t , `SELECT * FROM system.namespace` ))
117
+ dumpRows ("descriptor" , tdb .Query (t , "SELECT id, encode(descriptor, 'hex') FROM system.descriptor" ))
118
+ // Dump out a more human readable version of the above as well to allow for
119
+ // easy debugging by hand.
120
+ // NB: A LEFT JOIN is used here because not all descriptors (looking at you
121
+ // functions) have namespace entries.
122
+ dumpRows ("ns-desc-json" , tdb .Query (t , `
123
+ SELECT
124
+ "parentID",
125
+ "parentSchemaID",
126
+ descriptor.id,
127
+ name,
128
+ crdb_internal.pb_to_json('cockroach.sql.sqlbase.Descriptor', descriptor)
129
+ FROM system.descriptor
130
+ LEFT JOIN system.namespace ON namespace.id = descriptor.id
131
+ ` ))
132
+ tdb .Exec (t , "BACKUP DATABASE schemachange INTO 'nodelocal://1/backup'" )
133
+ t .Logf ("backup, tracing data, and system table dumps in %s" , dir )
134
+ }
135
+
136
+ // Drop the database and run validation again. Test DROP DATABASE behavior
137
+ // with legacy schema changer 50% of the time.
138
+ schemaChangerSetting := "on"
139
+ if rng .Float32 () < 0.5 {
140
+ schemaChangerSetting = "off"
77
141
}
78
- // Dump namespace and descriptor in their raw format. This is useful for
79
- // processing results with some degree of scripting.
80
- dumpRows ("namespace" , tdb .Query (t , `SELECT * FROM system.namespace` ))
81
- dumpRows ("descriptor" , tdb .Query (t , "SELECT id, encode(descriptor, 'hex') FROM system.descriptor" ))
82
- // Dump out a more human readable version of the above as well to allow for
83
- // easy debugging by hand.
84
- // NB: A LEFT JOIN is used here because not all descriptors (looking at you
85
- // functions) have namespace entries.
86
- dumpRows ("ns-desc-json" , tdb .Query (t , `
87
- SELECT
88
- "parentID",
89
- "parentSchemaID",
90
- descriptor.id,
91
- name,
92
- crdb_internal.pb_to_json('cockroach.sql.sqlbase.Descriptor', descriptor)
93
- FROM system.descriptor
94
- LEFT JOIN system.namespace ON namespace.id = descriptor.id
95
- ` ))
96
- tdb .Exec (t , "BACKUP DATABASE schemachange INTO 'nodelocal://1/backup'" )
97
- t .Logf ("backup, tracing data, and system table dumps in %s" , dir )
142
+ t .Logf ("running DROP with use_declarative_schema_changer = %s" , schemaChangerSetting )
143
+ tdb .Exec (t , "SET use_declarative_schema_changer = $1" , schemaChangerSetting )
144
+ tdb .Exec (t , "DROP DATABASE schemachange CASCADE" )
145
+ tdb .Exec (t , "RESET use_declarative_schema_changer" )
146
+ findInvalidObjects ()
98
147
}()
99
148
100
149
pgURL , cleanup := pgurlutils .PGUrl (t , tc .Server (0 ).AdvSQLAddr (), t .Name (), url .User ("testuser" ))
0 commit comments