From ceba034018eb80898bc0daf6ee8043ab405be5de Mon Sep 17 00:00:00 2001 From: Radu Berinde Date: Thu, 7 Mar 2019 11:24:09 -0500 Subject: [PATCH 1/7] opt: add more cost for lookup joins with more ON conditions This is a very limited fix for #34810. The core problem is that we don't take into account that if we have an ON condition, not only there's a cost to evaluate it on each row, but we are generating more internal rows to get a given number of output rows. I attempted to do a more general fix (for all join types), where I tried to estimate the "internal" number of rows using `unknownFilterSelectivity` for each ON condition. There were two problems: - in some cases (especially with lookup joins) we have an extra ON condition that doesn't actually do anything: `ab JOIN xy ON a=x AND a=10` becomes `ab JOIN xy ON a=x AND a=10 AND x=10` becomes and `a=10` could remain as an ON condition. This results in bad query plans in important cases (e.g. TPCC) where it prefers to do an extra lookup join (due to a non-covering index) just because of that condition. - we don't have the equality columns readily available for hash join (and didn't want to extract them each time we cost). In the future we may split the planning into a logical and physical stage, and we should then separate the logical joins from hash join. For 19.1, we simply simply add a cost for lookup joins that is proportional to the number of remaining ON conditions. This is the least disruptive method that still fixes the case observed in #34810. I will leave the issue open to address this properly in the next release. Note that although hash joins and merge joins have the same issue in principle, in practice we always generate these expressions with equality on all possible columns. Release note: None --- pkg/sql/opt/optgen/exprgen/testdata/join | 2 +- pkg/sql/opt/xform/coster.go | 27 +++ pkg/sql/opt/xform/testdata/coster/join | 155 ++++++++++++++++++ pkg/sql/opt/xform/testdata/coster/zone | 4 +- pkg/sql/opt/xform/testdata/external/tpcc | 4 +- .../opt/xform/testdata/external/tpcc-no-stats | 8 +- pkg/sql/opt/xform/testdata/rules/join | 4 +- 7 files changed, 193 insertions(+), 11 deletions(-) diff --git a/pkg/sql/opt/optgen/exprgen/testdata/join b/pkg/sql/opt/optgen/exprgen/testdata/join index 72a44b63f45c..94d66d22cac6 100644 --- a/pkg/sql/opt/optgen/exprgen/testdata/join +++ b/pkg/sql/opt/optgen/exprgen/testdata/join @@ -66,7 +66,7 @@ left-join (lookup abc@ab) ├── columns: t.public.abc.a:5(int) t.public.abc.b:6(int) ├── key columns: [5] = [5] ├── stats: [rows=333333.333] - ├── cost: 355060.02 + ├── cost: 358393.353 ├── scan t.public.def │ ├── columns: t.public.def.d:1(int) t.public.def.e:2(int) │ ├── stats: [rows=1000] diff --git a/pkg/sql/opt/xform/coster.go b/pkg/sql/opt/xform/coster.go index 95a316922567..ebf5e9722ec1 100644 --- a/pkg/sql/opt/xform/coster.go +++ b/pkg/sql/opt/xform/coster.go @@ -363,6 +363,33 @@ func (c *coster) computeLookupJoinCost(join *memo.LookupJoinExpr) memo.Cost { // cost of emitting the rows. numLookupCols := join.Cols.Difference(join.Input.Relational().OutputCols).Len() perRowCost := seqIOCostFactor + c.rowScanCost(join.Table, join.Index, numLookupCols) + + // Add a cost if we have to evaluate an ON condition on every row. The more + // leftover conditions, the more expensive it should be. We want to + // differentiate between two lookup joins where one uses only a subset of the + // columns. For example: + // abc JOIN xyz ON a=x AND b=y + // We could have a lookup join using an index on y (and left-over condition + // a=x), and another lookup join on an index on x,y. The latter is definitely + // preferable (the former could generate a lot of internal results that are + // then discarded). + // + // TODO(radu): we should take into account that the "internal" row count is + // higher, according to the selectivities of the conditions. Unfortunately + // this is very tricky, in particular because of left-over conditions that are + // not selective. + // For example: + // ab JOIN xy ON a=x AND x=10 + // becomes (during normalization): + // ab JOIN xy ON a=x AND a=10 AND x=10 + // which can become a lookup join with left-over condition x=10 which doesn't + // actually filter anything. + // + // TODO(radu): this should be extended to all join types. It's tricky for hash + // joins where we don't have the equality and leftover filters readily + // available. + perRowCost += cpuCostFactor * memo.Cost(len(join.On)) + cost += memo.Cost(join.Relational().Stats.RowCount) * perRowCost return cost } diff --git a/pkg/sql/opt/xform/testdata/coster/join b/pkg/sql/opt/xform/testdata/coster/join index 09417b25aa97..7e47f37927eb 100644 --- a/pkg/sql/opt/xform/testdata/coster/join +++ b/pkg/sql/opt/xform/testdata/coster/join @@ -166,3 +166,158 @@ index-join abc ├── cost: 10.306 ├── key: (1) └── fd: ()-->(3) + +# Regression test for #34810: make sure we pick the lookup join that uses +# all equality columns. + +exec-ddl +CREATE TABLE abcde ( + a TEXT NOT NULL, + b UUID NOT NULL, + c UUID NOT NULL, + d VARCHAR(255) NOT NULL, + e TEXT NOT NULL, + CONSTRAINT "primary" PRIMARY KEY (a, b, c), + UNIQUE INDEX idx_abd (a, b, d), + UNIQUE INDEX idx_abcd (a, b, c, d) +) +---- +TABLE abcde + ├── a string not null + ├── b uuid not null + ├── c uuid not null + ├── d string not null + ├── e string not null + ├── INDEX primary + │ ├── a string not null + │ ├── b uuid not null + │ └── c uuid not null + ├── INDEX idx_abd + │ ├── a string not null + │ ├── b uuid not null + │ ├── d string not null + │ └── c uuid not null (storing) + └── INDEX idx_abcd + ├── a string not null + ├── b uuid not null + ├── c uuid not null + └── d string not null + +exec-ddl +ALTER TABLE abcde INJECT STATISTICS '[ + { + "columns": ["a"], + "created_at": "2019-02-08 04:10:40.001179+00:00", + "row_count": 250000, + "distinct_count": 1 + }, + { + "columns": ["b"], + "created_at": "2019-02-08 04:10:40.119954+00:00", + "row_count": 250000, + "distinct_count": 2 + }, + { + "columns": ["d"], + "created_at": "2019-02-08 04:10:40.119954+00:00", + "row_count": 250000, + "distinct_count": 125000 + } +]' +---- + +exec-ddl +CREATE TABLE wxyz ( + w TEXT NOT NULL, + x UUID NOT NULL, + y UUID NOT NULL, + z TEXT NOT NULL, + CONSTRAINT "primary" PRIMARY KEY (w, x, y), + CONSTRAINT "foreign" FOREIGN KEY (w, x, y) REFERENCES abcde (a, b, c) +) +---- +TABLE wxyz + ├── w string not null + ├── x uuid not null + ├── y uuid not null + ├── z string not null + ├── INDEX primary + │ ├── w string not null + │ ├── x uuid not null + │ └── y uuid not null + └── FOREIGN KEY (w, x, y) REFERENCES t.public.abcde (a, b, c) + +exec-ddl +ALTER TABLE wxyz INJECT STATISTICS '[ + { + "columns": ["w"], + "created_at": "2019-02-08 04:10:40.001179+00:00", + "row_count": 10000, + "distinct_count": 1 + }, + { + "columns": ["x"], + "created_at": "2019-02-08 04:10:40.119954+00:00", + "row_count": 10000, + "distinct_count": 1 + }, + { + "columns": ["y"], + "created_at": "2019-02-08 04:10:40.119954+00:00", + "row_count": 10000, + "distinct_count": 2500 + } +]' +---- + +opt +SELECT w, x, y, z +FROM wxyz +INNER JOIN abcde +ON w = a AND x = b AND y = c +WHERE w = 'foo' AND x = '2AB23800-06B1-4E19-A3BB-DF3768B808D2' +ORDER BY d +LIMIT 10 +---- +project + ├── columns: w:1(string!null) x:2(uuid!null) y:3(uuid!null) z:4(string!null) [hidden: d:8(string!null)] + ├── cardinality: [0 - 10] + ├── stats: [rows=10] + ├── cost: 122481.301 + ├── key: (8) + ├── fd: ()-->(1,2), (3)-->(4,8), (8)-->(3,4) + ├── ordering: +8 opt(1,2) [actual: +8] + └── limit + ├── columns: w:1(string!null) x:2(uuid!null) y:3(uuid!null) z:4(string!null) a:5(string!null) b:6(uuid!null) c:7(uuid!null) d:8(string!null) + ├── internal-ordering: +8 opt(1,2,5,6) + ├── cardinality: [0 - 10] + ├── stats: [rows=10] + ├── cost: 122481.191 + ├── key: (7) + ├── fd: ()-->(1,2,5,6), (3)-->(4), (7)-->(8), (8)-->(7), (1)==(5), (5)==(1), (2)==(6), (6)==(2), (3)==(7), (7)==(3) + ├── ordering: +8 opt(1,2,5,6) [actual: +8] + ├── sort + │ ├── columns: w:1(string!null) x:2(uuid!null) y:3(uuid!null) z:4(string!null) a:5(string!null) b:6(uuid!null) c:7(uuid!null) d:8(string!null) + │ ├── stats: [rows=50048.8759, distinct(1)=1, null(1)=0, distinct(2)=1, null(2)=0, distinct(3)=2500, null(3)=0, distinct(4)=1000, null(4)=0, distinct(5)=1, null(5)=0, distinct(6)=1, null(6)=0, distinct(7)=2500, null(7)=0, distinct(8)=38781.1698, null(8)=0] + │ ├── cost: 122481.081 + │ ├── key: (7) + │ ├── fd: ()-->(1,2,5,6), (3)-->(4), (7)-->(8), (8)-->(7), (1)==(5), (5)==(1), (2)==(6), (6)==(2), (3)==(7), (7)==(3) + │ ├── ordering: +8 opt(1,2,5,6) [actual: +8] + │ └── inner-join (lookup abcde@idx_abcd) + │ ├── columns: w:1(string!null) x:2(uuid!null) y:3(uuid!null) z:4(string!null) a:5(string!null) b:6(uuid!null) c:7(uuid!null) d:8(string!null) + │ ├── key columns: [1 2 3] = [5 6 7] + │ ├── stats: [rows=50048.8759, distinct(1)=1, null(1)=0, distinct(2)=1, null(2)=0, distinct(3)=2500, null(3)=0, distinct(4)=1000, null(4)=0, distinct(5)=1, null(5)=0, distinct(6)=1, null(6)=0, distinct(7)=2500, null(7)=0, distinct(8)=38781.1698, null(8)=0] + │ ├── cost: 105853.783 + │ ├── key: (7) + │ ├── fd: ()-->(1,2,5,6), (3)-->(4), (7)-->(8), (8)-->(7), (1)==(5), (5)==(1), (2)==(6), (6)==(2), (3)==(7), (7)==(3) + │ ├── scan wxyz + │ │ ├── columns: w:1(string!null) x:2(uuid!null) y:3(uuid!null) z:4(string!null) + │ │ ├── constraint: /1/2/3: [/'foo'/'2ab23800-06b1-4e19-a3bb-df3768b808d2' - /'foo'/'2ab23800-06b1-4e19-a3bb-df3768b808d2'] + │ │ ├── stats: [rows=10000, distinct(1)=1, null(1)=0, distinct(2)=1, null(2)=0, distinct(3)=2500, null(3)=0, distinct(4)=1000, null(4)=0] + │ │ ├── cost: 10800.01 + │ │ ├── key: (3) + │ │ └── fd: ()-->(1,2), (3)-->(4) + │ └── filters + │ ├── a = 'foo' [type=bool, outer=(5), constraints=(/5: [/'foo' - /'foo']; tight), fd=()-->(5)] + │ └── b = '2ab23800-06b1-4e19-a3bb-df3768b808d2' [type=bool, outer=(6), constraints=(/6: [/'2ab23800-06b1-4e19-a3bb-df3768b808d2' - /'2ab23800-06b1-4e19-a3bb-df3768b808d2']; tight), fd=()-->(6)] + └── const: 10 [type=int] diff --git a/pkg/sql/opt/xform/testdata/coster/zone b/pkg/sql/opt/xform/testdata/coster/zone index 26432a72067a..3eb9e44ce7bc 100644 --- a/pkg/sql/opt/xform/testdata/coster/zone +++ b/pkg/sql/opt/xform/testdata/coster/zone @@ -317,7 +317,7 @@ inner-join (lookup xy@y2) ├── flags: no-merge-join;no-hash-join ├── key columns: [2] = [5] ├── stats: [rows=98.01, distinct(1)=9.9, null(1)=0, distinct(2)=1, null(2)=0, distinct(4)=9.9, null(4)=0, distinct(5)=1, null(5)=0] - ├── cost: 152.0444 + ├── cost: 153.0245 ├── key: (1,4) ├── fd: ()-->(2,5), (1)-->(3), (2,3)~~>(1), (2)==(5), (5)==(2) ├── prune: (1,3,4) @@ -359,7 +359,7 @@ inner-join (lookup xy@y1) ├── flags: no-merge-join;no-hash-join ├── key columns: [2] = [5] ├── stats: [rows=98.01, distinct(1)=9.9, null(1)=0, distinct(2)=1, null(2)=0, distinct(4)=9.9, null(4)=0, distinct(5)=1, null(5)=0] - ├── cost: 152.0444 + ├── cost: 153.0245 ├── key: (1,4) ├── fd: ()-->(2,5), (1)-->(3), (2,3)~~>(1), (2)==(5), (5)==(2) ├── prune: (1,3,4) diff --git a/pkg/sql/opt/xform/testdata/external/tpcc b/pkg/sql/opt/xform/testdata/external/tpcc index 00feeb0304c9..a58eb257b0ed 100644 --- a/pkg/sql/opt/xform/testdata/external/tpcc +++ b/pkg/sql/opt/xform/testdata/external/tpcc @@ -904,7 +904,7 @@ scalar-group-by ├── columns: count:28(int) ├── cardinality: [1 - 1] ├── stats: [rows=1] - ├── cost: 1.82111111 + ├── cost: 1.84111111 ├── key: () ├── fd: ()-->(28) ├── prune: (28) @@ -912,7 +912,7 @@ scalar-group-by │ ├── columns: ol_o_id:1(int!null) ol_d_id:2(int!null) ol_w_id:3(int!null) ol_i_id:5(int!null) s_i_id:11(int!null) s_w_id:12(int!null) s_quantity:13(int!null) │ ├── key columns: [3 5] = [12 11] │ ├── stats: [rows=1, distinct(1)=0.11109736, null(1)=0, distinct(2)=0.111097416, null(2)=0, distinct(3)=0.111111111, null(3)=0, distinct(5)=0.111111056, null(5)=0, distinct(11)=0.111111056, null(11)=0, distinct(12)=0.111111111, null(12)=0, distinct(13)=1, null(13)=0] - │ ├── cost: 1.79111111 + │ ├── cost: 1.81111111 │ ├── fd: ()-->(2,3,12), (11)-->(13), (5)==(11), (11)==(5), (3)==(12), (12)==(3) │ ├── interesting orderings: (+3,+2,-1) │ ├── scan order_line diff --git a/pkg/sql/opt/xform/testdata/external/tpcc-no-stats b/pkg/sql/opt/xform/testdata/external/tpcc-no-stats index 636cd49d3b7a..e9a6331c7d78 100644 --- a/pkg/sql/opt/xform/testdata/external/tpcc-no-stats +++ b/pkg/sql/opt/xform/testdata/external/tpcc-no-stats @@ -709,7 +709,7 @@ scalar-group-by ├── columns: count:28(int) ├── cardinality: [1 - 1] ├── stats: [rows=1] - ├── cost: 0.141477778 + ├── cost: 0.142211111 ├── key: () ├── fd: ()-->(28) ├── prune: (28) @@ -717,7 +717,7 @@ scalar-group-by │ ├── columns: ol_o_id:1(int!null) ol_d_id:2(int!null) ol_w_id:3(int!null) ol_i_id:5(int!null) s_i_id:11(int!null) s_w_id:12(int!null) s_quantity:13(int!null) │ ├── key columns: [3 5] = [12 11] │ ├── stats: [rows=0.0366666667, distinct(1)=0.0111105556, null(1)=0, distinct(2)=0.0111111111, null(2)=0, distinct(3)=0.0111111111, null(3)=0, distinct(5)=0.0111105556, null(5)=0, distinct(11)=0.0111105556, null(11)=0, distinct(12)=0.0111111111, null(12)=0, distinct(13)=0.0366666667, null(13)=0] - │ ├── cost: 0.121111111 + │ ├── cost: 0.121844444 │ ├── fd: ()-->(2,3,12), (11)-->(13), (5)==(11), (11)==(5), (3)==(12), (12)==(3) │ ├── interesting orderings: (+3,+2,-1) │ ├── scan order_line @@ -762,7 +762,7 @@ scalar-group-by ├── columns: count:22(int) ├── cardinality: [1 - 1] ├── stats: [rows=1] - ├── cost: 1588.01 + ├── cost: 1588.34 ├── key: () ├── fd: ()-->(22) ├── prune: (22) @@ -770,7 +770,7 @@ scalar-group-by │ ├── columns: w_id:1(int!null) w_ytd:9(decimal!null) d_w_id:11(int!null) sum:21(decimal!null) │ ├── key columns: [11] = [1] │ ├── stats: [rows=33, distinct(1)=33, null(1)=0, distinct(9)=28.3508504, null(9)=0, distinct(11)=33, null(11)=0, distinct(21)=28.3508504, null(21)=0] - │ ├── cost: 1587.66 + │ ├── cost: 1587.99 │ ├── key: (11) │ ├── fd: (1)-->(9), (11)-->(21), (1)==(11), (11)==(1) │ ├── interesting orderings: (+11) diff --git a/pkg/sql/opt/xform/testdata/rules/join b/pkg/sql/opt/xform/testdata/rules/join index dae0ca231323..00d22c265e4e 100644 --- a/pkg/sql/opt/xform/testdata/rules/join +++ b/pkg/sql/opt/xform/testdata/rules/join @@ -1879,11 +1879,11 @@ memo (optimized, ~11KB, required=[presentation: a:1]) ├── G1: (project G2 G3 a) │ └── [presentation: a:1] │ ├── best: (project G2 G3 a) - │ └── cost: 87.93 + │ └── cost: 88.05 ├── G2: (select G4 G5) (lookup-join G6 G5 t5,keyCols=[1],outCols=(1,2)) (select G7 G5) │ └── [] │ ├── best: (lookup-join G6 G5 t5,keyCols=[1],outCols=(1,2)) - │ └── cost: 87.80 + │ └── cost: 87.92 ├── G3: (projections) ├── G4: (scan t5,cols=(1,2)) │ └── [] From 893e69f29405895ff22beeeaf6e4e720b91c7cf5 Mon Sep 17 00:00:00 2001 From: Nathan VanBenschoten Date: Sat, 9 Mar 2019 21:55:05 -0500 Subject: [PATCH 2/7] storage/tscache: fix skiplist arena re-use This was incorrectly assuming that `Arena.Size` returned the full capacity of the memory arena instead of the currently allocated size. Since it is rare that the arena ever fills up without some overflow, it was effectively disabling this optimization. The size check turns out to not even be needed. I believe it was added back when the page size was dynamic and hooked up to a cluster setting. Since it isn't currently, we don't need the check. Release note: None --- pkg/storage/tscache/interval_skl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/storage/tscache/interval_skl.go b/pkg/storage/tscache/interval_skl.go index 80194d4bbced..80473ede1244 100644 --- a/pkg/storage/tscache/interval_skl.go +++ b/pkg/storage/tscache/interval_skl.go @@ -374,7 +374,7 @@ func (s *intervalSkl) frontPage() *sklPage { // pushNewPage prepends a new empty page to the front of the pages list. It // accepts an optional arena argument to facilitate re-use. func (s *intervalSkl) pushNewPage(maxWallTime int64, arena *arenaskl.Arena) { - if arena != nil && arena.Size() == s.pageSize { + if arena != nil { // Re-use the provided arena, if possible. arena.Reset() } else { From 2d35cc9e577fae88d2133752dab3c5efc574c2f4 Mon Sep 17 00:00:00 2001 From: Nathan VanBenschoten Date: Mon, 11 Mar 2019 23:08:47 -0400 Subject: [PATCH 3/7] storage/tscache: Pick up andy-kimball/arenaskl fix Fixes #31624. Fixes #35557. This commit picks up https://github.com/andy-kimball/arenaskl/pull/4. I strongly suspect that the uint32 overflow fixed in that PR was the cause of the two index out of bounds panics. See that commit for more details. Release note: None --- Gopkg.lock | 4 ++-- pkg/storage/tscache/interval_skl_test.go | 4 ++-- vendor | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index a867d1e49f50..478d4e9b0458 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -143,11 +143,11 @@ [[projects]] branch = "master" - digest = "1:dfe2c5eadcbaf622a726116baf37582aa82fa8d364f05e168b58fbe96551832d" + digest = "1:caed868e37c6cda382a217d8ad4f55da579e1a1d046836de57f11a569e383443" name = "github.com/andy-kimball/arenaskl" packages = ["."] pruneopts = "UT" - revision = "224761e552afe64db9d93004f8d5d3a686b89771" + revision = "6bf06cf57626e536063e9398a57dfe1417ed0799" [[projects]] digest = "1:66b3310cf22cdc96c35ef84ede4f7b9b370971c4025f394c89a2638729653b11" diff --git a/pkg/storage/tscache/interval_skl_test.go b/pkg/storage/tscache/interval_skl_test.go index 713e70584cd6..13639f6eefcf 100644 --- a/pkg/storage/tscache/interval_skl_test.go +++ b/pkg/storage/tscache/interval_skl_test.go @@ -1218,10 +1218,10 @@ func BenchmarkIntervalSklAddAndLookup(b *testing.B) { rng := rand.New(rand.NewSource(timeutil.Now().UnixNano())) for n := 0; n < b.N/parallel; n++ { - readFrac := rng.Int31() + readFrac := rng.Int31n(10) keyNum := rng.Int31n(max) - if (readFrac % 10) < int32(i) { + if readFrac < int32(i) { key := []byte(fmt.Sprintf("%020d", keyNum)) s.LookupTimestamp(key) } else { diff --git a/vendor b/vendor index 33eeb37f6f67..2b619c3efb04 160000 --- a/vendor +++ b/vendor @@ -1 +1 @@ -Subproject commit 33eeb37f6f67ba330d5343ca2da83c8c25d6b974 +Subproject commit 2b619c3efb048f876d9ab26e45872bafb7099e5c From df0f652deea11539680f0cc4f78d730f360ec247 Mon Sep 17 00:00:00 2001 From: Nathan VanBenschoten Date: Tue, 12 Mar 2019 00:55:49 -0400 Subject: [PATCH 4/7] storage/tscache: return ErrArenaFull whenever a node cantInit This change returns `ErrArenaFull` in all cases where `cantInit` is true for a node in `ratchetValueSet`, instead of just when `cantInit` is true and `ratchetValueSet` is attempting to initialize the node. We already know any update to the node is going to fail, so there's no sense in trying to update it again. This should avoid a few memory copies and atomic loads for scans over nodes that get stuck in a `cantInit` state in immutable `sklPages`. Release note: None --- pkg/storage/tscache/interval_skl.go | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/pkg/storage/tscache/interval_skl.go b/pkg/storage/tscache/interval_skl.go index 80473ede1244..6fe843edd865 100644 --- a/pkg/storage/tscache/interval_skl.go +++ b/pkg/storage/tscache/interval_skl.go @@ -837,26 +837,25 @@ func (p *sklPage) ratchetValueSet( // attempt then we must have raced with node initialization before. return nil } - - var keyValUpdate, gapValUpdate bool - oldKeyVal, oldGapVal := decodeValueSet(it.Value(), meta) - keyVal, keyValUpdate = ratchetValue(oldKeyVal, keyVal) - gapVal, gapValUpdate = ratchetValue(oldGapVal, gapVal) - updateVals := keyValUpdate || gapValUpdate - - newMeta := meta - updateInit := setInit && !inited - if updateInit { + if (meta & cantInit) != 0 { // If the meta has the cantInit flag set to true, we fail with an // ErrArenaFull error to force the current goroutine to retry on a // new page. - if (meta & cantInit) != 0 { - return arenaskl.ErrArenaFull - } + return arenaskl.ErrArenaFull + } + newMeta := meta + updateInit := setInit && !inited + if updateInit { newMeta |= initialized } + var keyValUpdate, gapValUpdate bool + oldKeyVal, oldGapVal := decodeValueSet(it.Value(), meta) + keyVal, keyValUpdate = ratchetValue(oldKeyVal, keyVal) + gapVal, gapValUpdate = ratchetValue(oldGapVal, gapVal) + updateVals := keyValUpdate || gapValUpdate + if updateVals { // If we're updating the values (and maybe the init flag) then we // need to call it.Set. This can return an ErrArenaFull, which we From 49d15e2c6c292105fb7a02188218e2ac62a9dcc7 Mon Sep 17 00:00:00 2001 From: Radu Berinde Date: Tue, 12 Mar 2019 10:58:39 -0400 Subject: [PATCH 5/7] opt: use correct ordering for mutation input in execbuilder We were setting up a projection on the mutation's input but we were accidentally using the parent's ordering instead of that of the input. Fixes #35564. Release note (bug fix): Fixed a "column not in input" crash when `INSERT / UPDATE / UPSERT ... RETURNING` is used inside a clause that requires an ordering. --- .../exec/execbuilder/relational_builder.go | 8 ++--- pkg/sql/opt/exec/execbuilder/testdata/insert | 27 ++++++++++++++ pkg/sql/opt/exec/execbuilder/testdata/update | 26 ++++++++++++++ pkg/sql/opt/exec/execbuilder/testdata/upsert | 35 +++++++++++++++++++ 4 files changed, 92 insertions(+), 4 deletions(-) diff --git a/pkg/sql/opt/exec/execbuilder/relational_builder.go b/pkg/sql/opt/exec/execbuilder/relational_builder.go index 3cc4ef9bddf9..a310ab5cea06 100644 --- a/pkg/sql/opt/exec/execbuilder/relational_builder.go +++ b/pkg/sql/opt/exec/execbuilder/relational_builder.go @@ -1297,7 +1297,7 @@ func (b *Builder) buildInsert(ins *memo.InsertExpr) (execPlan, error) { colList := make(opt.ColList, 0, len(ins.InsertCols)+len(ins.CheckCols)) colList = appendColsWhenPresent(colList, ins.InsertCols) colList = appendColsWhenPresent(colList, ins.CheckCols) - input, err = b.ensureColumns(input, colList, nil, ins.ProvidedPhysical().Ordering) + input, err = b.ensureColumns(input, colList, nil, ins.Input.ProvidedPhysical().Ordering) if err != nil { return execPlan{}, err } @@ -1348,7 +1348,7 @@ func (b *Builder) buildUpdate(upd *memo.UpdateExpr) (execPlan, error) { colList = appendColsWhenPresent(colList, upd.FetchCols) colList = appendColsWhenPresent(colList, upd.UpdateCols) colList = appendColsWhenPresent(colList, upd.CheckCols) - input, err = b.ensureColumns(input, colList, nil, upd.ProvidedPhysical().Ordering) + input, err = b.ensureColumns(input, colList, nil, upd.Input.ProvidedPhysical().Ordering) if err != nil { return execPlan{}, err } @@ -1414,7 +1414,7 @@ func (b *Builder) buildUpsert(ups *memo.UpsertExpr) (execPlan, error) { colList = append(colList, ups.CanaryCol) } colList = appendColsWhenPresent(colList, ups.CheckCols) - input, err = b.ensureColumns(input, colList, nil, ups.ProvidedPhysical().Ordering) + input, err = b.ensureColumns(input, colList, nil, ups.Input.ProvidedPhysical().Ordering) if err != nil { return execPlan{}, err } @@ -1473,7 +1473,7 @@ func (b *Builder) buildDelete(del *memo.DeleteExpr) (execPlan, error) { // Upgrade execution engine to not require this. colList := make(opt.ColList, 0, len(del.FetchCols)) colList = appendColsWhenPresent(colList, del.FetchCols) - input, err = b.ensureColumns(input, colList, nil, del.ProvidedPhysical().Ordering) + input, err = b.ensureColumns(input, colList, nil, del.Input.ProvidedPhysical().Ordering) if err != nil { return execPlan{}, err } diff --git a/pkg/sql/opt/exec/execbuilder/testdata/insert b/pkg/sql/opt/exec/execbuilder/testdata/insert index 927f4f416b21..f455d2e2cc95 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/insert +++ b/pkg/sql/opt/exec/execbuilder/testdata/insert @@ -467,3 +467,30 @@ count · · () statement ok ROLLBACK + +# Regression test for #35564: make sure we use the Insert's input required +# ordering for the internal projection. + +statement ok +CREATE TABLE abc (a INT, b INT, c INT, INDEX(c) STORING(a,b)) + +statement ok +CREATE TABLE xyz (x INT, y INT, z INT) + +query TTTTT +EXPLAIN (VERBOSE) SELECT * FROM [INSERT INTO xyz SELECT a, b, c FROM abc RETURNING z] ORDER BY z +---- +render · · (z) +z + │ render 0 z · · + └── run · · (x, y, z, rowid[hidden]) · + └── insert · · (x, y, z, rowid[hidden]) · + │ into xyz(x, y, z, rowid) · · + │ strategy inserter · · + └── render · · (a, b, c, column9) +c + │ render 0 a · · + │ render 1 b · · + │ render 2 c · · + │ render 3 unique_rowid() · · + └── scan · · (a, b, c) +c +· table abc@abc_c_idx · · +· spans ALL · · diff --git a/pkg/sql/opt/exec/execbuilder/testdata/update b/pkg/sql/opt/exec/execbuilder/testdata/update index f2b6db8ca2c9..02ee30a15baf 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/update +++ b/pkg/sql/opt/exec/execbuilder/testdata/update @@ -296,3 +296,29 @@ Del /Table/57/1/1/1/1 Del /Table/57/1/1/2/1 fast path completed rows affected: 1 + +# Regression test for #35564: make sure we use the Update's input required +# ordering for the internal projection. + +statement ok +CREATE TABLE abc (a INT, b INT, c INT, INDEX(c) STORING(a,b)) + +query TTTTT +EXPLAIN (VERBOSE) SELECT * FROM [ UPDATE abc SET a=c RETURNING a ] ORDER BY a +---- +render · · (a) +a + │ render 0 a · · + └── run · · (a, b, c, rowid[hidden]) · + └── update · · (a, b, c, rowid[hidden]) · + │ table abc · · + │ set a · · + │ strategy updater · · + └── render · · (a, b, c, rowid, c) +c + │ render 0 a · · + │ render 1 b · · + │ render 2 c · · + │ render 3 rowid · · + │ render 4 c · · + └── scan · · (a, b, c, rowid[hidden]) +c +· table abc@abc_c_idx · · +· spans ALL · · diff --git a/pkg/sql/opt/exec/execbuilder/testdata/upsert b/pkg/sql/opt/exec/execbuilder/testdata/upsert index 1b6b5e2bc3d1..49ee92abe999 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/upsert +++ b/pkg/sql/opt/exec/execbuilder/testdata/upsert @@ -307,3 +307,38 @@ INSERT INTO t5 VALUES (1, 10, 9) ON CONFLICT (k) DO NOTHING statement ok INSERT INTO t5 VALUES (1, 10, 20) ON CONFLICT (k) DO NOTHING + +# Regression test for #35564: make sure we use the Upsert's input required +# ordering for the internal projection. + +statement ok +CREATE TABLE abc (a INT, b INT, c INT, INDEX(c) STORING(a,b)) + +statement ok +CREATE TABLE xyz (x INT, y INT, z INT) + +query TTTTT +EXPLAIN (VERBOSE) SELECT * FROM [UPSERT INTO xyz SELECT a, b, c FROM abc RETURNING z] ORDER BY z +---- +render · · (z) +z + │ render 0 z · · + └── run · · (x, y, z, rowid[hidden]) · + └── upsert · · (x, y, z, rowid[hidden]) · + │ into xyz(x, y, z, rowid) · · + │ strategy opt upserter · · + └── render · · (a, b, c, column9, a, b, c) +c + │ render 0 a · · + │ render 1 b · · + │ render 2 c · · + │ render 3 column9 · · + │ render 4 a · · + │ render 5 b · · + │ render 6 c · · + └── render · · (column9, a, b, c) +c + │ render 0 unique_rowid() · · + │ render 1 a · · + │ render 2 b · · + │ render 3 c · · + └── scan · · (a, b, c) +c +· table abc@abc_c_idx · · +· spans ALL · · From 6c1e1ac4f08c46da09d87d74fe91382cd1573028 Mon Sep 17 00:00:00 2001 From: Celia La Date: Mon, 11 Mar 2019 19:33:48 -0400 Subject: [PATCH 6/7] jobs, sql, ui: Create `AutoCreateStats` job type With #34279, enabling the cluster setting `sql.stats.experimental_automatic_collection.enabled` has the potential to create many CreateStats jobs, which can cause the Jobs view on the AdminUI to become cluttered. This commit creates a new `AutoCreateStats` job type for these auto-created CreateStats jobs, so that users are able to still see their own manual runs of CREATE STATISTICS, via the pre-existing `CreateStats` type. ![jobs-auto-create-stats](https://user-images.githubusercontent.com/3051672/54212467-5cea2c80-44b9-11e9-9c11-db749814f019.gif) Release note (admin ui change): AutoCreateStats type added to Jobs page to filter automatic statistics jobs. Fixes #34377. --- pkg/jobs/jobspb/jobs.pb.go | 383 ++++++++++++++++---------------- pkg/jobs/jobspb/jobs.proto | 1 + pkg/jobs/jobspb/wrap.go | 5 + pkg/sql/create_stats.go | 4 +- pkg/ui/src/views/jobs/index.tsx | 1 + 5 files changed, 203 insertions(+), 191 deletions(-) diff --git a/pkg/jobs/jobspb/jobs.pb.go b/pkg/jobs/jobspb/jobs.pb.go index f6d31e425e7f..e20e9aefadc9 100644 --- a/pkg/jobs/jobspb/jobs.pb.go +++ b/pkg/jobs/jobspb/jobs.pb.go @@ -55,19 +55,20 @@ func (x Status) String() string { return proto.EnumName(Status_name, int32(x)) } func (Status) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{0} + return fileDescriptor_jobs_672575a1a0b382a2, []int{0} } type Type int32 const ( - TypeUnspecified Type = 0 - TypeBackup Type = 1 - TypeRestore Type = 2 - TypeSchemaChange Type = 3 - TypeImport Type = 4 - TypeChangefeed Type = 5 - TypeCreateStats Type = 6 + TypeUnspecified Type = 0 + TypeBackup Type = 1 + TypeRestore Type = 2 + TypeSchemaChange Type = 3 + TypeImport Type = 4 + TypeChangefeed Type = 5 + TypeCreateStats Type = 6 + TypeAutoCreateStats Type = 7 ) var Type_name = map[int32]string{ @@ -78,19 +79,21 @@ var Type_name = map[int32]string{ 4: "IMPORT", 5: "CHANGEFEED", 6: "CREATE_STATS", + 7: "AUTO_CREATE_STATS", } var Type_value = map[string]int32{ - "UNSPECIFIED": 0, - "BACKUP": 1, - "RESTORE": 2, - "SCHEMA_CHANGE": 3, - "IMPORT": 4, - "CHANGEFEED": 5, - "CREATE_STATS": 6, + "UNSPECIFIED": 0, + "BACKUP": 1, + "RESTORE": 2, + "SCHEMA_CHANGE": 3, + "IMPORT": 4, + "CHANGEFEED": 5, + "CREATE_STATS": 6, + "AUTO_CREATE_STATS": 7, } func (Type) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{1} + return fileDescriptor_jobs_672575a1a0b382a2, []int{1} } type Lease struct { @@ -106,7 +109,7 @@ func (m *Lease) Reset() { *m = Lease{} } func (m *Lease) String() string { return proto.CompactTextString(m) } func (*Lease) ProtoMessage() {} func (*Lease) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{0} + return fileDescriptor_jobs_672575a1a0b382a2, []int{0} } func (m *Lease) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -144,7 +147,7 @@ func (m *BackupDetails) Reset() { *m = BackupDetails{} } func (m *BackupDetails) String() string { return proto.CompactTextString(m) } func (*BackupDetails) ProtoMessage() {} func (*BackupDetails) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{1} + return fileDescriptor_jobs_672575a1a0b382a2, []int{1} } func (m *BackupDetails) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -178,7 +181,7 @@ func (m *BackupProgress) Reset() { *m = BackupProgress{} } func (m *BackupProgress) String() string { return proto.CompactTextString(m) } func (*BackupProgress) ProtoMessage() {} func (*BackupProgress) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{2} + return fileDescriptor_jobs_672575a1a0b382a2, []int{2} } func (m *BackupProgress) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -217,7 +220,7 @@ func (m *RestoreDetails) Reset() { *m = RestoreDetails{} } func (m *RestoreDetails) String() string { return proto.CompactTextString(m) } func (*RestoreDetails) ProtoMessage() {} func (*RestoreDetails) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{3} + return fileDescriptor_jobs_672575a1a0b382a2, []int{3} } func (m *RestoreDetails) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -253,7 +256,7 @@ func (m *RestoreDetails_TableRewrite) Reset() { *m = RestoreDetails_Tabl func (m *RestoreDetails_TableRewrite) String() string { return proto.CompactTextString(m) } func (*RestoreDetails_TableRewrite) ProtoMessage() {} func (*RestoreDetails_TableRewrite) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{3, 0} + return fileDescriptor_jobs_672575a1a0b382a2, []int{3, 0} } func (m *RestoreDetails_TableRewrite) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -288,7 +291,7 @@ func (m *RestoreProgress) Reset() { *m = RestoreProgress{} } func (m *RestoreProgress) String() string { return proto.CompactTextString(m) } func (*RestoreProgress) ProtoMessage() {} func (*RestoreProgress) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{4} + return fileDescriptor_jobs_672575a1a0b382a2, []int{4} } func (m *RestoreProgress) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -341,7 +344,7 @@ func (m *ImportDetails) Reset() { *m = ImportDetails{} } func (m *ImportDetails) String() string { return proto.CompactTextString(m) } func (*ImportDetails) ProtoMessage() {} func (*ImportDetails) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{5} + return fileDescriptor_jobs_672575a1a0b382a2, []int{5} } func (m *ImportDetails) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -378,7 +381,7 @@ func (m *ImportDetails_Table) Reset() { *m = ImportDetails_Table{} } func (m *ImportDetails_Table) String() string { return proto.CompactTextString(m) } func (*ImportDetails_Table) ProtoMessage() {} func (*ImportDetails_Table) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{5, 0} + return fileDescriptor_jobs_672575a1a0b382a2, []int{5, 0} } func (m *ImportDetails_Table) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -419,7 +422,7 @@ func (m *ImportProgress) Reset() { *m = ImportProgress{} } func (m *ImportProgress) String() string { return proto.CompactTextString(m) } func (*ImportProgress) ProtoMessage() {} func (*ImportProgress) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{6} + return fileDescriptor_jobs_672575a1a0b382a2, []int{6} } func (m *ImportProgress) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -454,7 +457,7 @@ func (m *ResumeSpanList) Reset() { *m = ResumeSpanList{} } func (m *ResumeSpanList) String() string { return proto.CompactTextString(m) } func (*ResumeSpanList) ProtoMessage() {} func (*ResumeSpanList) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{7} + return fileDescriptor_jobs_672575a1a0b382a2, []int{7} } func (m *ResumeSpanList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -491,7 +494,7 @@ func (m *DroppedTableDetails) Reset() { *m = DroppedTableDetails{} } func (m *DroppedTableDetails) String() string { return proto.CompactTextString(m) } func (*DroppedTableDetails) ProtoMessage() {} func (*DroppedTableDetails) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{8} + return fileDescriptor_jobs_672575a1a0b382a2, []int{8} } func (m *DroppedTableDetails) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -535,7 +538,7 @@ func (m *SchemaChangeDetails) Reset() { *m = SchemaChangeDetails{} } func (m *SchemaChangeDetails) String() string { return proto.CompactTextString(m) } func (*SchemaChangeDetails) ProtoMessage() {} func (*SchemaChangeDetails) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{9} + return fileDescriptor_jobs_672575a1a0b382a2, []int{9} } func (m *SchemaChangeDetails) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -569,7 +572,7 @@ func (m *SchemaChangeProgress) Reset() { *m = SchemaChangeProgress{} } func (m *SchemaChangeProgress) String() string { return proto.CompactTextString(m) } func (*SchemaChangeProgress) ProtoMessage() {} func (*SchemaChangeProgress) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{10} + return fileDescriptor_jobs_672575a1a0b382a2, []int{10} } func (m *SchemaChangeProgress) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -604,7 +607,7 @@ func (m *ChangefeedTarget) Reset() { *m = ChangefeedTarget{} } func (m *ChangefeedTarget) String() string { return proto.CompactTextString(m) } func (*ChangefeedTarget) ProtoMessage() {} func (*ChangefeedTarget) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{11} + return fileDescriptor_jobs_672575a1a0b382a2, []int{11} } func (m *ChangefeedTarget) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -659,7 +662,7 @@ func (m *ChangefeedDetails) Reset() { *m = ChangefeedDetails{} } func (m *ChangefeedDetails) String() string { return proto.CompactTextString(m) } func (*ChangefeedDetails) ProtoMessage() {} func (*ChangefeedDetails) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{12} + return fileDescriptor_jobs_672575a1a0b382a2, []int{12} } func (m *ChangefeedDetails) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -695,7 +698,7 @@ func (m *ResolvedSpan) Reset() { *m = ResolvedSpan{} } func (m *ResolvedSpan) String() string { return proto.CompactTextString(m) } func (*ResolvedSpan) ProtoMessage() {} func (*ResolvedSpan) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{13} + return fileDescriptor_jobs_672575a1a0b382a2, []int{13} } func (m *ResolvedSpan) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -730,7 +733,7 @@ func (m *ChangefeedProgress) Reset() { *m = ChangefeedProgress{} } func (m *ChangefeedProgress) String() string { return proto.CompactTextString(m) } func (*ChangefeedProgress) ProtoMessage() {} func (*ChangefeedProgress) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{14} + return fileDescriptor_jobs_672575a1a0b382a2, []int{14} } func (m *ChangefeedProgress) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -775,7 +778,7 @@ func (m *CreateStatsDetails) Reset() { *m = CreateStatsDetails{} } func (m *CreateStatsDetails) String() string { return proto.CompactTextString(m) } func (*CreateStatsDetails) ProtoMessage() {} func (*CreateStatsDetails) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{15} + return fileDescriptor_jobs_672575a1a0b382a2, []int{15} } func (m *CreateStatsDetails) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -810,7 +813,7 @@ func (m *CreateStatsDetails_ColList) Reset() { *m = CreateStatsDetails_C func (m *CreateStatsDetails_ColList) String() string { return proto.CompactTextString(m) } func (*CreateStatsDetails_ColList) ProtoMessage() {} func (*CreateStatsDetails_ColList) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{15, 0} + return fileDescriptor_jobs_672575a1a0b382a2, []int{15, 0} } func (m *CreateStatsDetails_ColList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -844,7 +847,7 @@ func (m *CreateStatsProgress) Reset() { *m = CreateStatsProgress{} } func (m *CreateStatsProgress) String() string { return proto.CompactTextString(m) } func (*CreateStatsProgress) ProtoMessage() {} func (*CreateStatsProgress) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{16} + return fileDescriptor_jobs_672575a1a0b382a2, []int{16} } func (m *CreateStatsProgress) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -899,7 +902,7 @@ func (m *Payload) Reset() { *m = Payload{} } func (m *Payload) String() string { return proto.CompactTextString(m) } func (*Payload) ProtoMessage() {} func (*Payload) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{17} + return fileDescriptor_jobs_672575a1a0b382a2, []int{17} } func (m *Payload) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1178,7 +1181,7 @@ func (m *Progress) Reset() { *m = Progress{} } func (m *Progress) String() string { return proto.CompactTextString(m) } func (*Progress) ProtoMessage() {} func (*Progress) Descriptor() ([]byte, []int) { - return fileDescriptor_jobs_8f4fceb1a78d438f, []int{18} + return fileDescriptor_jobs_672575a1a0b382a2, []int{18} } func (m *Progress) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -7184,157 +7187,159 @@ var ( ErrIntOverflowJobs = fmt.Errorf("proto: integer overflow") ) -func init() { proto.RegisterFile("jobs/jobspb/jobs.proto", fileDescriptor_jobs_8f4fceb1a78d438f) } - -var fileDescriptor_jobs_8f4fceb1a78d438f = []byte{ - // 2381 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xdf, 0x6f, 0xe3, 0x58, - 0xf5, 0x8f, 0x13, 0x27, 0x71, 0x4e, 0x7e, 0xd4, 0xbd, 0xed, 0x77, 0xd7, 0x1b, 0xed, 0x36, 0xf9, - 0x06, 0x76, 0xb7, 0x3b, 0xc3, 0x24, 0xd0, 0x11, 0x3b, 0xcc, 0x08, 0x56, 0xe4, 0x57, 0xa7, 0xc9, - 0x74, 0x9a, 0xae, 0x93, 0xce, 0xc2, 0x22, 0x30, 0x4e, 0x7c, 0xdb, 0x98, 0x26, 0xb1, 0xeb, 0xeb, - 0xcc, 0x30, 0x2b, 0x24, 0x10, 0xe2, 0x01, 0xcd, 0x13, 0x7f, 0x00, 0x23, 0x21, 0x01, 0x12, 0x2f, - 0x08, 0x9e, 0xf8, 0x1b, 0xe6, 0x05, 0xb1, 0x88, 0x17, 0x10, 0x52, 0x16, 0xc2, 0x0b, 0x7f, 0xc3, - 0x3c, 0xa1, 0x7b, 0xaf, 0xed, 0x38, 0x9d, 0xd2, 0x5f, 0x12, 0x2f, 0x6d, 0x7c, 0xee, 0x39, 0xc7, - 0xf7, 0x9c, 0xf3, 0x39, 0x9f, 0x7b, 0xae, 0xe1, 0xb5, 0xef, 0x59, 0x7d, 0x52, 0xa1, 0x7f, 0xec, - 0x3e, 0xfb, 0x57, 0xb6, 0x1d, 0xcb, 0xb5, 0xd0, 0x1b, 0x03, 0x6b, 0x70, 0xec, 0x58, 0xfa, 0x60, +func init() { proto.RegisterFile("jobs/jobspb/jobs.proto", fileDescriptor_jobs_672575a1a0b382a2) } + +var fileDescriptor_jobs_672575a1a0b382a2 = []byte{ + // 2404 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xdf, 0x6f, 0x23, 0x57, + 0xf5, 0xf7, 0xd8, 0x63, 0x7b, 0x7c, 0xfc, 0x23, 0x93, 0x9b, 0x7c, 0xdb, 0xa9, 0xd5, 0xc6, 0xfe, + 0x1a, 0xda, 0xa6, 0x2d, 0xb5, 0x21, 0x15, 0x5d, 0x76, 0x05, 0x15, 0xfe, 0x95, 0x8d, 0xbd, 0xd9, + 0x38, 0x1d, 0x3b, 0x5b, 0x28, 0x82, 0x61, 0xec, 0xb9, 0x89, 0x87, 0xd8, 0x9e, 0xc9, 0xdc, 0xf1, + 0x2e, 0x5b, 0x21, 0x21, 0x21, 0x1e, 0x50, 0x9e, 0xf8, 0x03, 0x88, 0x84, 0x04, 0x48, 0xbc, 0x20, + 0xfa, 0xc4, 0xdf, 0xb0, 0x2f, 0x88, 0x22, 0x5e, 0x40, 0x48, 0x2e, 0x98, 0x17, 0xfe, 0x86, 0x7d, + 0x42, 0xf7, 0xde, 0x99, 0xf1, 0x38, 0x1b, 0xf2, 0x4b, 0xe2, 0x25, 0xf1, 0x9c, 0x7b, 0xce, 0x99, + 0x7b, 0xce, 0xf9, 0x9c, 0xcf, 0x3d, 0x77, 0xe0, 0xa5, 0x1f, 0x58, 0x7d, 0x52, 0xa1, 0x7f, 0xec, + 0x3e, 0xfb, 0x57, 0xb6, 0x1d, 0xcb, 0xb5, 0xd0, 0x2b, 0x03, 0x6b, 0x70, 0xec, 0x58, 0xfa, 0x60, 0x58, 0x26, 0x27, 0xa3, 0x32, 0x5b, 0xe1, 0x5a, 0xf9, 0xf5, 0x23, 0xeb, 0xc8, 0x62, 0x5a, 0x15, 0xfa, 0x8b, 0x1b, 0xe4, 0x11, 0x53, 0xb6, 0xfb, 0x15, 0x43, 0x77, 0x75, 0x4f, 0xa6, 0xf8, 0x32, - 0xd3, 0xba, 0x75, 0x68, 0x39, 0x63, 0xdd, 0xf5, 0xdc, 0xe7, 0xdf, 0x24, 0x27, 0xa3, 0x0a, 0x39, - 0x19, 0xf5, 0x75, 0x82, 0x2b, 0xc4, 0x75, 0xa6, 0x03, 0x77, 0xea, 0x60, 0xc3, 0xb7, 0x9b, 0xba, - 0xe6, 0xa8, 0x32, 0x1c, 0x0d, 0x2a, 0xae, 0x39, 0xc6, 0xc4, 0xd5, 0xc7, 0x36, 0x5f, 0x29, 0xfd, - 0x10, 0xe2, 0xbb, 0x58, 0x27, 0x18, 0x7d, 0x0c, 0xc9, 0x89, 0x65, 0x60, 0xcd, 0x34, 0x14, 0xa1, - 0x28, 0x6c, 0x66, 0x6b, 0xd5, 0xf9, 0xac, 0x90, 0xd8, 0xb3, 0x0c, 0xdc, 0x6a, 0xbc, 0x9c, 0x15, - 0x6e, 0x1f, 0x99, 0xee, 0x70, 0xda, 0x2f, 0x0f, 0xac, 0x71, 0x25, 0x88, 0xc4, 0xe8, 0x2f, 0x7e, - 0x57, 0xec, 0xe3, 0xa3, 0x8a, 0xb7, 0xbd, 0x32, 0x37, 0x53, 0x13, 0xd4, 0x63, 0xcb, 0x40, 0xeb, - 0x10, 0xc7, 0xb6, 0x35, 0x18, 0x2a, 0xd1, 0xa2, 0xb0, 0x19, 0x53, 0xf9, 0xc3, 0x3d, 0xf1, 0xdf, - 0xbf, 0x28, 0x08, 0xa5, 0xbf, 0x0b, 0x90, 0xad, 0xe9, 0x83, 0xe3, 0xa9, 0xdd, 0xc0, 0xae, 0x6e, - 0x8e, 0x08, 0xaa, 0x01, 0x10, 0x57, 0x77, 0x5c, 0x8d, 0xee, 0x95, 0x6d, 0x26, 0xbd, 0xf5, 0x56, - 0x79, 0x91, 0x3e, 0x1a, 0x4b, 0x79, 0x38, 0x1a, 0x94, 0x7b, 0x7e, 0x2c, 0x35, 0xf1, 0xc5, 0xac, - 0x10, 0x51, 0x53, 0xcc, 0x8c, 0x4a, 0xd1, 0x07, 0x20, 0xe1, 0x89, 0xc1, 0x3d, 0x44, 0x2f, 0xef, - 0x21, 0x89, 0x27, 0x06, 0xb3, 0x7f, 0x03, 0x62, 0x53, 0xc7, 0x54, 0x62, 0x45, 0x61, 0x33, 0x55, - 0x4b, 0xce, 0x67, 0x85, 0xd8, 0x81, 0xda, 0x52, 0xa9, 0x0c, 0xdd, 0x84, 0xd5, 0x3e, 0xdb, 0xaf, - 0x66, 0x60, 0x32, 0x70, 0x4c, 0xdb, 0xb5, 0x1c, 0x45, 0x2c, 0x0a, 0x9b, 0x19, 0x55, 0xee, 0x7b, - 0x81, 0xf8, 0xf2, 0x92, 0x0c, 0x39, 0x1e, 0xdc, 0xbe, 0x63, 0x1d, 0x39, 0x98, 0x90, 0xd2, 0xdf, - 0xe2, 0x90, 0x53, 0x31, 0x71, 0x2d, 0x07, 0xfb, 0x01, 0xff, 0x5c, 0x80, 0x9c, 0xab, 0xf7, 0x47, - 0x58, 0x73, 0xf0, 0x13, 0xc7, 0x74, 0x31, 0x51, 0xa2, 0xc5, 0xd8, 0x66, 0x7a, 0xeb, 0xab, 0xe5, - 0xff, 0x0a, 0x9a, 0xf2, 0xb2, 0x8f, 0x72, 0x8f, 0xda, 0xab, 0x9e, 0x79, 0x73, 0xe2, 0x3a, 0x4f, - 0x6b, 0x77, 0x7e, 0xfc, 0xd9, 0x25, 0xcb, 0x16, 0xc2, 0x4e, 0xb9, 0xd5, 0x50, 0xb3, 0x6e, 0xd8, - 0x19, 0x7a, 0x13, 0xc4, 0xa9, 0x63, 0x12, 0x25, 0x56, 0x8c, 0x6d, 0xa6, 0x6a, 0xd2, 0x7c, 0x56, - 0x10, 0x0f, 0xd4, 0x16, 0x51, 0x99, 0x74, 0x29, 0xd3, 0xe2, 0x35, 0x32, 0x7d, 0x1f, 0xd2, 0x3c, - 0x76, 0x9a, 0x4d, 0xa2, 0xc4, 0x59, 0xe0, 0xef, 0x9c, 0x0a, 0xdc, 0xdf, 0x1c, 0x8b, 0x72, 0x91, - 0x5e, 0x15, 0x5c, 0x5f, 0x40, 0x50, 0x05, 0xd2, 0xd6, 0x63, 0xec, 0x38, 0xa6, 0x81, 0x35, 0xa3, - 0xaf, 0x24, 0x58, 0xe9, 0x72, 0xf3, 0x59, 0x01, 0x3a, 0x9e, 0xb8, 0x51, 0x53, 0xc1, 0x57, 0x69, - 0xf4, 0xf3, 0x7f, 0x12, 0x20, 0x13, 0x4e, 0x1b, 0xfa, 0x36, 0x48, 0x7c, 0x2b, 0x41, 0x0f, 0xd4, - 0xe6, 0xb3, 0x42, 0x92, 0xe9, 0x5c, 0xa1, 0x09, 0x4e, 0x65, 0x33, 0xc9, 0x7c, 0xb6, 0x0c, 0xf4, - 0x5d, 0x48, 0xd9, 0xba, 0x83, 0x27, 0x2e, 0xf5, 0x1f, 0x65, 0xfe, 0xeb, 0xf3, 0x59, 0x41, 0xda, - 0x67, 0xc2, 0xeb, 0xbf, 0x40, 0xe2, 0x5e, 0x5b, 0x46, 0xfe, 0xfb, 0x80, 0x5e, 0xc5, 0x01, 0x92, - 0x21, 0x76, 0x8c, 0x9f, 0xf2, 0x88, 0x54, 0xfa, 0x13, 0xed, 0x42, 0xfc, 0xb1, 0x3e, 0x9a, 0xfa, - 0xad, 0xf1, 0xfe, 0xf5, 0x60, 0xa6, 0x72, 0x27, 0xf7, 0xa2, 0x5f, 0x11, 0xda, 0xa2, 0x24, 0xc8, - 0xd1, 0xd2, 0x17, 0x61, 0xc5, 0xd3, 0xf7, 0xe1, 0x8e, 0xde, 0x02, 0x18, 0x9a, 0x47, 0x43, 0xed, - 0x89, 0xee, 0x62, 0x87, 0xed, 0x21, 0xa3, 0xa6, 0xa8, 0xe4, 0x23, 0x2a, 0x28, 0x7d, 0x16, 0x87, - 0x6c, 0x6b, 0x6c, 0x5b, 0x8e, 0xeb, 0x37, 0xc3, 0x2e, 0x24, 0x58, 0xc2, 0x88, 0x22, 0x30, 0x28, - 0x94, 0xcf, 0xd9, 0xdc, 0x92, 0x25, 0xdf, 0x9b, 0x07, 0x2f, 0xcf, 0x47, 0x80, 0xdd, 0xe8, 0x99, - 0xd8, 0xfd, 0x1a, 0x24, 0x38, 0x8b, 0xb2, 0x46, 0x4f, 0x6f, 0x15, 0x42, 0xef, 0xf2, 0xa9, 0xac, - 0xd5, 0xd9, 0x36, 0x47, 0x78, 0x9b, 0xa9, 0xf9, 0xce, 0xb9, 0x11, 0x7a, 0x07, 0x24, 0x42, 0x5c, - 0x8d, 0x98, 0x9f, 0x70, 0xe8, 0xc7, 0x6a, 0x69, 0x8a, 0x97, 0x6e, 0xb7, 0xd7, 0x35, 0x3f, 0xc1, - 0x6a, 0x92, 0x10, 0x97, 0xfe, 0x40, 0x79, 0x90, 0x9e, 0xe8, 0xa3, 0x11, 0x6b, 0x91, 0x38, 0x63, - 0xc0, 0xe0, 0x79, 0x19, 0x14, 0x89, 0xff, 0x01, 0x28, 0x50, 0x01, 0xd2, 0x1e, 0x5f, 0xd9, 0xba, - 0x3b, 0x54, 0x92, 0xb4, 0x2f, 0x54, 0xe0, 0xa2, 0x7d, 0xdd, 0x1d, 0x22, 0x05, 0x92, 0x44, 0x1f, - 0xdb, 0x34, 0xe5, 0x52, 0x31, 0xb6, 0x99, 0x51, 0xfd, 0x47, 0xb4, 0x01, 0xac, 0x5f, 0xf8, 0xa3, - 0x92, 0x62, 0x5b, 0x0f, 0x49, 0x58, 0x02, 0x8e, 0x4d, 0x5b, 0x3b, 0x3c, 0x26, 0x0a, 0x14, 0x85, - 0x4d, 0xc9, 0x4b, 0xc0, 0xb1, 0x69, 0x6f, 0x3f, 0x20, 0x6a, 0x92, 0x2e, 0x6e, 0x1f, 0x13, 0xf4, - 0x2e, 0xac, 0x98, 0x93, 0x23, 0x4c, 0x5c, 0xcd, 0x30, 0x1d, 0x3c, 0x70, 0x47, 0x4f, 0x95, 0x34, - 0x55, 0x57, 0x73, 0x5c, 0xdc, 0xf0, 0xa4, 0xf9, 0x4f, 0x05, 0x88, 0xb3, 0x32, 0xa2, 0x7b, 0x20, - 0x52, 0x42, 0xf0, 0xe8, 0xff, 0xb2, 0x7c, 0xc0, 0x6c, 0x10, 0x02, 0x71, 0xa2, 0x8f, 0xb1, 0x82, - 0x58, 0xa8, 0xec, 0x37, 0x7a, 0x1d, 0x92, 0x04, 0x9f, 0x68, 0x8f, 0xf5, 0x91, 0xb2, 0xc6, 0xe2, - 0x48, 0x10, 0x7c, 0xf2, 0x48, 0x1f, 0xb5, 0x45, 0x29, 0x2a, 0xc7, 0xda, 0xa2, 0x14, 0x93, 0xc5, - 0xb6, 0x28, 0x89, 0x72, 0xbc, 0x2d, 0x4a, 0x71, 0x39, 0xd1, 0x16, 0xa5, 0x84, 0x9c, 0x6c, 0x8b, - 0x52, 0x52, 0x96, 0xda, 0xa2, 0x24, 0xc9, 0xa9, 0xb6, 0x28, 0xa5, 0x64, 0x68, 0x8b, 0x12, 0xc8, - 0xe9, 0xb6, 0x28, 0xa5, 0xe5, 0x4c, 0x5b, 0x94, 0x32, 0x72, 0xb6, 0x2d, 0x4a, 0x59, 0x39, 0xd7, - 0x16, 0xa5, 0x9c, 0xbc, 0xd2, 0x16, 0xa5, 0x15, 0x59, 0x6e, 0x8b, 0x92, 0x2c, 0xaf, 0xb6, 0x45, - 0x69, 0x55, 0x46, 0xa5, 0x3f, 0x0a, 0x90, 0xe3, 0x38, 0x0d, 0x7a, 0xe2, 0x26, 0xac, 0xb2, 0x04, - 0x9a, 0x93, 0x23, 0xcd, 0xf6, 0x84, 0x0c, 0xed, 0x51, 0x55, 0xf6, 0x17, 0x02, 0xe5, 0xcf, 0x41, - 0xd6, 0xc1, 0xba, 0xb1, 0x50, 0x8c, 0x32, 0xc5, 0x0c, 0x15, 0x06, 0x4a, 0x6f, 0x43, 0x8e, 0xb5, - 0xe4, 0x42, 0x2b, 0xc6, 0xb4, 0xb2, 0x4c, 0x1a, 0xa8, 0xd5, 0x20, 0x4b, 0x6c, 0x7d, 0xb2, 0xd0, - 0x12, 0x59, 0x8b, 0xbd, 0x7e, 0x06, 0xec, 0xbb, 0xb6, 0x3e, 0xf1, 0xe0, 0x9e, 0xa1, 0x36, 0xc1, - 0xf9, 0xa5, 0xb2, 0xe3, 0x6b, 0x3a, 0xc6, 0x54, 0x63, 0xd7, 0x24, 0x2e, 0xfa, 0x3a, 0x64, 0x1c, - 0x26, 0xd1, 0xa8, 0xa2, 0xdf, 0xb7, 0x17, 0x38, 0x4d, 0x3b, 0x81, 0x13, 0x52, 0xfa, 0xad, 0x00, - 0x6b, 0x0d, 0xc7, 0xb2, 0x6d, 0x6c, 0x78, 0x15, 0xe5, 0x5c, 0xe0, 0x17, 0x52, 0x08, 0x15, 0xf2, - 0x3e, 0x44, 0x5b, 0x0d, 0x8f, 0x3e, 0xef, 0x5c, 0xb7, 0x3b, 0xa2, 0xad, 0x06, 0xba, 0x0b, 0x09, - 0xe2, 0xea, 0xee, 0x94, 0xb0, 0xe6, 0xcf, 0x6d, 0xfd, 0xff, 0x39, 0x44, 0xd3, 0x65, 0x8a, 0xaa, - 0x67, 0x50, 0xfa, 0x73, 0x14, 0xd6, 0xba, 0x83, 0x21, 0x1e, 0xeb, 0xf5, 0xa1, 0x3e, 0x39, 0x0a, - 0xf6, 0xfb, 0x4d, 0x90, 0x43, 0x99, 0xd0, 0x46, 0x26, 0x71, 0xbd, 0x93, 0xfc, 0xbd, 0xf3, 0x29, - 0x36, 0x94, 0x4e, 0x2f, 0x3f, 0x39, 0x67, 0x39, 0xc9, 0xdf, 0x82, 0x9c, 0xc1, 0x33, 0xa4, 0x79, - 0xf4, 0x18, 0xbb, 0x90, 0x1e, 0xcf, 0x48, 0xa9, 0xe7, 0x3d, 0x6b, 0x84, 0x96, 0x08, 0xfa, 0x01, - 0xac, 0xf9, 0xce, 0xe9, 0xb0, 0x49, 0xb3, 0x44, 0xe9, 0x48, 0x64, 0x49, 0xde, 0x9d, 0xcf, 0x0a, - 0xab, 0x9e, 0xab, 0x86, 0xb7, 0x7a, 0x7d, 0x5e, 0x5a, 0x35, 0x4e, 0x79, 0x32, 0xbc, 0xb3, 0xe3, - 0x35, 0x58, 0x0f, 0xa7, 0x34, 0xc0, 0x5b, 0x0d, 0x64, 0x2e, 0x39, 0xc4, 0x74, 0xbf, 0xce, 0x11, - 0x76, 0x51, 0x19, 0xd6, 0x68, 0x25, 0xf0, 0x98, 0xf2, 0x26, 0xa5, 0x51, 0x2d, 0x04, 0x93, 0xd5, - 0x60, 0x89, 0xce, 0x17, 0x7b, 0xfa, 0x18, 0x97, 0x7e, 0x27, 0xc2, 0xea, 0xc2, 0x89, 0x5f, 0x2d, - 0xca, 0x5e, 0xe6, 0xe4, 0x58, 0x5b, 0x0c, 0x7a, 0x9c, 0xbd, 0xcc, 0xc9, 0x31, 0x1d, 0xf6, 0x92, - 0x74, 0xf1, 0xc0, 0x31, 0x51, 0x1b, 0x44, 0xcb, 0x76, 0xfd, 0x66, 0x39, 0xef, 0xb0, 0x7c, 0xe5, - 0x1d, 0xe5, 0x8e, 0xed, 0xf2, 0x53, 0x58, 0x65, 0x3e, 0xd0, 0xaf, 0x05, 0x48, 0xba, 0x2c, 0x08, - 0xa2, 0x24, 0x98, 0xbf, 0xbb, 0x57, 0xf2, 0xc7, 0x13, 0xe0, 0x0d, 0x78, 0xfb, 0xb4, 0x96, 0x2f, - 0x67, 0x85, 0xd5, 0xd3, 0x09, 0x22, 0xd7, 0x9d, 0xfc, 0xfc, 0xbd, 0xa1, 0x36, 0xe4, 0x96, 0x33, - 0xcc, 0xce, 0x8d, 0x4b, 0xce, 0x76, 0xd9, 0xa5, 0x0a, 0xe4, 0x8f, 0xe8, 0x98, 0xb5, 0xd8, 0xf6, - 0x19, 0xf3, 0x48, 0x75, 0x79, 0x1e, 0xb9, 0x79, 0xa9, 0x94, 0x70, 0x9f, 0xa1, 0x21, 0x24, 0x7f, - 0x07, 0x52, 0x41, 0xbe, 0xc3, 0x6f, 0x49, 0xf1, 0xb7, 0xac, 0x87, 0xdf, 0x92, 0x7a, 0x65, 0x7a, - 0x09, 0x4e, 0x82, 0xb8, 0x9c, 0x28, 0xfd, 0x44, 0x80, 0x8c, 0x8a, 0x89, 0x35, 0x7a, 0x8c, 0x0d, - 0xda, 0x83, 0xe8, 0x4b, 0x20, 0xd2, 0x9e, 0xf6, 0xce, 0xa3, 0x0b, 0xc8, 0x8d, 0xa9, 0xa2, 0x2a, - 0xa4, 0x82, 0xdb, 0xd6, 0x55, 0x2e, 0x21, 0x0b, 0xab, 0x92, 0x0d, 0x68, 0x11, 0x70, 0x40, 0xe3, - 0x3d, 0xa0, 0xec, 0xc0, 0xf6, 0xe6, 0x51, 0x2e, 0x27, 0x99, 0x77, 0xcf, 0x27, 0x99, 0x20, 0x18, - 0xbf, 0x4c, 0x4e, 0x48, 0x46, 0xbc, 0x36, 0xfc, 0x43, 0x0c, 0x50, 0xdd, 0xc1, 0xba, 0x8b, 0x29, - 0xe7, 0x91, 0xf3, 0x98, 0xb8, 0x06, 0x71, 0x46, 0x45, 0x5e, 0x6c, 0x97, 0x3c, 0xa3, 0xbd, 0x97, - 0x73, 0x53, 0xf4, 0x1d, 0xc8, 0x0c, 0xac, 0xd1, 0x74, 0xcc, 0xc9, 0xd2, 0x27, 0xb5, 0x2f, 0x9f, - 0x07, 0x80, 0x57, 0x36, 0x57, 0xae, 0x5b, 0xa3, 0x10, 0x73, 0xa6, 0xb9, 0x43, 0x2a, 0xa1, 0xf3, - 0x5f, 0x2a, 0x00, 0x23, 0xe3, 0xb3, 0x94, 0xba, 0x10, 0xa0, 0x2d, 0x88, 0xeb, 0x44, 0xb3, 0x0e, - 0xd9, 0x54, 0x76, 0x51, 0x75, 0x54, 0x51, 0x27, 0x9d, 0x43, 0x74, 0x1b, 0xb2, 0x87, 0x27, 0x9c, - 0x83, 0x39, 0xeb, 0xf0, 0x8b, 0xc6, 0xca, 0x7c, 0x56, 0x48, 0x6f, 0x7f, 0xc8, 0x82, 0xa5, 0x9c, - 0xa3, 0xa6, 0x0f, 0x4f, 0x82, 0x87, 0xbc, 0x0e, 0x49, 0x6f, 0x93, 0xe8, 0x11, 0xc4, 0x4c, 0x83, - 0x1f, 0x92, 0xd9, 0x5a, 0x83, 0xde, 0x2c, 0x5b, 0x0d, 0xf2, 0x72, 0x56, 0xb8, 0x7b, 0xe5, 0x7e, - 0xad, 0xb3, 0x38, 0x5b, 0x0d, 0x95, 0x3a, 0x2c, 0xfd, 0x1f, 0xac, 0x85, 0x52, 0x13, 0xd0, 0xe7, - 0x5f, 0x12, 0x90, 0xdc, 0xd7, 0x9f, 0x8e, 0x2c, 0xdd, 0x40, 0x45, 0x48, 0xfb, 0x57, 0x56, 0xd3, - 0x9a, 0x78, 0xb5, 0x0c, 0x8b, 0xe8, 0xa4, 0x3a, 0x25, 0xd8, 0x61, 0x71, 0xf1, 0x2e, 0x09, 0x9e, - 0xe9, 0x8c, 0xc1, 0xee, 0xd7, 0xd8, 0xd0, 0xc6, 0xe6, 0xc0, 0xb1, 0xf8, 0xb9, 0x19, 0x63, 0xdd, - 0x4e, 0xa5, 0x0f, 0x99, 0x90, 0xce, 0x7a, 0x87, 0xe6, 0xc4, 0x24, 0xc3, 0x85, 0x1e, 0x9b, 0x8d, - 0xd5, 0x9c, 0x2f, 0xf6, 0x14, 0x2d, 0xc8, 0x2d, 0x2e, 0xd0, 0x1a, 0xcd, 0x49, 0x82, 0xe5, 0x64, - 0x67, 0x3e, 0x2b, 0x64, 0x17, 0x78, 0xe1, 0xd9, 0xb9, 0xde, 0x3d, 0x76, 0xe1, 0xbf, 0x65, 0x10, - 0xf6, 0x15, 0xc2, 0x71, 0x2c, 0x47, 0x91, 0x78, 0xff, 0xb3, 0x07, 0xf4, 0x3e, 0xc4, 0x47, 0x58, - 0x27, 0x7c, 0xbc, 0x4d, 0x6f, 0x15, 0xcf, 0x81, 0x1e, 0xfb, 0x50, 0xa2, 0x72, 0x75, 0x54, 0x83, - 0x04, 0x9f, 0xa1, 0xd9, 0xe4, 0x9b, 0xde, 0xda, 0x3c, 0xc7, 0x70, 0xe9, 0xfb, 0xc6, 0x4e, 0x44, - 0xf5, 0x2c, 0x51, 0x13, 0x92, 0x0e, 0xbf, 0x2f, 0xb1, 0x79, 0xf8, 0xc2, 0x31, 0x21, 0x74, 0x13, - 0xdb, 0x89, 0xa8, 0xbe, 0x2d, 0xea, 0x41, 0x86, 0x84, 0x8e, 0x4e, 0x25, 0xc3, 0x7c, 0x9d, 0x37, - 0x19, 0x9c, 0x31, 0xbc, 0xec, 0xd0, 0x41, 0x2f, 0x24, 0xa6, 0x01, 0x9a, 0x6c, 0x6e, 0x55, 0xb2, - 0x17, 0x06, 0xb8, 0x74, 0x11, 0xa3, 0x01, 0x72, 0x4b, 0xb4, 0x07, 0x30, 0x08, 0xf8, 0x4b, 0xc9, - 0x31, 0x3f, 0x5f, 0xb8, 0xca, 0x81, 0xb7, 0x13, 0x51, 0x43, 0x1e, 0xd0, 0x87, 0x90, 0x1e, 0x2c, - 0x40, 0xae, 0xac, 0x30, 0x87, 0xb7, 0xae, 0xc4, 0x16, 0x3b, 0x94, 0x21, 0x16, 0xd2, 0x65, 0x86, - 0x90, 0x4f, 0x31, 0x44, 0x2d, 0x05, 0x49, 0x83, 0xdb, 0x05, 0xd7, 0x82, 0xa4, 0x2c, 0x95, 0x7e, - 0x1f, 0x07, 0x29, 0xa0, 0xe3, 0x0a, 0xa0, 0x43, 0x47, 0x1f, 0xd0, 0x06, 0xd2, 0x06, 0x16, 0xbd, - 0x18, 0xb9, 0x98, 0x7f, 0x40, 0x88, 0xee, 0x44, 0xd4, 0x55, 0x7f, 0xad, 0xee, 0x2f, 0xd1, 0x16, - 0x19, 0x5b, 0x86, 0x79, 0x68, 0x2e, 0x5a, 0x84, 0x7f, 0x18, 0xcb, 0xf9, 0x62, 0xaf, 0x45, 0x3e, - 0x58, 0xba, 0x3c, 0xc7, 0x2e, 0x41, 0x52, 0x3b, 0x91, 0xd0, 0xed, 0x9a, 0xb6, 0xac, 0x33, 0x9d, - 0x4c, 0xe8, 0x3d, 0xc3, 0x1b, 0x75, 0x39, 0x05, 0x66, 0x3d, 0x29, 0x1f, 0x6b, 0x51, 0xfd, 0x14, - 0x94, 0xdf, 0xbb, 0x10, 0xca, 0x7e, 0xec, 0x3b, 0x42, 0x80, 0xe5, 0xed, 0xd3, 0x58, 0xbe, 0x71, - 0x31, 0x96, 0x43, 0x6e, 0x02, 0x30, 0x1f, 0x9c, 0x09, 0xe6, 0xca, 0x25, 0xc1, 0x1c, 0xf2, 0xb8, - 0x8c, 0xe6, 0xfa, 0x29, 0x34, 0xbf, 0x77, 0x21, 0x9a, 0xc3, 0x31, 0x7a, 0x70, 0xee, 0x9c, 0x01, - 0xe7, 0x5b, 0x97, 0x82, 0x73, 0xc8, 0x59, 0x18, 0xcf, 0xea, 0x59, 0x78, 0x2e, 0x5f, 0x0e, 0xcf, - 0x21, 0x97, 0x61, 0x27, 0x35, 0x00, 0xc9, 0xbf, 0xdf, 0x85, 0xe0, 0x7b, 0xe3, 0x1b, 0x90, 0xf0, - 0xca, 0x8d, 0x20, 0xd7, 0x50, 0xab, 0xad, 0xbd, 0xd6, 0xde, 0x7d, 0x6d, 0xaf, 0xfa, 0xb0, 0xd9, - 0x95, 0x23, 0x48, 0x81, 0xf5, 0x8f, 0xaa, 0xad, 0x9e, 0xb6, 0xdd, 0x51, 0xb5, 0xfb, 0x75, 0xad, - 0xb5, 0xd7, 0x6b, 0xaa, 0x8f, 0xaa, 0xbb, 0xb2, 0x80, 0x5e, 0x03, 0xa4, 0x76, 0xea, 0x0f, 0xba, - 0x8d, 0x9a, 0x56, 0xef, 0x3c, 0xdc, 0xaf, 0xd6, 0x7b, 0xad, 0xce, 0x9e, 0x1c, 0x45, 0x12, 0x88, - 0x8d, 0xce, 0x5e, 0x53, 0x86, 0x1b, 0x3f, 0x8a, 0x82, 0xd8, 0x7b, 0x6a, 0x63, 0xf4, 0x79, 0x48, - 0x1f, 0xec, 0x75, 0xf7, 0x9b, 0xf5, 0xd6, 0x76, 0xab, 0xd9, 0x90, 0x23, 0xf9, 0xb5, 0x67, 0xcf, - 0x8b, 0x2b, 0x74, 0xe9, 0x60, 0x42, 0x6c, 0x3c, 0x60, 0xd0, 0x46, 0x79, 0x48, 0xd4, 0xaa, 0xf5, - 0x07, 0x07, 0xfb, 0xb2, 0x90, 0xcf, 0x3d, 0x7b, 0x5e, 0x04, 0xaa, 0xc0, 0x61, 0x85, 0xde, 0x84, - 0xa4, 0xda, 0xec, 0xf6, 0x3a, 0x6a, 0x53, 0x8e, 0xe6, 0x57, 0x9e, 0x3d, 0x2f, 0xa6, 0xe9, 0xa2, - 0x87, 0x16, 0xf4, 0x2e, 0x64, 0xbb, 0xf5, 0x9d, 0xe6, 0xc3, 0xaa, 0x56, 0xdf, 0xa9, 0xee, 0xdd, - 0x6f, 0xca, 0xb1, 0xfc, 0xfa, 0xb3, 0xe7, 0x45, 0x99, 0xea, 0x84, 0x41, 0x40, 0x5f, 0xd1, 0x7a, - 0xb8, 0xdf, 0x51, 0x7b, 0xb2, 0xb8, 0x78, 0x05, 0xaf, 0x2a, 0x2a, 0x01, 0x70, 0xeb, 0xed, 0x66, - 0xb3, 0x21, 0xc7, 0xf3, 0xe8, 0xd9, 0xf3, 0x62, 0x8e, 0xae, 0x2f, 0x8a, 0x85, 0xde, 0x86, 0x4c, - 0x5d, 0x6d, 0x56, 0x7b, 0x4d, 0xad, 0xdb, 0xab, 0xf6, 0xba, 0x72, 0x62, 0x11, 0x49, 0xa8, 0x00, - 0x79, 0xe9, 0xa7, 0xbf, 0xdc, 0x88, 0xfc, 0xe6, 0x57, 0x1b, 0x91, 0x5a, 0xf1, 0xc5, 0x3f, 0x37, - 0x22, 0x2f, 0xe6, 0x1b, 0xc2, 0xa7, 0xf3, 0x0d, 0xe1, 0xaf, 0xf3, 0x0d, 0xe1, 0x1f, 0xf3, 0x0d, - 0xe1, 0x67, 0xff, 0xda, 0x88, 0x7c, 0x9c, 0xe0, 0x85, 0xeb, 0x27, 0xd8, 0xe7, 0xf6, 0xdb, 0xff, - 0x09, 0x00, 0x00, 0xff, 0xff, 0xcd, 0xe9, 0x69, 0xab, 0x1f, 0x18, 0x00, 0x00, + 0xd3, 0x7a, 0xf7, 0xd0, 0x72, 0xc6, 0xba, 0xeb, 0xb9, 0xcf, 0xbf, 0x4a, 0x4e, 0x46, 0x15, 0x72, + 0x32, 0xea, 0xeb, 0x04, 0x57, 0x88, 0xeb, 0x4c, 0x07, 0xee, 0xd4, 0xc1, 0x86, 0x6f, 0x37, 0x75, + 0xcd, 0x51, 0x65, 0x38, 0x1a, 0x54, 0x5c, 0x73, 0x8c, 0x89, 0xab, 0x8f, 0x6d, 0xbe, 0x52, 0xfa, + 0x31, 0xc4, 0x77, 0xb1, 0x4e, 0x30, 0xfa, 0x18, 0x92, 0x13, 0xcb, 0xc0, 0x9a, 0x69, 0x28, 0x42, + 0x51, 0xd8, 0xcc, 0xd6, 0xaa, 0xf3, 0x59, 0x21, 0xb1, 0x67, 0x19, 0xb8, 0xd5, 0x78, 0x3e, 0x2b, + 0xbc, 0x77, 0x64, 0xba, 0xc3, 0x69, 0xbf, 0x3c, 0xb0, 0xc6, 0x95, 0x20, 0x12, 0xa3, 0xbf, 0xf8, + 0x5d, 0xb1, 0x8f, 0x8f, 0x2a, 0xde, 0xf6, 0xca, 0xdc, 0x4c, 0x4d, 0x50, 0x8f, 0x2d, 0x03, 0xad, + 0x43, 0x1c, 0xdb, 0xd6, 0x60, 0xa8, 0x44, 0x8b, 0xc2, 0x66, 0x4c, 0xe5, 0x0f, 0xf7, 0xc4, 0x7f, + 0xff, 0xb2, 0x20, 0x94, 0xfe, 0x2e, 0x40, 0xb6, 0xa6, 0x0f, 0x8e, 0xa7, 0x76, 0x03, 0xbb, 0xba, + 0x39, 0x22, 0xa8, 0x06, 0x40, 0x5c, 0xdd, 0x71, 0x35, 0xba, 0x57, 0xb6, 0x99, 0xf4, 0xd6, 0x6b, + 0xe5, 0x45, 0xfa, 0x68, 0x2c, 0xe5, 0xe1, 0x68, 0x50, 0xee, 0xf9, 0xb1, 0xd4, 0xc4, 0x67, 0xb3, + 0x42, 0x44, 0x4d, 0x31, 0x33, 0x2a, 0x45, 0x1f, 0x80, 0x84, 0x27, 0x06, 0xf7, 0x10, 0xbd, 0xbe, + 0x87, 0x24, 0x9e, 0x18, 0xcc, 0xfe, 0x15, 0x88, 0x4d, 0x1d, 0x53, 0x89, 0x15, 0x85, 0xcd, 0x54, + 0x2d, 0x39, 0x9f, 0x15, 0x62, 0x07, 0x6a, 0x4b, 0xa5, 0x32, 0xf4, 0x0e, 0xac, 0xf6, 0xd9, 0x7e, + 0x35, 0x03, 0x93, 0x81, 0x63, 0xda, 0xae, 0xe5, 0x28, 0x62, 0x51, 0xd8, 0xcc, 0xa8, 0x72, 0xdf, + 0x0b, 0xc4, 0x97, 0x97, 0x64, 0xc8, 0xf1, 0xe0, 0xf6, 0x1d, 0xeb, 0xc8, 0xc1, 0x84, 0x94, 0xfe, + 0x16, 0x87, 0x9c, 0x8a, 0x89, 0x6b, 0x39, 0xd8, 0x0f, 0xf8, 0x17, 0x02, 0xe4, 0x5c, 0xbd, 0x3f, + 0xc2, 0x9a, 0x83, 0x9f, 0x38, 0xa6, 0x8b, 0x89, 0x12, 0x2d, 0xc6, 0x36, 0xd3, 0x5b, 0x5f, 0x2f, + 0xff, 0x57, 0xd0, 0x94, 0x97, 0x7d, 0x94, 0x7b, 0xd4, 0x5e, 0xf5, 0xcc, 0x9b, 0x13, 0xd7, 0x79, + 0x5a, 0xbb, 0xf3, 0x93, 0xcf, 0xaf, 0x59, 0xb6, 0x10, 0x76, 0xca, 0xad, 0x86, 0x9a, 0x75, 0xc3, + 0xce, 0xd0, 0xab, 0x20, 0x4e, 0x1d, 0x93, 0x28, 0xb1, 0x62, 0x6c, 0x33, 0x55, 0x93, 0xe6, 0xb3, + 0x82, 0x78, 0xa0, 0xb6, 0x88, 0xca, 0xa4, 0x4b, 0x99, 0x16, 0x6f, 0x91, 0xe9, 0xfb, 0x90, 0xe6, + 0xb1, 0xd3, 0x6c, 0x12, 0x25, 0xce, 0x02, 0x7f, 0xe3, 0x5c, 0xe0, 0xfe, 0xe6, 0x58, 0x94, 0x8b, + 0xf4, 0xaa, 0xe0, 0xfa, 0x02, 0x82, 0x2a, 0x90, 0xb6, 0x1e, 0x63, 0xc7, 0x31, 0x0d, 0xac, 0x19, + 0x7d, 0x25, 0xc1, 0x4a, 0x97, 0x9b, 0xcf, 0x0a, 0xd0, 0xf1, 0xc4, 0x8d, 0x9a, 0x0a, 0xbe, 0x4a, + 0xa3, 0x9f, 0xff, 0x93, 0x00, 0x99, 0x70, 0xda, 0xd0, 0x77, 0x41, 0xe2, 0x5b, 0x09, 0x7a, 0xa0, + 0x36, 0x9f, 0x15, 0x92, 0x4c, 0xe7, 0x06, 0x4d, 0x70, 0x2e, 0x9b, 0x49, 0xe6, 0xb3, 0x65, 0xa0, + 0xef, 0x43, 0xca, 0xd6, 0x1d, 0x3c, 0x71, 0xa9, 0xff, 0x28, 0xf3, 0x5f, 0x9f, 0xcf, 0x0a, 0xd2, + 0x3e, 0x13, 0xde, 0xfe, 0x05, 0x12, 0xf7, 0xda, 0x32, 0xf2, 0x3f, 0x04, 0xf4, 0x22, 0x0e, 0x90, + 0x0c, 0xb1, 0x63, 0xfc, 0x94, 0x47, 0xa4, 0xd2, 0x9f, 0x68, 0x17, 0xe2, 0x8f, 0xf5, 0xd1, 0xd4, + 0x6f, 0x8d, 0xf7, 0x6f, 0x07, 0x33, 0x95, 0x3b, 0xb9, 0x17, 0xfd, 0x9a, 0xd0, 0x16, 0x25, 0x41, + 0x8e, 0x96, 0xbe, 0x0c, 0x2b, 0x9e, 0xbe, 0x0f, 0x77, 0xf4, 0x1a, 0xc0, 0xd0, 0x3c, 0x1a, 0x6a, + 0x4f, 0x74, 0x17, 0x3b, 0x6c, 0x0f, 0x19, 0x35, 0x45, 0x25, 0x1f, 0x51, 0x41, 0xe9, 0xf3, 0x38, + 0x64, 0x5b, 0x63, 0xdb, 0x72, 0x5c, 0xbf, 0x19, 0x76, 0x21, 0xc1, 0x12, 0x46, 0x14, 0x81, 0x41, + 0xa1, 0x7c, 0xc9, 0xe6, 0x96, 0x2c, 0xf9, 0xde, 0x3c, 0x78, 0x79, 0x3e, 0x02, 0xec, 0x46, 0x2f, + 0xc4, 0xee, 0x37, 0x20, 0xc1, 0x59, 0x94, 0x35, 0x7a, 0x7a, 0xab, 0x10, 0x7a, 0x97, 0x4f, 0x65, + 0xad, 0xce, 0xb6, 0x39, 0xc2, 0xdb, 0x4c, 0xcd, 0x77, 0xce, 0x8d, 0xd0, 0x1b, 0x20, 0x11, 0xe2, + 0x6a, 0xc4, 0xfc, 0x84, 0x43, 0x3f, 0x56, 0x4b, 0x53, 0xbc, 0x74, 0xbb, 0xbd, 0xae, 0xf9, 0x09, + 0x56, 0x93, 0x84, 0xb8, 0xf4, 0x07, 0xca, 0x83, 0xf4, 0x44, 0x1f, 0x8d, 0x58, 0x8b, 0xc4, 0x19, + 0x03, 0x06, 0xcf, 0xcb, 0xa0, 0x48, 0xfc, 0x0f, 0x40, 0x81, 0x0a, 0x90, 0xf6, 0xf8, 0xca, 0xd6, + 0xdd, 0xa1, 0x92, 0xa4, 0x7d, 0xa1, 0x02, 0x17, 0xed, 0xeb, 0xee, 0x10, 0x29, 0x90, 0x24, 0xfa, + 0xd8, 0xa6, 0x29, 0x97, 0x8a, 0xb1, 0xcd, 0x8c, 0xea, 0x3f, 0xa2, 0x0d, 0x60, 0xfd, 0xc2, 0x1f, + 0x95, 0x14, 0xdb, 0x7a, 0x48, 0xc2, 0x12, 0x70, 0x6c, 0xda, 0xda, 0xe1, 0x31, 0x51, 0xa0, 0x28, + 0x6c, 0x4a, 0x5e, 0x02, 0x8e, 0x4d, 0x7b, 0xfb, 0x01, 0x51, 0x93, 0x74, 0x71, 0xfb, 0x98, 0xa0, + 0x37, 0x61, 0xc5, 0x9c, 0x1c, 0x61, 0xe2, 0x6a, 0x86, 0xe9, 0xe0, 0x81, 0x3b, 0x7a, 0xaa, 0xa4, + 0xa9, 0xba, 0x9a, 0xe3, 0xe2, 0x86, 0x27, 0xcd, 0x7f, 0x26, 0x40, 0x9c, 0x95, 0x11, 0xdd, 0x03, + 0x91, 0x12, 0x82, 0x47, 0xff, 0xd7, 0xe5, 0x03, 0x66, 0x83, 0x10, 0x88, 0x13, 0x7d, 0x8c, 0x15, + 0xc4, 0x42, 0x65, 0xbf, 0xd1, 0xcb, 0x90, 0x24, 0xf8, 0x44, 0x7b, 0xac, 0x8f, 0x94, 0x35, 0x16, + 0x47, 0x82, 0xe0, 0x93, 0x47, 0xfa, 0xa8, 0x2d, 0x4a, 0x51, 0x39, 0xd6, 0x16, 0xa5, 0x98, 0x2c, + 0xb6, 0x45, 0x49, 0x94, 0xe3, 0x6d, 0x51, 0x8a, 0xcb, 0x89, 0xb6, 0x28, 0x25, 0xe4, 0x64, 0x5b, + 0x94, 0x92, 0xb2, 0xd4, 0x16, 0x25, 0x49, 0x4e, 0xb5, 0x45, 0x29, 0x25, 0x43, 0x5b, 0x94, 0x40, + 0x4e, 0xb7, 0x45, 0x29, 0x2d, 0x67, 0xda, 0xa2, 0x94, 0x91, 0xb3, 0x6d, 0x51, 0xca, 0xca, 0xb9, + 0xb6, 0x28, 0xe5, 0xe4, 0x95, 0xb6, 0x28, 0xad, 0xc8, 0x72, 0x5b, 0x94, 0x64, 0x79, 0xb5, 0x2d, + 0x4a, 0xab, 0x32, 0x2a, 0xfd, 0x51, 0x80, 0x1c, 0xc7, 0x69, 0xd0, 0x13, 0xef, 0xc0, 0x2a, 0x4b, + 0xa0, 0x39, 0x39, 0xd2, 0x6c, 0x4f, 0xc8, 0xd0, 0x1e, 0x55, 0x65, 0x7f, 0x21, 0x50, 0xfe, 0x02, + 0x64, 0x1d, 0xac, 0x1b, 0x0b, 0xc5, 0x28, 0x53, 0xcc, 0x50, 0x61, 0xa0, 0xf4, 0x3a, 0xe4, 0x58, + 0x4b, 0x2e, 0xb4, 0x62, 0x4c, 0x2b, 0xcb, 0xa4, 0x81, 0x5a, 0x0d, 0xb2, 0xc4, 0xd6, 0x27, 0x0b, + 0x2d, 0x91, 0xb5, 0xd8, 0xcb, 0x17, 0xc0, 0xbe, 0x6b, 0xeb, 0x13, 0x0f, 0xee, 0x19, 0x6a, 0x13, + 0x9c, 0x5f, 0x2a, 0x3b, 0xbe, 0xa6, 0x63, 0x4c, 0x35, 0x76, 0x4d, 0xe2, 0xa2, 0x6f, 0x42, 0xc6, + 0x61, 0x12, 0x8d, 0x2a, 0xfa, 0x7d, 0x7b, 0x85, 0xd3, 0xb4, 0x13, 0x38, 0x21, 0xa5, 0xdf, 0x09, + 0xb0, 0xd6, 0x70, 0x2c, 0xdb, 0xc6, 0x86, 0x57, 0x51, 0xce, 0x05, 0x7e, 0x21, 0x85, 0x50, 0x21, + 0xef, 0x43, 0xb4, 0xd5, 0xf0, 0xe8, 0xf3, 0xce, 0x6d, 0xbb, 0x23, 0xda, 0x6a, 0xa0, 0xbb, 0x90, + 0x20, 0xae, 0xee, 0x4e, 0x09, 0x6b, 0xfe, 0xdc, 0xd6, 0xff, 0x5f, 0x42, 0x34, 0x5d, 0xa6, 0xa8, + 0x7a, 0x06, 0xa5, 0x3f, 0x47, 0x61, 0xad, 0x3b, 0x18, 0xe2, 0xb1, 0x5e, 0x1f, 0xea, 0x93, 0xa3, + 0x60, 0xbf, 0xdf, 0x06, 0x39, 0x94, 0x09, 0x6d, 0x64, 0x12, 0xd7, 0x3b, 0xc9, 0xdf, 0xba, 0x9c, + 0x62, 0x43, 0xe9, 0xf4, 0xf2, 0x93, 0x73, 0x96, 0x93, 0xfc, 0x1d, 0xc8, 0x19, 0x3c, 0x43, 0x9a, + 0x47, 0x8f, 0xb1, 0x2b, 0xe9, 0xf1, 0x82, 0x94, 0x7a, 0xde, 0xb3, 0x46, 0x68, 0x89, 0xa0, 0x1f, + 0xc1, 0x9a, 0xef, 0x9c, 0x0e, 0x9b, 0x34, 0x4b, 0x94, 0x8e, 0x44, 0x96, 0xe4, 0xdd, 0xf9, 0xac, + 0xb0, 0xea, 0xb9, 0x6a, 0x78, 0xab, 0xb7, 0xe7, 0xa5, 0x55, 0xe3, 0x9c, 0x27, 0xc3, 0x3b, 0x3b, + 0x5e, 0x82, 0xf5, 0x70, 0x4a, 0x03, 0xbc, 0xd5, 0x40, 0xe6, 0x92, 0x43, 0x4c, 0xf7, 0xeb, 0x1c, + 0x61, 0x17, 0x95, 0x61, 0x8d, 0x56, 0x02, 0x8f, 0x29, 0x6f, 0x52, 0x1a, 0xd5, 0x42, 0x30, 0x59, + 0x0d, 0x96, 0xe8, 0x7c, 0xb1, 0xa7, 0x8f, 0x71, 0xe9, 0xf7, 0x22, 0xac, 0x2e, 0x9c, 0xf8, 0xd5, + 0xa2, 0xec, 0x65, 0x4e, 0x8e, 0xb5, 0xc5, 0xa0, 0xc7, 0xd9, 0xcb, 0x9c, 0x1c, 0xd3, 0x61, 0x2f, + 0x49, 0x17, 0x0f, 0x1c, 0x13, 0xb5, 0x41, 0xb4, 0x6c, 0xd7, 0x6f, 0x96, 0xcb, 0x0e, 0xcb, 0x17, + 0xde, 0x51, 0xee, 0xd8, 0x2e, 0x3f, 0x85, 0x55, 0xe6, 0x03, 0xfd, 0x46, 0x80, 0xa4, 0xcb, 0x82, + 0x20, 0x4a, 0x82, 0xf9, 0xbb, 0x7b, 0x23, 0x7f, 0x3c, 0x01, 0xde, 0x80, 0xb7, 0x4f, 0x6b, 0xf9, + 0x7c, 0x56, 0x58, 0x3d, 0x9f, 0x20, 0x72, 0xdb, 0xc9, 0xcf, 0xdf, 0x1b, 0x6a, 0x43, 0x6e, 0x39, + 0xc3, 0xec, 0xdc, 0xb8, 0xe6, 0x6c, 0x97, 0x5d, 0xaa, 0x40, 0xfe, 0x88, 0x8e, 0x59, 0x8b, 0x6d, + 0x5f, 0x30, 0x8f, 0x54, 0x97, 0xe7, 0x91, 0x77, 0xae, 0x95, 0x12, 0xee, 0x33, 0x34, 0x84, 0xe4, + 0xef, 0x40, 0x2a, 0xc8, 0x77, 0xf8, 0x2d, 0x29, 0xfe, 0x96, 0xf5, 0xf0, 0x5b, 0x52, 0x2f, 0x4c, + 0x2f, 0xc1, 0x49, 0x10, 0x97, 0x13, 0xa5, 0x9f, 0x0a, 0x90, 0x51, 0x31, 0xb1, 0x46, 0x8f, 0xb1, + 0x41, 0x7b, 0x10, 0x7d, 0x05, 0x44, 0xda, 0xd3, 0xde, 0x79, 0x74, 0x05, 0xb9, 0x31, 0x55, 0x54, + 0x85, 0x54, 0x70, 0xdb, 0xba, 0xc9, 0x25, 0x64, 0x61, 0x55, 0xb2, 0x01, 0x2d, 0x02, 0x0e, 0x68, + 0xbc, 0x07, 0x94, 0x1d, 0xd8, 0xde, 0x3c, 0xca, 0xe5, 0x24, 0xf3, 0xe6, 0xe5, 0x24, 0x13, 0x04, + 0xe3, 0x97, 0xc9, 0x09, 0xc9, 0x88, 0xd7, 0x86, 0x7f, 0x88, 0x01, 0xaa, 0x3b, 0x58, 0x77, 0x31, + 0xe5, 0x3c, 0x72, 0x19, 0x13, 0xd7, 0x20, 0xce, 0xa8, 0xc8, 0x8b, 0xed, 0x9a, 0x67, 0xb4, 0xf7, + 0x72, 0x6e, 0x8a, 0xbe, 0x07, 0x99, 0x81, 0x35, 0x9a, 0x8e, 0x39, 0x59, 0xfa, 0xa4, 0xf6, 0xd5, + 0xcb, 0x00, 0xf0, 0xc2, 0xe6, 0xca, 0x75, 0x6b, 0x14, 0x62, 0xce, 0x34, 0x77, 0x48, 0x25, 0x74, + 0xfe, 0x4b, 0x05, 0x60, 0x64, 0x7c, 0x96, 0x52, 0x17, 0x02, 0xb4, 0x05, 0x71, 0x9d, 0x68, 0xd6, + 0x21, 0x9b, 0xca, 0xae, 0xaa, 0x8e, 0x2a, 0xea, 0xa4, 0x73, 0x88, 0xde, 0x83, 0xec, 0xe1, 0x09, + 0xe7, 0x60, 0xce, 0x3a, 0xfc, 0xa2, 0xb1, 0x32, 0x9f, 0x15, 0xd2, 0xdb, 0x1f, 0xb2, 0x60, 0x29, + 0xe7, 0xa8, 0xe9, 0xc3, 0x93, 0xe0, 0x21, 0xaf, 0x43, 0xd2, 0xdb, 0x24, 0x7a, 0x04, 0x31, 0xd3, + 0xe0, 0x87, 0x64, 0xb6, 0xd6, 0xa0, 0x37, 0xcb, 0x56, 0x83, 0x3c, 0x9f, 0x15, 0xee, 0xde, 0xb8, + 0x5f, 0xeb, 0x2c, 0xce, 0x56, 0x43, 0xa5, 0x0e, 0x4b, 0xff, 0x07, 0x6b, 0xa1, 0xd4, 0x04, 0xf4, + 0xf9, 0x97, 0x04, 0x24, 0xf7, 0xf5, 0xa7, 0x23, 0x4b, 0x37, 0x50, 0x11, 0xd2, 0xfe, 0x95, 0xd5, + 0xb4, 0x26, 0x5e, 0x2d, 0xc3, 0x22, 0x3a, 0xa9, 0x4e, 0x09, 0x76, 0x58, 0x5c, 0xbc, 0x4b, 0x82, + 0x67, 0x3a, 0x63, 0xb0, 0xfb, 0x35, 0x36, 0xb4, 0xb1, 0x39, 0x70, 0x2c, 0x7e, 0x6e, 0xc6, 0x58, + 0xb7, 0x53, 0xe9, 0x43, 0x26, 0xa4, 0xb3, 0xde, 0xa1, 0x39, 0x31, 0xc9, 0x70, 0xa1, 0xc7, 0x66, + 0x63, 0x35, 0xe7, 0x8b, 0x3d, 0x45, 0x0b, 0x72, 0x8b, 0x0b, 0xb4, 0x46, 0x73, 0x92, 0x60, 0x39, + 0xd9, 0x99, 0xcf, 0x0a, 0xd9, 0x05, 0x5e, 0x78, 0x76, 0x6e, 0x77, 0x8f, 0x5d, 0xf8, 0x6f, 0x19, + 0x84, 0x7d, 0x85, 0x70, 0x1c, 0xcb, 0x51, 0x24, 0xde, 0xff, 0xec, 0x01, 0xbd, 0x0f, 0xf1, 0x11, + 0xd6, 0x09, 0x1f, 0x6f, 0xd3, 0x5b, 0xc5, 0x4b, 0xa0, 0xc7, 0x3e, 0x94, 0xa8, 0x5c, 0x1d, 0xd5, + 0x20, 0xc1, 0x67, 0x68, 0x36, 0xf9, 0xa6, 0xb7, 0x36, 0x2f, 0x31, 0x5c, 0xfa, 0xbe, 0xb1, 0x13, + 0x51, 0x3d, 0x4b, 0xd4, 0x84, 0xa4, 0xc3, 0xef, 0x4b, 0x6c, 0x1e, 0xbe, 0x72, 0x4c, 0x08, 0xdd, + 0xc4, 0x76, 0x22, 0xaa, 0x6f, 0x8b, 0x7a, 0x90, 0x21, 0xa1, 0xa3, 0x53, 0xc9, 0x30, 0x5f, 0x97, + 0x4d, 0x06, 0x17, 0x0c, 0x2f, 0x3b, 0x74, 0xd0, 0x0b, 0x89, 0x69, 0x80, 0x26, 0x9b, 0x5b, 0x95, + 0xec, 0x95, 0x01, 0x2e, 0x5d, 0xc4, 0x68, 0x80, 0xdc, 0x12, 0xed, 0x01, 0x0c, 0x02, 0xfe, 0x52, + 0x72, 0xcc, 0xcf, 0x97, 0x6e, 0x72, 0xe0, 0xed, 0x44, 0xd4, 0x90, 0x07, 0xf4, 0x21, 0xa4, 0x07, + 0x0b, 0x90, 0x2b, 0x2b, 0xcc, 0xe1, 0xbb, 0x37, 0x62, 0x8b, 0x1d, 0xca, 0x10, 0x0b, 0xe9, 0x32, + 0x43, 0xc8, 0xe7, 0x18, 0xa2, 0x96, 0x82, 0xa4, 0xc1, 0xed, 0x82, 0x6b, 0x41, 0x52, 0x96, 0x4a, + 0x9f, 0xc6, 0x41, 0x0a, 0xe8, 0xb8, 0x02, 0xe8, 0xd0, 0xd1, 0x07, 0xb4, 0x81, 0xb4, 0x81, 0x45, + 0x2f, 0x46, 0x2e, 0xe6, 0x1f, 0x10, 0xa2, 0x3b, 0x11, 0x75, 0xd5, 0x5f, 0xab, 0xfb, 0x4b, 0xb4, + 0x45, 0xc6, 0x96, 0x61, 0x1e, 0x9a, 0x8b, 0x16, 0xe1, 0x1f, 0xc6, 0x72, 0xbe, 0xd8, 0x6b, 0x91, + 0x0f, 0x96, 0x2e, 0xcf, 0xb1, 0x6b, 0x90, 0xd4, 0x4e, 0x24, 0x74, 0xbb, 0xa6, 0x2d, 0xeb, 0x4c, + 0x27, 0x13, 0x7a, 0xcf, 0xf0, 0x46, 0x5d, 0x4e, 0x81, 0x59, 0x4f, 0xca, 0xc7, 0x5a, 0x54, 0x3f, + 0x07, 0xe5, 0xb7, 0xae, 0x84, 0xb2, 0x1f, 0xfb, 0x8e, 0x10, 0x60, 0x79, 0xfb, 0x3c, 0x96, 0xdf, + 0xbe, 0x1a, 0xcb, 0x21, 0x37, 0x01, 0x98, 0x0f, 0x2e, 0x04, 0x73, 0xe5, 0x9a, 0x60, 0x0e, 0x79, + 0x5c, 0x46, 0x73, 0xfd, 0x1c, 0x9a, 0xdf, 0xba, 0x12, 0xcd, 0xe1, 0x18, 0x3d, 0x38, 0x77, 0x2e, + 0x80, 0xf3, 0xbb, 0xd7, 0x82, 0x73, 0xc8, 0x59, 0x18, 0xcf, 0xea, 0x45, 0x78, 0x2e, 0x5f, 0x0f, + 0xcf, 0x21, 0x97, 0x61, 0x27, 0x35, 0x00, 0xc9, 0xbf, 0xdf, 0x85, 0xe0, 0xfb, 0xf6, 0xb7, 0x20, + 0xe1, 0x95, 0x1b, 0x41, 0xae, 0xa1, 0x56, 0x5b, 0x7b, 0xad, 0xbd, 0xfb, 0xda, 0x5e, 0xf5, 0x61, + 0xb3, 0x2b, 0x47, 0x90, 0x02, 0xeb, 0x1f, 0x55, 0x5b, 0x3d, 0x6d, 0xbb, 0xa3, 0x6a, 0xf7, 0xeb, + 0x5a, 0x6b, 0xaf, 0xd7, 0x54, 0x1f, 0x55, 0x77, 0x65, 0x01, 0xbd, 0x04, 0x48, 0xed, 0xd4, 0x1f, + 0x74, 0x1b, 0x35, 0xad, 0xde, 0x79, 0xb8, 0x5f, 0xad, 0xf7, 0x5a, 0x9d, 0x3d, 0x39, 0x8a, 0x24, + 0x10, 0x1b, 0x9d, 0xbd, 0xa6, 0x0c, 0x6f, 0x7f, 0x1a, 0x05, 0xb1, 0xf7, 0xd4, 0xc6, 0xe8, 0x8b, + 0x90, 0x3e, 0xd8, 0xeb, 0xee, 0x37, 0xeb, 0xad, 0xed, 0x56, 0xb3, 0x21, 0x47, 0xf2, 0x6b, 0xa7, + 0x67, 0xc5, 0x15, 0xba, 0x74, 0x30, 0x21, 0x36, 0x1e, 0x30, 0x68, 0xa3, 0x3c, 0x24, 0x6a, 0xd5, + 0xfa, 0x83, 0x83, 0x7d, 0x59, 0xc8, 0xe7, 0x4e, 0xcf, 0x8a, 0x40, 0x15, 0x38, 0xac, 0xd0, 0xab, + 0x90, 0x54, 0x9b, 0xdd, 0x5e, 0x47, 0x6d, 0xca, 0xd1, 0xfc, 0xca, 0xe9, 0x59, 0x31, 0x4d, 0x17, + 0x3d, 0xb4, 0xa0, 0x37, 0x21, 0xdb, 0xad, 0xef, 0x34, 0x1f, 0x56, 0xb5, 0xfa, 0x4e, 0x75, 0xef, + 0x7e, 0x53, 0x8e, 0xe5, 0xd7, 0x4f, 0xcf, 0x8a, 0x32, 0xd5, 0x09, 0x83, 0x80, 0xbe, 0xa2, 0xf5, + 0x70, 0xbf, 0xa3, 0xf6, 0x64, 0x71, 0xf1, 0x0a, 0x5e, 0x55, 0x54, 0x02, 0xe0, 0xd6, 0xdb, 0xcd, + 0x66, 0x43, 0x8e, 0xe7, 0xd1, 0xe9, 0x59, 0x31, 0x47, 0xd7, 0x17, 0xc5, 0x42, 0xaf, 0x43, 0xa6, + 0xae, 0x36, 0xab, 0xbd, 0xa6, 0xd6, 0xed, 0x55, 0x7b, 0x5d, 0x39, 0xb1, 0x88, 0x24, 0x54, 0x00, + 0x54, 0x86, 0xd5, 0xea, 0x41, 0xaf, 0xa3, 0x2d, 0xe9, 0x26, 0xf3, 0x2f, 0x9f, 0x9e, 0x15, 0xd7, + 0xa8, 0x6e, 0x75, 0xea, 0x5a, 0x21, 0xfd, 0xbc, 0xf4, 0xb3, 0x5f, 0x6d, 0x44, 0x7e, 0xfb, 0xeb, + 0x8d, 0x48, 0xad, 0xf8, 0xec, 0x9f, 0x1b, 0x91, 0x67, 0xf3, 0x0d, 0xe1, 0xb3, 0xf9, 0x86, 0xf0, + 0xd7, 0xf9, 0x86, 0xf0, 0x8f, 0xf9, 0x86, 0xf0, 0xf3, 0x7f, 0x6d, 0x44, 0x3e, 0x4e, 0xf0, 0x42, + 0xf7, 0x13, 0xec, 0xf3, 0xfc, 0x7b, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0x45, 0xc5, 0x65, 0xa2, + 0x4f, 0x18, 0x00, 0x00, } diff --git a/pkg/jobs/jobspb/jobs.proto b/pkg/jobs/jobspb/jobs.proto index aeec8d1c2de1..0b48be0ded99 100644 --- a/pkg/jobs/jobspb/jobs.proto +++ b/pkg/jobs/jobspb/jobs.proto @@ -281,4 +281,5 @@ enum Type { IMPORT = 4 [(gogoproto.enumvalue_customname) = "TypeImport"]; CHANGEFEED = 5 [(gogoproto.enumvalue_customname) = "TypeChangefeed"]; CREATE_STATS = 6 [(gogoproto.enumvalue_customname) = "TypeCreateStats"]; + AUTO_CREATE_STATS = 7 [(gogoproto.enumvalue_customname) = "TypeAutoCreateStats"]; } diff --git a/pkg/jobs/jobspb/wrap.go b/pkg/jobs/jobspb/wrap.go index ca69434cfd37..c895f79e91ff 100644 --- a/pkg/jobs/jobspb/wrap.go +++ b/pkg/jobs/jobspb/wrap.go @@ -19,6 +19,7 @@ import ( "strings" "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" + "github.com/cockroachdb/cockroach/pkg/sql/stats" ) // Details is a marker interface for job details proto structs. @@ -58,6 +59,10 @@ func DetailsType(d isPayload_Details) Type { case *Payload_Changefeed: return TypeChangefeed case *Payload_CreateStats: + createStatsName := d.(*Payload_CreateStats).CreateStats.Name + if createStatsName == stats.AutoStatsName { + return TypeAutoCreateStats + } return TypeCreateStats default: panic(fmt.Sprintf("Payload.Type called on a payload with an unknown details type: %T", d)) diff --git a/pkg/sql/create_stats.go b/pkg/sql/create_stats.go index fedc5947990d..4edc0056e91b 100644 --- a/pkg/sql/create_stats.go +++ b/pkg/sql/create_stats.go @@ -383,7 +383,7 @@ func checkRunningJobs(ctx context.Context, job *jobs.Job, p *planner) error { return err } - if payload.Type() == jobspb.TypeCreateStats { + if payload.Type() == jobspb.TypeCreateStats || payload.Type() == jobspb.TypeAutoCreateStats { id := (*int64)(row[0].(*tree.DInt)) if *id == jobID { break @@ -443,7 +443,7 @@ func (r *createStatsResumer) OnTerminal( func init() { jobs.AddResumeHook(func(typ jobspb.Type, settings *cluster.Settings) jobs.Resumer { - if typ != jobspb.TypeCreateStats { + if typ != jobspb.TypeCreateStats && typ != jobspb.TypeAutoCreateStats { return nil } return &createStatsResumer{} diff --git a/pkg/ui/src/views/jobs/index.tsx b/pkg/ui/src/views/jobs/index.tsx index feda599c8f29..be1ff51b61a2 100644 --- a/pkg/ui/src/views/jobs/index.tsx +++ b/pkg/ui/src/views/jobs/index.tsx @@ -64,6 +64,7 @@ const typeOptions = [ { value: JobType.SCHEMA_CHANGE.toString(), label: "Schema Changes" }, { value: JobType.CHANGEFEED.toString(), label: "Changefeed"}, { value: JobType.CREATE_STATS.toString(), label: "Statistics Creation"}, + { value: JobType.AUTO_CREATE_STATS.toString(), label: "Auto-Statistics Creation"}, ]; const typeSetting = new LocalSetting( From fb80f9d31eea0af7b5f0d1092c964d9c64ad27ff Mon Sep 17 00:00:00 2001 From: Rebecca Taft Date: Fri, 1 Mar 2019 17:51:09 -0500 Subject: [PATCH 7/7] opt: propagate set operation output types to input columns This commit updates the optbuilder logic for set operations in which the types of the input columns do not match the types of the output columns. This can happen if a column on one side has type Unknown, but the corresponding column on the other side has a known type such as Int. The known type must be propagated to the side with the unknown type to prevent errors in the execution engine related to decoding types. If there are any column types on either side that don't match the output, then the optbuilder propagates the output types of the set operation down to the input columns by wrapping the side with mismatched types in a Project operation. The Project operation passes through columns that already have the correct type, and creates cast expressions for those that don't. Fixes #34524 Release note (bug fix): Fixed an error that happened when executing some set operations containing only nulls in one of the input columns. --- pkg/sql/opt/exec/execbuilder/testdata/union | 11 +- pkg/sql/opt/norm/custom_funcs.go | 59 +++--- pkg/sql/opt/norm/rules/select.opt | 30 --- pkg/sql/opt/norm/rules/set.opt | 33 +++ pkg/sql/opt/norm/testdata/rules/select | 48 ----- pkg/sql/opt/norm/testdata/rules/set | 59 ++++++ pkg/sql/opt/ops/relational.opt | 3 + pkg/sql/opt/optbuilder/scope.go | 21 +- pkg/sql/opt/optbuilder/testdata/union | 216 ++++++++++++++++++-- pkg/sql/opt/optbuilder/union.go | 77 +++++-- 10 files changed, 410 insertions(+), 147 deletions(-) create mode 100644 pkg/sql/opt/norm/rules/set.opt create mode 100644 pkg/sql/opt/norm/testdata/rules/set diff --git a/pkg/sql/opt/exec/execbuilder/testdata/union b/pkg/sql/opt/exec/execbuilder/testdata/union index c0b956ebda19..71edebee0619 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/union +++ b/pkg/sql/opt/exec/execbuilder/testdata/union @@ -1,4 +1,4 @@ -# LogicTest: local-opt +# LogicTest: local-opt fakedist-opt statement ok CREATE TABLE uniontest ( @@ -101,3 +101,12 @@ render · · ("?column?", "?column? · row 0, expr 0 '' · · · row 0, expr 1 '' · · · row 0, expr 2 'x' · · + +statement ok +CREATE TABLE a (a INT PRIMARY KEY) + +# Regression test for #34524. This test is here because the issue still exists +# in the heuristic planner. +query I +(SELECT NULL FROM a) EXCEPT (VALUES((SELECT 1 FROM a LIMIT 1)), (1)) +---- diff --git a/pkg/sql/opt/norm/custom_funcs.go b/pkg/sql/opt/norm/custom_funcs.go index 967c2b04eb34..e518bf5c8443 100644 --- a/pkg/sql/opt/norm/custom_funcs.go +++ b/pkg/sql/opt/norm/custom_funcs.go @@ -658,32 +658,6 @@ func (c *CustomFuncs) AreProjectionsCorrelated( return false } -// ProjectColMapLeft returns a Projections operator that maps the left side -// columns in a SetPrivate to the output columns in it. Useful for replacing set -// operations with simpler constructs. -func (c *CustomFuncs) ProjectColMapLeft(set *memo.SetPrivate) memo.ProjectionsExpr { - return c.projectColMapSide(set.OutCols, set.LeftCols) -} - -// ProjectColMapRight returns a Project operator that maps the right side -// columns in a SetPrivate to the output columns in it. Useful for replacing set -// operations with simpler constructs. -func (c *CustomFuncs) ProjectColMapRight(set *memo.SetPrivate) memo.ProjectionsExpr { - return c.projectColMapSide(set.OutCols, set.RightCols) -} - -// projectColMapSide implements the side-agnostic logic from ProjectColMapLeft -// and ProjectColMapRight. -func (c *CustomFuncs) projectColMapSide(toList, fromList opt.ColList) memo.ProjectionsExpr { - items := make(memo.ProjectionsExpr, len(toList)) - for idx, fromCol := range fromList { - toCol := toList[idx] - items[idx].Element = c.f.ConstructVariable(fromCol) - items[idx].Col = toCol - } - return items -} - // MakeEmptyColSet returns a column set with no columns in it. func (c *CustomFuncs) MakeEmptyColSet() opt.ColSet { return opt.ColSet{} @@ -885,6 +859,39 @@ func (c *CustomFuncs) ZipOuterCols(zip memo.ZipExpr) opt.ColSet { return colSet } +// ---------------------------------------------------------------------- +// +// Set Rules +// Custom match and replace functions used with set.opt rules. +// +// ---------------------------------------------------------------------- + +// ProjectColMapLeft returns a Projections operator that maps the left side +// columns in a SetPrivate to the output columns in it. Useful for replacing set +// operations with simpler constructs. +func (c *CustomFuncs) ProjectColMapLeft(set *memo.SetPrivate) memo.ProjectionsExpr { + return c.projectColMapSide(set.OutCols, set.LeftCols) +} + +// ProjectColMapRight returns a Project operator that maps the right side +// columns in a SetPrivate to the output columns in it. Useful for replacing set +// operations with simpler constructs. +func (c *CustomFuncs) ProjectColMapRight(set *memo.SetPrivate) memo.ProjectionsExpr { + return c.projectColMapSide(set.OutCols, set.RightCols) +} + +// projectColMapSide implements the side-agnostic logic from ProjectColMapLeft +// and ProjectColMapRight. +func (c *CustomFuncs) projectColMapSide(toList, fromList opt.ColList) memo.ProjectionsExpr { + items := make(memo.ProjectionsExpr, len(toList)) + for idx, fromCol := range fromList { + toCol := toList[idx] + items[idx].Element = c.f.ConstructVariable(fromCol) + items[idx].Col = toCol + } + return items +} + // ---------------------------------------------------------------------- // // Boolean Rules diff --git a/pkg/sql/opt/norm/rules/select.opt b/pkg/sql/opt/norm/rules/select.opt index 868693c87706..a7f36d05c048 100644 --- a/pkg/sql/opt/norm/rules/select.opt +++ b/pkg/sql/opt/norm/rules/select.opt @@ -344,33 +344,3 @@ $input (RemoveFiltersItem $filters $item) ) - -# EliminateUnionAllLeft replaces a union all with a right side having a -# cardinality of zero, with just the left side operand. -[EliminateUnionAllLeft, Normalize] -(UnionAll - $left:* - $right:* & (HasZeroRows $right) - $colmap:* -) -=> -(Project - $left - (ProjectColMapLeft $colmap) - (MakeEmptyColSet) -) - -# EliminateUnionAllRight replaces a union all with a left side having a -# cardinality of zero, with just the right side operand. -[EliminateUnionAllRight, Normalize] -(UnionAll - $left:* & (HasZeroRows $left) - $right:* - $colmap:* -) -=> -(Project - $right - (ProjectColMapRight $colmap) - (MakeEmptyColSet) -) diff --git a/pkg/sql/opt/norm/rules/set.opt b/pkg/sql/opt/norm/rules/set.opt new file mode 100644 index 000000000000..465d5aaf69a0 --- /dev/null +++ b/pkg/sql/opt/norm/rules/set.opt @@ -0,0 +1,33 @@ +# ============================================================================= +# set.opt contains normalization rules for set operators. +# ============================================================================= + +# EliminateUnionAllLeft replaces a union all with a right side having a +# cardinality of zero, with just the left side operand. +[EliminateUnionAllLeft, Normalize] +(UnionAll + $left:* + $right:* & (HasZeroRows $right) + $colmap:* +) +=> +(Project + $left + (ProjectColMapLeft $colmap) + (MakeEmptyColSet) +) + +# EliminateUnionAllRight replaces a union all with a left side having a +# cardinality of zero, with just the right side operand. +[EliminateUnionAllRight, Normalize] +(UnionAll + $left:* & (HasZeroRows $left) + $right:* + $colmap:* +) +=> +(Project + $right + (ProjectColMapRight $colmap) + (MakeEmptyColSet) +) diff --git a/pkg/sql/opt/norm/testdata/rules/select b/pkg/sql/opt/norm/testdata/rules/select index 09e5193352ee..7bb59784b516 100644 --- a/pkg/sql/opt/norm/testdata/rules/select +++ b/pkg/sql/opt/norm/testdata/rules/select @@ -1133,51 +1133,3 @@ values ├── cardinality: [0 - 0] ├── key: () └── fd: ()-->(1) - -# -------------------------------------------------- -# EliminateUnionAllLeft -# -------------------------------------------------- - -opt expect=EliminateUnionAllLeft -SELECT k FROM - (SELECT k FROM b) - UNION ALL - (SELECT k FROM b WHERE k IN ()) ----- -project - ├── columns: k:11(int) - ├── scan b - │ ├── columns: b.k:1(int!null) - │ └── key: (1) - └── projections - └── variable: b.k [type=int, outer=(1)] - -# -------------------------------------------------- -# EliminateUnionAllRight -# -------------------------------------------------- - -opt expect=EliminateUnionAllRight -SELECT k FROM - (SELECT k FROM b WHERE Null) - UNION ALL - (SELECT k FROM b) ----- -project - ├── columns: k:11(int) - ├── scan b - │ ├── columns: b.k:6(int!null) - │ └── key: (6) - └── projections - └── variable: b.k [type=int, outer=(6)] - -opt -SELECT k FROM - (SELECT k FROM b WHERE False) - UNION ALL - (SELECT k FROM b WHERE i IN ()) ----- -values - ├── columns: k:11(int) - ├── cardinality: [0 - 0] - ├── key: () - └── fd: ()-->(11) diff --git a/pkg/sql/opt/norm/testdata/rules/set b/pkg/sql/opt/norm/testdata/rules/set new file mode 100644 index 000000000000..660ea2b5f0e2 --- /dev/null +++ b/pkg/sql/opt/norm/testdata/rules/set @@ -0,0 +1,59 @@ +exec-ddl +CREATE TABLE b (k INT PRIMARY KEY, i INT, f FLOAT, s STRING NOT NULL, j JSON) +---- +TABLE b + ├── k int not null + ├── i int + ├── f float + ├── s string not null + ├── j jsonb + └── INDEX primary + └── k int not null + +# -------------------------------------------------- +# EliminateUnionAllLeft +# -------------------------------------------------- + +opt expect=EliminateUnionAllLeft +SELECT k FROM + (SELECT k FROM b) + UNION ALL + (SELECT k FROM b WHERE k IN ()) +---- +project + ├── columns: k:11(int) + ├── scan b + │ ├── columns: b.k:1(int!null) + │ └── key: (1) + └── projections + └── variable: b.k [type=int, outer=(1)] + +# -------------------------------------------------- +# EliminateUnionAllRight +# -------------------------------------------------- + +opt expect=EliminateUnionAllRight +SELECT k FROM + (SELECT k FROM b WHERE Null) + UNION ALL + (SELECT k FROM b) +---- +project + ├── columns: k:11(int) + ├── scan b + │ ├── columns: b.k:6(int!null) + │ └── key: (6) + └── projections + └── variable: b.k [type=int, outer=(6)] + +opt +SELECT k FROM + (SELECT k FROM b WHERE False) + UNION ALL + (SELECT k FROM b WHERE i IN ()) +---- +values + ├── columns: k:11(int) + ├── cardinality: [0 - 0] + ├── key: () + └── fd: ()-->(11) diff --git a/pkg/sql/opt/ops/relational.opt b/pkg/sql/opt/ops/relational.opt index 783a461bba06..f9a8e91c736f 100644 --- a/pkg/sql/opt/ops/relational.opt +++ b/pkg/sql/opt/ops/relational.opt @@ -605,6 +605,9 @@ define Union { # Left: [2, 1] # Right: [4, 3] # Out: [5, 6] <-- synthesized output columns +# +# To make normalization rules and execution simpler, both inputs to the set op +# must have matching types. [Private] define SetPrivate { LeftCols ColList diff --git a/pkg/sql/opt/optbuilder/scope.go b/pkg/sql/opt/optbuilder/scope.go index 59fe77cf33b3..45adb69f20ba 100644 --- a/pkg/sql/opt/optbuilder/scope.go +++ b/pkg/sql/opt/optbuilder/scope.go @@ -135,29 +135,38 @@ func (s *scope) replace() *scope { } // appendColumnsFromScope adds newly bound variables to this scope. -// The groups in the new columns are reset to 0. +// The expressions in the new columns are reset to nil. func (s *scope) appendColumnsFromScope(src *scope) { l := len(s.cols) s.cols = append(s.cols, src.cols...) - // We want to reset the groups, as these become pass-through columns in the - // new scope. + // We want to reset the expressions, as these become pass-through columns in + // the new scope. for i := l; i < len(s.cols); i++ { s.cols[i].scalar = nil } } // appendColumns adds newly bound variables to this scope. -// The groups in the new columns are reset to 0. +// The expressions in the new columns are reset to nil. func (s *scope) appendColumns(cols []scopeColumn) { l := len(s.cols) s.cols = append(s.cols, cols...) - // We want to reset the groups, as these become pass-through columns in the - // new scope. + // We want to reset the expressions, as these become pass-through columns in + // the new scope. for i := l; i < len(s.cols); i++ { s.cols[i].scalar = nil } } +// appendColumn adds a newly bound variable to this scope. +// The expression in the new column is reset to nil. +func (s *scope) appendColumn(col *scopeColumn) { + s.cols = append(s.cols, *col) + // We want to reset the expression, as this becomes a pass-through column in + // the new scope. + s.cols[len(s.cols)-1].scalar = nil +} + // addExtraColumns adds the given columns as extra columns, ignoring any // duplicate columns that are already in the scope. func (s *scope) addExtraColumns(cols []scopeColumn) { diff --git a/pkg/sql/opt/optbuilder/testdata/union b/pkg/sql/opt/optbuilder/testdata/union index 8c186fa0e8e3..dd95d4dfa02c 100644 --- a/pkg/sql/opt/optbuilder/testdata/union +++ b/pkg/sql/opt/optbuilder/testdata/union @@ -286,12 +286,17 @@ sort ├── ordering: +3 └── union-all ├── columns: column1:3(int) - ├── left columns: column1:1(unknown) + ├── left columns: column1:4(int) ├── right columns: column1:2(int) - ├── values - │ ├── columns: column1:1(unknown) - │ └── tuple [type=tuple{unknown}] - │ └── null [type=unknown] + ├── project + │ ├── columns: column1:4(int) + │ ├── values + │ │ ├── columns: column1:1(unknown) + │ │ └── tuple [type=tuple{unknown}] + │ │ └── null [type=unknown] + │ └── projections + │ └── cast: INT8 [type=int] + │ └── variable: column1 [type=unknown] └── values ├── columns: column1:2(int) └── tuple [type=tuple{int}] @@ -317,18 +322,23 @@ build SELECT x, pg_typeof(y) FROM (SELECT 1 AS a, NULL AS b UNION ALL SELECT 2 AS a, 4 AS b) AS t(x, y) ---- project - ├── columns: x:5(int!null) pg_typeof:7(string) + ├── columns: x:5(int!null) pg_typeof:8(string) ├── union-all │ ├── columns: a:5(int!null) b:6(int) - │ ├── left columns: a:1(int) b:2(unknown) + │ ├── left columns: a:1(int) b:7(int) │ ├── right columns: a:3(int) b:4(int) │ ├── project - │ │ ├── columns: a:1(int!null) b:2(unknown) - │ │ ├── values - │ │ │ └── tuple [type=tuple] + │ │ ├── columns: b:7(int) a:1(int!null) + │ │ ├── project + │ │ │ ├── columns: a:1(int!null) b:2(unknown) + │ │ │ ├── values + │ │ │ │ └── tuple [type=tuple] + │ │ │ └── projections + │ │ │ ├── const: 1 [type=int] + │ │ │ └── null [type=unknown] │ │ └── projections - │ │ ├── const: 1 [type=int] - │ │ └── null [type=unknown] + │ │ └── cast: INT8 [type=int] + │ │ └── variable: b [type=unknown] │ └── project │ ├── columns: a:3(int!null) b:4(int!null) │ ├── values @@ -344,11 +354,11 @@ build SELECT x, pg_typeof(y) FROM (SELECT 1 AS a, 3 AS b UNION ALL SELECT 2 AS a, NULL AS b) AS t(x, y) ---- project - ├── columns: x:5(int!null) pg_typeof:7(string) + ├── columns: x:5(int!null) pg_typeof:8(string) ├── union-all │ ├── columns: a:5(int!null) b:6(int) │ ├── left columns: a:1(int) b:2(int) - │ ├── right columns: a:3(int) b:4(unknown) + │ ├── right columns: a:3(int) b:7(int) │ ├── project │ │ ├── columns: a:1(int!null) b:2(int!null) │ │ ├── values @@ -357,12 +367,17 @@ project │ │ ├── const: 1 [type=int] │ │ └── const: 3 [type=int] │ └── project - │ ├── columns: a:3(int!null) b:4(unknown) - │ ├── values - │ │ └── tuple [type=tuple] + │ ├── columns: b:7(int) a:3(int!null) + │ ├── project + │ │ ├── columns: a:3(int!null) b:4(unknown) + │ │ ├── values + │ │ │ └── tuple [type=tuple] + │ │ └── projections + │ │ ├── const: 2 [type=int] + │ │ └── null [type=unknown] │ └── projections - │ ├── const: 2 [type=int] - │ └── null [type=unknown] + │ └── cast: INT8 [type=int] + │ └── variable: b [type=unknown] └── projections └── function: pg_typeof [type=string] └── variable: b [type=int] @@ -839,3 +854,166 @@ except ├── columns: a:5(string) b:6(string!null) c:7(string!null) └── scan abc └── columns: a:5(string) b:6(string!null) c:7(string!null) rowid:8(int!null) + +# Tests for type propagation. + +build +VALUES (NULL, NULL), (NULL, 'x') UNION VALUES (1, 'a'), (2, 'b') +---- +union + ├── columns: column1:5(int) column2:6(string) + ├── left columns: column1:7(int) column2:2(string) + ├── right columns: column1:3(int) column2:4(string) + ├── project + │ ├── columns: column1:7(int) column2:2(string) + │ ├── values + │ │ ├── columns: column1:1(unknown) column2:2(string) + │ │ ├── tuple [type=tuple{unknown, string}] + │ │ │ ├── null [type=unknown] + │ │ │ └── null [type=unknown] + │ │ └── tuple [type=tuple{unknown, string}] + │ │ ├── null [type=unknown] + │ │ └── const: 'x' [type=string] + │ └── projections + │ └── cast: INT8 [type=int] + │ └── variable: column1 [type=unknown] + └── values + ├── columns: column1:3(int) column2:4(string) + ├── tuple [type=tuple{int, string}] + │ ├── const: 1 [type=int] + │ └── const: 'a' [type=string] + └── tuple [type=tuple{int, string}] + ├── const: 2 [type=int] + └── const: 'b' [type=string] + +build +VALUES (3, NULL), (NULL, 'x') INTERSECT VALUES (1, NULL), (2, NULL) +---- +intersect + ├── columns: column1:1(int) column2:2(string) + ├── left columns: column1:1(int) column2:2(string) + ├── right columns: column1:3(int) column2:5(string) + ├── values + │ ├── columns: column1:1(int) column2:2(string) + │ ├── tuple [type=tuple{int, string}] + │ │ ├── const: 3 [type=int] + │ │ └── null [type=unknown] + │ └── tuple [type=tuple{int, string}] + │ ├── null [type=unknown] + │ └── const: 'x' [type=string] + └── project + ├── columns: column2:5(string) column1:3(int) + ├── values + │ ├── columns: column1:3(int) column2:4(unknown) + │ ├── tuple [type=tuple{int, unknown}] + │ │ ├── const: 1 [type=int] + │ │ └── null [type=unknown] + │ └── tuple [type=tuple{int, unknown}] + │ ├── const: 2 [type=int] + │ └── null [type=unknown] + └── projections + └── cast: STRING [type=string] + └── variable: column2 [type=unknown] + +build +VALUES (NULL, NULL), (NULL, 'x') UNION ALL VALUES (1, NULL), (2, NULL) +---- +union-all + ├── columns: column1:5(int) column2:6(string) + ├── left columns: column1:7(int) column2:2(string) + ├── right columns: column1:3(int) column2:8(string) + ├── project + │ ├── columns: column1:7(int) column2:2(string) + │ ├── values + │ │ ├── columns: column1:1(unknown) column2:2(string) + │ │ ├── tuple [type=tuple{unknown, string}] + │ │ │ ├── null [type=unknown] + │ │ │ └── null [type=unknown] + │ │ └── tuple [type=tuple{unknown, string}] + │ │ ├── null [type=unknown] + │ │ └── const: 'x' [type=string] + │ └── projections + │ └── cast: INT8 [type=int] + │ └── variable: column1 [type=unknown] + └── project + ├── columns: column2:8(string) column1:3(int) + ├── values + │ ├── columns: column1:3(int) column2:4(unknown) + │ ├── tuple [type=tuple{int, unknown}] + │ │ ├── const: 1 [type=int] + │ │ └── null [type=unknown] + │ └── tuple [type=tuple{int, unknown}] + │ ├── const: 2 [type=int] + │ └── null [type=unknown] + └── projections + └── cast: STRING [type=string] + └── variable: column2 [type=unknown] + +build +VALUES (NULL, NULL), (NULL, NULL) UNION ALL VALUES (NULL, NULL), (NULL, NULL) +---- +union-all + ├── columns: column1:5(unknown) column2:6(unknown) + ├── left columns: column1:1(unknown) column2:2(unknown) + ├── right columns: column1:3(unknown) column2:4(unknown) + ├── values + │ ├── columns: column1:1(unknown) column2:2(unknown) + │ ├── tuple [type=tuple{unknown, unknown}] + │ │ ├── null [type=unknown] + │ │ └── null [type=unknown] + │ └── tuple [type=tuple{unknown, unknown}] + │ ├── null [type=unknown] + │ └── null [type=unknown] + └── values + ├── columns: column1:3(unknown) column2:4(unknown) + ├── tuple [type=tuple{unknown, unknown}] + │ ├── null [type=unknown] + │ └── null [type=unknown] + └── tuple [type=tuple{unknown, unknown}] + ├── null [type=unknown] + └── null [type=unknown] + +exec-ddl +CREATE TABLE a (a INT PRIMARY KEY) +---- +TABLE a + ├── a int not null + └── INDEX primary + └── a int not null + +# Regression test for #34524. +build +(SELECT NULL FROM a) EXCEPT (VALUES((SELECT 1 FROM a LIMIT 1)), (1)) +---- +except + ├── columns: "?column?":6(int) + ├── left columns: "?column?":6(int) + ├── right columns: column1:5(int) + ├── project + │ ├── columns: "?column?":6(int) + │ ├── project + │ │ ├── columns: "?column?":2(unknown) + │ │ ├── scan a + │ │ │ └── columns: a:1(int!null) + │ │ └── projections + │ │ └── null [type=unknown] + │ └── projections + │ └── cast: INT8 [type=int] + │ └── variable: ?column? [type=unknown] + └── values + ├── columns: column1:5(int) + ├── tuple [type=tuple{int}] + │ └── subquery [type=int] + │ └── max1-row + │ ├── columns: "?column?":4(int!null) + │ └── limit + │ ├── columns: "?column?":4(int!null) + │ ├── project + │ │ ├── columns: "?column?":4(int!null) + │ │ ├── scan a + │ │ │ └── columns: a:3(int!null) + │ │ └── projections + │ │ └── const: 1 [type=int] + │ └── const: 1 [type=int] + └── tuple [type=tuple{int}] + └── const: 1 [type=int] diff --git a/pkg/sql/opt/optbuilder/union.go b/pkg/sql/opt/optbuilder/union.go index 9f117ad83537..a27d1ed9cf01 100644 --- a/pkg/sql/opt/optbuilder/union.go +++ b/pkg/sql/opt/optbuilder/union.go @@ -17,6 +17,7 @@ package optbuilder import ( "fmt" + "github.com/cockroachdb/cockroach/pkg/sql/coltypes" "github.com/cockroachdb/cockroach/pkg/sql/opt" "github.com/cockroachdb/cockroach/pkg/sql/opt/memo" "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" @@ -49,7 +50,6 @@ func (b *Builder) buildUnion( } outScope = inScope.push() - outScope.appendColumnsFromScope(leftScope) // newColsNeeded indicates whether or not we need to synthesize output // columns. This is always required for a UNION, because the output columns @@ -57,21 +57,21 @@ func (b *Builder) buildUnion( // synthesize new columns to contain these values. This is not necessary for // INTERSECT or EXCEPT, since these operations are basically filters on the // left relation. - // - // Another benefit to synthesizing new columns is to handle the case - // when the type of one of the columns in the left relation is unknown, but - // the type of the matching column in the right relation is known. - // For example: - // SELECT NULL UNION SELECT 1 - // The type of NULL is unknown, and the type of 1 is int. We need to - // synthesize a new column so the output column will have the correct type. newColsNeeded := clause.Type == tree.UnionOp if newColsNeeded { - // Create a new scope to hold the new synthesized columns. - outScope = outScope.push() outScope.cols = make([]scopeColumn, 0, len(leftScope.cols)) } + // propagateTypesLeft/propagateTypesRight indicate whether we need to wrap + // the left/right side in a projection to cast some of the columns to the + // correct type. + // For example: + // SELECT NULL UNION SELECT 1 + // The type of NULL is unknown, and the type of 1 is int. We need to + // wrap the left side in a project operation with a Cast expression so the + // output column will have the correct type. + var propagateTypesLeft, propagateTypesRight bool + // Build map from left columns to right columns. for i := range leftScope.cols { l := &leftScope.cols[i] @@ -88,18 +88,31 @@ func (b *Builder) buildUnion( panic(fmt.Errorf("%v types cannot be matched", clause.Type)) } - if newColsNeeded { - var typ types.T - if l.typ != types.Unknown { - typ = l.typ - } else { - typ = r.typ + var typ types.T + if l.typ != types.Unknown { + typ = l.typ + if r.typ == types.Unknown { + propagateTypesRight = true } + } else { + typ = r.typ + if r.typ != types.Unknown { + propagateTypesLeft = true + } + } + if newColsNeeded { b.synthesizeColumn(outScope, string(l.name), typ, nil, nil /* scalar */) } } + if propagateTypesLeft { + leftScope = b.propagateTypes(leftScope, rightScope) + } + if propagateTypesRight { + rightScope = b.propagateTypes(rightScope, leftScope) + } + // Create the mapping between the left-side columns, right-side columns and // new columns (if needed). leftCols := colsToColList(leftScope.cols) @@ -108,6 +121,7 @@ func (b *Builder) buildUnion( if newColsNeeded { newCols = colsToColList(outScope.cols) } else { + outScope.appendColumnsFromScope(leftScope) newCols = leftCols } @@ -137,3 +151,32 @@ func (b *Builder) buildUnion( return outScope } + +// propagateTypes propagates the types of the source columns to the destination +// columns by wrapping the destination in a Project operation. The Project +// operation passes through columns that already have the correct type, and +// creates cast expressions for those that don't. +func (b *Builder) propagateTypes(dst, src *scope) *scope { + expr := dst.expr.(memo.RelExpr) + dstCols := dst.cols + + dst = dst.push() + dst.cols = make([]scopeColumn, 0, len(dstCols)) + + for i := 0; i < len(dstCols); i++ { + dstType := dstCols[i].typ + srcType := src.cols[i].typ + if dstType == types.Unknown && srcType != types.Unknown { + // Create a new column which casts the old column to the correct type. + colType, _ := coltypes.DatumTypeToColumnType(srcType) + castExpr := b.factory.ConstructCast(b.factory.ConstructVariable(dstCols[i].id), colType) + b.synthesizeColumn(dst, string(dstCols[i].name), srcType, nil /* expr */, castExpr) + } else { + // The column is already the correct type, so add it as a passthrough + // column. + dst.appendColumn(&dstCols[i]) + } + } + dst.expr = b.constructProject(expr, dst.cols) + return dst +}