Skip to content

Commit a382a18

Browse files
craig[bot]kev-caoyuzefovich
committed
144958: backup: fail compaction jobs upon encountering range keys r=msbutler a=kev-cao Previously if a compaction job encountered a range key, it would erroneously continue the job and succeed. As the current implementation of the backup compaction iterator skips range keys, if the compaction job encounters an SST file that contains range keys, it should fail the job. Epic: None Release note: Compaction jobs now properly fail upon encountering range keys. 145456: sql: prohibit jsonpath as element in composite type r=yuzefovich a=yuzefovich This commit ties a few loose ends around the jsonpath data type: - it prohibits creation of a composite type with jsonpath as an element (it should be fine, but we're doing this out of caution until we have encoding for jsonpath) - it adds a validation for each element of a composite type for whether it can be used as a column type (under an assumption that if a type cannot be used as a column type, then any composite types consisting of that type cannot either) - it also adds the issue number to the errors. Informs: #144910. Fixes: #144911. Release note: None Co-authored-by: Kevin Cao <[email protected]> Co-authored-by: Yahor Yuzefovich <[email protected]>
3 parents c8e3617 + 56b62b8 + 25a6c16 commit a382a18

File tree

8 files changed

+128
-14
lines changed

8 files changed

+128
-14
lines changed

pkg/backup/compaction_job.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ func (c compactionChain) createCompactionManifest(
534534
// range keys.
535535
lastBackup := c.lastBackup()
536536
if len(lastBackup.Tenants) != 0 {
537-
return nil, errors.New("backup compactions does not yet support range keys")
537+
return nil, errors.New("backup compactions does not support range keys")
538538
}
539539
if err := checkCoverage(ctx, c.lastBackup().Spans, c.backupChain); err != nil {
540540
return nil, err

pkg/backup/compaction_processor.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,11 @@ func openSSTs(
367367
storeFiles := make([]storageccl.StoreFile, 0, len(entry.Files))
368368
for idx := range entry.Files {
369369
file := entry.Files[idx]
370+
if file.HasRangeKeys {
371+
// TODO (kev-cao): Come back and update this to range keys when
372+
// SSTSinkKeyWriter has been updated to support range keys.
373+
return mergedSST{}, errors.New("backup compactions does not support range keys")
374+
}
370375
dir, err := execCfg.DistSQLSrv.ExternalStorage(ctx, file.Dir)
371376
if err != nil {
372377
return mergedSST{}, err
@@ -375,8 +380,6 @@ func openSSTs(
375380
storeFiles = append(storeFiles, storageccl.StoreFile{Store: dir, FilePath: file.Path})
376381
}
377382
iterOpts := storage.IterOptions{
378-
// TODO (kev-cao): Come back and update this to range keys when
379-
// SSTSinkKeyWriter has been updated to support range keys.
380383
KeyTypes: storage.IterKeyTypePointsOnly,
381384
LowerBound: keys.LocalMax,
382385
UpperBound: keys.MaxKey,

pkg/backup/datadriven_test.go

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,10 @@ func (d *datadrivenTestState) getSQLDBForVC(
397397
// - expect-pausepoint: expects the backup job to end up in a paused state because
398398
// of a pausepoint error.
399399
//
400+
// - aost: expects a tag referencing a previously saved cluster timestamp
401+
// using `save-cluster-ts`. It then runs the backup as of the saved cluster
402+
// timestamp.
403+
//
400404
// - "restore" [args]
401405
// Executes restore specific operations.
402406
//
@@ -410,13 +414,29 @@ func (d *datadrivenTestState) getSQLDBForVC(
410414
// - aost: expects a tag referencing a previously saved cluster timestamp
411415
// using `save-cluster-ts`. It then runs the restore as of the saved cluster
412416
// timestamp.
417+
418+
// - "compact" [args]
419+
// Executes compaction specific operations.
420+
//
421+
// Supported arguments:
422+
//
423+
// - tag=<tag>: tag the compaction job to reference it in the future.
424+
//
425+
// - expect-pausepoint: expects the restore job to end up in a paused state because
426+
// of a pausepoint error.
427+
//
428+
// - start: expects a tag referencing a previously saved cluster timestamp
429+
// using `save-cluster-ts`.
430+
//
431+
// - end: expects a tag referencing a previously saved cluster timestamp
432+
// using `save-cluster-ts`.
413433
//
414434
// - "schema" [args]
415435
// Executes schema change specific operations.
416436
//
417437
// Supported arguments:
418438
//
419-
// - tag=<tag>: tag the schema change job to reference it in the future.
439+
// - tag=<tag>: tag the schema change job to reference it in the future.
420440
//
421441
// - expect-pausepoint: expects the schema change job to end up in a paused state because
422442
// of a pausepoint error.
@@ -426,9 +446,9 @@ func (d *datadrivenTestState) getSQLDBForVC(
426446
//
427447
// Supported arguments:
428448
//
429-
// - type: kv request type. Currently, only DeleteRange is supported
449+
// - type: kv request type. Currently, only DeleteRange is supported
430450
//
431-
// - target: SQL target. Currently, only table names are supported.
451+
// - target: SQL target. Currently, only table names are supported.
432452
//
433453
// - "corrupt-backup" uri=<collectionUri>
434454
// Finds the latest backup in the provided collection uri an flips a bit in one SST in the backup
@@ -797,6 +817,18 @@ func runTestDataDriven(t *testing.T, testFilePathFromWorkspace string) {
797817
return ""
798818

799819
case "backup":
820+
if d.HasArg("aost") {
821+
var aost string
822+
d.ScanArgs(t, "aost", &aost)
823+
var ts string
824+
var ok bool
825+
if ts, ok = ds.clusterTimestamps[aost]; !ok {
826+
t.Fatalf("no cluster timestamp found for %s", aost)
827+
}
828+
// Replace the ts tag with the actual timestamp.
829+
d.Input = strings.Replace(d.Input, aost,
830+
fmt.Sprintf("'%s'", ts), 1)
831+
}
800832
return execWithTagAndPausePoint(jobspb.TypeBackup)
801833

802834
case "import":
@@ -818,6 +850,29 @@ func runTestDataDriven(t *testing.T, testFilePathFromWorkspace string) {
818850
}
819851
return execWithTagAndPausePoint(jobspb.TypeRestore)
820852

853+
case "compact":
854+
if !d.HasArg("start") || !d.HasArg("end") {
855+
t.Fatalf("must specify start and end for compaction")
856+
}
857+
var start, end string
858+
d.ScanArgs(t, "start", &start)
859+
d.ScanArgs(t, "end", &end)
860+
var startTs, endTs string
861+
var ok bool
862+
if startTs, ok = ds.clusterTimestamps[start]; !ok {
863+
t.Fatalf("no cluster timestamp found for %s", start)
864+
}
865+
if endTs, ok = ds.clusterTimestamps[end]; !ok {
866+
t.Fatalf("no cluster timestamp found for %s", end)
867+
}
868+
// Replace the ts tag with the actual timestamp.
869+
// ds.clusterTimestamps stores a stringified nanosecond epoch.
870+
d.Input = strings.Replace(d.Input, start,
871+
fmt.Sprintf("'%s'::DECIMAL", startTs), 1)
872+
d.Input = strings.Replace(d.Input, end,
873+
fmt.Sprintf("'%s'::DECIMAL", endTs), 1)
874+
875+
return execWithTagAndPausePoint(jobspb.TypeBackup)
821876
case "new-schema-change":
822877
return execWithTagAndPausePoint(jobspb.TypeNewSchemaChange)
823878

pkg/backup/testdata/backup-restore/rangekeys

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,11 @@ exec-sql
2929
INSERT INTO foo VALUES (3,'z');
3030
----
3131

32-
exec-sql
33-
BACKUP INTO 'nodelocal://1/test-root/';
32+
save-cluster-ts tag=start
33+
----
34+
35+
backup aost=start
36+
BACKUP INTO 'nodelocal://1/test-root/' AS OF SYSTEM TIME start;
3437
----
3538

3639
exec-sql
@@ -61,15 +64,27 @@ exec-sql
6164
INSERT INTO foo VALUES (4,'a'),(5,'b');
6265
----
6366

67+
# Create two incremental backups to test compaction
68+
exec-sql
69+
BACKUP INTO LATEST IN 'nodelocal://1/test-root/';
70+
----
71+
72+
exec-sql
73+
INSERT INTO foo VALUES (6,'a'),(7,'b');
74+
----
75+
6476
kv request=DeleteRange target=baz
6577
----
6678

6779
exec-sql
6880
INSERT INTO baz VALUES (33,'zz');
6981
----
7082

71-
exec-sql
72-
BACKUP INTO LATEST IN 'nodelocal://1/test-root/';
83+
save-cluster-ts tag=end
84+
----
85+
86+
backup aost=end
87+
BACKUP INTO LATEST IN 'nodelocal://1/test-root/' AS OF SYSTEM TIME end;
7388
----
7489

7590
exec-sql
@@ -84,9 +99,25 @@ regex matches error
8499
query-sql
85100
SELECT count(*) from orig1.foo
86101
----
87-
3
102+
5
88103

89104
query-sql
90105
SELECT count(*) from orig1.baz
91106
----
92107
1
108+
109+
let $backup_path
110+
SHOW BACKUPS IN 'nodelocal://1/test-root/';
111+
----
112+
113+
compact start=start end=end tag=comp_job
114+
SELECT crdb_internal.backup_compaction('BACKUP INTO LATEST IN ''nodelocal://1/test-root/''', '$backup_path', start, end);
115+
----
116+
117+
job tag=comp_job wait-for-state=failed
118+
----
119+
120+
query-sql regex=(compactions does not support range keys)
121+
SELECT error FROM [SHOW JOBS] WHERE job_type = 'BACKUP' AND status = 'failed' ORDER BY created DESC LIMIT 1;
122+
----
123+
true

pkg/sql/catalog/colinfo/col_type_info.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ func ValidateColumnDefType(ctx context.Context, st *cluster.Settings, t *types.T
9797
return unimplemented.NewWithIssueDetailf(23468, t.String(),
9898
"arrays of JSON unsupported as column type")
9999
}
100+
if t.ArrayContents().Family() == types.JsonpathFamily {
101+
return unimplemented.NewWithIssueDetailf(144910, t.String(),
102+
"arrays of jsonpath unsupported as column type")
103+
}
100104
if err := types.CheckArrayElementType(t.ArrayContents()); err != nil {
101105
return err
102106
}
@@ -109,13 +113,22 @@ func ValidateColumnDefType(ctx context.Context, st *cluster.Settings, t *types.T
109113
types.TSQueryFamily, types.TSVectorFamily, types.PGLSNFamily, types.PGVectorFamily, types.RefCursorFamily:
110114
// These types are OK.
111115

116+
case types.JsonpathFamily:
117+
return unimplemented.NewWithIssueDetailf(144910, t.String(),
118+
"jsonpath unsupported as column type")
119+
112120
case types.TupleFamily:
113121
if !t.UserDefined() {
114122
return pgerror.New(pgcode.InvalidTableDefinition, "cannot use anonymous record type as table column")
115123
}
116124
if t.TypeMeta.ImplicitRecordType {
117125
return unimplemented.NewWithIssue(70099, "cannot use table record type as table column")
118126
}
127+
for _, typ := range t.TupleContents() {
128+
if err := ValidateColumnDefType(ctx, st, typ); err != nil {
129+
return err
130+
}
131+
}
119132

120133
default:
121134
return pgerror.Newf(pgcode.InvalidTableDefinition,

pkg/sql/create_type.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descs"
2020
"github.com/cockroachdb/cockroach/pkg/sql/catalog/typedesc"
2121
"github.com/cockroachdb/cockroach/pkg/sql/enum"
22+
"github.com/cockroachdb/cockroach/pkg/sql/oidext"
2223
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
2324
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
2425
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgnotice"
@@ -400,6 +401,10 @@ func CreateEnumTypeDesc(
400401
}).BuildCreatedMutableType(), nil
401402
}
402403

404+
var jsonpathInCompositeErr = unimplemented.NewWithIssueDetailf(
405+
144910, "", "jsonpath cannot be used in a composite type",
406+
)
407+
403408
// createCompositeTypeDesc creates a new composite type descriptor.
404409
func createCompositeTypeDesc(
405410
params runParams,
@@ -426,6 +431,10 @@ func createCompositeTypeDesc(
426431
if typ.Identical(types.Trigger) {
427432
return nil, tree.CannotAcceptTriggerErr
428433
}
434+
if typ.Oid() == oidext.T_jsonpath || typ.Oid() == oidext.T__jsonpath {
435+
// TODO(#144910): this is unsupported for now, out of caution.
436+
return nil, jsonpathInCompositeErr
437+
}
429438
if err = tree.CheckUnsupportedType(params.ctx, &params.p.semaCtx, typ); err != nil {
430439
return nil, err
431440
}

pkg/sql/logictest/testdata/logic_test/jsonpath

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@ SELECT '$.a'::JSONPATH
1010
----
1111
$."a"
1212

13-
statement error pq: value type jsonpath cannot be used for table columns
13+
statement error pq: unimplemented: jsonpath unsupported as column type
1414
CREATE TABLE a (j JSONPATH)
1515

16-
statement error pq: value type jsonpath cannot be used for table columns
16+
statement error pq: unimplemented: arrays of jsonpath unsupported as column type
1717
CREATE TABLE a (j JSONPATH[])
1818

19+
statement error pq: unimplemented: jsonpath cannot be used in a composite type
20+
CREATE TYPE typ AS (j JSONPATH);
21+
1922
query T
2023
SELECT '$'::JSONPATH
2124
----

pkg/sql/sem/tree/create.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ type CreateType struct {
370370
Variety CreateTypeVariety
371371
// EnumLabels is set when this represents a CREATE TYPE ... AS ENUM statement.
372372
EnumLabels EnumValueList
373-
// CompositeTypeList is set when this repesnets a CREATE TYPE ... AS ( )
373+
// CompositeTypeList is set when this represents a CREATE TYPE ... AS ( )
374374
// statement.
375375
CompositeTypeList []CompositeTypeElem
376376
// IfNotExists is true if IF NOT EXISTS was requested.

0 commit comments

Comments
 (0)