github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/build_constraint_util.go (about) 1 // Copyright 2022 Matrix Origin 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 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package plan 16 17 import ( 18 "context" 19 "fmt" 20 21 "github.com/google/uuid" 22 23 "github.com/matrixorigin/matrixone/pkg/catalog" 24 "github.com/matrixorigin/matrixone/pkg/common/moerr" 25 "github.com/matrixorigin/matrixone/pkg/config" 26 "github.com/matrixorigin/matrixone/pkg/container/batch" 27 "github.com/matrixorigin/matrixone/pkg/container/types" 28 "github.com/matrixorigin/matrixone/pkg/container/vector" 29 "github.com/matrixorigin/matrixone/pkg/defines" 30 "github.com/matrixorigin/matrixone/pkg/pb/plan" 31 "github.com/matrixorigin/matrixone/pkg/pb/timestamp" 32 "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" 33 "github.com/matrixorigin/matrixone/pkg/sql/plan/function" 34 "github.com/matrixorigin/matrixone/pkg/sql/util" 35 ) 36 37 const ( 38 derivedTableName = "_t" 39 defaultmaxRowThenUnusePkFilterExpr = 1024 40 ) 41 42 type dmlSelectInfo struct { 43 typ string 44 45 projectList []*Expr 46 tblInfo *dmlTableInfo 47 idx int32 48 rootId int32 49 derivedTableId int32 50 51 onDuplicateIdx []int32 52 onDuplicateExpr map[string]*Expr 53 onDuplicateNeedAgg bool // if table have pk & unique key, that will be true. 54 onDuplicateIsIgnore bool 55 } 56 57 type dmlTableInfo struct { 58 typ string 59 objRef []*ObjectRef 60 tableDefs []*TableDef 61 isClusterTable []bool 62 haveConstraint bool 63 isMulti bool 64 needAggFilter bool 65 updateKeys []map[string]tree.Expr // This slice index correspond to tableDefs 66 oldColPosMap []map[string]int // origin table values to their position in derived table 67 newColPosMap []map[string]int // insert/update values to their position in derived table 68 nameToIdx map[string]int // Mapping of table full path name to tableDefs index,such as: 'tpch.nation -> 0' 69 idToName map[uint64]string // Mapping of tableId to full path name of table 70 alias map[string]int // Mapping of table aliases to tableDefs array index,If there is no alias, replace it with the original name of the table 71 } 72 73 var constTextType plan.Type 74 75 func init() { 76 typ := types.T_text.ToType() 77 constTextType = makePlan2Type(&typ) 78 } 79 80 func getAliasToName(ctx CompilerContext, expr tree.TableExpr, alias string, aliasMap map[string][2]string) { 81 switch t := expr.(type) { 82 case *tree.TableName: 83 dbName := string(t.SchemaName) 84 if dbName == "" { 85 dbName = ctx.DefaultDatabase() 86 } 87 tblName := string(t.ObjectName) 88 if alias != "" { 89 aliasMap[alias] = [2]string{dbName, tblName} 90 } 91 case *tree.AliasedTableExpr: 92 alias := string(t.As.Alias) 93 getAliasToName(ctx, t.Expr, alias, aliasMap) 94 case *tree.JoinTableExpr: 95 getAliasToName(ctx, t.Left, alias, aliasMap) 96 getAliasToName(ctx, t.Right, alias, aliasMap) 97 } 98 } 99 100 func getUpdateTableInfo(ctx CompilerContext, stmt *tree.Update) (*dmlTableInfo, error) { 101 tblInfo, err := getDmlTableInfo(ctx, stmt.Tables, stmt.With, nil, "update") 102 if err != nil { 103 return nil, err 104 } 105 106 // check update field and set updateKeys 107 usedTbl := make(map[string]map[string]tree.Expr) 108 allColumns := make(map[string]map[string]struct{}) 109 for alias, idx := range tblInfo.alias { 110 allColumns[alias] = make(map[string]struct{}) 111 for _, col := range tblInfo.tableDefs[idx].Cols { 112 allColumns[alias][col.Name] = struct{}{} 113 } 114 } 115 116 appendToTbl := func(table, column string, expr tree.Expr) { 117 if _, exists := usedTbl[table]; !exists { 118 usedTbl[table] = make(map[string]tree.Expr) 119 } 120 usedTbl[table][column] = expr 121 } 122 123 for _, updateExpr := range stmt.Exprs { 124 if len(updateExpr.Names) > 1 { 125 return nil, moerr.NewNYI(ctx.GetContext(), "unsupport expr") 126 } 127 parts := updateExpr.Names[0] 128 expr := updateExpr.Expr 129 if parts.NumParts > 1 { 130 colName := parts.Parts[0] 131 tblName := parts.Parts[1] 132 if _, tblExists := tblInfo.alias[tblName]; tblExists { 133 if _, colExists := allColumns[tblName][colName]; colExists { 134 appendToTbl(tblName, colName, expr) 135 } else { 136 return nil, moerr.NewInternalError(ctx.GetContext(), "column '%v' not found in table %s", colName, tblName) 137 } 138 } else { 139 return nil, moerr.NewNoSuchTable(ctx.GetContext(), "", tblName) 140 } 141 } else { 142 colName := parts.Parts[0] 143 tblName := "" 144 found := false 145 for alias, colulmns := range allColumns { 146 if _, colExists := colulmns[colName]; colExists { 147 if tblName != "" { 148 return nil, moerr.NewInternalError(ctx.GetContext(), "Column '%v' in field list is ambiguous", colName) 149 } 150 found = true 151 appendToTbl(alias, colName, expr) 152 } 153 } 154 if !found && stmt.With != nil { 155 var str string 156 for i, c := range stmt.With.CTEs { 157 if i > 0 { 158 str += ", " 159 } 160 str += string(c.Name.Alias) 161 } 162 return nil, moerr.NewInternalError(ctx.GetContext(), "column '%v' not found in table or the target table %s of the UPDATE is not updatable", colName, str) 163 } else if !found { 164 return nil, moerr.NewInternalError(ctx.GetContext(), "column '%v' not found in table %s", colName, tblName) 165 } 166 } 167 } 168 169 // remove unused table 170 newTblInfo := &dmlTableInfo{ 171 nameToIdx: make(map[string]int), 172 idToName: make(map[uint64]string), 173 alias: make(map[string]int), 174 isMulti: tblInfo.isMulti, 175 needAggFilter: tblInfo.needAggFilter, 176 } 177 for alias, columns := range usedTbl { 178 idx := tblInfo.alias[alias] 179 tblDef := tblInfo.tableDefs[idx] 180 newTblInfo.objRef = append(newTblInfo.objRef, tblInfo.objRef[idx]) 181 newTblInfo.tableDefs = append(newTblInfo.tableDefs, tblDef) 182 newTblInfo.isClusterTable = append(newTblInfo.isClusterTable, tblInfo.isClusterTable[idx]) 183 newTblInfo.alias[alias] = len(newTblInfo.tableDefs) - 1 184 newTblInfo.updateKeys = append(newTblInfo.updateKeys, columns) 185 186 if !newTblInfo.haveConstraint { 187 if len(tblDef.RefChildTbls) > 0 { 188 newTblInfo.haveConstraint = true 189 } else if len(tblDef.Fkeys) > 0 { 190 newTblInfo.haveConstraint = true 191 } else { 192 for _, indexdef := range tblDef.Indexes { 193 if indexdef.Unique { 194 newTblInfo.haveConstraint = true 195 break 196 } 197 } 198 } 199 } 200 } 201 for idx, ref := range newTblInfo.objRef { 202 key := ref.SchemaName + "." + ref.ObjName 203 newTblInfo.idToName[newTblInfo.tableDefs[idx].TblId] = key 204 newTblInfo.nameToIdx[key] = idx 205 } 206 207 return newTblInfo, nil 208 } 209 210 func setTableExprToDmlTableInfo(ctx CompilerContext, tbl tree.TableExpr, tblInfo *dmlTableInfo, aliasMap map[string][2]string, withMap map[string]struct{}) error { 211 var tblName, dbName, alias string 212 213 if aliasTbl, ok := tbl.(*tree.AliasedTableExpr); ok { 214 alias = string(aliasTbl.As.Alias) 215 tbl = aliasTbl.Expr 216 } 217 218 if joinTbl, ok := tbl.(*tree.JoinTableExpr); ok { 219 tblInfo.needAggFilter = true 220 err := setTableExprToDmlTableInfo(ctx, joinTbl.Left, tblInfo, aliasMap, withMap) 221 if err != nil { 222 return err 223 } 224 if joinTbl.Right != nil { 225 return setTableExprToDmlTableInfo(ctx, joinTbl.Right, tblInfo, aliasMap, withMap) 226 } 227 return nil 228 } 229 230 if baseTbl, ok := tbl.(*tree.TableName); ok { 231 tblName = string(baseTbl.ObjectName) 232 dbName = string(baseTbl.SchemaName) 233 } 234 235 if _, exist := withMap[tblName]; exist { 236 return nil 237 } 238 239 if aliasNames, exist := aliasMap[tblName]; exist { 240 alias = tblName // work in delete statement 241 dbName = aliasNames[0] 242 tblName = aliasNames[1] 243 } 244 245 if tblName == "" { 246 return nil 247 } 248 249 if dbName == "" { 250 dbName = ctx.DefaultDatabase() 251 } 252 253 // snapshot to fix 254 obj, tableDef := ctx.Resolve(dbName, tblName, Snapshot{TS: ×tamp.Timestamp{}}) 255 if tableDef == nil { 256 return moerr.NewNoSuchTable(ctx.GetContext(), dbName, tblName) 257 } 258 259 if tableDef.TableType == catalog.SystemSourceRel { 260 return moerr.NewInvalidInput(ctx.GetContext(), "cannot insert/update/delete from source") 261 } else if tableDef.TableType == catalog.SystemExternalRel { 262 return moerr.NewInvalidInput(ctx.GetContext(), "cannot insert/update/delete from external table") 263 } else if tableDef.TableType == catalog.SystemViewRel { 264 return moerr.NewInvalidInput(ctx.GetContext(), "cannot insert/update/delete from view") 265 } else if tableDef.TableType == catalog.SystemSequenceRel && ctx.GetContext().Value(defines.BgKey{}) == nil { 266 return moerr.NewInvalidInput(ctx.GetContext(), "Cannot insert/update/delete from sequence") 267 } 268 269 var newCols []*ColDef 270 for _, col := range tableDef.Cols { 271 if col.Hidden && tblInfo.typ == "insert" { 272 if col.Name == catalog.FakePrimaryKeyColName { 273 // fake pk is auto increment, need to fill. 274 // TODO(fagongzi): we need to use a separate tag to mark the columns 275 // for these behaviors, instead of using column names, which needs to 276 // be changed after 0.8 277 newCols = append(newCols, col) 278 } 279 } else { 280 newCols = append(newCols, col) 281 } 282 } 283 // note: the `rowId` column has been excluded from `TableDef` in the `insert` statement 284 tableDef.Cols = newCols 285 286 isClusterTable := util.TableIsClusterTable(tableDef.GetTableType()) 287 accountId, err := ctx.GetAccountId() 288 if err != nil { 289 return err 290 } 291 if isClusterTable && accountId != catalog.System_Account { 292 return moerr.NewInternalError(ctx.GetContext(), "only the sys account can insert/update/delete the cluster table") 293 } 294 295 if util.TableIsClusterTable(tableDef.GetTableType()) && accountId != catalog.System_Account { 296 return moerr.NewInternalError(ctx.GetContext(), "only the sys account can insert/update/delete the cluster table %s", tableDef.GetName()) 297 } 298 if obj.PubInfo != nil { 299 return moerr.NewInternalError(ctx.GetContext(), "cannot insert/update/delete from public table") 300 } 301 302 if !tblInfo.haveConstraint { 303 if len(tableDef.RefChildTbls) > 0 { 304 tblInfo.haveConstraint = true 305 } else if len(tableDef.Fkeys) > 0 { 306 tblInfo.haveConstraint = true 307 } else { 308 for _, indexdef := range tableDef.Indexes { 309 if indexdef.Unique { 310 tblInfo.haveConstraint = true 311 break 312 } 313 } 314 } 315 } 316 317 nowIdx := len(tblInfo.tableDefs) 318 tblInfo.isClusterTable = append(tblInfo.isClusterTable, isClusterTable) 319 tblInfo.objRef = append(tblInfo.objRef, &ObjectRef{ 320 Obj: int64(tableDef.TblId), 321 SchemaName: dbName, 322 ObjName: tblName, 323 }) 324 tblInfo.tableDefs = append(tblInfo.tableDefs, tableDef) 325 key := dbName + "." + tblName 326 tblInfo.nameToIdx[key] = nowIdx 327 tblInfo.idToName[tableDef.TblId] = key 328 if alias == "" { 329 alias = tblName 330 } 331 tblInfo.alias[alias] = nowIdx 332 333 return nil 334 } 335 336 func getDmlTableInfo(ctx CompilerContext, tableExprs tree.TableExprs, with *tree.With, aliasMap map[string][2]string, typ string) (*dmlTableInfo, error) { 337 tblInfo := &dmlTableInfo{ 338 typ: typ, 339 nameToIdx: make(map[string]int), 340 idToName: make(map[uint64]string), 341 alias: make(map[string]int), 342 } 343 344 cteMap := make(map[string]struct{}) 345 if with != nil { 346 for _, cte := range with.CTEs { 347 cteMap[string(cte.Name.Alias)] = struct{}{} 348 } 349 } 350 351 for _, tbl := range tableExprs { 352 err := setTableExprToDmlTableInfo(ctx, tbl, tblInfo, aliasMap, cteMap) 353 if err != nil { 354 return nil, err 355 } 356 } 357 tblInfo.isMulti = len(tblInfo.objRef) > 1 358 tblInfo.needAggFilter = tblInfo.needAggFilter || tblInfo.isMulti 359 360 return tblInfo, nil 361 } 362 363 func initInsertStmt(builder *QueryBuilder, bindCtx *BindContext, stmt *tree.Insert, info *dmlSelectInfo) (bool, map[string]bool, error) { 364 var err error 365 var syntaxHasColumnNames bool 366 var insertColumns []string 367 tableDef := info.tblInfo.tableDefs[0] 368 tableObjRef := info.tblInfo.objRef[0] 369 colToIdx := make(map[string]int) 370 oldColPosMap := make(map[string]int) 371 tableDef.Name2ColIndex = make(map[string]int32) 372 for i, col := range tableDef.Cols { 373 colToIdx[col.Name] = i 374 oldColPosMap[col.Name] = i 375 tableDef.Name2ColIndex[col.Name] = int32(i) 376 } 377 info.tblInfo.oldColPosMap = append(info.tblInfo.oldColPosMap, oldColPosMap) 378 info.tblInfo.newColPosMap = append(info.tblInfo.newColPosMap, oldColPosMap) 379 380 ifExistAutoPkCol := false 381 insertWithoutUniqueKeyMap := make(map[string]bool) 382 383 if insertColumns, err = getInsertColsFromStmt(builder.GetContext(), stmt, tableDef); err != nil { 384 return false, nil, err 385 } 386 if stmt.Columns != nil { 387 syntaxHasColumnNames = true 388 } 389 390 var astSlt *tree.Select 391 switch slt := stmt.Rows.Select.(type) { 392 // rewrite 'insert into tbl values (1,1)' to 'insert into tbl select * from (values row(1,1))' 393 case *tree.ValuesClause: 394 isAllDefault := false 395 if slt.Rows[0] == nil { 396 isAllDefault = true 397 } 398 if isAllDefault { 399 for j, row := range slt.Rows { 400 if row != nil { 401 return false, nil, moerr.NewWrongValueCountOnRow(builder.GetContext(), j+1) 402 } 403 } 404 } else { 405 colCount := len(insertColumns) 406 for j, row := range slt.Rows { 407 if len(row) != colCount { 408 return false, nil, moerr.NewWrongValueCountOnRow(builder.GetContext(), j+1) 409 } 410 } 411 } 412 413 // example1:insert into a values (); 414 // but it does not work at the case: 415 // insert into a(a) values (); insert into a values (0),(); 416 if isAllDefault && syntaxHasColumnNames { 417 return false, nil, moerr.NewInvalidInput(builder.GetContext(), "insert values does not match the number of columns") 418 } 419 err = buildValueScan(isAllDefault, info, builder, bindCtx, tableDef, slt, insertColumns, colToIdx, stmt.OnDuplicateUpdate) 420 if err != nil { 421 return false, nil, err 422 } 423 424 case *tree.SelectClause: 425 astSlt = stmt.Rows 426 427 subCtx := NewBindContext(builder, bindCtx) 428 info.rootId, err = builder.buildSelect(astSlt, subCtx, false) 429 if err != nil { 430 return false, nil, err 431 } 432 433 case *tree.ParenSelect: 434 astSlt = slt.Select 435 436 subCtx := NewBindContext(builder, bindCtx) 437 info.rootId, err = builder.buildSelect(astSlt, subCtx, false) 438 if err != nil { 439 return false, nil, err 440 } 441 442 default: 443 return false, nil, moerr.NewInvalidInput(builder.GetContext(), "insert has unknown select statement") 444 } 445 446 err = builder.addBinding(info.rootId, tree.AliasClause{ 447 Alias: derivedTableName, 448 }, bindCtx) 449 if err != nil { 450 return false, nil, err 451 } 452 453 lastNode := builder.qry.Nodes[info.rootId] 454 if len(insertColumns) != len(lastNode.ProjectList) { 455 return false, nil, moerr.NewInvalidInput(builder.GetContext(), "insert values does not match the number of columns") 456 } 457 458 tag := builder.qry.Nodes[info.rootId].BindingTags[0] 459 info.derivedTableId = info.rootId 460 oldProject := append([]*Expr{}, lastNode.ProjectList...) 461 462 insertColToExpr := make(map[string]*Expr) 463 for i, column := range insertColumns { 464 colIdx := colToIdx[column] 465 projExpr := &plan.Expr{ 466 Typ: oldProject[i].Typ, 467 Expr: &plan.Expr_Col{ 468 Col: &plan.ColRef{ 469 RelPos: tag, 470 ColPos: int32(i), 471 }, 472 }, 473 } 474 if tableDef.Cols[colIdx].Typ.Id == int32(types.T_enum) { 475 projExpr, err = funcCastForEnumType(builder.GetContext(), projExpr, tableDef.Cols[colIdx].Typ) 476 if err != nil { 477 return false, nil, err 478 } 479 } else { 480 projExpr, err = forceCastExpr(builder.GetContext(), projExpr, tableDef.Cols[colIdx].Typ) 481 if err != nil { 482 return false, nil, err 483 } 484 } 485 insertColToExpr[column] = projExpr 486 } 487 488 // create table t(a int, b int unique key); 489 // insert into t(a) values (1); -> isInsertWithoutUniqueKey = true, then we do not need a plan to insert unique_key_hidden_table; 490 // create table t(a int, b int unique key auto_increment) -> isInsertWithoutUniqueKey is allways false 491 // create table t(a int, b int unique key default 10) -> isInsertWithoutUniqueKey is allways false 492 for _, idx := range tableDef.Indexes { 493 if idx.Unique { 494 withoutUniqueCol := true 495 for _, name := range idx.Parts { 496 _, ok := insertColToExpr[name] 497 if ok { 498 withoutUniqueCol = false 499 break 500 } else { 501 // insert without unique 502 // then need check col is not auto_incr & default is not null 503 col := tableDef.Cols[tableDef.Name2ColIndex[name]] 504 if col.Typ.AutoIncr || (col.Default.Expr != nil && !isNullExpr(col.Default.Expr)) { 505 withoutUniqueCol = false 506 break 507 } 508 } 509 } 510 insertWithoutUniqueKeyMap[idx.IndexName] = withoutUniqueCol 511 } 512 } 513 514 // have tables : t1(a default 0, b int, pk(a,b)) , t2(j int,k int) 515 // rewrite 'insert into t1 select * from t2' to 516 // select 'select _t.j, _t.k from (select * from t2) _t(j,k) 517 // -------- 518 // rewrite 'insert into t1(b) values (1)' to 519 // select 'select 0, _t.column_0 from (select * from values (1)) _t(column_0) 520 projectList := make([]*Expr, 0, len(tableDef.Cols)) 521 for _, col := range tableDef.Cols { 522 if oldExpr, exists := insertColToExpr[col.Name]; exists { 523 projectList = append(projectList, oldExpr) 524 } else { 525 defExpr, err := getDefaultExpr(builder.GetContext(), col) 526 if err != nil { 527 return false, nil, err 528 } 529 530 if col.Typ.AutoIncr && col.Name == tableDef.Pkey.PkeyColName { 531 ifExistAutoPkCol = true 532 } 533 534 projectList = append(projectList, defExpr) 535 } 536 } 537 538 // append ProjectNode 539 projectCtx := NewBindContext(builder, bindCtx) 540 lastTag := builder.genNewTag() 541 info.rootId = builder.appendNode(&plan.Node{ 542 NodeType: plan.Node_PROJECT, 543 ProjectList: projectList, 544 Children: []int32{info.rootId}, 545 BindingTags: []int32{lastTag}, 546 }, projectCtx) 547 548 info.projectList = make([]*Expr, 0, len(projectList)) 549 info.derivedTableId = info.rootId 550 for i, e := range projectList { 551 info.projectList = append(info.projectList, &plan.Expr{ 552 Typ: e.Typ, 553 Expr: &plan.Expr_Col{ 554 Col: &plan.ColRef{ 555 RelPos: lastTag, 556 ColPos: int32(i), 557 }, 558 }, 559 }) 560 } 561 info.idx = int32(len(info.projectList)) 562 563 // if insert with on duplicate key . need append a join node 564 // create table t1 (a int primary key, b int unique key, c int); 565 // insert into t1 values (1,1,3),(2,2,3) on duplicate key update a=a+1, b=b-2; 566 // rewrite to : select _t.*, t1.a, t1.b,t1.c, t1.row_id from 567 // (select * from values (1,1,3),(2,2,3)) _t(a,b,c) left join t1 on _t.a=t1.a or _t.b=t1.b 568 if len(stmt.OnDuplicateUpdate) > 0 { 569 isIgnore := len(stmt.OnDuplicateUpdate) == 1 && stmt.OnDuplicateUpdate[0] == nil 570 if isIgnore { 571 stmt.OnDuplicateUpdate = nil 572 } 573 574 rightTableDef := DeepCopyTableDef(tableDef, true) 575 rightObjRef := DeepCopyObjectRef(tableObjRef) 576 uniqueCols := GetUniqueColAndIdxFromTableDef(rightTableDef) 577 if rightTableDef.Pkey != nil && rightTableDef.Pkey.PkeyColName == catalog.CPrimaryKeyColName { 578 // rightTableDef.Cols = append(rightTableDef.Cols, MakeHiddenColDefByName(catalog.CPrimaryKeyColName)) 579 rightTableDef.Cols = append(rightTableDef.Cols, rightTableDef.Pkey.CompPkeyCol) 580 } 581 if rightTableDef.ClusterBy != nil && util.JudgeIsCompositeClusterByColumn(rightTableDef.ClusterBy.Name) { 582 // rightTableDef.Cols = append(rightTableDef.Cols, MakeHiddenColDefByName(rightTableDef.ClusterBy.Name)) 583 rightTableDef.Cols = append(rightTableDef.Cols, rightTableDef.ClusterBy.CompCbkeyCol) 584 } 585 rightTableDef.Cols = append(rightTableDef.Cols, MakeRowIdColDef()) 586 rightTableDef.Name2ColIndex = map[string]int32{} 587 for i, col := range rightTableDef.Cols { 588 rightTableDef.Name2ColIndex[col.Name] = int32(i) 589 } 590 591 // if table have unique columns, we do the rewrite. if not, do nothing(do not throw error) 592 if len(uniqueCols) > 0 { 593 594 joinCtx := NewBindContext(builder, bindCtx) 595 rightCtx := NewBindContext(builder, joinCtx) 596 rightId := builder.appendNode(&plan.Node{ 597 NodeType: plan.Node_TABLE_SCAN, 598 ObjRef: rightObjRef, 599 TableDef: rightTableDef, 600 BindingTags: []int32{builder.genNewTag()}, 601 }, rightCtx) 602 rightTag := builder.qry.Nodes[rightId].BindingTags[0] 603 baseNodeTag := builder.qry.Nodes[info.rootId].BindingTags[0] 604 605 // get update cols 606 updateCols := make(map[string]tree.Expr) 607 for _, updateExpr := range stmt.OnDuplicateUpdate { 608 col := updateExpr.Names[0].Parts[0] 609 updateCols[col] = updateExpr.Expr 610 } 611 612 var defExpr *Expr 613 idxs := make([]int32, len(rightTableDef.Cols)) 614 updateExprs := make(map[string]*Expr) 615 for i, col := range rightTableDef.Cols { 616 info.idx = info.idx + 1 617 idxs[i] = info.idx 618 if updateExpr, exists := updateCols[col.Name]; exists { 619 binder := NewUpdateBinder(builder.GetContext(), nil, nil, rightTableDef.Cols) 620 binder.builder = builder 621 if _, ok := updateExpr.(*tree.DefaultVal); ok { 622 defExpr, err = getDefaultExpr(builder.GetContext(), col) 623 if err != nil { 624 return false, nil, err 625 } 626 } else { 627 defExpr, err = binder.BindExpr(updateExpr, 0, true) 628 if err != nil { 629 return false, nil, err 630 } 631 } 632 defExpr, err = forceCastExpr(builder.GetContext(), defExpr, col.Typ) 633 if err != nil { 634 return false, nil, err 635 } 636 updateExprs[col.Name] = defExpr 637 } 638 info.projectList = append(info.projectList, &plan.Expr{ 639 Typ: col.Typ, 640 Expr: &plan.Expr_Col{ 641 Col: &plan.ColRef{ 642 RelPos: rightTag, 643 ColPos: int32(i), 644 }, 645 }, 646 }) 647 } 648 649 // get join condition 650 var joinConds *Expr 651 joinIdx := 0 652 for _, uniqueColMap := range uniqueCols { 653 var condExpr *Expr 654 condIdx := int(0) 655 for _, colIdx := range uniqueColMap { 656 col := rightTableDef.Cols[colIdx] 657 leftExpr := &Expr{ 658 Typ: col.Typ, 659 Expr: &plan.Expr_Col{ 660 Col: &plan.ColRef{ 661 RelPos: baseNodeTag, 662 ColPos: int32(colIdx), 663 }, 664 }, 665 } 666 rightExpr := &plan.Expr{ 667 Typ: col.Typ, 668 Expr: &plan.Expr_Col{ 669 Col: &plan.ColRef{ 670 RelPos: rightTag, 671 ColPos: int32(colIdx), 672 }, 673 }, 674 } 675 eqExpr, err := BindFuncExprImplByPlanExpr(builder.GetContext(), "=", []*Expr{leftExpr, rightExpr}) 676 if err != nil { 677 return false, nil, err 678 } 679 if condIdx == 0 { 680 condExpr = eqExpr 681 } else { 682 condExpr, err = BindFuncExprImplByPlanExpr(builder.GetContext(), "and", []*Expr{condExpr, eqExpr}) 683 if err != nil { 684 return false, nil, err 685 } 686 } 687 condIdx++ 688 } 689 690 if joinIdx == 0 { 691 joinConds = condExpr 692 } else { 693 joinConds, err = BindFuncExprImplByPlanExpr(builder.GetContext(), "or", []*Expr{joinConds, condExpr}) 694 if err != nil { 695 return false, nil, err 696 } 697 } 698 joinIdx++ 699 } 700 701 // append join node 702 leftCtx := builder.ctxByNode[info.rootId] 703 err = joinCtx.mergeContexts(builder.GetContext(), leftCtx, rightCtx) 704 if err != nil { 705 return false, nil, err 706 } 707 newRootId := builder.appendNode(&plan.Node{ 708 NodeType: plan.Node_JOIN, 709 Children: []int32{info.rootId, rightId}, 710 JoinType: plan.Node_LEFT, 711 OnList: []*Expr{joinConds}, 712 }, joinCtx) 713 bindCtx.binder = NewTableBinder(builder, bindCtx) 714 info.rootId = newRootId 715 info.onDuplicateIdx = idxs 716 info.onDuplicateExpr = updateExprs 717 info.onDuplicateNeedAgg = len(uniqueCols) > 1 718 info.onDuplicateIsIgnore = isIgnore 719 720 // append ProjectNode 721 info.rootId = builder.appendNode(&plan.Node{ 722 NodeType: plan.Node_PROJECT, 723 ProjectList: info.projectList, 724 Children: []int32{info.rootId}, 725 BindingTags: []int32{builder.genNewTag()}, 726 }, bindCtx) 727 bindCtx.results = info.projectList 728 } 729 } 730 731 return ifExistAutoPkCol, insertWithoutUniqueKeyMap, nil 732 } 733 734 func deleteToSelect(builder *QueryBuilder, bindCtx *BindContext, node *tree.Delete, haveConstraint bool, tblInfo *dmlTableInfo) (int32, error) { 735 var selectList []tree.SelectExpr 736 fromTables := &tree.From{} 737 738 getResolveExpr := func(alias string) { 739 var ret *tree.UnresolvedName 740 if haveConstraint { 741 defIdx := tblInfo.alias[alias] 742 for _, col := range tblInfo.tableDefs[defIdx].Cols { 743 ret, _ = tree.NewUnresolvedName(builder.GetContext(), alias, col.Name) 744 selectList = append(selectList, tree.SelectExpr{ 745 Expr: ret, 746 }) 747 } 748 } else { 749 defIdx := tblInfo.alias[alias] 750 ret, _ = tree.NewUnresolvedName(builder.GetContext(), alias, catalog.Row_ID) 751 selectList = append(selectList, tree.SelectExpr{ 752 Expr: ret, 753 }) 754 pkName := getTablePriKeyName(tblInfo.tableDefs[defIdx].Pkey) 755 if pkName != "" { 756 ret, _ = tree.NewUnresolvedName(builder.GetContext(), alias, pkName) 757 selectList = append(selectList, tree.SelectExpr{ 758 Expr: ret, 759 }) 760 } 761 } 762 } 763 764 for _, tbl := range node.Tables { 765 if aliasTbl, ok := tbl.(*tree.AliasedTableExpr); ok { 766 alias := string(aliasTbl.As.Alias) 767 if alias != "" { 768 getResolveExpr(alias) 769 } else { 770 astTbl := aliasTbl.Expr.(*tree.TableName) 771 getResolveExpr(string(astTbl.ObjectName)) 772 } 773 } else if astTbl, ok := tbl.(*tree.TableName); ok { 774 getResolveExpr(string(astTbl.ObjectName)) 775 } 776 } 777 778 if node.TableRefs != nil { 779 fromTables.Tables = node.TableRefs 780 } else { 781 fromTables.Tables = node.Tables 782 } 783 784 astSelect := &tree.Select{ 785 Select: &tree.SelectClause{ 786 Distinct: false, 787 Exprs: selectList, 788 From: fromTables, 789 Where: node.Where, 790 }, 791 OrderBy: node.OrderBy, 792 Limit: node.Limit, 793 With: node.With, 794 } 795 // ftCtx := tree.NewFmtCtx(dialectType) 796 // astSelect.Format(ftCtx) 797 // sql := ftCtx.String() 798 // fmt.Print(sql) 799 800 return builder.buildSelect(astSelect, bindCtx, false) 801 } 802 803 func checkNotNull(ctx context.Context, expr *Expr, tableDef *TableDef, col *ColDef) error { 804 isConstantNull := false 805 if ef, ok := expr.Expr.(*plan.Expr_Lit); ok { 806 isConstantNull = ef.Lit.Isnull 807 } 808 if !isConstantNull { 809 return nil 810 } 811 if col.Default != nil && !col.Default.NullAbility { 812 return moerr.NewConstraintViolation(ctx, fmt.Sprintf("Column '%s' cannot be null", col.Name)) 813 } 814 815 // if col.NotNull { 816 // return moerr.NewConstraintViolation(ctx, fmt.Sprintf("Column '%s' cannot be null", col.Name)) 817 // } 818 819 // if (col.Primary && !col.Typ.AutoIncr) || 820 // (col.Default != nil && !col.Default.NullAbility) { 821 // return moerr.NewConstraintViolation(ctx, fmt.Sprintf("Column '%s' cannot be null", col.Name)) 822 // } 823 824 // if tableDef.Pkey != nil && len(tableDef.Pkey.Names) > 1 { 825 // names := tableDef.Pkey.Names 826 // for _, name := range names { 827 // if name == col.Name { 828 // return moerr.NewConstraintViolation(ctx, fmt.Sprintf("Column '%s' cannot be null", name)) 829 // } 830 // } 831 // } 832 833 return nil 834 } 835 836 var ForceCastExpr = forceCastExpr 837 838 func forceCastExpr2(ctx context.Context, expr *Expr, t2 types.Type, targetType *plan.Expr) (*Expr, error) { 839 if targetType.Typ.Id == 0 { 840 return expr, nil 841 } 842 t1 := makeTypeByPlan2Expr(expr) 843 if t1.Eq(t2) { 844 return expr, nil 845 } 846 847 targetType.Typ.NotNullable = expr.Typ.NotNullable 848 fGet, err := function.GetFunctionByName(ctx, "cast", []types.Type{t1, t2}) 849 if err != nil { 850 return nil, err 851 } 852 return &plan.Expr{ 853 Expr: &plan.Expr_F{ 854 F: &plan.Function{ 855 Func: &ObjectRef{Obj: fGet.GetEncodedOverloadID(), ObjName: "cast"}, 856 Args: []*Expr{expr, targetType}, 857 }, 858 }, 859 Typ: targetType.Typ, 860 }, nil 861 } 862 863 func forceCastExpr(ctx context.Context, expr *Expr, targetType Type) (*Expr, error) { 864 if targetType.Id == 0 { 865 return expr, nil 866 } 867 t1, t2 := makeTypeByPlan2Expr(expr), makeTypeByPlan2Type(targetType) 868 if t1.Eq(t2) { 869 return expr, nil 870 } 871 872 targetType.NotNullable = expr.Typ.NotNullable 873 fGet, err := function.GetFunctionByName(ctx, "cast", []types.Type{t1, t2}) 874 if err != nil { 875 return nil, err 876 } 877 t := &plan.Expr{ 878 Typ: targetType, 879 Expr: &plan.Expr_T{ 880 T: &plan.TargetType{}, 881 }, 882 } 883 return &plan.Expr{ 884 Expr: &plan.Expr_F{ 885 F: &plan.Function{ 886 Func: &ObjectRef{Obj: fGet.GetEncodedOverloadID(), ObjName: "cast"}, 887 Args: []*Expr{expr, t}, 888 }, 889 }, 890 Typ: targetType, 891 }, nil 892 } 893 894 func buildValueScan( 895 isAllDefault bool, 896 info *dmlSelectInfo, 897 builder *QueryBuilder, 898 bindCtx *BindContext, 899 tableDef *TableDef, 900 slt *tree.ValuesClause, 901 updateColumns []string, 902 colToIdx map[string]int, 903 OnDuplicateUpdate tree.UpdateExprs, 904 ) error { 905 var err error 906 907 proc := builder.compCtx.GetProcess() 908 lastTag := builder.genNewTag() 909 colCount := len(updateColumns) 910 rowsetData := &plan.RowsetData{ 911 Cols: make([]*plan.ColData, colCount), 912 } 913 for i := 0; i < colCount; i++ { 914 rowsetData.Cols[i] = new(plan.ColData) 915 } 916 valueScanTableDef := &plan.TableDef{ 917 TblId: 0, 918 Name: "", 919 Cols: make([]*plan.ColDef, colCount), 920 } 921 projectList := make([]*Expr, colCount) 922 bat := batch.NewWithSize(len(updateColumns)) 923 924 for i, colName := range updateColumns { 925 col := tableDef.Cols[colToIdx[colName]] 926 colTyp := makeTypeByPlan2Type(col.Typ) 927 vec := proc.GetVector(colTyp) 928 bat.Vecs[i] = vec 929 targetTyp := &plan.Expr{ 930 Typ: col.Typ, 931 Expr: &plan.Expr_T{ 932 T: &plan.TargetType{}, 933 }, 934 } 935 var defExpr *Expr 936 if isAllDefault { 937 defExpr, err := getDefaultExpr(builder.GetContext(), col) 938 if err != nil { 939 return err 940 } 941 defExpr, err = forceCastExpr2(builder.GetContext(), defExpr, colTyp, targetTyp) 942 if err != nil { 943 return err 944 } 945 for j := range slt.Rows { 946 if err := vector.AppendBytes(vec, nil, true, proc.Mp()); err != nil { 947 bat.Clean(proc.Mp()) 948 return err 949 } 950 rowsetData.Cols[i].Data = append(rowsetData.Cols[i].Data, &plan.RowsetExpr{ 951 Pos: -1, 952 RowPos: int32(j), 953 Expr: defExpr, 954 }) 955 } 956 } else { 957 binder := NewDefaultBinder(builder.GetContext(), nil, nil, col.Typ, nil) 958 binder.builder = builder 959 for j, r := range slt.Rows { 960 if nv, ok := r[i].(*tree.NumVal); ok { 961 canInsert, err := util.SetInsertValue(proc, nv, vec) 962 if err != nil { 963 bat.Clean(proc.Mp()) 964 return err 965 } 966 if canInsert { 967 continue 968 } 969 } 970 971 if err := vector.AppendBytes(vec, nil, true, proc.Mp()); err != nil { 972 bat.Clean(proc.Mp()) 973 return err 974 } 975 if _, ok := r[i].(*tree.DefaultVal); ok { 976 defExpr, err = getDefaultExpr(builder.GetContext(), col) 977 if err != nil { 978 bat.Clean(proc.Mp()) 979 return err 980 } 981 } else if nv, ok := r[i].(*tree.ParamExpr); ok { 982 if !builder.isPrepareStatement { 983 bat.Clean(proc.Mp()) 984 return moerr.NewInvalidInput(builder.GetContext(), "only prepare statement can use ? expr") 985 } 986 rowsetData.Cols[i].Data = append(rowsetData.Cols[i].Data, &plan.RowsetExpr{ 987 RowPos: int32(j), 988 Pos: int32(nv.Offset), 989 Expr: &plan.Expr{ 990 Typ: constTextType, 991 Expr: &plan.Expr_P{ 992 P: &plan.ParamRef{ 993 Pos: int32(nv.Offset), 994 }, 995 }, 996 }, 997 }) 998 continue 999 } else { 1000 defExpr, err = binder.BindExpr(r[i], 0, true) 1001 if err != nil { 1002 bat.Clean(proc.Mp()) 1003 return err 1004 } 1005 if col.Typ.Id == int32(types.T_enum) { 1006 defExpr, err = funcCastForEnumType(builder.GetContext(), defExpr, col.Typ) 1007 if err != nil { 1008 bat.Clean(proc.Mp()) 1009 return err 1010 } 1011 } 1012 } 1013 defExpr, err = forceCastExpr2(builder.GetContext(), defExpr, colTyp, targetTyp) 1014 if err != nil { 1015 return err 1016 } 1017 if nv, ok := r[i].(*tree.ParamExpr); ok { 1018 if !builder.isPrepareStatement { 1019 bat.Clean(proc.Mp()) 1020 return moerr.NewInvalidInput(builder.GetContext(), "only prepare statement can use ? expr") 1021 } 1022 rowsetData.Cols[i].Data = append(rowsetData.Cols[i].Data, &plan.RowsetExpr{ 1023 RowPos: int32(j), 1024 Pos: int32(nv.Offset), 1025 Expr: defExpr, 1026 }) 1027 continue 1028 } 1029 rowsetData.Cols[i].Data = append(rowsetData.Cols[i].Data, &plan.RowsetExpr{ 1030 Pos: -1, 1031 RowPos: int32(j), 1032 Expr: defExpr, 1033 }) 1034 } 1035 } 1036 colName := fmt.Sprintf("column_%d", i) // like MySQL 1037 valueScanTableDef.Cols[i] = &plan.ColDef{ 1038 ColId: 0, 1039 Name: colName, 1040 Typ: col.Typ, 1041 } 1042 expr := &plan.Expr{ 1043 Typ: col.Typ, 1044 Expr: &plan.Expr_Col{ 1045 Col: &plan.ColRef{ 1046 RelPos: lastTag, 1047 ColPos: int32(i), 1048 }, 1049 }, 1050 } 1051 projectList[i] = expr 1052 } 1053 1054 onUpdateExprs := make([]*plan.Expr, 0) 1055 if builder.isPrepareStatement && !(len(OnDuplicateUpdate) == 1 && OnDuplicateUpdate[0] == nil) { 1056 for _, expr := range OnDuplicateUpdate { 1057 var updateExpr *plan.Expr 1058 col := tableDef.Cols[colToIdx[expr.Names[0].Parts[0]]] 1059 if nv, ok := expr.Expr.(*tree.ParamExpr); ok { 1060 updateExpr = &plan.Expr{ 1061 Typ: constTextType, 1062 Expr: &plan.Expr_P{ 1063 P: &plan.ParamRef{ 1064 Pos: int32(nv.Offset), 1065 }, 1066 }, 1067 } 1068 } else if nv, ok := expr.Expr.(*tree.FuncExpr); ok { 1069 if checkExprHasParamExpr(nv.Exprs) { 1070 binder := NewDefaultBinder(builder.GetContext(), nil, nil, col.Typ, nil) 1071 binder.builder = builder 1072 binder.ctx = bindCtx 1073 updateExpr, err = binder.BindExpr(nv, 0, true) 1074 if err != nil { 1075 return err 1076 } 1077 } 1078 } else if nv, ok := expr.Expr.(*tree.BinaryExpr); ok { 1079 if checkExprHasParamExpr([]tree.Expr{nv.Right}) { 1080 binder := NewDefaultBinder(builder.GetContext(), nil, nil, col.Typ, nil) 1081 binder.builder = builder 1082 binder.ctx = bindCtx 1083 updateExpr, err = binder.BindExpr(nv.Right, 0, true) 1084 if err != nil { 1085 return err 1086 } 1087 } 1088 } 1089 if updateExpr != nil { 1090 onUpdateExprs = append(onUpdateExprs, updateExpr) 1091 } 1092 } 1093 } 1094 bat.SetRowCount(len(slt.Rows)) 1095 rowsetData.RowCount = int32(len(slt.Rows)) 1096 nodeId, _ := uuid.NewV7() 1097 scanNode := &plan.Node{ 1098 NodeType: plan.Node_VALUE_SCAN, 1099 RowsetData: rowsetData, 1100 TableDef: valueScanTableDef, 1101 BindingTags: []int32{lastTag}, 1102 Uuid: nodeId[:], 1103 OnUpdateExprs: onUpdateExprs, 1104 } 1105 if builder.isPrepareStatement { 1106 proc.SetPrepareBatch(bat) 1107 } else { 1108 proc.SetValueScanBatch(nodeId, bat) 1109 } 1110 info.rootId = builder.appendNode(scanNode, bindCtx) 1111 err = builder.addBinding(info.rootId, tree.AliasClause{ 1112 Alias: "_ValueScan", 1113 }, bindCtx) 1114 if err != nil { 1115 return err 1116 } 1117 lastTag = builder.genNewTag() 1118 info.rootId = builder.appendNode(&plan.Node{ 1119 NodeType: plan.Node_PROJECT, 1120 ProjectList: projectList, 1121 Children: []int32{info.rootId}, 1122 BindingTags: []int32{lastTag}, 1123 }, bindCtx) 1124 return nil 1125 } 1126 1127 // if table have fk. then append join node & filter node 1128 // sink_scan -> join -> filter 1129 func appendForeignConstrantPlan( 1130 builder *QueryBuilder, 1131 bindCtx *BindContext, 1132 tableDef *TableDef, 1133 objRef *ObjectRef, 1134 sourceStep int32, 1135 isFkRecursionCall bool, 1136 ) error { 1137 enabled, err := IsForeignKeyChecksEnabled(builder.compCtx) 1138 if err != nil { 1139 return err 1140 } 1141 1142 if enabled && !isFkRecursionCall && len(tableDef.Fkeys) > 0 { 1143 lastNodeId := appendSinkScanNode(builder, bindCtx, sourceStep) 1144 1145 lastNodeId, err := appendJoinNodeForParentFkCheck(builder, bindCtx, objRef, tableDef, lastNodeId) 1146 if err != nil { 1147 return err 1148 } 1149 1150 // if the all fk are fk self refer, the lastNodeId is -1. 1151 // skip fk self refer here 1152 if lastNodeId >= 0 { 1153 lastNode := builder.qry.Nodes[lastNodeId] 1154 beginIdx := len(lastNode.ProjectList) - len(tableDef.Fkeys) 1155 1156 // get filter exprs 1157 rowIdTyp := types.T_Rowid.ToType() 1158 filters := make([]*Expr, len(tableDef.Fkeys)) 1159 errExpr := makePlan2StringConstExprWithType("Cannot add or update a child row: a foreign key constraint fails") 1160 for i := range tableDef.Fkeys { 1161 colExpr := &plan.Expr{ 1162 Typ: makePlan2Type(&rowIdTyp), 1163 Expr: &plan.Expr_Col{ 1164 Col: &plan.ColRef{ 1165 ColPos: int32(beginIdx + i), 1166 // Name: catalog.Row_ID, 1167 }, 1168 }, 1169 } 1170 nullCheckExpr, err := BindFuncExprImplByPlanExpr(builder.GetContext(), "isnotnull", []*Expr{colExpr}) 1171 if err != nil { 1172 return err 1173 } 1174 filterExpr, err := BindFuncExprImplByPlanExpr(builder.GetContext(), "assert", []*Expr{nullCheckExpr, errExpr}) 1175 if err != nil { 1176 return err 1177 } 1178 filters[i] = filterExpr 1179 } 1180 1181 // append filter node 1182 filterNode := &Node{ 1183 NodeType: plan.Node_FILTER, 1184 Children: []int32{lastNodeId}, 1185 FilterList: filters, 1186 ProjectList: getProjectionByLastNode(builder, lastNodeId), 1187 } 1188 lastNodeId = builder.appendNode(filterNode, bindCtx) 1189 1190 builder.appendStep(lastNodeId) 1191 } 1192 } 1193 return nil 1194 } 1195 1196 // sink_scan -> Fuzzyfilter 1197 // table_scan -----^ 1198 // there will be some cases that no need to check 1199 // 1200 // case 1: For SQL that contains on duplicate update 1201 // case 2: the only primary key is auto increment type 1202 func appendPrimaryConstrantPlan( 1203 builder *QueryBuilder, 1204 bindCtx *BindContext, 1205 tableDef *TableDef, 1206 objRef *ObjectRef, 1207 partitionExpr *Expr, 1208 pkFilterExprs []*Expr, 1209 indexSourceColTypes []*plan.Type, 1210 sourceStep int32, 1211 isUpdate bool, 1212 updatePkCol bool, 1213 fuzzymessage *OriginTableMessageForFuzzy, 1214 ) error { 1215 var lastNodeId int32 1216 var err error 1217 1218 // need more comments here to explain checkCondition, for example, why updatePkCol is needed 1219 // we should not checkInsertPkDup any more, insert into t values (1) checkInsertPkDup is false, however it may still conflict with pk already exists 1220 if pkPos, pkTyp := getPkPos(tableDef, true); pkPos != -1 { 1221 // needCheck := true 1222 needCheck := !builder.qry.LoadTag 1223 useFuzzyFilter := config.CNPrimaryCheck 1224 if isUpdate { 1225 needCheck = updatePkCol 1226 useFuzzyFilter = false 1227 } 1228 1229 // insert stmt or update pk col, we need check insert pk dup 1230 if needCheck && !useFuzzyFilter { 1231 // make plan: sink_scan -> group_by -> filter //check if pk is unique in rows 1232 lastNodeId = appendSinkScanNode(builder, bindCtx, sourceStep) 1233 pkColExpr := &plan.Expr{ 1234 Typ: pkTyp, 1235 Expr: &plan.Expr_Col{ 1236 Col: &plan.ColRef{ 1237 ColPos: int32(pkPos), 1238 Name: tableDef.Pkey.PkeyColName, 1239 }, 1240 }, 1241 } 1242 lastNodeId, err = appendAggCountGroupByColExpr(builder, bindCtx, lastNodeId, pkColExpr) 1243 if err != nil { 1244 return err 1245 } 1246 1247 countType := types.T_int64.ToType() 1248 countColExpr := &plan.Expr{ 1249 Typ: makePlan2TypeValue(&countType), 1250 Expr: &plan.Expr_Col{ 1251 Col: &plan.ColRef{ 1252 Name: tableDef.Pkey.PkeyColName, 1253 }, 1254 }, 1255 } 1256 1257 eqCheckExpr, err := BindFuncExprImplByPlanExpr(builder.GetContext(), "=", []*Expr{MakePlan2Int64ConstExprWithType(1), countColExpr}) 1258 if err != nil { 1259 return err 1260 } 1261 varcharType := types.T_varchar.ToType() 1262 varcharExpr, err := makePlan2CastExpr(builder.GetContext(), &Expr{ 1263 Typ: tableDef.Cols[pkPos].Typ, 1264 Expr: &plan.Expr_Col{ 1265 Col: &plan.ColRef{ColPos: 1, Name: tableDef.Cols[pkPos].Name}, 1266 }, 1267 }, makePlan2Type(&varcharType)) 1268 if err != nil { 1269 return err 1270 } 1271 colTypes := string("") 1272 for i := range indexSourceColTypes { 1273 if types.T(indexSourceColTypes[i].Id).IsDecimal() { 1274 colTypes = colTypes + string(byte(indexSourceColTypes[i].Scale)) 1275 } else { 1276 colTypes = colTypes + "0" 1277 } 1278 } 1279 filterExpr, err := BindFuncExprImplByPlanExpr(builder.GetContext(), "assert", []*Expr{eqCheckExpr, varcharExpr, makePlan2StringConstExprWithType(tableDef.Cols[pkPos].Name), makePlan2StringConstExprWithType(colTypes)}) 1280 if err != nil { 1281 return err 1282 } 1283 filterNode := &Node{ 1284 NodeType: plan.Node_FILTER, 1285 Children: []int32{lastNodeId}, 1286 FilterList: []*Expr{filterExpr}, 1287 IsEnd: true, 1288 } 1289 lastNodeId = builder.appendNode(filterNode, bindCtx) 1290 builder.appendStep(lastNodeId) 1291 } 1292 1293 if needCheck && useFuzzyFilter { 1294 rfTag := builder.genNewMsgTag() 1295 probeExpr := &plan.Expr{ 1296 Typ: pkTyp, 1297 Expr: &plan.Expr_Col{ 1298 Col: &plan.ColRef{ 1299 Name: tableDef.Pkey.PkeyColName, 1300 }, 1301 }, 1302 } 1303 // sink_scan 1304 sinkScanNode := &Node{ 1305 NodeType: plan.Node_SINK_SCAN, 1306 Stats: &plan.Stats{}, 1307 SourceStep: []int32{sourceStep}, 1308 ProjectList: []*Expr{ 1309 &plan.Expr{ 1310 Typ: pkTyp, 1311 Expr: &plan.Expr_Col{ 1312 Col: &plan.ColRef{ 1313 ColPos: int32(pkPos), 1314 Name: tableDef.Pkey.PkeyColName, 1315 }, 1316 }, 1317 }, 1318 }, 1319 } 1320 lastNodeId = builder.appendNode(sinkScanNode, bindCtx) 1321 1322 pkNameMap := make(map[string]int) 1323 for i, n := range tableDef.Pkey.Names { 1324 pkNameMap[n] = i 1325 } 1326 pkSize := len(tableDef.Pkey.Names) 1327 if pkSize > 1 { 1328 pkSize++ 1329 } 1330 scanTableDef := DeepCopyTableDef(tableDef, false) 1331 scanTableDef.Cols = make([]*ColDef, pkSize) 1332 for _, col := range tableDef.Cols { 1333 if i, ok := pkNameMap[col.Name]; ok { 1334 scanTableDef.Cols[i] = DeepCopyColDef(col) 1335 } else if col.Name == scanTableDef.Pkey.PkeyColName { 1336 scanTableDef.Cols[pkSize-1] = DeepCopyColDef(col) 1337 break 1338 } 1339 } 1340 1341 if scanTableDef.Partition != nil && partitionExpr != nil { 1342 scanTableDef.Partition.PartitionExpression = partitionExpr 1343 } 1344 1345 scanNode := &plan.Node{ 1346 NodeType: plan.Node_TABLE_SCAN, 1347 Stats: &plan.Stats{}, 1348 ObjRef: objRef, 1349 TableDef: scanTableDef, 1350 ProjectList: []*Expr{{ 1351 Typ: pkTyp, 1352 Expr: &plan.Expr_Col{ 1353 Col: &ColRef{ 1354 ColPos: int32(len(scanTableDef.Cols) - 1), 1355 Name: tableDef.Pkey.PkeyColName, 1356 }, 1357 }, 1358 }}, 1359 RuntimeFilterProbeList: []*plan.RuntimeFilterSpec{MakeRuntimeFilter(rfTag, false, 0, probeExpr)}, 1360 } 1361 1362 var tableScanId int32 1363 1364 if len(pkFilterExprs) > 0 { 1365 var blockFilterList []*Expr 1366 scanNode.FilterList = pkFilterExprs 1367 blockFilterList = make([]*Expr, len(pkFilterExprs)) 1368 for i, e := range pkFilterExprs { 1369 blockFilterList[i] = DeepCopyExpr(e) 1370 } 1371 tableScanId = builder.appendNode(scanNode, bindCtx) 1372 scanNode.BlockFilterList = blockFilterList 1373 scanNode.RuntimeFilterProbeList = nil // can not use both 1374 } else { 1375 tableScanId = builder.appendNode(scanNode, bindCtx) 1376 // temporary solution for the plan of dml go without optimizer 1377 // prevent table scan from running on multiple CNs. 1378 // because the runtime filter can only run on one now. 1379 scanNode.Stats = DefaultMinimalStats() 1380 } 1381 1382 // Perform partition pruning on the full table scan of the partitioned table in the insert statement 1383 if scanTableDef.Partition != nil && partitionExpr != nil { 1384 builder.partitionPrune(tableScanId) 1385 } 1386 1387 // fuzzy_filter 1388 fuzzyFilterNode := &Node{ 1389 NodeType: plan.Node_FUZZY_FILTER, 1390 Children: []int32{tableScanId, lastNodeId}, // right table build hash 1391 TableDef: tableDef, 1392 ObjRef: objRef, 1393 } 1394 1395 if fuzzymessage != nil { 1396 fuzzyFilterNode.Fuzzymessage = &plan.OriginTableMessageForFuzzy{ 1397 ParentTableName: fuzzymessage.ParentTableName, 1398 ParentUniqueCols: fuzzymessage.ParentUniqueCols, 1399 } 1400 } 1401 1402 if len(pkFilterExprs) == 0 { 1403 buildExpr := &plan.Expr{ 1404 Typ: pkTyp, 1405 Expr: &plan.Expr_Col{ 1406 Col: &plan.ColRef{ 1407 RelPos: 0, 1408 ColPos: 0, 1409 }, 1410 }, 1411 } 1412 fuzzyFilterNode.RuntimeFilterBuildList = []*plan.RuntimeFilterSpec{MakeRuntimeFilter(rfTag, false, GetInFilterCardLimitOnPK(scanNode.Stats.TableCnt), buildExpr)} 1413 } 1414 1415 lastNodeId = builder.appendNode(fuzzyFilterNode, bindCtx) 1416 builder.appendStep(lastNodeId) 1417 } 1418 } 1419 1420 // The refactor that using fuzzy filter has not been completely finished, Update type Insert cannot directly use fuzzy filter for duplicate detection. 1421 // so the original logic is retained. should be deleted later 1422 // make plan: sink_scan -> join -> filter // check if pk is unique in rows & snapshot 1423 if config.CNPrimaryCheck { 1424 if pkPos, pkTyp := getPkPos(tableDef, true); pkPos != -1 { 1425 rfTag := builder.genNewMsgTag() 1426 1427 if isUpdate && updatePkCol { // update stmt && pk included in update cols 1428 lastNodeId = appendSinkScanNode(builder, bindCtx, sourceStep) 1429 scanTableDef := DeepCopyTableDef(tableDef, false) 1430 1431 rowIdIdx := len(tableDef.Cols) 1432 rowIdDef := MakeRowIdColDef() 1433 tableDef.Cols = append(tableDef.Cols, rowIdDef) 1434 1435 scanTableDef.Cols = []*plan.ColDef{DeepCopyColDef(tableDef.Cols[pkPos]), DeepCopyColDef(rowIdDef)} 1436 1437 scanPkExpr := &Expr{ 1438 Typ: pkTyp, 1439 Expr: &plan.Expr_Col{ 1440 Col: &ColRef{ 1441 Name: tableDef.Pkey.PkeyColName, 1442 }, 1443 }, 1444 } 1445 scanRowIdExpr := &Expr{ 1446 Typ: rowIdDef.Typ, 1447 Expr: &plan.Expr_Col{ 1448 Col: &ColRef{ 1449 ColPos: 1, 1450 Name: rowIdDef.Name, 1451 }, 1452 }, 1453 } 1454 1455 probeExpr := &plan.Expr{ 1456 Typ: pkTyp, 1457 Expr: &plan.Expr_Col{ 1458 Col: &plan.ColRef{ 1459 Name: tableDef.Pkey.PkeyColName, 1460 }, 1461 }, 1462 } 1463 scanNode := &Node{ 1464 NodeType: plan.Node_TABLE_SCAN, 1465 Stats: &plan.Stats{}, 1466 ObjRef: objRef, 1467 TableDef: scanTableDef, 1468 ProjectList: []*Expr{scanPkExpr, scanRowIdExpr}, 1469 RuntimeFilterProbeList: []*plan.RuntimeFilterSpec{MakeRuntimeFilter(rfTag, false, 0, probeExpr)}, 1470 } 1471 rightId := builder.appendNode(scanNode, bindCtx) 1472 1473 pkColExpr := &Expr{ 1474 Typ: pkTyp, 1475 Expr: &plan.Expr_Col{ 1476 Col: &ColRef{ 1477 RelPos: 1, 1478 ColPos: int32(pkPos), 1479 Name: tableDef.Pkey.PkeyColName, 1480 }, 1481 }, 1482 } 1483 rightExpr := &Expr{ 1484 Typ: pkTyp, 1485 Expr: &plan.Expr_Col{ 1486 Col: &plan.ColRef{ 1487 Name: tableDef.Pkey.PkeyColName, 1488 }, 1489 }, 1490 } 1491 condExpr, err := BindFuncExprImplByPlanExpr(builder.GetContext(), "=", []*Expr{pkColExpr, rightExpr}) 1492 if err != nil { 1493 return err 1494 } 1495 rightRowIdExpr := &Expr{ 1496 Typ: rowIdDef.Typ, 1497 Expr: &plan.Expr_Col{ 1498 Col: &ColRef{ 1499 ColPos: 1, 1500 Name: rowIdDef.Name, 1501 }, 1502 }, 1503 } 1504 rowIdExpr := &Expr{ 1505 Typ: rowIdDef.Typ, 1506 Expr: &plan.Expr_Col{ 1507 Col: &ColRef{ 1508 RelPos: 1, 1509 ColPos: int32(rowIdIdx), 1510 Name: rowIdDef.Name, 1511 }, 1512 }, 1513 } 1514 1515 buildExpr := &plan.Expr{ 1516 Typ: pkTyp, 1517 Expr: &plan.Expr_Col{ 1518 Col: &plan.ColRef{ 1519 RelPos: 0, 1520 ColPos: 0, 1521 }, 1522 }, 1523 } 1524 joinNode := &plan.Node{ 1525 NodeType: plan.Node_JOIN, 1526 Children: []int32{rightId, lastNodeId}, 1527 JoinType: plan.Node_RIGHT, 1528 OnList: []*Expr{condExpr}, 1529 ProjectList: []*Expr{rowIdExpr, rightRowIdExpr, pkColExpr}, 1530 RuntimeFilterBuildList: []*plan.RuntimeFilterSpec{MakeRuntimeFilter(rfTag, false, GetInFilterCardLimitOnPK(scanNode.Stats.TableCnt), buildExpr)}, 1531 } 1532 lastNodeId = builder.appendNode(joinNode, bindCtx) 1533 1534 // append agg node. 1535 aggGroupBy := []*Expr{ 1536 { 1537 Typ: rowIdExpr.Typ, 1538 Expr: &plan.Expr_Col{ 1539 Col: &ColRef{ 1540 ColPos: 0, 1541 Name: catalog.Row_ID, 1542 }, 1543 }}, 1544 { 1545 Typ: rowIdExpr.Typ, 1546 Expr: &plan.Expr_Col{ 1547 Col: &ColRef{ 1548 ColPos: 1, 1549 Name: catalog.Row_ID, 1550 }, 1551 }}, 1552 { 1553 Typ: pkColExpr.Typ, 1554 Expr: &plan.Expr_Col{ 1555 Col: &ColRef{ 1556 ColPos: 2, 1557 Name: tableDef.Pkey.PkeyColName, 1558 }, 1559 }}, 1560 } 1561 aggProject := []*Expr{ 1562 { 1563 Typ: rowIdExpr.Typ, 1564 Expr: &plan.Expr_Col{ 1565 Col: &ColRef{ 1566 RelPos: -1, 1567 ColPos: 0, 1568 Name: catalog.Row_ID, 1569 }, 1570 }}, 1571 { 1572 Typ: rowIdExpr.Typ, 1573 Expr: &plan.Expr_Col{ 1574 Col: &ColRef{ 1575 RelPos: -1, 1576 ColPos: 1, 1577 Name: catalog.Row_ID, 1578 }, 1579 }}, 1580 { 1581 Typ: pkColExpr.Typ, 1582 Expr: &plan.Expr_Col{ 1583 Col: &ColRef{ 1584 RelPos: -1, 1585 ColPos: 2, 1586 Name: tableDef.Pkey.PkeyColName, 1587 }, 1588 }}, 1589 } 1590 aggNode := &Node{ 1591 NodeType: plan.Node_AGG, 1592 Children: []int32{lastNodeId}, 1593 GroupBy: aggGroupBy, 1594 ProjectList: aggProject, 1595 } 1596 lastNodeId = builder.appendNode(aggNode, bindCtx) 1597 1598 // append filter node 1599 filterExpr, err := BindFuncExprImplByPlanExpr(builder.GetContext(), "not_in_rows", []*Expr{ 1600 { 1601 Typ: rowIdExpr.Typ, 1602 Expr: &plan.Expr_Col{ 1603 Col: &ColRef{ColPos: 1, Name: catalog.Row_ID}, 1604 }, 1605 }, 1606 { 1607 Typ: rowIdExpr.Typ, 1608 Expr: &plan.Expr_Col{ 1609 Col: &ColRef{ColPos: 0, Name: catalog.Row_ID}, 1610 }, 1611 }, 1612 }) 1613 if err != nil { 1614 return err 1615 } 1616 colExpr := &Expr{ 1617 Typ: rowIdDef.Typ, 1618 Expr: &plan.Expr_Col{ 1619 Col: &plan.ColRef{ 1620 Name: rowIdDef.Name, 1621 }, 1622 }, 1623 } 1624 1625 lastNodeId = builder.appendNode(&Node{ 1626 NodeType: plan.Node_FILTER, 1627 Children: []int32{lastNodeId}, 1628 FilterList: []*Expr{filterExpr}, 1629 ProjectList: []*Expr{ 1630 colExpr, 1631 { 1632 Typ: tableDef.Cols[pkPos].Typ, 1633 Expr: &plan.Expr_Col{ 1634 Col: &plan.ColRef{ColPos: 2, Name: tableDef.Cols[pkPos].Name}, 1635 }, 1636 }, 1637 }, 1638 }, bindCtx) 1639 1640 // append assert node 1641 isEmptyExpr, err := BindFuncExprImplByPlanExpr(builder.GetContext(), "isempty", []*Expr{colExpr}) 1642 if err != nil { 1643 return err 1644 } 1645 1646 varcharType := types.T_varchar.ToType() 1647 varcharExpr, err := makePlan2CastExpr(builder.GetContext(), &Expr{ 1648 Typ: tableDef.Cols[pkPos].Typ, 1649 Expr: &plan.Expr_Col{ 1650 Col: &plan.ColRef{ColPos: 1, Name: tableDef.Cols[pkPos].Name}, 1651 }, 1652 }, makePlan2Type(&varcharType)) 1653 if err != nil { 1654 return err 1655 } 1656 colTypes := string("") 1657 for i := range indexSourceColTypes { 1658 if types.T(indexSourceColTypes[i].Id).IsDecimal() { 1659 colTypes = colTypes + string(byte(indexSourceColTypes[i].Scale)) 1660 } else { 1661 colTypes = colTypes + "0" 1662 } 1663 } 1664 assertExpr, err := BindFuncExprImplByPlanExpr(builder.GetContext(), "assert", []*Expr{isEmptyExpr, varcharExpr, makePlan2StringConstExprWithType(tableDef.Cols[pkPos].Name), makePlan2StringConstExprWithType(colTypes)}) 1665 if err != nil { 1666 return err 1667 } 1668 lastNodeId = builder.appendNode(&Node{ 1669 NodeType: plan.Node_FILTER, 1670 Children: []int32{lastNodeId}, 1671 FilterList: []*Expr{assertExpr}, 1672 IsEnd: true, 1673 }, bindCtx) 1674 builder.appendStep(lastNodeId) 1675 } 1676 } 1677 } 1678 1679 return nil 1680 }