Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

planner: incorrect query result using ISNULL in the nested expressions #55306

Merged
merged 9 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions pkg/planner/core/issuetest/planner_issue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,92 @@ func TestIssue54803(t *testing.T) {
" └─TableReader_24 10.00 root partition:p0 data:Selection_23",
" └─Selection_23 10.00 cop[tikv] isnull(test.t1db47fc1.col_68), or(isnull(test.t1db47fc1.col_68), in(test.t1db47fc1.col_68, 62, 200, 196, 99))",
" └─TableFullScan_22 10000.00 cop[tikv] table:t1db47fc1 keep order:false, stats:pseudo"))
// Issue55299
tk.MustExec(`
CREATE TABLE tcd8c2aac (
col_21 char(87) COLLATE utf8mb4_general_ci DEFAULT NULL,
KEY idx_12 (col_21(1))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
`)
tk.MustExec(`
CREATE TABLE tle50fd846 (
col_42 date DEFAULT '1989-10-30',
col_43 varbinary(122) NOT NULL DEFAULT 'Vz!3_P0LOdG',
col_44 json DEFAULT NULL,
col_45 binary(129) DEFAULT NULL,
col_46 double NOT NULL DEFAULT '4264.32300782421',
col_47 char(251) NOT NULL DEFAULT 'g7uo-dlBEY22!fx3@&',
col_48 char(229) NOT NULL,
col_49 blob NOT NULL,
col_50 blob DEFAULT NULL,
col_51 json DEFAULT NULL,
PRIMARY KEY (col_48) /*T![clustered_index] NONCLUSTERED */
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
`)
tk.MustExec("INSERT INTO `tcd8c2aac` VALUES(NULL),(NULL),('u!Vk+9B-3bn@'),('&PpQ*z!kQwj4g*ag#');")
tk.MustExec(`INSERT INTO tle50fd846
VALUES
('2029-05-09', x'757640736a42316c384162793124246b', '["YXt8UJAnVMWeMEZj1CzhNUzTMDJfzsmTWQkyOvVCsciA3eobvH8heH8gtr6ogxXa"]', x'577340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', 526.0218366710487, '%gMk', '58reJ%D&54', x'39254c48242556737474', x'6c66762b303567236f4068', '[2984188985038968170, 2580328438245089106, 4624130652422829118]');`)
tk.MustQuery(`
EXPLAIN SELECT GROUP_CONCAT(tcd8c2aac.col_21 ORDER BY tcd8c2aac.col_21 SEPARATOR ',') AS r0
FROM tcd8c2aac
JOIN tle50fd846
WHERE ISNULL(tcd8c2aac.col_21) OR tcd8c2aac.col_21='yJTkLeL5^yJ'
GROUP BY tcd8c2aac.col_21
HAVING ISNULL(tcd8c2aac.col_21)
LIMIT 48579914;`).Check(testkit.Rows(
"Limit_16 6.40 root offset:0, count:48579914",
"└─HashAgg_17 6.40 root group by:test.tcd8c2aac.col_21, funcs:group_concat(test.tcd8c2aac.col_21 order by test.tcd8c2aac.col_21 separator \",\")->Column#14",
" └─HashJoin_20 80000.00 root CARTESIAN inner join",
" ├─IndexLookUp_27(Build) 8.00 root ",
" │ ├─Selection_26(Build) 8.00 cop[tikv] isnull(test.tcd8c2aac.col_21)",
" │ │ └─IndexRangeScan_24 10.00 cop[tikv] table:tcd8c2aac, index:idx_12(col_21) range:[NULL,NULL], keep order:false, stats:pseudo",
" │ └─TableRowIDScan_25(Probe) 8.00 cop[tikv] table:tcd8c2aac keep order:false, stats:pseudo",
" └─IndexReader_31(Probe) 10000.00 root index:IndexFullScan_30",
" └─IndexFullScan_30 10000.00 cop[tikv] table:tle50fd846, index:PRIMARY(col_48) keep order:false, stats:pseudo"))
tk.MustQuery(`SELECT GROUP_CONCAT(tcd8c2aac.col_21 ORDER BY tcd8c2aac.col_21 SEPARATOR ',') AS r0
FROM tcd8c2aac
JOIN tle50fd846
WHERE ISNULL(tcd8c2aac.col_21) OR tcd8c2aac.col_21='yJTkLeL5^yJ'
GROUP BY tcd8c2aac.col_21
HAVING ISNULL(tcd8c2aac.col_21)
LIMIT 48579914;`).Check(testkit.Rows("<nil>"))

tk.MustExec(`CREATE TABLE ta31c32a7 (
col_63 double DEFAULT '9963.92512636973',
KEY idx_24 (col_63),
KEY idx_25 (col_63),
KEY idx_26 (col_63)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;`)
tk.MustExec(`INSERT INTO ta31c32a7 VALUES
(5496.073863178138), (4027.8475888445246), (2995.154396178381), (3045.228783606007), (3618.0432407275603), (1156.6077897338241),
(348.56448524702813), (2138.361831358777), (5904.959667345741), (2815.6976889801267), (6455.25717613724),
(9721.34540217101), (6793.035010125108), (6080.120357332818), (NULL), (1780.7418079754723),
(1222.1954607008702), (3576.2079432921923), (2187.4672702135276), (9129.689249510902),
(1065.3222700463314), (7509.347382423184), (7413.331945779306), (986.9882817569359),
(747.4145098692578), (4850.840161745998), (2607.5009231086797), (6499.136742855925),
(2501.691252762187), (6138.096783185339);`)
tk.MustQuery(`explain SELECT BIT_XOR(ta31c32a7.col_63) AS r0
FROM ta31c32a7
WHERE ISNULL(ta31c32a7.col_63)
OR ta31c32a7.col_63 IN (1780.7418079754723, 5904.959667345741, 1531.4023068774668)
GROUP BY ta31c32a7.col_63
HAVING ISNULL(ta31c32a7.col_63)
LIMIT 65122436;`).Check(testkit.Rows(
"Limit_13 6.40 root offset:0, count:65122436",
"└─StreamAgg_37 6.40 root group by:test.ta31c32a7.col_63, funcs:bit_xor(Column#6)->Column#3",
" └─IndexReader_38 6.40 root index:StreamAgg_17",
" └─StreamAgg_17 6.40 cop[tikv] group by:test.ta31c32a7.col_63, funcs:bit_xor(cast(test.ta31c32a7.col_63, bigint(22) BINARY))->Column#6",
" └─IndexRangeScan_34 10.00 cop[tikv] table:ta31c32a7, index:idx_24(col_63) range:[NULL,NULL], keep order:true, stats:pseudo"))
tk.MustQuery(`explain SELECT BIT_XOR(ta31c32a7.col_63) AS r0
FROM ta31c32a7
WHERE ISNULL(ta31c32a7.col_63)
OR ta31c32a7.col_63 IN (1780.7418079754723, 5904.959667345741, 1531.4023068774668)
GROUP BY ta31c32a7.col_63
LIMIT 65122436;`).Check(testkit.Rows(
"Limit_11 32.00 root offset:0, count:65122436",
"└─StreamAgg_35 32.00 root group by:test.ta31c32a7.col_63, funcs:bit_xor(Column#5)->Column#3",
" └─IndexReader_36 32.00 root index:StreamAgg_15",
" └─StreamAgg_15 32.00 cop[tikv] group by:test.ta31c32a7.col_63, funcs:bit_xor(cast(test.ta31c32a7.col_63, bigint(22) BINARY))->Column#5",
" └─IndexRangeScan_32 40.00 cop[tikv] table:ta31c32a7, index:idx_24(col_63) range:[NULL,NULL], [1531.4023068774668,1531.4023068774668], [1780.7418079754723,1780.7418079754723], [5904.959667345741,5904.959667345741], keep order:true, stats:pseudo"))
}
8 changes: 3 additions & 5 deletions pkg/util/ranger/detacher.go
Original file line number Diff line number Diff line change
Expand Up @@ -755,11 +755,9 @@ func ExtractEqAndInCondition(sctx *rangerctx.RangerContext, conditions []express
return nil, nil, nil, nil, true
} else {
// All Intervals are single points
if f, ok := accesses[i].(*expression.ScalarFunction); !ok || (ok && f.FuncName.L != ast.IsNull) {
// isnull is not equal to a = NULL
accesses[i] = points2EqOrInCond(sctx.ExprCtx, points[i], cols[i])
newConditions = append(newConditions, accesses[i])
}

accesses[i] = points2EqOrInCond(sctx.ExprCtx, points[i], cols[i])
newConditions = append(newConditions, accesses[i])
if f, ok := accesses[i].(*expression.ScalarFunction); ok && f.FuncName.L == ast.EQ {
// Actually the constant column value may not be mutable. Here we assume it is mutable to keep it simple.
// Maybe we can improve it later.
Expand Down
34 changes: 26 additions & 8 deletions pkg/util/ranger/ranger.go
Original file line number Diff line number Diff line change
Expand Up @@ -735,18 +735,36 @@ func points2EqOrInCond(ctx expression.BuildContext, points []*point, col *expres
retType := col.GetType(ctx.GetEvalCtx())
args := make([]expression.Expression, 0, len(points)/2)
args = append(args, col)
orArgs := make([]expression.Expression, 0, 2)
for i := 0; i < len(points); i = i + 2 {
value := &expression.Constant{
Value: points[i].value,
RetType: retType,
if points[i].value.IsNull() {
orArgs = append(orArgs, expression.NewFunctionInternal(ctx, ast.IsNull, retType, col))
} else {
value := &expression.Constant{
Value: points[i].value,
RetType: retType,
}
args = append(args, value)
}
}
var result expression.Expression
if len(args) > 1 {
funcName := ast.EQ
if len(args) > 2 {
funcName = ast.In
}
args = append(args, value)
result = expression.NewFunctionInternal(ctx, funcName, col.GetType(ctx.GetEvalCtx()), args...)
}
if len(orArgs) == 0 {
return result
}
if result != nil {
orArgs = append(orArgs, result)
}
funcName := ast.EQ
if len(args) > 2 {
funcName = ast.In
if len(orArgs) == 1 {
return orArgs[0]
}
return expression.NewFunctionInternal(ctx, funcName, col.GetType(ctx.GetEvalCtx()), args...)
return expression.NewFunctionInternal(ctx, ast.Or, col.GetType(ctx.GetEvalCtx()), orArgs...)
}

// RangesToString print a list of Ranges into a string which can appear in an SQL as a condition.
Expand Down