@@ -149,6 +149,8 @@ func TestDetectIndexConsistencyErrors(t *testing.T) {
149
149
// Each element corresponds to the issue at the same index in expectedIssues.
150
150
// For non-internal-error issues, the corresponding element should be nil.
151
151
expectedInternalErrorPatterns []map [string ]string
152
+ // useTimestampBeforeCorruption uses a timestamp from before corruption is introduced
153
+ useTimestampBeforeCorruption bool
152
154
}{
153
155
{
154
156
desc : "happy path sanity" ,
@@ -236,6 +238,15 @@ func TestDetectIndexConsistencyErrors(t *testing.T) {
236
238
},
237
239
postIndexSQL : "DELETE FROM test.t" , /* delete all rows to test hasRows=false code path */
238
240
},
241
+ {
242
+ desc : "timestamp before corruption - no issues found" ,
243
+ splitRangeDDL : "ALTER TABLE test.t SPLIT AT VALUES (500)" ,
244
+ indexDDL : []string {
245
+ "CREATE INDEX idx_t_a ON test.t (a) STORING (c)" ,
246
+ },
247
+ danglingIndexEntryInsertQuery : "SELECT 15, 30, 300, 'corrupt', 'e_3', 300.5" , // Add dangling entry after timestamp
248
+ useTimestampBeforeCorruption : true , // Use timestamp from before corruption
249
+ },
239
250
} {
240
251
t .Run (tc .desc , func (t * testing.T ) {
241
252
issueLogger .reset ()
@@ -288,6 +299,19 @@ func TestDetectIndexConsistencyErrors(t *testing.T) {
288
299
r .Exec (t , tc .postIndexSQL )
289
300
}
290
301
302
+ // Get timestamp before corruption if needed
303
+ var expectedASOFTime time.Time
304
+
305
+ if tc .useTimestampBeforeCorruption {
306
+ // Get timestamp before corruption
307
+ r .QueryRow (t , "SELECT now()::timestamp" ).Scan (& expectedASOFTime )
308
+ expectedASOFTime = expectedASOFTime .UTC ()
309
+
310
+ // Sleep for 1 millisecond to ensure corruption happens after timestamp
311
+ // This should be long enough to guarantee a different timestamp
312
+ time .Sleep (1 * time .Millisecond )
313
+ }
314
+
291
315
tableDesc := desctestutils .TestingGetPublicTableDescriptor (kvDB , codec , "test" , "t" )
292
316
secIndex := tableDesc .PublicNonPrimaryIndexes ()[0 ]
293
317
@@ -341,7 +365,18 @@ func TestDetectIndexConsistencyErrors(t *testing.T) {
341
365
// TODO(148365): Run INSPECT instead of SCRUB.
342
366
_ , err = db .Exec (`SET enable_scrub_job=true` )
343
367
require .NoError (t , err )
344
- _ , err = db .Query (`EXPERIMENTAL SCRUB TABLE test.t WITH OPTIONS INDEX ALL` )
368
+
369
+ // If not using timestamp before corruption, get current timestamp
370
+ if ! tc .useTimestampBeforeCorruption {
371
+ // Convert relative timestamp to absolute timestamp using CRDB
372
+ r .QueryRow (t , "SELECT (now() + '-1us')::timestamp" ).Scan (& expectedASOFTime )
373
+ expectedASOFTime = expectedASOFTime .UTC ()
374
+ }
375
+
376
+ // Use the absolute timestamp in nanoseconds for inspect command
377
+ absoluteTimestamp := fmt .Sprintf ("'%d'" , expectedASOFTime .UnixNano ())
378
+ scrubQuery := fmt .Sprintf (`EXPERIMENTAL SCRUB TABLE test.t AS OF SYSTEM TIME %s WITH OPTIONS INDEX ALL` , absoluteTimestamp )
379
+ _ , err = db .Query (scrubQuery )
345
380
if tc .expectedErrRegex == "" {
346
381
require .NoError (t , err )
347
382
require .Equal (t , 0 , issueLogger .numIssuesFound ())
@@ -380,7 +415,7 @@ func TestDetectIndexConsistencyErrors(t *testing.T) {
380
415
require .NotEqual (t , 0 , foundIssue .DatabaseID , "expected issue to have a database ID: %s" , expectedIssue )
381
416
require .NotEqual (t , 0 , foundIssue .SchemaID , "expected issue to have a schema ID: %s" , expectedIssue )
382
417
require .NotEqual (t , 0 , foundIssue .ObjectID , "expected issue to have an object ID: %s" , expectedIssue )
383
- require .NotEqual (t , time. Time {} , foundIssue .AOST , "expected issue to have an AOST time: %s" , expectedIssue )
418
+ require .Equal (t , expectedASOFTime , foundIssue .AOST . UTC () )
384
419
385
420
// Additional validation for internal errors
386
421
if foundIssue .ErrorType == "internal_error" {
@@ -460,7 +495,7 @@ func TestIndexConsistencyWithReservedWordColumns(t *testing.T) {
460
495
// TODO(148365): Run INSPECT instead of SCRUB.
461
496
_ , err := db .Exec (`SET enable_scrub_job=true` )
462
497
require .NoError (t , err )
463
- _ , err = db .Query (`EXPERIMENTAL SCRUB TABLE test.reserved_table WITH OPTIONS INDEX ALL` )
498
+ _ , err = db .Query (`EXPERIMENTAL SCRUB TABLE test.reserved_table AS OF SYSTEM TIME '-1us' WITH OPTIONS INDEX ALL` )
464
499
require .NoError (t , err , "should succeed on table with reserved word column names" )
465
500
require .Equal (t , 0 , issueLogger .numIssuesFound (), "No issues should be found in happy path test" )
466
501
0 commit comments