Skip to content

Commit

Permalink
planner: incorrect query result using ISNULL in the nested expressions (
Browse files Browse the repository at this point in the history
#55306)

close #55299
  • Loading branch information
hawkingrei authored Aug 13, 2024
1 parent 29d52a7 commit 9a7e5cc
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 13 deletions.
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

0 comments on commit 9a7e5cc

Please sign in to comment.