Skip to content

Commit 9d1ac81

Browse files
authored
sysvar: add tidb_enable_strict_not_null_check (#68109)
close #68108
1 parent 0e5e814 commit 9d1ac81

7 files changed

Lines changed: 191 additions & 1 deletion

File tree

pkg/executor/executor_pkg_test.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ func TestErrLevelsForResetStmtContext(t *testing.T) {
341341
require.NotEmpty(t, c.stmt, c.name)
342342
for _, stmt := range c.stmt {
343343
msg := fmt.Sprintf("%d: %s, stmt: %T", i, c.name, stmt)
344+
ctx.GetSessionVars().EnableStrictNotNullCheck = true
344345
ctx.GetSessionVars().SQLMode = c.sqlMode
345346
require.NoError(t, ResetContextOfStmt(ctx, stmt), msg)
346347
ec := ctx.GetSessionVars().StmtCtx.ErrCtx()
@@ -457,3 +458,98 @@ func TestAddUnchangedKeysForLockByRow_GlobalIndexNewTableID(t *testing.T) {
457458
require.Len(t, gotKeys, 1)
458459
require.Equal(t, expectedKey, []byte(gotKeys[0]))
459460
}
461+
462+
func TestStrictNotNullCheckForInsert(t *testing.T) {
463+
ctx := mock.NewContext()
464+
ctx.BindDomainAndSchValidator(&domain.Domain{}, nil)
465+
466+
cases := []struct {
467+
name string
468+
sqlMode mysql.SQLMode
469+
enableStrictNotNullCheck bool
470+
isSingleInsert bool
471+
expectBadNullLevel errctx.Level
472+
expectNoDefaultLevel errctx.Level
473+
}{
474+
{
475+
name: "non-strict,single-row,disable",
476+
sqlMode: mysql.ModeErrorForDivisionByZero,
477+
enableStrictNotNullCheck: false,
478+
isSingleInsert: true,
479+
expectBadNullLevel: errctx.LevelWarn,
480+
expectNoDefaultLevel: errctx.LevelWarn,
481+
},
482+
{
483+
name: "strict,single-row,disable",
484+
sqlMode: mysql.ModeStrictAllTables | mysql.ModeErrorForDivisionByZero,
485+
enableStrictNotNullCheck: false,
486+
isSingleInsert: true,
487+
expectBadNullLevel: errctx.LevelWarn,
488+
expectNoDefaultLevel: errctx.LevelError,
489+
},
490+
{
491+
name: "non-strict,single-row,enable",
492+
sqlMode: mysql.ModeErrorForDivisionByZero,
493+
enableStrictNotNullCheck: true,
494+
isSingleInsert: true,
495+
expectBadNullLevel: errctx.LevelError,
496+
expectNoDefaultLevel: errctx.LevelWarn,
497+
},
498+
{
499+
name: "strict,single-row,enable",
500+
sqlMode: mysql.ModeStrictAllTables | mysql.ModeErrorForDivisionByZero,
501+
enableStrictNotNullCheck: true,
502+
isSingleInsert: true,
503+
expectBadNullLevel: errctx.LevelError,
504+
expectNoDefaultLevel: errctx.LevelError,
505+
},
506+
{
507+
name: "non-strict,multi-row,disable",
508+
sqlMode: mysql.ModeErrorForDivisionByZero,
509+
enableStrictNotNullCheck: false,
510+
isSingleInsert: false,
511+
expectBadNullLevel: errctx.LevelWarn,
512+
expectNoDefaultLevel: errctx.LevelWarn,
513+
},
514+
{
515+
name: "strict,multi-row,disable",
516+
sqlMode: mysql.ModeStrictAllTables | mysql.ModeErrorForDivisionByZero,
517+
enableStrictNotNullCheck: false,
518+
isSingleInsert: false,
519+
expectBadNullLevel: errctx.LevelWarn,
520+
expectNoDefaultLevel: errctx.LevelError,
521+
},
522+
{
523+
name: "non-strict,multi-row,enable",
524+
sqlMode: mysql.ModeErrorForDivisionByZero,
525+
enableStrictNotNullCheck: true,
526+
isSingleInsert: false,
527+
expectBadNullLevel: errctx.LevelWarn,
528+
expectNoDefaultLevel: errctx.LevelWarn,
529+
},
530+
{
531+
name: "strict,multi-row,enable",
532+
sqlMode: mysql.ModeStrictAllTables | mysql.ModeErrorForDivisionByZero,
533+
enableStrictNotNullCheck: true,
534+
isSingleInsert: false,
535+
expectBadNullLevel: errctx.LevelError,
536+
expectNoDefaultLevel: errctx.LevelError,
537+
},
538+
}
539+
540+
for _, c := range cases {
541+
ctx.GetSessionVars().EnableStrictNotNullCheck = true
542+
ctx.GetSessionVars().SQLMode = c.sqlMode
543+
ctx.GetSessionVars().EnableStrictNotNullCheck = c.enableStrictNotNullCheck
544+
stmt := &ast.InsertStmt{Lists: [][]ast.ExprNode{{}}}
545+
if c.isSingleInsert {
546+
stmt.Lists = make([][]ast.ExprNode, 1)
547+
} else {
548+
stmt.Lists = make([][]ast.ExprNode, 2)
549+
}
550+
require.NoError(t, ResetContextOfStmt(ctx, stmt), c.name)
551+
ec := ctx.GetSessionVars().StmtCtx.ErrCtx()
552+
require.Equal(t, c.expectBadNullLevel, ec.LevelMap()[errctx.ErrGroupBadNull], "%s: BadNull level", c.name)
553+
require.Equal(t, c.expectNoDefaultLevel, ec.LevelMap()[errctx.ErrGroupNoDefault], "%s: NoDefault level", c.name)
554+
}
555+
}

pkg/executor/select.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1124,7 +1124,8 @@ func ResetContextOfStmt(ctx sessionctx.Context, s ast.StmtNode) (err error) {
11241124
// For single-row INSERT statements, ignore non-strict mode
11251125
// See https://dev.mysql.com/doc/refman/5.7/en/constraint-invalid-data.html
11261126
isSingleInsert := len(stmt.Lists) == 1
1127-
errLevels[errctx.ErrGroupBadNull] = errctx.ResolveErrLevel(false, (!strictSQLMode && !isSingleInsert) || stmt.IgnoreErr)
1127+
enableStrictNotNullCheck := vars.EnableStrictNotNullCheck
1128+
errLevels[errctx.ErrGroupBadNull] = errctx.ResolveErrLevel(false, !((strictSQLMode || isSingleInsert) && enableStrictNotNullCheck) || stmt.IgnoreErr)
11281129
errLevels[errctx.ErrGroupNoDefault] = errctx.ResolveErrLevel(false, !strictSQLMode || stmt.IgnoreErr)
11291130
errLevels[errctx.ErrGroupDividedByZero] = errctx.ResolveErrLevel(
11301131
!vars.SQLMode.HasErrorForDivisionByZeroMode(),

pkg/sessionctx/vardef/tidb_vars.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,9 @@ const (
652652
// TiDBEnablePipelinedWindowFunction is used to control whether to use pipelined window function, it only works when tidb_enable_window_function = true.
653653
TiDBEnablePipelinedWindowFunction = "tidb_enable_pipelined_window_function"
654654

655+
// TiDBEnableStrictNotNullCheck is used to control whether to enable strict not-null check for single-row insert in non-strict mode.
656+
TiDBEnableStrictNotNullCheck = "tidb_enable_strict_not_null_check"
657+
655658
// TiDBEnableStrictDoubleTypeCheck is used to control table field double type syntax check.
656659
TiDBEnableStrictDoubleTypeCheck = "tidb_enable_strict_double_type_check"
657660

@@ -1549,6 +1552,7 @@ const (
15491552
DefTiDBForcePriority = mysql.NoPriority
15501553
DefEnableWindowFunction = true
15511554
DefEnablePipelinedWindowFunction = true
1555+
DefTiDBEnableStrictNotNullCheck = true
15521556
DefEnableStrictDoubleTypeCheck = true
15531557
DefEnableVectorizedExpression = true
15541558
DefTiDBOptJoinReorderThreshold = 0

pkg/sessionctx/variable/session.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,6 +1229,9 @@ type SessionVars struct {
12291229
// AllowProjectionPushDown enables pushdown projection on TiKV.
12301230
AllowProjectionPushDown bool
12311231

1232+
// EnableStrictNotNullCheck enables strict not-null check for single-row insert in non-strict mode.
1233+
EnableStrictNotNullCheck bool
1234+
12321235
// EnableStrictDoubleTypeCheck enables table field double type check.
12331236
EnableStrictDoubleTypeCheck bool
12341237

pkg/sessionctx/variable/sysvar.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2544,6 +2544,10 @@ var defaultSysVars = []*SysVar{
25442544
s.EnableStrictDoubleTypeCheck = TiDBOptOn(val)
25452545
return nil
25462546
}},
2547+
{Scope: vardef.ScopeGlobal | vardef.ScopeSession, Name: vardef.TiDBEnableStrictNotNullCheck, Value: BoolToOnOff(vardef.DefTiDBEnableStrictNotNullCheck), Type: vardef.TypeBool, SetSession: func(s *SessionVars, val string) error {
2548+
s.EnableStrictNotNullCheck = TiDBOptOn(val)
2549+
return nil
2550+
}},
25472551
{Scope: vardef.ScopeGlobal | vardef.ScopeSession, Name: vardef.TiDBEnableVectorizedExpression, Value: BoolToOnOff(vardef.DefEnableVectorizedExpression), Type: vardef.TypeBool, SetSession: func(s *SessionVars, val string) error {
25482552
s.EnableVectorizedExpression = TiDBOptOn(val)
25492553
return nil

tests/integrationtest/r/executor/insert.result

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2222,6 +2222,60 @@ INSERT IGNORE INTO t1 VALUES (127);
22222222
show warnings;
22232223
Level Code Message
22242224
Warning 1062 Duplicate entry '\x00\x00\x7F' for key 't1.id'
2225+
drop table if exists t1;
2226+
create table t1 (id int primary key, col1 varchar(10) not null default '');
2227+
set session sql_mode = '';
2228+
set session tidb_enable_strict_not_null_check = off;
2229+
insert into t1 values (1,null),(2,null);
2230+
insert into t1 values (3, null);
2231+
select * from t1;
2232+
id col1
2233+
1
2234+
2
2235+
3
2236+
set session tidb_enable_strict_not_null_check = on;
2237+
insert into t1 values (4,null),(5,null);
2238+
insert into t1 values (6, null);
2239+
Error 1048 (23000): Column 'col1' cannot be null
2240+
select * from t1;
2241+
id col1
2242+
1
2243+
2
2244+
3
2245+
4
2246+
5
2247+
set session sql_mode = 'STRICT_TRANS_TABLES';
2248+
set session tidb_enable_strict_not_null_check = off;
2249+
insert into t1 values (6,null),(7,null);
2250+
insert into t1 values (8, null);
2251+
select * from t1;
2252+
id col1
2253+
1
2254+
2
2255+
3
2256+
4
2257+
5
2258+
6
2259+
7
2260+
8
2261+
set session tidb_enable_strict_not_null_check = on;
2262+
insert into t1 values (9, null),(10,null);
2263+
Error 1048 (23000): Column 'col1' cannot be null
2264+
insert into t1 values (9, null);
2265+
Error 1048 (23000): Column 'col1' cannot be null
2266+
select * from t1;
2267+
id col1
2268+
1
2269+
2
2270+
3
2271+
4
2272+
5
2273+
6
2274+
7
2275+
8
2276+
set session tidb_enable_strict_not_null_check = default;
2277+
set session sql_mode = default;
2278+
drop table t1;
22252279
SET @old_time_zone = @@time_zone;
22262280
SET @@time_zone = 'Europe/Amsterdam';
22272281
SET @old_sql_mode = @@sql_mode;

tests/integrationtest/t/executor/insert.test

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1679,6 +1679,34 @@ INSERT IGNORE INTO t1 VALUES (127);
16791679
INSERT IGNORE INTO t1 VALUES (127);
16801680
show warnings;
16811681

1682+
# Test tidb_enable_strict_not_null_check
1683+
drop table if exists t1;
1684+
create table t1 (id int primary key, col1 varchar(10) not null default '');
1685+
set session sql_mode = '';
1686+
set session tidb_enable_strict_not_null_check = off;
1687+
insert into t1 values (1,null),(2,null);
1688+
insert into t1 values (3, null);
1689+
select * from t1;
1690+
set session tidb_enable_strict_not_null_check = on;
1691+
insert into t1 values (4,null),(5,null);
1692+
-- error 1048
1693+
insert into t1 values (6, null);
1694+
select * from t1;
1695+
set session sql_mode = 'STRICT_TRANS_TABLES';
1696+
set session tidb_enable_strict_not_null_check = off;
1697+
insert into t1 values (6,null),(7,null);
1698+
insert into t1 values (8, null);
1699+
select * from t1;
1700+
set session tidb_enable_strict_not_null_check = on;
1701+
-- error 1048
1702+
insert into t1 values (9, null),(10,null);
1703+
-- error 1048
1704+
insert into t1 values (9, null);
1705+
select * from t1;
1706+
set session tidb_enable_strict_not_null_check = default;
1707+
set session sql_mode = default;
1708+
drop table t1;
1709+
16821710
# Testing Timestamp and invalid dates and DST transitions
16831711
--enable_warnings
16841712
SET @old_time_zone = @@time_zone;

0 commit comments

Comments
 (0)