github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/syncer/expr_filter_group.go (about) 1 // Copyright 2021 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package syncer 15 16 import ( 17 "github.com/pingcap/tidb/pkg/expression" 18 "github.com/pingcap/tidb/pkg/parser/model" 19 "github.com/pingcap/tidb/pkg/sessionctx" 20 "github.com/pingcap/tidb/pkg/util/chunk" 21 "github.com/pingcap/tidb/pkg/util/dbterror/plannererrors" 22 "github.com/pingcap/tidb/pkg/util/dbutil" 23 "github.com/pingcap/tidb/pkg/util/filter" 24 "github.com/pingcap/tiflow/dm/config" 25 tcontext "github.com/pingcap/tiflow/dm/pkg/context" 26 "github.com/pingcap/tiflow/dm/pkg/log" 27 "github.com/pingcap/tiflow/dm/pkg/utils" 28 "go.uber.org/zap" 29 ) 30 31 // ExprFilterGroup groups many related fields about expression filter. 32 type ExprFilterGroup struct { 33 configs map[string][]*config.ExpressionFilter // tableName -> raw config 34 insertExprs map[string][]expression.Expression // tableName -> expr 35 updateOldExprs map[string][]expression.Expression // tableName -> expr 36 updateNewExprs map[string][]expression.Expression // tableName -> expr 37 deleteExprs map[string][]expression.Expression // tableName -> expr 38 39 hasInsertFilter map[string]struct{} // set(tableName) 40 hasUpdateFilter map[string]struct{} // set(tableName) 41 hasDeleteFilter map[string]struct{} // set(tableName) 42 43 tidbCtx sessionctx.Context 44 logCtx *tcontext.Context 45 } 46 47 // NewExprFilterGroup creates an ExprFilterGroup. 48 func NewExprFilterGroup(logCtx *tcontext.Context, tidbCtx sessionctx.Context, exprConfig []*config.ExpressionFilter) *ExprFilterGroup { 49 ret := &ExprFilterGroup{ 50 configs: map[string][]*config.ExpressionFilter{}, 51 insertExprs: map[string][]expression.Expression{}, 52 updateOldExprs: map[string][]expression.Expression{}, 53 updateNewExprs: map[string][]expression.Expression{}, 54 deleteExprs: map[string][]expression.Expression{}, 55 hasInsertFilter: map[string]struct{}{}, 56 hasUpdateFilter: map[string]struct{}{}, 57 hasDeleteFilter: map[string]struct{}{}, 58 tidbCtx: tidbCtx, 59 logCtx: logCtx, 60 } 61 for _, c := range exprConfig { 62 tableName := dbutil.TableName(c.Schema, c.Table) 63 ret.configs[tableName] = append(ret.configs[tableName], c) 64 65 if c.InsertValueExpr != "" { 66 ret.hasInsertFilter[tableName] = struct{}{} 67 } 68 if c.UpdateOldValueExpr != "" || c.UpdateNewValueExpr != "" { 69 ret.hasUpdateFilter[tableName] = struct{}{} 70 } 71 if c.DeleteValueExpr != "" { 72 ret.hasDeleteFilter[tableName] = struct{}{} 73 } 74 } 75 return ret 76 } 77 78 // GetInsertExprs returns the expression filters for given table to filter INSERT events. 79 // This function will lazy calculate expressions if not initialized. 80 func (g *ExprFilterGroup) GetInsertExprs(table *filter.Table, ti *model.TableInfo) ([]expression.Expression, error) { 81 tableID := utils.GenTableID(table) 82 83 if ret, ok := g.insertExprs[tableID]; ok { 84 return ret, nil 85 } 86 if _, ok := g.hasInsertFilter[tableID]; !ok { 87 return nil, nil 88 } 89 90 for _, c := range g.configs[tableID] { 91 if c.InsertValueExpr != "" { 92 expr, err2 := getSimpleExprOfTable(g.tidbCtx, c.InsertValueExpr, ti, g.logCtx.L()) 93 if err2 != nil { 94 // TODO: terror 95 return nil, err2 96 } 97 g.insertExprs[tableID] = append(g.insertExprs[tableID], expr) 98 } 99 } 100 return g.insertExprs[tableID], nil 101 } 102 103 // GetUpdateExprs returns two lists of expression filters for given table, to filter UPDATE events by old values and new 104 // values respectively. The two lists should have same length, and the corresponding expressions is AND logic. 105 // This function will lazy calculate expressions if not initialized. 106 func (g *ExprFilterGroup) GetUpdateExprs(table *filter.Table, ti *model.TableInfo) ([]expression.Expression, []expression.Expression, error) { 107 tableID := utils.GenTableID(table) 108 109 retOld, ok1 := g.updateOldExprs[tableID] 110 retNew, ok2 := g.updateNewExprs[tableID] 111 if ok1 || ok2 { 112 return retOld, retNew, nil 113 } 114 115 if _, ok := g.hasUpdateFilter[tableID]; ok { 116 for _, c := range g.configs[tableID] { 117 if c.UpdateOldValueExpr == "" && c.UpdateNewValueExpr == "" { 118 continue 119 } 120 if c.UpdateOldValueExpr != "" { 121 expr, err := getSimpleExprOfTable(g.tidbCtx, c.UpdateOldValueExpr, ti, g.logCtx.L()) 122 if err != nil { 123 // TODO: terror 124 return nil, nil, err 125 } 126 g.updateOldExprs[tableID] = append(g.updateOldExprs[tableID], expr) 127 } else { 128 g.updateOldExprs[tableID] = append(g.updateOldExprs[tableID], expression.NewOne()) 129 } 130 131 if c.UpdateNewValueExpr != "" { 132 expr, err := getSimpleExprOfTable(g.tidbCtx, c.UpdateNewValueExpr, ti, g.logCtx.L()) 133 if err != nil { 134 // TODO: terror 135 return nil, nil, err 136 } 137 g.updateNewExprs[tableID] = append(g.updateNewExprs[tableID], expr) 138 } else { 139 g.updateNewExprs[tableID] = append(g.updateNewExprs[tableID], expression.NewOne()) 140 } 141 } 142 } 143 144 return g.updateOldExprs[tableID], g.updateNewExprs[tableID], nil 145 } 146 147 // GetDeleteExprs returns the expression filters for given table to filter DELETE events. 148 // This function will lazy calculate expressions if not initialized. 149 func (g *ExprFilterGroup) GetDeleteExprs(table *filter.Table, ti *model.TableInfo) ([]expression.Expression, error) { 150 tableID := utils.GenTableID(table) 151 152 if ret, ok := g.deleteExprs[tableID]; ok { 153 return ret, nil 154 } 155 if _, ok := g.hasDeleteFilter[tableID]; !ok { 156 return nil, nil 157 } 158 159 for _, c := range g.configs[tableID] { 160 if c.DeleteValueExpr != "" { 161 expr, err2 := getSimpleExprOfTable(g.tidbCtx, c.DeleteValueExpr, ti, g.logCtx.L()) 162 if err2 != nil { 163 // TODO: terror 164 return nil, err2 165 } 166 g.deleteExprs[tableID] = append(g.deleteExprs[tableID], expr) 167 } 168 } 169 return g.deleteExprs[tableID], nil 170 } 171 172 // ResetExprs deletes the expressions generated before. This should be called after table structure changed. 173 func (g *ExprFilterGroup) ResetExprs(table *filter.Table) { 174 tableID := utils.GenTableID(table) 175 delete(g.insertExprs, tableID) 176 delete(g.updateOldExprs, tableID) 177 delete(g.updateNewExprs, tableID) 178 delete(g.deleteExprs, tableID) 179 } 180 181 // SkipDMLByExpression returns true when given row matches the expr, which means this row should be skipped. 182 func SkipDMLByExpression(ctx sessionctx.Context, row []interface{}, expr expression.Expression, upstreamCols []*model.ColumnInfo) (bool, error) { 183 // TODO: add MetricsProxies 184 log.L().Debug("will evaluate the expression", zap.Stringer("expression", expr), zap.Any("raw row", row)) 185 data, err := utils.AdjustBinaryProtocolForDatum(ctx, row, upstreamCols) 186 if err != nil { 187 return false, err 188 } 189 r := chunk.MutRowFromDatums(data).ToRow() 190 191 d, err := expr.Eval(ctx.GetExprCtx().GetEvalCtx(), r) 192 if err != nil { 193 return false, err 194 } 195 return d.GetInt64() == 1, nil 196 } 197 198 // getSimpleExprOfTable returns an expression of given `expr` string, using the table structure that is tracked before. 199 func getSimpleExprOfTable(ctx sessionctx.Context, expr string, ti *model.TableInfo, logger log.Logger) (expression.Expression, error) { 200 // TODO: use upstream timezone? 201 e, err := expression.ParseSimpleExprWithTableInfo(ctx.GetExprCtx(), expr, ti) 202 if err != nil { 203 // if expression contains an unknown column, we return an expression that skips nothing 204 if plannererrors.ErrUnknownColumn.Equal(err) { 205 logger.Warn("meet unknown column when generating expression, return a FALSE expression instead", 206 zap.String("expression", expr), 207 zap.Error(err)) 208 e = expression.NewZero() 209 } else { 210 return nil, err 211 } 212 } 213 214 return e, nil 215 }