Skip to content

Commit e145cc2

Browse files
craig[bot]mgartnerZach Litewenyihu6
committed
107995: opt: do not remap columns with non-identical types r=mgartner a=mgartner This commit limits the remapping of column during join elimination to only destination columns with identical types to their equivalent source columns. This prevents the optimizer from producing an incorrect query plan. See the test cases for examples. Fixes cockroachdb#107850 There is no release note because this bug does not exist in any releases. Release note: None 108045: opt: propagate HasUDF in cached shared logical properties r=mgartner a=mgartner This commit fixes a minor bug where the `props.Shared.HasUDF` property was not correctly propagated from cached shared properties of an expression's children. As far as I can tell, this bug currently has no effect on any optimizer behavior. `HasUDF` is only used in determining if the insert fast path can be used and there are other, more strict restrictions for the insert fast path that preclude acceptance of any expression in which `HasUDF` may not be properly propagated (e.g., a Values expression without subqueries is required and the only way I can figure to include a UDF invocation in a relational expression that's a child of a Values clause is with a subquery). Epic: None Release note: None 108049: ui: fix infinite cluster setting refresh r=zachlite a=zachlite The DatabaseTablePage was unconditionally refreshing cluster settings causing a flood of network requests. Epic: none Release note (bux fix): A bug has been fixed that caused a flood of requests to refresh cluster settings on the Table Detail page. If a user would like to see the effect of a modified cluster setting in DB Console, a page-reload is required. 108106: asim: still non-deterministic r=kvoli a=wenyihu6 Part Of: cockroachdb#105904, cockroachdb#108092 Release Note: None Co-authored-by: Marcus Gartner <[email protected]> Co-authored-by: Zach Lite <[email protected]> Co-authored-by: wenyihu6 <[email protected]>
5 parents 03b1d4c + 0e5c06a + 3c4c4e1 + 8a69c35 + fd009f8 commit e145cc2

File tree

8 files changed

+210
-26
lines changed

8 files changed

+210
-26
lines changed

pkg/kv/kvserver/asim/asim_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func TestRunAllocatorSimulator(t *testing.T) {
4040
}
4141

4242
func TestAsimDeterministic(t *testing.T) {
43-
skip.UnderRace(t, 105904, "asim is non-deterministic under race")
43+
skip.WithIssue(t, 105904, "asim is non-deterministic")
4444
settings := config.DefaultSimulationSettings()
4545

4646
runs := 3

pkg/sql/logictest/testdata/logic_test/join

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,3 +1217,24 @@ SELECT * FROM (SELECT * FROM t106371 ORDER BY y LIMIT 1) a
12171217
JOIN (SELECT DISTINCT ON (x) * FROM (SELECT * FROM t106371 WHERE y = 2)) b ON a.x = b.x;
12181218
----
12191219
1 1 1 2
1220+
1221+
# Regression test for #107850. Do not eliminate joins and remap columns that are
1222+
# equivalent but have non-identical types.
1223+
subtest regression_107850
1224+
1225+
statement ok
1226+
CREATE TABLE t107850a (
1227+
d2 DECIMAL(10, 2) NOT NULL UNIQUE
1228+
);
1229+
CREATE TABLE t107850b (
1230+
d0 DECIMAL(10, 0) NOT NULL REFERENCES t107850a (d2)
1231+
);
1232+
INSERT INTO t107850a VALUES (1.00);
1233+
INSERT INTO t107850b VALUES (1);
1234+
1235+
query R
1236+
SELECT d2 FROM t107850a JOIN t107850b ON d2 = d0
1237+
----
1238+
1.00
1239+
1240+
subtest end

pkg/sql/opt/memo/logical_props_builder.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1730,6 +1730,9 @@ func BuildSharedProps(e opt.Expr, shared *props.Shared, evalCtx *eval.Context) {
17301730
if cached.HasCorrelatedSubquery {
17311731
shared.HasCorrelatedSubquery = true
17321732
}
1733+
if cached.HasUDF {
1734+
shared.HasUDF = true
1735+
}
17331736
} else {
17341737
BuildSharedProps(e.Child(i), shared, evalCtx)
17351738
}

pkg/sql/opt/memo/testdata/logprops/udf

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,68 @@ project
209209
│ └── projections
210210
│ └── const: 1 [as="?column?":5, type=int]
211211
└── const: 1 [type=int]
212+
213+
# The "udf" property should propagate to the top-most filter.
214+
build
215+
SELECT i FROM (VALUES (1), (2)) v(i) WHERE i = (SELECT a FROM ab WHERE b = fn_leakproof())
216+
----
217+
select
218+
├── columns: i:1(int!null)
219+
├── cardinality: [0 - 2]
220+
├── values
221+
│ ├── columns: column1:1(int!null)
222+
│ ├── cardinality: [2 - 2]
223+
│ ├── prune: (1)
224+
│ ├── tuple [type=tuple{int}]
225+
│ │ └── const: 1 [type=int]
226+
│ └── tuple [type=tuple{int}]
227+
│ └── const: 2 [type=int]
228+
└── filters
229+
└── eq [type=bool, outer=(1), subquery, udf, constraints=(/1: (/NULL - ])]
230+
├── variable: column1:1 [type=int]
231+
└── subquery [type=int]
232+
└── max1-row
233+
├── columns: a:2(int!null)
234+
├── error: "more than one row returned by a subquery used as an expression"
235+
├── cardinality: [0 - 1]
236+
├── key: ()
237+
├── fd: ()-->(2)
238+
└── project
239+
├── columns: a:2(int!null)
240+
├── key: (2)
241+
├── prune: (2)
242+
├── interesting orderings: (+2)
243+
└── select
244+
├── columns: a:2(int!null) b:3(int!null) crdb_internal_mvcc_timestamp:4(decimal) tableoid:5(oid)
245+
├── key: (2)
246+
├── fd: ()-->(3), (2)-->(4,5)
247+
├── prune: (2,4,5)
248+
├── interesting orderings: (+2 opt(3))
249+
├── scan ab
250+
│ ├── columns: a:2(int!null) b:3(int) crdb_internal_mvcc_timestamp:4(decimal) tableoid:5(oid)
251+
│ ├── key: (2)
252+
│ ├── fd: (2)-->(3-5)
253+
│ ├── prune: (2-5)
254+
│ └── interesting orderings: (+2)
255+
└── filters
256+
└── eq [type=bool, outer=(3), udf, constraints=(/3: (/NULL - ]), fd=()-->(3)]
257+
├── variable: b:3 [type=int]
258+
└── udf: fn_leakproof [type=int]
259+
└── body
260+
└── limit
261+
├── columns: "?column?":6(int!null)
262+
├── cardinality: [1 - 1]
263+
├── key: ()
264+
├── fd: ()-->(6)
265+
├── project
266+
│ ├── columns: "?column?":6(int!null)
267+
│ ├── cardinality: [1 - 1]
268+
│ ├── key: ()
269+
│ ├── fd: ()-->(6)
270+
│ ├── values
271+
│ │ ├── cardinality: [1 - 1]
272+
│ │ ├── key: ()
273+
│ │ └── tuple [type=tuple]
274+
│ └── projections
275+
│ └── const: 1 [as="?column?":6, type=int]
276+
└── const: 1 [type=int]

pkg/sql/opt/norm/general_funcs.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,15 +308,34 @@ func (c *CustomFuncs) MakeBoolCol() opt.ColumnID {
308308
// CanRemapCols returns true if it's possible to remap every column in the
309309
// "from" set to a column in the "to" set using the given FDs.
310310
func (c *CustomFuncs) CanRemapCols(from, to opt.ColSet, fds *props.FuncDepSet) bool {
311-
for col, ok := from.Next(0); ok; col, ok = from.Next(col + 1) {
312-
if !fds.ComputeEquivGroup(col).Intersects(to) {
311+
for fromCol, ok := from.Next(0); ok; fromCol, ok = from.Next(fromCol + 1) {
312+
if _, ok := c.remapColWithIdenticalType(fromCol, to, fds); !ok {
313313
// It is not possible to remap this column to one from the "to" set.
314314
return false
315315
}
316316
}
317317
return true
318318
}
319319

320+
// remapColWithIdenticalType returns a column in the "to" set that is equivalent
321+
// to "fromCol" and has the identical type. It returns ok=false if no such
322+
// column exists.
323+
func (c *CustomFuncs) remapColWithIdenticalType(
324+
fromCol opt.ColumnID, to opt.ColSet, fds *props.FuncDepSet,
325+
) (_ opt.ColumnID, ok bool) {
326+
md := c.mem.Metadata()
327+
fromColType := md.ColumnMeta(fromCol).Type
328+
equivCols := fds.ComputeEquivGroup(fromCol)
329+
equivCols.IntersectionWith(to)
330+
for equivCol, ok := equivCols.Next(0); ok; equivCol, ok = equivCols.Next(equivCol + 1) {
331+
equivColType := md.ColumnMeta(equivCol).Type
332+
if fromColType.Identical(equivColType) {
333+
return equivCol, true
334+
}
335+
}
336+
return 0, false
337+
}
338+
320339
// ----------------------------------------------------------------------
321340
//
322341
// Outer column functions

pkg/sql/opt/norm/project_funcs.go

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -859,14 +859,10 @@ func (c *CustomFuncs) ProjectRemappedCols(
859859
) (projections memo.ProjectionsExpr) {
860860
for col, ok := from.Next(0); ok; col, ok = from.Next(col + 1) {
861861
if !to.Contains(col) {
862-
// TODO(mgartner): We don't need to compute the entire equivalence group,
863-
// we only need to find the first equivalent column that's in the to set.
864-
candidates := fds.ComputeEquivGroup(col)
865-
candidates.IntersectionWith(to)
866-
if candidates.Empty() {
862+
toCol, ok := c.remapColWithIdenticalType(col, to, fds)
863+
if !ok {
867864
panic(errors.AssertionFailedf("cannot remap column %v", col))
868865
}
869-
toCol, _ := candidates.Next(0)
870866
projections = append(
871867
projections,
872868
c.f.ConstructProjectionsItem(c.f.ConstructVariable(toCol), col),
@@ -881,18 +877,6 @@ func (c *CustomFuncs) ProjectRemappedCols(
881877
func (c *CustomFuncs) RemapProjectionCols(
882878
projections memo.ProjectionsExpr, to opt.ColSet, fds *props.FuncDepSet,
883879
) memo.ProjectionsExpr {
884-
getReplacement := func(col opt.ColumnID) opt.ColumnID {
885-
// TODO(mgartner): We don't need to compute the entire equivalence group, we
886-
// only need to find the first equivalent column that's in the to set.
887-
candidates := fds.ComputeEquivGroup(col)
888-
candidates.IntersectionWith(to)
889-
if candidates.Empty() {
890-
panic(errors.AssertionFailedf("cannot remap column"))
891-
}
892-
replacement, _ := candidates.Next(0)
893-
return replacement
894-
}
895-
896880
// Use the projection outer columns to filter out columns that are synthesized
897881
// within the projections themselves (e.g. in a subquery).
898882
outerCols := c.ProjectionOuterCols(projections)
@@ -902,7 +886,11 @@ func (c *CustomFuncs) RemapProjectionCols(
902886
replace = func(e opt.Expr) opt.Expr {
903887
if v, ok := e.(*memo.VariableExpr); ok && !to.Contains(v.Col) && outerCols.Contains(v.Col) {
904888
// This variable needs to be remapped.
905-
return c.f.ConstructVariable(getReplacement(v.Col))
889+
toCol, ok := c.remapColWithIdenticalType(v.Col, to, fds)
890+
if !ok {
891+
panic(errors.AssertionFailedf("cannot remap column %v", v.Col))
892+
}
893+
return c.f.ConstructVariable(toCol)
906894
}
907895
return c.f.Replace(e, replace)
908896
}

pkg/sql/opt/norm/testdata/rules/project

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,14 @@ project
266266
└── projections
267267
└── child.parent_id:2 [as=parent_id:9, outer=(2)]
268268

269+
exec-ddl
270+
DROP TABLE child
271+
----
272+
273+
exec-ddl
274+
DROP TABLE parent
275+
----
276+
269277
# The join can be eliminated as long as it doesn't require remapping with
270278
# OptimizerUseImprovedJoinElimination disabled.
271279
norm set=optimizer_use_improved_join_elimination=false expect=EliminateJoinUnderProjectLeft
@@ -395,6 +403,87 @@ project
395403
└── projections
396404
└── NULL [as="?column?":5]
397405

406+
# Regression test for #107850 - columns should not be mapped if their types are
407+
# not identical.
408+
exec-ddl
409+
CREATE TABLE parent (
410+
id DECIMAL(10, 2) PRIMARY KEY
411+
)
412+
----
413+
414+
exec-ddl
415+
CREATE TABLE child (
416+
id INT PRIMARY KEY,
417+
parent_id DECIMAL(10, 0) NOT NULL REFERENCES parent(id),
418+
parent_id2 DECIMAL(10, 2) NOT NULL REFERENCES parent(id)
419+
)
420+
----
421+
422+
norm expect-not=EliminateJoinUnderProjectRight
423+
SELECT parent.id FROM parent JOIN child ON parent.id = child.parent_id
424+
----
425+
project
426+
├── columns: id:1!null
427+
├── immutable
428+
└── inner-join (hash)
429+
├── columns: parent.id:1!null parent_id:5!null
430+
├── multiplicity: left-rows(zero-or-more), right-rows(exactly-one)
431+
├── immutable
432+
├── fd: (1)==(5), (5)==(1)
433+
├── scan parent
434+
│ ├── columns: parent.id:1!null
435+
│ └── key: (1)
436+
├── scan child
437+
│ └── columns: parent_id:5!null
438+
└── filters
439+
└── parent.id:1 = parent_id:5 [outer=(1,5), immutable, constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)]
440+
441+
# The projected column with the identical type, child.parent_id2, should be
442+
# remapped if there are multiple equivalent columns.
443+
norm
444+
SELECT parent.id FROM parent JOIN child ON parent.id = child.parent_id AND child.parent_id = child.parent_id2
445+
----
446+
project
447+
├── columns: id:1!null
448+
├── immutable
449+
├── select
450+
│ ├── columns: parent_id:5!null parent_id2:6!null
451+
│ ├── immutable
452+
│ ├── fd: (5)==(6), (6)==(5)
453+
│ ├── scan child
454+
│ │ └── columns: parent_id:5!null parent_id2:6!null
455+
│ └── filters
456+
│ └── parent_id:5 = parent_id2:6 [outer=(5,6), immutable, constraints=(/5: (/NULL - ]; /6: (/NULL - ]), fd=(5)==(6), (6)==(5)]
457+
└── projections
458+
└── parent_id2:6 [as=parent.id:1, outer=(6)]
459+
460+
# In a projection expression the column with the identical type,
461+
# child.parent_id2, should be remapped if there are multiple equivalent columns.
462+
norm
463+
SELECT 1 + parent.id FROM parent JOIN child ON parent.id = child.parent_id AND child.parent_id = child.parent_id2
464+
----
465+
project
466+
├── columns: "?column?":9!null
467+
├── immutable
468+
├── select
469+
│ ├── columns: parent_id:5!null parent_id2:6!null
470+
│ ├── immutable
471+
│ ├── fd: (5)==(6), (6)==(5)
472+
│ ├── scan child
473+
│ │ └── columns: parent_id:5!null parent_id2:6!null
474+
│ └── filters
475+
│ └── parent_id:5 = parent_id2:6 [outer=(5,6), immutable, constraints=(/5: (/NULL - ]; /6: (/NULL - ]), fd=(5)==(6), (6)==(5)]
476+
└── projections
477+
└── parent_id2:6 + 1 [as="?column?":9, outer=(6), immutable]
478+
479+
exec-ddl
480+
DROP TABLE child
481+
----
482+
483+
exec-ddl
484+
DROP TABLE parent
485+
----
486+
398487
# --------------------------------------------------
399488
# EliminateProject
400489
# --------------------------------------------------

pkg/ui/workspaces/cluster-ui/src/databaseTablePage/databaseTablePage.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@ export class DatabaseTablePage extends React.Component<
246246

247247
componentDidMount(): void {
248248
this.refresh();
249+
if (this.props.refreshSettings != null) {
250+
this.props.refreshSettings();
251+
}
249252
}
250253

251254
componentDidUpdate(prevProp: Readonly<DatabaseTablePageProps>): void {
@@ -284,10 +287,6 @@ export class DatabaseTablePage extends React.Component<
284287
this.props.name,
285288
);
286289
}
287-
288-
if (this.props.refreshSettings != null) {
289-
this.props.refreshSettings();
290-
}
291290
}
292291

293292
private changeIndexSortSetting(sortSetting: SortSetting) {

0 commit comments

Comments
 (0)