Skip to content

Commit 8c0426c

Browse files
craig[bot]DrewKimballjaylim-crl
committed
108070: opt: don't remap cols with non-identical types during decorrelation r=DrewKimball a=DrewKimball #### opt: don't remap cols with non-identical types during decorrelation The decorrelation rules `TryRemapJoinOuterColsRight`, `TryRemapJoinOuterColsLeft`, and `TryRemapSelectOuterCols` attempt to decorrelate an expression by replacing an outer-column reference with an equivalent non-outer column reference. However, this includes columns that are _equivalent_ but not _identical_, the difference being that equivalent columns can have different width or precision, while identical types are exactly the same. This could cause incorrect results, like the following example: ``` statement ok CREATE TABLE xy108057 (x DECIMAL(10, 2) PRIMARY KEY, y DECIMAL(10, 2)); CREATE TABLE ab108057 (a DECIMAL(10, 0), b DECIMAL(10, 0)); statement ok INSERT INTO xy108057 VALUES (1.00, 1.00); INSERT INTO ab108057 VALUES (1, 1); query RRRR SELECT * FROM xy108057 INNER JOIN LATERAL (SELECT a, a+x FROM ab108057) ON a = x ---- 1.00 1.00 1 2.00 ``` This patch fixes this bug by checking that the replacement column is identical, not just equivalent, to the outer column. Fixes cockroachdb#108057 Release note (bug fix): Fixed a bug introduced in 23.1 that could cause the precision of some values to be incorrectly truncated for a query with a correlated subquery and an equality between a column from the subquery and the outer query. This applies to types that are "equivalent" but have different precision levels, e.g. `DECIMAL(10, 0)` vs `DECIMAL(10, 2)` or `NAME` vs `CHAR`. 108174: ccl/sqlproxyccl: fixes a data race in the ACL's watcher r=JeffSwenson a=jaylim-crl Fixes cockroachdb#108156. Regression from cockroachdb#108097. Previously, we updated the code to return w.controllers after releasing the lock because checkConnection may be long running, and we did not want to block new connections. We had forgotten the contract where fields on the Watcher object needs `mu` as they may be updated, so that approach had data races. This commit address that by ensuring that a copy of w.controllers is returned instead. Release note: None Epic: none Co-authored-by: Drew Kimball <[email protected]> Co-authored-by: Jay <[email protected]>
3 parents 142b971 + 52d519e + 7f9d0e9 commit 8c0426c

File tree

4 files changed

+66
-6
lines changed

4 files changed

+66
-6
lines changed

pkg/ccl/sqlproxyccl/acl/watcher.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,9 @@ func (w *Watcher) ListenForDenied(
276276

277277
w.listeners.ReplaceOrInsert(l)
278278

279-
return l, w.controllers
279+
// We need a new copy of w.controllers so that it doesn't race with the
280+
// add and update operations.
281+
return l, append([]AccessController(nil), w.controllers...)
280282
}()
281283
if err := checkConnection(ctx, connection, controllers); err != nil {
282284
w.removeListener(lst)

pkg/sql/logictest/testdata/logic_test/subquery_correlated

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,3 +1332,22 @@ SELECT (2, 20) = ANY (
13321332
----
13331333
NULL
13341334
NULL
1335+
1336+
# Regression test for #108057 - maintain the precision of the a+x operation.
1337+
statement ok
1338+
CREATE TABLE xy108057 (x DECIMAL(10, 2) PRIMARY KEY, y DECIMAL(10, 2));
1339+
CREATE TABLE ab108057 (a DECIMAL(10, 0), b DECIMAL(10, 0));
1340+
1341+
statement ok
1342+
INSERT INTO xy108057 VALUES (1.00, 1.00);
1343+
INSERT INTO ab108057 VALUES (1, 1);
1344+
1345+
query RRRR
1346+
SELECT * FROM xy108057 INNER JOIN LATERAL (SELECT a, a+x FROM ab108057) ON a = x
1347+
----
1348+
1.00 1.00 1 2.00
1349+
1350+
query RRRR
1351+
SELECT * FROM ab108057 INNER JOIN LATERAL (SELECT x, x+a FROM xy108057) ON a = x
1352+
----
1353+
1 1 1.00 2.00

pkg/sql/opt/norm/decorrelate_funcs.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,8 +1147,8 @@ func (c *CustomFuncs) TryRemapOuterCols(
11471147
}
11481148

11491149
// tryRemapOuterCols handles the traversal and outer-column replacement for
1150-
// TryRemapOuterCols. It returns the replacement expression and whether an
1151-
// outer-column reference was successfully remapped.
1150+
// TryRemapOuterCols. It returns the replacement expression, which may be
1151+
// unchanged if remapping was not possible.
11521152
func (c *CustomFuncs) tryRemapOuterCols(
11531153
expr opt.Expr, outerCol opt.ColumnID, substituteCols opt.ColSet,
11541154
) opt.Expr {
@@ -1160,9 +1160,15 @@ func (c *CustomFuncs) tryRemapOuterCols(
11601160
switch t := expr.(type) {
11611161
case *memo.VariableExpr:
11621162
if t.Col == outerCol {
1163-
if replaceCol, ok := substituteCols.Next(0); ok {
1164-
// This outer-column reference can be remapped.
1165-
return c.f.ConstructVariable(replaceCol)
1163+
md := c.mem.Metadata()
1164+
outerColTyp := md.ColumnMeta(outerCol).Type
1165+
replaceCol, ok := substituteCols.Next(0)
1166+
for ; ok; replaceCol, ok = substituteCols.Next(replaceCol + 1) {
1167+
if outerColTyp.Identical(md.ColumnMeta(replaceCol).Type) {
1168+
// Only perform the replacement if the types are identical.
1169+
// This outer-column reference can be remapped.
1170+
return c.f.ConstructVariable(replaceCol)
1171+
}
11661172
}
11671173
}
11681174
case memo.RelExpr:

pkg/sql/opt/norm/testdata/rules/decorrelate

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ exec-ddl
1818
CREATE TABLE ab (a INT, b INT)
1919
----
2020

21+
exec-ddl
22+
CREATE TABLE xy_decimal (x DECIMAL(10, 2) PRIMARY KEY, y DECIMAL(10, 2));
23+
----
24+
25+
exec-ddl
26+
CREATE TABLE ab_decimal (a DECIMAL(10, 0), b DECIMAL(10, 0));
27+
----
28+
2129
# --------------------------------------------------
2230
# DecorrelateJoin
2331
# --------------------------------------------------
@@ -6925,6 +6933,31 @@ project
69256933
└── filters
69266934
└── corr = x
69276935

6936+
# Regression test for #108057. Do not remap a column into an equivalent, but not
6937+
# identically typed column. The a + x projection should remain.
6938+
norm expect-not=(TryRemapJoinOuterColsRight,TryRemapJoinOuterColsLeft,TryRemapSelectOuterCols)
6939+
SELECT * FROM xy_decimal INNER JOIN LATERAL (SELECT a, a+x FROM ab_decimal) ON a = x
6940+
----
6941+
project
6942+
├── columns: x:1!null y:2 a:5!null "?column?":10!null
6943+
├── immutable
6944+
├── fd: (1)-->(2), (1)==(5), (5)==(1), (5)-->(10)
6945+
├── inner-join (hash)
6946+
│ ├── columns: x:1!null y:2 a:5!null
6947+
│ ├── multiplicity: left-rows(zero-or-more), right-rows(zero-or-one)
6948+
│ ├── immutable
6949+
│ ├── fd: (1)-->(2), (1)==(5), (5)==(1)
6950+
│ ├── scan xy_decimal
6951+
│ │ ├── columns: x:1!null y:2
6952+
│ │ ├── key: (1)
6953+
│ │ └── fd: (1)-->(2)
6954+
│ ├── scan ab_decimal
6955+
│ │ └── columns: a:5
6956+
│ └── filters
6957+
│ └── a:5 = x:1 [outer=(1,5), immutable, constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)]
6958+
└── projections
6959+
└── a:5 + x:1 [as="?column?":10, outer=(1,5), immutable]
6960+
69286961
# --------------------------------------------------
69296962
# TryRemapJoinOuterColsLeft
69306963
# --------------------------------------------------

0 commit comments

Comments
 (0)