diff --git a/br/pkg/restore/snap_client/systable_restore_test.go b/br/pkg/restore/snap_client/systable_restore_test.go index 691293fb35a3e..59d503b1a5381 100644 --- a/br/pkg/restore/snap_client/systable_restore_test.go +++ b/br/pkg/restore/snap_client/systable_restore_test.go @@ -393,7 +393,7 @@ func TestCheckPrivilegeTableRowsCollateCompatibility(t *testing.T) { // // The above variables are in the file br/pkg/restore/systable_restore.go func TestMonitorTheSystemTableIncremental(t *testing.T) { - require.Equal(t, int64(254), session.CurrentBootstrapVersion) + require.Equal(t, int64(255), session.CurrentBootstrapVersion) } func TestIsStatsTemporaryTable(t *testing.T) { diff --git a/pkg/parser/ast/expressions.go b/pkg/parser/ast/expressions.go index e8721d68dd201..5109c2364a96d 100644 --- a/pkg/parser/ast/expressions.go +++ b/pkg/parser/ast/expressions.go @@ -904,6 +904,8 @@ type PatternLikeOrIlikeExpr struct { IsLike bool Escape byte + // EscapeExplicit indicates whether ESCAPE clause is specified explicitly. + EscapeExplicit bool PatChars []byte PatTypes []byte @@ -933,10 +935,9 @@ func (n *PatternLikeOrIlikeExpr) Restore(ctx *format.RestoreCtx) error { return errors.Annotate(err, "An error occurred while restore PatternLikeOrIlikeExpr.Pattern") } - escape := string(n.Escape) - if escape != "\\" { + if n.EscapeExplicit && n.Escape != '\\' { ctx.WriteKeyWord(" ESCAPE ") - ctx.WriteString(escape) + ctx.WriteString(string(n.Escape)) } return nil } @@ -959,7 +960,7 @@ func (n *PatternLikeOrIlikeExpr) Format(w io.Writer) { } n.Pattern.Format(w) - if n.Escape != '\\' { + if n.EscapeExplicit && n.Escape != '\\' { fmt.Fprint(w, " ESCAPE ") fmt.Fprintf(w, "'%c'", n.Escape) } diff --git a/pkg/parser/parser.go b/pkg/parser/parser.go index f42b1017acbb9..64e8ccd58eb1c 100644 --- a/pkg/parser/parser.go +++ b/pkg/parser/parser.go @@ -41,6 +41,11 @@ import ( "github.com/pingcap/tidb/pkg/parser/types" ) +type likeEscapeSpec struct { + escape string + explicit bool +} + type yySymType struct { yys int offset int // offset @@ -17993,36 +17998,44 @@ yynewstate: } case 762: { - escape := yyS[yypt-0].ident + escapeSpec := yyS[yypt-0].item.(*likeEscapeSpec) + escape := escapeSpec.escape + explicit := escapeSpec.explicit if len(escape) > 1 { yylex.AppendError(ErrWrongArguments.GenWithStackByArgs("ESCAPE")) return 1 } else if len(escape) == 0 { escape = "\\" + explicit = false } parser.yyVAL.expr = &ast.PatternLikeOrIlikeExpr{ - Expr: yyS[yypt-3].expr, - Pattern: yyS[yypt-1].expr, - Not: !yyS[yypt-2].item.(bool), - Escape: escape[0], - IsLike: true, + Expr: yyS[yypt-3].expr, + Pattern: yyS[yypt-1].expr, + Not: !yyS[yypt-2].item.(bool), + Escape: escape[0], + EscapeExplicit: explicit, + IsLike: true, } } case 763: { - escape := yyS[yypt-0].ident + escapeSpec := yyS[yypt-0].item.(*likeEscapeSpec) + escape := escapeSpec.escape + explicit := escapeSpec.explicit if len(escape) > 1 { yylex.AppendError(ErrWrongArguments.GenWithStackByArgs("ESCAPE")) return 1 } else if len(escape) == 0 { escape = "\\" + explicit = false } parser.yyVAL.expr = &ast.PatternLikeOrIlikeExpr{ - Expr: yyS[yypt-3].expr, - Pattern: yyS[yypt-1].expr, - Not: !yyS[yypt-2].item.(bool), - Escape: escape[0], - IsLike: false, + Expr: yyS[yypt-3].expr, + Pattern: yyS[yypt-1].expr, + Not: !yyS[yypt-2].item.(bool), + Escape: escape[0], + EscapeExplicit: explicit, + IsLike: false, } } case 764: @@ -18035,11 +18048,11 @@ yynewstate: } case 769: { - parser.yyVAL.ident = "\\" + parser.yyVAL.item = &likeEscapeSpec{escape: "\\", explicit: false} } case 770: { - parser.yyVAL.ident = yyS[yypt-0].ident + parser.yyVAL.item = &likeEscapeSpec{escape: yyS[yypt-0].ident, explicit: true} } case 771: { @@ -22584,9 +22597,10 @@ yynewstate: case 2194: { parser.yyVAL.item = &ast.PatternLikeOrIlikeExpr{ - Pattern: yyS[yypt-0].expr, - Escape: '\\', - IsLike: true, + Pattern: yyS[yypt-0].expr, + Escape: '\\', + EscapeExplicit: false, + IsLike: true, } } case 2195: diff --git a/pkg/parser/parser.y b/pkg/parser/parser.y index 98774d3d46a63..9567af81b80e0 100644 --- a/pkg/parser/parser.y +++ b/pkg/parser/parser.y @@ -37,6 +37,11 @@ import ( "github.com/pingcap/tidb/pkg/parser/types" "github.com/pingcap/tidb/pkg/parser/duration" ) + +type likeEscapeSpec struct { + escape string + explicit bool +} %} %union { @@ -1121,6 +1126,7 @@ import ( %type AdminShowSlow "Admin Show Slow statement" AdminStmtLimitOpt "Admin show ddl jobs limit option" + LikeOrIlikeEscapeOpt "like or ilike escape option" AllOrPartitionNameList "All or partition name list" AlgorithmClause "Alter table algorithm" AlterJobOptionList "Alter job option list" @@ -1641,7 +1647,6 @@ import ( FieldTerminator "Field terminator" FlashbackToNewName "Flashback to new name" HashString "Hashed string" - LikeOrIlikeEscapeOpt "like or ilike escape option" OptCharset "Optional Character setting" OptCollate "Optional Collate setting" PasswordOpt "Password option" @@ -1799,17 +1804,17 @@ SplitIndexListOpt: { $$ = nil } -| SplitIndexList %prec lowerThanComma +| SplitIndexList %prec lowerThanComma { $$ = $1.([]*ast.SplitIndexOption) } SplitIndexList: - SplitIndexOption + SplitIndexOption { $$ = []*ast.SplitIndexOption{$1.(*ast.SplitIndexOption)} } -| SplitIndexList SplitIndexOption +| SplitIndexList SplitIndexOption { $$ = append($1.([]*ast.SplitIndexOption), $2.(*ast.SplitIndexOption)) } @@ -1819,22 +1824,22 @@ SplitIndexOption: { $$ = &ast.SplitIndexOption{ PrimaryKey: true, - IndexName: ast.NewCIStr(mysql.PrimaryKeyName), - SplitOpt: $4.(*ast.SplitOption), + IndexName: ast.NewCIStr(mysql.PrimaryKeyName), + SplitOpt: $4.(*ast.SplitOption), } } | "SPLIT" "INDEX" Identifier SplitOptionBetween { $$ = &ast.SplitIndexOption{ IndexName: ast.NewCIStr($3), - SplitOpt: $4.(*ast.SplitOption), + SplitOpt: $4.(*ast.SplitOption), } } | "SPLIT" SplitOptionBetween { $$ = &ast.SplitIndexOption{ TableLevel: true, - SplitOpt: $2.(*ast.SplitOption), + SplitOpt: $2.(*ast.SplitOption), } } @@ -2221,8 +2226,8 @@ AlterTableSpecSingleOpt: | SplitIndexOption { $$ = &ast.AlterTableSpec{ - Tp: ast.AlterTableSplitIndex, - SplitIndex: $1.(*ast.SplitIndexOption), + Tp: ast.AlterTableSplitIndex, + SplitIndex: $1.(*ast.SplitIndexOption), } } | "SPLIT" "MAXVALUE" "PARTITION" "LESS" "THAN" '(' BitExpr ')' @@ -6619,36 +6624,44 @@ PredicateExpr: } | BitExpr LikeOrNotOp SimpleExpr LikeOrIlikeEscapeOpt { - escape := $4 + escapeSpec := $4.(*likeEscapeSpec) + escape := escapeSpec.escape + explicit := escapeSpec.explicit if len(escape) > 1 { yylex.AppendError(ErrWrongArguments.GenWithStackByArgs("ESCAPE")) return 1 } else if len(escape) == 0 { escape = "\\" + explicit = false } $$ = &ast.PatternLikeOrIlikeExpr{ - Expr: $1, - Pattern: $3, - Not: !$2.(bool), - Escape: escape[0], - IsLike: true, + Expr: $1, + Pattern: $3, + Not: !$2.(bool), + Escape: escape[0], + EscapeExplicit: explicit, + IsLike: true, } } | BitExpr IlikeOrNotOp SimpleExpr LikeOrIlikeEscapeOpt { - escape := $4 + escapeSpec := $4.(*likeEscapeSpec) + escape := escapeSpec.escape + explicit := escapeSpec.explicit if len(escape) > 1 { yylex.AppendError(ErrWrongArguments.GenWithStackByArgs("ESCAPE")) return 1 } else if len(escape) == 0 { escape = "\\" + explicit = false } $$ = &ast.PatternLikeOrIlikeExpr{ - Expr: $1, - Pattern: $3, - Not: !$2.(bool), - Escape: escape[0], - IsLike: false, + Expr: $1, + Pattern: $3, + Not: !$2.(bool), + Escape: escape[0], + EscapeExplicit: explicit, + IsLike: false, } } | BitExpr RegexpOrNotOp SimpleExpr @@ -6668,11 +6681,11 @@ RegexpSym: LikeOrIlikeEscapeOpt: %prec empty { - $$ = "\\" + $$ = &likeEscapeSpec{escape: "\\", explicit: false} } | "ESCAPE" stringLit { - $$ = $2 + $$ = &likeEscapeSpec{escape: $2, explicit: true} } Field: @@ -12411,9 +12424,10 @@ ShowLikeOrWhereOpt: | "LIKE" SimpleExpr { $$ = &ast.PatternLikeOrIlikeExpr{ - Pattern: $2, - Escape: '\\', - IsLike: true, + Pattern: $2, + Escape: '\\', + EscapeExplicit: false, + IsLike: true, } } | "WHERE" Expression diff --git a/pkg/parser/parser_test.go b/pkg/parser/parser_test.go index 8d868becf0ccd..12ed54a8f2217 100644 --- a/pkg/parser/parser_test.go +++ b/pkg/parser/parser_test.go @@ -7083,6 +7083,10 @@ func (checker *nodeTextCleaner) Enter(in ast.Node) (out ast.Node, skipChildren b } switch node := in.(type) { + case *ast.PatternLikeOrIlikeExpr: + if node.Escape == '\\' { + node.EscapeExplicit = false + } case *ast.CreateTableStmt: for _, opt := range node.Options { switch opt.Tp { diff --git a/pkg/planner/core/expression_rewriter.go b/pkg/planner/core/expression_rewriter.go index a0f8f5208077b..69b80eb819c2d 100644 --- a/pkg/planner/core/expression_rewriter.go +++ b/pkg/planner/core/expression_rewriter.go @@ -2177,6 +2177,16 @@ func (er *expressionRewriter) patternLikeOrIlikeToExpression(v *ast.PatternLikeO return } + escape := v.Escape + sessionVars, err := expropt.SessionVarsPropReader{}.GetSessionVars(er.sctx.GetEvalCtx()) + if err != nil { + er.err = err + return + } + if sessionVars.EnableNoBackslashEscapesInLike && !v.EscapeExplicit && er.sctx.GetEvalCtx().SQLMode().HasNoBackslashEscapesMode() { + escape = 0 + } + char, col := er.sctx.GetCharsetInfo() var function expression.Expression fieldType := &types.FieldType{} @@ -2189,7 +2199,7 @@ func (er *expressionRewriter) patternLikeOrIlikeToExpression(v *ast.PatternLikeO return } if !isNull { - patValue, patTypes := stringutil.CompilePattern(patString, v.Escape) + patValue, patTypes := stringutil.CompilePattern(patString, escape) if stringutil.IsExactMatch(patTypes) && er.ctxStack[l-2].GetType(er.sctx.GetEvalCtx()).EvalType() == types.ETString { op := ast.EQ if v.Not { @@ -2208,9 +2218,9 @@ func (er *expressionRewriter) patternLikeOrIlikeToExpression(v *ast.PatternLikeO if !v.IsLike { funcName = ast.Ilike } - types.DefaultTypeForValue(int(v.Escape), fieldType, char, col) + types.DefaultTypeForValue(int(escape), fieldType, char, col) function = er.notToExpression(v.Not, funcName, &v.Type, - er.ctxStack[l-2], er.ctxStack[l-1], &expression.Constant{Value: types.NewIntDatum(int64(v.Escape)), RetType: fieldType}) + er.ctxStack[l-2], er.ctxStack[l-1], &expression.Constant{Value: types.NewIntDatum(int64(escape)), RetType: fieldType}) } er.ctxStackPop(2) diff --git a/pkg/session/upgrade_def.go b/pkg/session/upgrade_def.go index f2681966505cf..f44f556fbbe81 100644 --- a/pkg/session/upgrade_def.go +++ b/pkg/session/upgrade_def.go @@ -478,6 +478,10 @@ const ( // Add index on start_time for mysql.tidb_runaway_watch and done_time for mysql.tidb_runaway_watch_done // to improve the performance of runaway watch sync loop. version254 = 254 + + // version255 + // Add tidb_enable_no_backslash_escapes_in_like global variable. + version255 = 255 ) // versionedUpgradeFunction is a struct that holds the upgrade function related @@ -491,7 +495,7 @@ type versionedUpgradeFunction struct { // currentBootstrapVersion is defined as a variable, so we can modify its value for testing. // please make sure this is the largest version -var currentBootstrapVersion int64 = version254 +var currentBootstrapVersion int64 = version255 var ( // this list must be ordered by version in ascending order, and the function @@ -670,6 +674,7 @@ var ( {version: version252, fn: upgradeToVer252}, {version: version253, fn: upgradeToVer253}, {version: version254, fn: upgradeToVer254}, + {version: version255, fn: upgradeToVer255}, } ) @@ -2049,3 +2054,8 @@ func upgradeToVer254(s sessionapi.Session, _ int64) { doReentrantDDL(s, "ALTER TABLE mysql.tidb_runaway_watch ADD INDEX idx_start_time(start_time) COMMENT 'accelerate the speed when syncing new watch records'", dbterror.ErrDupKeyName) doReentrantDDL(s, "ALTER TABLE mysql.tidb_runaway_watch_done ADD INDEX idx_done_time(done_time) COMMENT 'accelerate the speed when syncing done watch records'", dbterror.ErrDupKeyName) } + +func upgradeToVer255(s sessionapi.Session, _ int64) { + // Keep old behavior for upgraded clusters. + initGlobalVariableIfNotExists(s, vardef.TiDBEnableNoBackslashEscapesInLike, vardef.Off) +} diff --git a/pkg/sessionctx/vardef/tidb_vars.go b/pkg/sessionctx/vardef/tidb_vars.go index d89f720d09721..bbd46b151d490 100644 --- a/pkg/sessionctx/vardef/tidb_vars.go +++ b/pkg/sessionctx/vardef/tidb_vars.go @@ -680,6 +680,9 @@ const ( // TiDBEnableIndexMerge indicates to generate IndexMergePath. TiDBEnableIndexMerge = "tidb_enable_index_merge" + // TiDBEnableNoBackslashEscapesInLike controls whether NO_BACKSLASH_ESCAPES affects LIKE default escape. + TiDBEnableNoBackslashEscapesInLike = "tidb_enable_no_backslash_escapes_in_like" + // TiDBEnableNoopFuncs set true will enable using fake funcs(like get_lock release_lock) TiDBEnableNoopFuncs = "tidb_enable_noop_functions" @@ -1584,6 +1587,7 @@ const ( DefTiDBCapturePlanBaseline = Off DefTiDBIgnoreInlistPlanDigest = false DefTiDBEnableIndexMerge = true + DefTiDBEnableNoBackslashEscapesInLike = true DefEnableLegacyInstanceScope = true DefTiDBTableCacheLease = 3 // 3s DefTiDBPersistAnalyzeOptions = true diff --git a/pkg/sessionctx/variable/session.go b/pkg/sessionctx/variable/session.go index 478651a4c2c7f..837046a11693c 100644 --- a/pkg/sessionctx/variable/session.go +++ b/pkg/sessionctx/variable/session.go @@ -1306,6 +1306,8 @@ type SessionVars struct { // EnableIndexMerge enables the generation of IndexMergePath. enableIndexMerge bool + // EnableNoBackslashEscapesInLike controls whether NO_BACKSLASH_ESCAPES affects LIKE default escape. + EnableNoBackslashEscapesInLike bool // replicaRead is used for reading data from replicas, only follower is supported at this time. replicaRead kv.ReplicaReadType @@ -2256,143 +2258,144 @@ func (connInfo *ConnectionInfo) IsSecureTransport() bool { // NewSessionVars creates a session vars object. func NewSessionVars(hctx HookContext) *SessionVars { vars := &SessionVars{ - UserVars: NewUserVars(), - systems: make(map[string]string), - PreparedStmts: make(map[uint32]any), - PreparedStmtNameToID: make(map[string]uint32), - PlanCacheParams: NewPlanCacheParamList(), - TxnCtx: &TransactionContext{}, - RetryInfo: &RetryInfo{}, - ActiveRoles: make([]*auth.RoleIdentity, 0, 10), - AutoIncrementIncrement: vardef.DefAutoIncrementIncrement, - AutoIncrementOffset: vardef.DefAutoIncrementOffset, - StmtCtx: stmtctx.NewStmtCtx(), - AllowAggPushDown: false, - AllowCartesianBCJ: vardef.DefOptCartesianBCJ, - MPPOuterJoinFixedBuildSide: vardef.DefOptMPPOuterJoinFixedBuildSide, - BroadcastJoinThresholdSize: vardef.DefBroadcastJoinThresholdSize, - BroadcastJoinThresholdCount: vardef.DefBroadcastJoinThresholdCount, - OptimizerSelectivityLevel: vardef.DefTiDBOptimizerSelectivityLevel, - OptIndexPruneThreshold: vardef.DefTiDBOptIndexPruneThreshold, - RiskScaleNDVSkewRatio: vardef.DefOptRiskScaleNDVSkewRatio, - RiskGroupNDVSkewRatio: vardef.DefOptRiskGroupNDVSkewRatio, - AlwaysKeepJoinKey: vardef.DefOptAlwaysKeepJoinKey, - CartesianJoinOrderThreshold: vardef.DefOptCartesianJoinOrderThreshold, - EnableOuterJoinReorder: vardef.DefTiDBEnableOuterJoinReorder, - EnableNoDecorrelateInSelect: vardef.DefOptEnableNoDecorrelateInSelect, - EnableSemiJoinRewrite: vardef.DefOptEnableSemiJoinRewrite, - RetryLimit: vardef.DefTiDBRetryLimit, - DisableTxnAutoRetry: vardef.DefTiDBDisableTxnAutoRetry, - DDLReorgPriority: kv.PriorityLow, - allowInSubqToJoinAndAgg: vardef.DefOptInSubqToJoinAndAgg, - preferRangeScan: vardef.DefOptPreferRangeScan, - EnableCorrelationAdjustment: vardef.DefOptEnableCorrelationAdjustment, - LimitPushDownThreshold: vardef.DefOptLimitPushDownThreshold, - CorrelationThreshold: vardef.DefOptCorrelationThreshold, - CorrelationExpFactor: vardef.DefOptCorrelationExpFactor, - RiskEqSkewRatio: vardef.DefOptRiskEqSkewRatio, - RiskRangeSkewRatio: vardef.DefOptRiskRangeSkewRatio, - cpuFactor: vardef.DefOptCPUFactor, - copCPUFactor: vardef.DefOptCopCPUFactor, - CopTiFlashConcurrencyFactor: vardef.DefOptTiFlashConcurrencyFactor, - networkFactor: vardef.DefOptNetworkFactor, - scanFactor: vardef.DefOptScanFactor, - descScanFactor: vardef.DefOptDescScanFactor, - seekFactor: vardef.DefOptSeekFactor, - memoryFactor: vardef.DefOptMemoryFactor, - diskFactor: vardef.DefOptDiskFactor, - concurrencyFactor: vardef.DefOptConcurrencyFactor, - IndexScanCostFactor: vardef.DefOptIndexScanCostFactor, - IndexReaderCostFactor: vardef.DefOptIndexReaderCostFactor, - TableReaderCostFactor: vardef.DefOptTableReaderCostFactor, - TableFullScanCostFactor: vardef.DefOptTableFullScanCostFactor, - TableRangeScanCostFactor: vardef.DefOptTableRangeScanCostFactor, - TableRowIDScanCostFactor: vardef.DefOptTableRowIDScanCostFactor, - TableTiFlashScanCostFactor: vardef.DefOptTableTiFlashScanCostFactor, - IndexLookupCostFactor: vardef.DefOptIndexLookupCostFactor, - IndexMergeCostFactor: vardef.DefOptIndexMergeCostFactor, - SortCostFactor: vardef.DefOptSortCostFactor, - TopNCostFactor: vardef.DefOptTopNCostFactor, - LimitCostFactor: vardef.DefOptLimitCostFactor, - StreamAggCostFactor: vardef.DefOptStreamAggCostFactor, - HashAggCostFactor: vardef.DefOptHashAggCostFactor, - MergeJoinCostFactor: vardef.DefOptMergeJoinCostFactor, - HashJoinCostFactor: vardef.DefOptHashJoinCostFactor, - IndexJoinCostFactor: vardef.DefOptIndexJoinCostFactor, - SelectivityFactor: vardef.DefOptSelectivityFactor, - enableForceInlineCTE: vardef.DefOptForceInlineCTE, - EnableVectorizedExpression: vardef.DefEnableVectorizedExpression, - CommandValue: uint32(mysql.ComSleep), - TiDBOptJoinReorderThreshold: vardef.DefTiDBOptJoinReorderThreshold, - TiDBOptJoinReorderThroughSel: vardef.DefTiDBOptJoinReorderThroughSel, - SlowQueryFile: config.GetGlobalConfig().Log.SlowQueryFile, - WaitSplitRegionFinish: vardef.DefTiDBWaitSplitRegionFinish, - WaitSplitRegionTimeout: vardef.DefWaitSplitRegionTimeout, - enableIndexMerge: vardef.DefTiDBEnableIndexMerge, - NoopFuncsMode: TiDBOptOnOffWarn(vardef.DefTiDBEnableNoopFuncs), - replicaRead: kv.ReplicaReadLeader, - AllowRemoveAutoInc: vardef.DefTiDBAllowRemoveAutoInc, - UsePlanBaselines: vardef.DefTiDBUsePlanBaselines, - EvolvePlanBaselines: vardef.DefTiDBEvolvePlanBaselines, - EnableExtendedStats: false, - IsolationReadEngines: make(map[kv.StoreType]struct{}), - LockWaitTimeout: vardef.DefInnodbLockWaitTimeout * 1000, - MetricSchemaStep: vardef.DefTiDBMetricSchemaStep, - MetricSchemaRangeDuration: vardef.DefTiDBMetricSchemaRangeDuration, - SequenceState: NewSequenceState(), - WindowingUseHighPrecision: true, - PrevFoundInPlanCache: vardef.DefTiDBFoundInPlanCache, - FoundInPlanCache: vardef.DefTiDBFoundInPlanCache, - PrevFoundInBinding: vardef.DefTiDBFoundInBinding, - FoundInBinding: vardef.DefTiDBFoundInBinding, - SelectLimit: math.MaxUint64, - AllowAutoRandExplicitInsert: vardef.DefTiDBAllowAutoRandExplicitInsert, - EnableClusteredIndex: vardef.DefTiDBEnableClusteredIndex, - EnableParallelApply: vardef.DefTiDBEnableParallelApply, - ShardAllocateStep: vardef.DefTiDBShardAllocateStep, - EnablePointGetCache: vardef.DefTiDBPointGetCache, - PartitionPruneMode: *atomic2.NewString(vardef.DefTiDBPartitionPruneMode), - TxnScope: kv.NewDefaultTxnScopeVar(), - EnabledRateLimitAction: vardef.DefTiDBEnableRateLimitAction, - EnableAsyncCommit: vardef.DefTiDBEnableAsyncCommit, - Enable1PC: vardef.DefTiDBEnable1PC, - GuaranteeLinearizability: vardef.DefTiDBGuaranteeLinearizability, - AnalyzeVersion: vardef.DefTiDBAnalyzeVersion, - EnableIndexMergeJoin: vardef.DefTiDBEnableIndexMergeJoin, - AllowFallbackToTiKV: make(map[kv.StoreType]struct{}), - CTEMaxRecursionDepth: vardef.DefCTEMaxRecursionDepth, - TMPTableSize: vardef.DefTiDBTmpTableMaxSize, - MPPStoreFailTTL: vardef.DefTiDBMPPStoreFailTTL, - Rng: mathutil.NewWithTime(), - EnableLegacyInstanceScope: vardef.DefEnableLegacyInstanceScope, - RemoveOrderbyInSubquery: vardef.DefTiDBRemoveOrderbyInSubquery, - EnableSkewDistinctAgg: vardef.DefTiDBSkewDistinctAgg, - Enable3StageDistinctAgg: vardef.DefTiDB3StageDistinctAgg, - MaxAllowedPacket: vardef.DefMaxAllowedPacket, - TiFlashFastScan: vardef.DefTiFlashFastScan, - EnableTiFlashReadForWriteStmt: true, - ForeignKeyChecks: vardef.DefTiDBForeignKeyChecks, - HookContext: hctx, - EnableReuseChunk: vardef.DefTiDBEnableReusechunk, - preUseChunkAlloc: vardef.DefTiDBUseAlloc, - chunkPool: nil, - mppExchangeCompressionMode: vardef.DefaultExchangeCompressionMode, - mppVersion: kv.MppVersionUnspecified, - EnableLateMaterialization: vardef.DefTiDBOptEnableLateMaterialization, - TiFlashComputeDispatchPolicy: tiflashcompute.DispatchPolicyConsistentHash, - ResourceGroupName: resourcegroup.DefaultResourceGroupName, - DefaultCollationForUTF8MB4: mysql.DefaultCollationName, - GroupConcatMaxLen: vardef.DefGroupConcatMaxLen, - EnableRedactLog: vardef.DefTiDBRedactLog, - EnableWindowFunction: vardef.DefEnableWindowFunction, - CostModelVersion: vardef.DefTiDBCostModelVer, - OptimizerEnableNAAJ: vardef.DefTiDBEnableNAAJ, - OptOrderingIdxSelRatio: vardef.DefTiDBOptOrderingIdxSelRatio, - RegardNULLAsPoint: vardef.DefTiDBRegardNULLAsPoint, - AllowProjectionPushDown: vardef.DefOptEnableProjectionPushDown, - SkipMissingPartitionStats: vardef.DefTiDBSkipMissingPartitionStats, - IndexLookUpPushDownPolicy: vardef.DefTiDBIndexLookUpPushDownPolicy, - OptPartialOrderedIndexForTopN: vardef.DefTiDBOptPartialOrderedIndexForTopN, + UserVars: NewUserVars(), + systems: make(map[string]string), + PreparedStmts: make(map[uint32]any), + PreparedStmtNameToID: make(map[string]uint32), + PlanCacheParams: NewPlanCacheParamList(), + TxnCtx: &TransactionContext{}, + RetryInfo: &RetryInfo{}, + ActiveRoles: make([]*auth.RoleIdentity, 0, 10), + AutoIncrementIncrement: vardef.DefAutoIncrementIncrement, + AutoIncrementOffset: vardef.DefAutoIncrementOffset, + StmtCtx: stmtctx.NewStmtCtx(), + AllowAggPushDown: false, + AllowCartesianBCJ: vardef.DefOptCartesianBCJ, + MPPOuterJoinFixedBuildSide: vardef.DefOptMPPOuterJoinFixedBuildSide, + BroadcastJoinThresholdSize: vardef.DefBroadcastJoinThresholdSize, + BroadcastJoinThresholdCount: vardef.DefBroadcastJoinThresholdCount, + OptimizerSelectivityLevel: vardef.DefTiDBOptimizerSelectivityLevel, + OptIndexPruneThreshold: vardef.DefTiDBOptIndexPruneThreshold, + RiskScaleNDVSkewRatio: vardef.DefOptRiskScaleNDVSkewRatio, + RiskGroupNDVSkewRatio: vardef.DefOptRiskGroupNDVSkewRatio, + AlwaysKeepJoinKey: vardef.DefOptAlwaysKeepJoinKey, + CartesianJoinOrderThreshold: vardef.DefOptCartesianJoinOrderThreshold, + EnableOuterJoinReorder: vardef.DefTiDBEnableOuterJoinReorder, + EnableNoDecorrelateInSelect: vardef.DefOptEnableNoDecorrelateInSelect, + EnableSemiJoinRewrite: vardef.DefOptEnableSemiJoinRewrite, + RetryLimit: vardef.DefTiDBRetryLimit, + DisableTxnAutoRetry: vardef.DefTiDBDisableTxnAutoRetry, + DDLReorgPriority: kv.PriorityLow, + allowInSubqToJoinAndAgg: vardef.DefOptInSubqToJoinAndAgg, + preferRangeScan: vardef.DefOptPreferRangeScan, + EnableCorrelationAdjustment: vardef.DefOptEnableCorrelationAdjustment, + LimitPushDownThreshold: vardef.DefOptLimitPushDownThreshold, + CorrelationThreshold: vardef.DefOptCorrelationThreshold, + CorrelationExpFactor: vardef.DefOptCorrelationExpFactor, + RiskEqSkewRatio: vardef.DefOptRiskEqSkewRatio, + RiskRangeSkewRatio: vardef.DefOptRiskRangeSkewRatio, + cpuFactor: vardef.DefOptCPUFactor, + copCPUFactor: vardef.DefOptCopCPUFactor, + CopTiFlashConcurrencyFactor: vardef.DefOptTiFlashConcurrencyFactor, + networkFactor: vardef.DefOptNetworkFactor, + scanFactor: vardef.DefOptScanFactor, + descScanFactor: vardef.DefOptDescScanFactor, + seekFactor: vardef.DefOptSeekFactor, + memoryFactor: vardef.DefOptMemoryFactor, + diskFactor: vardef.DefOptDiskFactor, + concurrencyFactor: vardef.DefOptConcurrencyFactor, + IndexScanCostFactor: vardef.DefOptIndexScanCostFactor, + IndexReaderCostFactor: vardef.DefOptIndexReaderCostFactor, + TableReaderCostFactor: vardef.DefOptTableReaderCostFactor, + TableFullScanCostFactor: vardef.DefOptTableFullScanCostFactor, + TableRangeScanCostFactor: vardef.DefOptTableRangeScanCostFactor, + TableRowIDScanCostFactor: vardef.DefOptTableRowIDScanCostFactor, + TableTiFlashScanCostFactor: vardef.DefOptTableTiFlashScanCostFactor, + IndexLookupCostFactor: vardef.DefOptIndexLookupCostFactor, + IndexMergeCostFactor: vardef.DefOptIndexMergeCostFactor, + SortCostFactor: vardef.DefOptSortCostFactor, + TopNCostFactor: vardef.DefOptTopNCostFactor, + LimitCostFactor: vardef.DefOptLimitCostFactor, + StreamAggCostFactor: vardef.DefOptStreamAggCostFactor, + HashAggCostFactor: vardef.DefOptHashAggCostFactor, + MergeJoinCostFactor: vardef.DefOptMergeJoinCostFactor, + HashJoinCostFactor: vardef.DefOptHashJoinCostFactor, + IndexJoinCostFactor: vardef.DefOptIndexJoinCostFactor, + SelectivityFactor: vardef.DefOptSelectivityFactor, + enableForceInlineCTE: vardef.DefOptForceInlineCTE, + EnableVectorizedExpression: vardef.DefEnableVectorizedExpression, + CommandValue: uint32(mysql.ComSleep), + TiDBOptJoinReorderThreshold: vardef.DefTiDBOptJoinReorderThreshold, + TiDBOptJoinReorderThroughSel: vardef.DefTiDBOptJoinReorderThroughSel, + SlowQueryFile: config.GetGlobalConfig().Log.SlowQueryFile, + WaitSplitRegionFinish: vardef.DefTiDBWaitSplitRegionFinish, + WaitSplitRegionTimeout: vardef.DefWaitSplitRegionTimeout, + enableIndexMerge: vardef.DefTiDBEnableIndexMerge, + EnableNoBackslashEscapesInLike: vardef.DefTiDBEnableNoBackslashEscapesInLike, + NoopFuncsMode: TiDBOptOnOffWarn(vardef.DefTiDBEnableNoopFuncs), + replicaRead: kv.ReplicaReadLeader, + AllowRemoveAutoInc: vardef.DefTiDBAllowRemoveAutoInc, + UsePlanBaselines: vardef.DefTiDBUsePlanBaselines, + EvolvePlanBaselines: vardef.DefTiDBEvolvePlanBaselines, + EnableExtendedStats: false, + IsolationReadEngines: make(map[kv.StoreType]struct{}), + LockWaitTimeout: vardef.DefInnodbLockWaitTimeout * 1000, + MetricSchemaStep: vardef.DefTiDBMetricSchemaStep, + MetricSchemaRangeDuration: vardef.DefTiDBMetricSchemaRangeDuration, + SequenceState: NewSequenceState(), + WindowingUseHighPrecision: true, + PrevFoundInPlanCache: vardef.DefTiDBFoundInPlanCache, + FoundInPlanCache: vardef.DefTiDBFoundInPlanCache, + PrevFoundInBinding: vardef.DefTiDBFoundInBinding, + FoundInBinding: vardef.DefTiDBFoundInBinding, + SelectLimit: math.MaxUint64, + AllowAutoRandExplicitInsert: vardef.DefTiDBAllowAutoRandExplicitInsert, + EnableClusteredIndex: vardef.DefTiDBEnableClusteredIndex, + EnableParallelApply: vardef.DefTiDBEnableParallelApply, + ShardAllocateStep: vardef.DefTiDBShardAllocateStep, + EnablePointGetCache: vardef.DefTiDBPointGetCache, + PartitionPruneMode: *atomic2.NewString(vardef.DefTiDBPartitionPruneMode), + TxnScope: kv.NewDefaultTxnScopeVar(), + EnabledRateLimitAction: vardef.DefTiDBEnableRateLimitAction, + EnableAsyncCommit: vardef.DefTiDBEnableAsyncCommit, + Enable1PC: vardef.DefTiDBEnable1PC, + GuaranteeLinearizability: vardef.DefTiDBGuaranteeLinearizability, + AnalyzeVersion: vardef.DefTiDBAnalyzeVersion, + EnableIndexMergeJoin: vardef.DefTiDBEnableIndexMergeJoin, + AllowFallbackToTiKV: make(map[kv.StoreType]struct{}), + CTEMaxRecursionDepth: vardef.DefCTEMaxRecursionDepth, + TMPTableSize: vardef.DefTiDBTmpTableMaxSize, + MPPStoreFailTTL: vardef.DefTiDBMPPStoreFailTTL, + Rng: mathutil.NewWithTime(), + EnableLegacyInstanceScope: vardef.DefEnableLegacyInstanceScope, + RemoveOrderbyInSubquery: vardef.DefTiDBRemoveOrderbyInSubquery, + EnableSkewDistinctAgg: vardef.DefTiDBSkewDistinctAgg, + Enable3StageDistinctAgg: vardef.DefTiDB3StageDistinctAgg, + MaxAllowedPacket: vardef.DefMaxAllowedPacket, + TiFlashFastScan: vardef.DefTiFlashFastScan, + EnableTiFlashReadForWriteStmt: true, + ForeignKeyChecks: vardef.DefTiDBForeignKeyChecks, + HookContext: hctx, + EnableReuseChunk: vardef.DefTiDBEnableReusechunk, + preUseChunkAlloc: vardef.DefTiDBUseAlloc, + chunkPool: nil, + mppExchangeCompressionMode: vardef.DefaultExchangeCompressionMode, + mppVersion: kv.MppVersionUnspecified, + EnableLateMaterialization: vardef.DefTiDBOptEnableLateMaterialization, + TiFlashComputeDispatchPolicy: tiflashcompute.DispatchPolicyConsistentHash, + ResourceGroupName: resourcegroup.DefaultResourceGroupName, + DefaultCollationForUTF8MB4: mysql.DefaultCollationName, + GroupConcatMaxLen: vardef.DefGroupConcatMaxLen, + EnableRedactLog: vardef.DefTiDBRedactLog, + EnableWindowFunction: vardef.DefEnableWindowFunction, + CostModelVersion: vardef.DefTiDBCostModelVer, + OptimizerEnableNAAJ: vardef.DefTiDBEnableNAAJ, + OptOrderingIdxSelRatio: vardef.DefTiDBOptOrderingIdxSelRatio, + RegardNULLAsPoint: vardef.DefTiDBRegardNULLAsPoint, + AllowProjectionPushDown: vardef.DefOptEnableProjectionPushDown, + SkipMissingPartitionStats: vardef.DefTiDBSkipMissingPartitionStats, + IndexLookUpPushDownPolicy: vardef.DefTiDBIndexLookUpPushDownPolicy, + OptPartialOrderedIndexForTopN: vardef.DefTiDBOptPartialOrderedIndexForTopN, } vars.TiFlashFineGrainedShuffleBatchSize = vardef.DefTiFlashFineGrainedShuffleBatchSize vars.status.Store(uint32(mysql.ServerStatusAutocommit)) diff --git a/pkg/sessionctx/variable/setvar_affect.go b/pkg/sessionctx/variable/setvar_affect.go index c9e92d396e865..d8c7cc32197e0 100644 --- a/pkg/sessionctx/variable/setvar_affect.go +++ b/pkg/sessionctx/variable/setvar_affect.go @@ -99,6 +99,7 @@ var isHintUpdatableVerified = map[string]struct{}{ "tidb_enable_vectorized_expression": {}, "tidb_opt_join_reorder_threshold": {}, "tidb_enable_index_merge": {}, + "tidb_enable_no_backslash_escapes_in_like": {}, "tidb_enable_extended_stats": {}, "tidb_isolation_read_engines": {}, "tidb_executor_concurrency": {}, diff --git a/pkg/sessionctx/variable/sysvar.go b/pkg/sessionctx/variable/sysvar.go index 3bd2647e47496..13a2cbeb599d3 100644 --- a/pkg/sessionctx/variable/sysvar.go +++ b/pkg/sessionctx/variable/sysvar.go @@ -2434,6 +2434,10 @@ var defaultSysVars = []*SysVar{ s.SetEnableIndexMerge(TiDBOptOn(val)) return nil }}, + {Scope: vardef.ScopeGlobal | vardef.ScopeSession, Name: vardef.TiDBEnableNoBackslashEscapesInLike, Value: BoolToOnOff(vardef.DefTiDBEnableNoBackslashEscapesInLike), Type: vardef.TypeBool, SetSession: func(s *SessionVars, val string) error { + s.EnableNoBackslashEscapesInLike = TiDBOptOn(val) + return nil + }}, {Scope: vardef.ScopeGlobal | vardef.ScopeSession, Name: vardef.TiDBEnableTablePartition, Value: vardef.On, Type: vardef.TypeEnum, PossibleValues: []string{vardef.Off, vardef.On, "AUTO"}, Validation: func(vars *SessionVars, s string, s2 string, flag vardef.ScopeFlag) (string, error) { if s == vardef.Off { vars.StmtCtx.AppendWarning(errors.NewNoStackError("tidb_enable_table_partition is always turned on. This variable has been deprecated and will be removed in the future releases")) diff --git a/tests/integrationtest/r/expression/issues.result b/tests/integrationtest/r/expression/issues.result index 9c7615e103ede..57067599e29b0 100644 --- a/tests/integrationtest/r/expression/issues.result +++ b/tests/integrationtest/r/expression/issues.result @@ -3335,3 +3335,58 @@ Field Type Null Key Default Extra aes_encrypt(myid,'testkey') varbinary(32) YES NULL drop view v_aes; drop table t_aes; +create table cb_ast (id int, tname varchar(64)); +insert into cb_ast values (1, 'a\\a'), (2, 'a\\a'), (3, '中\\中'), (4, '中\\中'); +select @@tidb_enable_no_backslash_escapes_in_like; +@@tidb_enable_no_backslash_escapes_in_like +1 +set session sql_mode='NO_BACKSLASH_ESCAPES'; +select * from cb_ast; +id tname +1 a\a +2 a\a +3 中\中 +4 中\中 +select * from cb_ast where tname like '%%'; +id tname +1 a\a +2 a\a +3 中\中 +4 中\中 +select * from cb_ast where tname like '%\%'; +id tname +1 a\a +2 a\a +3 中\中 +4 中\中 +select 'David_' like 'David\_'; +'David_' like 'David\_' +0 +select 'David_' like 'David\_' escape '\'; +'David_' like 'David\_' escape '\' +1 +set session sql_mode=default; +set @@tidb_enable_no_backslash_escapes_in_like = 'off'; +set session sql_mode='NO_BACKSLASH_ESCAPES'; +select * from cb_ast; +id tname +1 a\a +2 a\a +3 中\中 +4 中\中 +select * from cb_ast where tname like '%%'; +id tname +1 a\a +2 a\a +3 中\中 +4 中\中 +select * from cb_ast where tname like '%\%'; +id tname +select 'David_' like 'David\_'; +'David_' like 'David\_' +1 +select 'David_' like 'David\_' escape '\'; +'David_' like 'David\_' escape '\' +1 +set session sql_mode=default; +set @@tidb_enable_no_backslash_escapes_in_like = default; diff --git a/tests/integrationtest/t/expression/issues.test b/tests/integrationtest/t/expression/issues.test index 2792f19eb06de..6294440f003b2 100644 --- a/tests/integrationtest/t/expression/issues.test +++ b/tests/integrationtest/t/expression/issues.test @@ -2260,3 +2260,28 @@ desc v_aes; show columns from v_aes; drop view v_aes; drop table t_aes; + +# TestIssue35302 +create table cb_ast (id int, tname varchar(64)); +insert into cb_ast values (1, 'a\\a'), (2, 'a\\a'), (3, '中\\中'), (4, '中\\中'); +# default values should be 'on' +select @@tidb_enable_no_backslash_escapes_in_like; +set session sql_mode='NO_BACKSLASH_ESCAPES'; +select * from cb_ast; +select * from cb_ast where tname like '%%'; +# like expression should consider 'NO_BACKSLASH_ESCAPES' and behavior the same as MySQL +select * from cb_ast where tname like '%\%'; +select 'David_' like 'David\_'; +select 'David_' like 'David\_' escape '\'; +set session sql_mode=default; +# keep buggy behavior for old tidb compatibility, only fix on newer version +set @@tidb_enable_no_backslash_escapes_in_like = 'off'; +set session sql_mode='NO_BACKSLASH_ESCAPES'; +select * from cb_ast; +select * from cb_ast where tname like '%%'; +# like expression should consider 'NO_BACKSLASH_ESCAPES' and behavior the same as MySQL +select * from cb_ast where tname like '%\%'; +select 'David_' like 'David\_'; +select 'David_' like 'David\_' escape '\'; +set session sql_mode=default; +set @@tidb_enable_no_backslash_escapes_in_like = default;