github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/build_insert.go (about) 1 // Copyright 2021 - 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 "strings" 20 "time" 21 22 "github.com/google/uuid" 23 24 "github.com/matrixorigin/matrixone/pkg/catalog" 25 "github.com/matrixorigin/matrixone/pkg/common/moerr" 26 "github.com/matrixorigin/matrixone/pkg/config" 27 "github.com/matrixorigin/matrixone/pkg/container/batch" 28 "github.com/matrixorigin/matrixone/pkg/container/nulls" 29 "github.com/matrixorigin/matrixone/pkg/container/types" 30 "github.com/matrixorigin/matrixone/pkg/container/vector" 31 "github.com/matrixorigin/matrixone/pkg/pb/plan" 32 "github.com/matrixorigin/matrixone/pkg/pb/timestamp" 33 "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" 34 "github.com/matrixorigin/matrixone/pkg/sql/plan/function" 35 "github.com/matrixorigin/matrixone/pkg/sql/plan/rule" 36 "github.com/matrixorigin/matrixone/pkg/sql/util" 37 v2 "github.com/matrixorigin/matrixone/pkg/util/metric/v2" 38 ) 39 40 func buildInsert(stmt *tree.Insert, ctx CompilerContext, isReplace bool, isPrepareStmt bool) (p *Plan, err error) { 41 start := time.Now() 42 defer func() { 43 v2.TxnStatementBuildInsertHistogram.Observe(time.Since(start).Seconds()) 44 }() 45 if isReplace { 46 return nil, moerr.NewNotSupported(ctx.GetContext(), "Not support replace statement") 47 } 48 49 tbl := stmt.Table.(*tree.TableName) 50 dbName := string(tbl.SchemaName) 51 tblName := string(tbl.ObjectName) 52 if len(dbName) == 0 { 53 dbName = ctx.DefaultDatabase() 54 } 55 56 _, t := ctx.Resolve(dbName, tblName, Snapshot{TS: ×tamp.Timestamp{}}) 57 if t == nil { 58 return nil, moerr.NewNoSuchTable(ctx.GetContext(), dbName, tblName) 59 } 60 if t.TableType == catalog.SystemSourceRel { 61 return nil, moerr.NewNYI(ctx.GetContext(), "insert stream %s", tblName) 62 } 63 64 tblInfo, err := getDmlTableInfo(ctx, tree.TableExprs{stmt.Table}, nil, nil, "insert") 65 if err != nil { 66 return nil, err 67 } 68 rewriteInfo := &dmlSelectInfo{ 69 typ: "insert", 70 rootId: -1, 71 tblInfo: tblInfo, 72 } 73 tableDef := tblInfo.tableDefs[0] 74 // clusterTable, err := getAccountInfoOfClusterTable(ctx, stmt.Accounts, tableDef, tblInfo.isClusterTable[0]) 75 // if err != nil { 76 // return nil, err 77 // } 78 // if len(stmt.OnDuplicateUpdate) > 0 && clusterTable.IsClusterTable { 79 // return nil, moerr.NewNotSupported(ctx.GetContext(), "INSERT ... ON DUPLICATE KEY UPDATE ... for cluster table") 80 // } 81 82 builder := NewQueryBuilder(plan.Query_SELECT, ctx, isPrepareStmt) 83 builder.haveOnDuplicateKey = len(stmt.OnDuplicateUpdate) > 0 84 if stmt.IsRestore { 85 oldSnapshot := builder.compCtx.GetSnapshot() 86 builder.compCtx.SetSnapshot(&Snapshot{ 87 Tenant: &plan.SnapshotTenant{ 88 TenantName: "xxx", 89 TenantID: stmt.FromDataTenantID, 90 }, 91 }) 92 defer func() { 93 builder.compCtx.SetSnapshot(oldSnapshot) 94 }() 95 } 96 97 bindCtx := NewBindContext(builder, nil) 98 ifExistAutoPkCol, insertWithoutUniqueKeyMap, err := initInsertStmt(builder, bindCtx, stmt, rewriteInfo) 99 if err != nil { 100 return nil, err 101 } 102 lastNodeId := rewriteInfo.rootId 103 sourceStep := builder.appendStep(lastNodeId) 104 query, err := builder.createQuery() 105 if err != nil { 106 return nil, err 107 } 108 builder.qry.Steps = append(builder.qry.Steps[:sourceStep], builder.qry.Steps[sourceStep+1:]...) 109 110 objRef := tblInfo.objRef[0] 111 if len(rewriteInfo.onDuplicateIdx) > 0 { 112 // append on duplicate key node 113 tableDef = DeepCopyTableDef(tableDef, true) 114 if tableDef.Pkey != nil && tableDef.Pkey.PkeyColName == catalog.CPrimaryKeyColName { 115 tableDef.Cols = append(tableDef.Cols, tableDef.Pkey.CompPkeyCol) 116 } 117 if tableDef.ClusterBy != nil && util.JudgeIsCompositeClusterByColumn(tableDef.ClusterBy.Name) { 118 tableDef.Cols = append(tableDef.Cols, tableDef.ClusterBy.CompCbkeyCol) 119 } 120 121 dupProjection := getProjectionByLastNode(builder, lastNodeId) 122 // if table have pk & unique key. we need append an agg node before on_duplicate_key 123 if rewriteInfo.onDuplicateNeedAgg { 124 colLen := len(tableDef.Cols) 125 aggGroupBy := make([]*Expr, 0, colLen) 126 aggList := make([]*Expr, 0, len(dupProjection)-colLen) 127 aggProject := make([]*Expr, 0, len(dupProjection)) 128 for i := 0; i < len(dupProjection); i++ { 129 if i < colLen { 130 aggGroupBy = append(aggGroupBy, &Expr{ 131 Typ: dupProjection[i].Typ, 132 Expr: &plan.Expr_Col{ 133 Col: &ColRef{ 134 ColPos: int32(i), 135 }, 136 }, 137 }) 138 aggProject = append(aggProject, &Expr{ 139 Typ: dupProjection[i].Typ, 140 Expr: &plan.Expr_Col{ 141 Col: &ColRef{ 142 RelPos: -1, 143 ColPos: int32(i), 144 }, 145 }, 146 }) 147 } else { 148 aggExpr, err := BindFuncExprImplByPlanExpr(builder.GetContext(), "any_value", []*Expr{ 149 { 150 Typ: dupProjection[i].Typ, 151 Expr: &plan.Expr_Col{ 152 Col: &ColRef{ 153 ColPos: int32(i), 154 }, 155 }, 156 }, 157 }) 158 if err != nil { 159 return nil, err 160 } 161 aggList = append(aggList, aggExpr) 162 aggProject = append(aggProject, &Expr{ 163 Typ: dupProjection[i].Typ, 164 Expr: &plan.Expr_Col{ 165 Col: &ColRef{ 166 RelPos: -2, 167 ColPos: int32(i), 168 }, 169 }, 170 }) 171 } 172 } 173 174 aggNode := &Node{ 175 NodeType: plan.Node_AGG, 176 Children: []int32{lastNodeId}, 177 GroupBy: aggGroupBy, 178 AggList: aggList, 179 ProjectList: aggProject, 180 } 181 lastNodeId = builder.appendNode(aggNode, bindCtx) 182 } 183 // construct the attrs and insertColCount for on_duplicate_key node 184 attrs := make([]string, 0) 185 insertColCount := int32(0) 186 for _, col := range tableDef.Cols { 187 if col.Hidden && col.Name != catalog.FakePrimaryKeyColName { 188 continue 189 } 190 attrs = append(attrs, col.Name) 191 insertColCount++ 192 } 193 for _, col := range tableDef.Cols { 194 attrs = append(attrs, col.Name) 195 } 196 attrs = append(attrs, catalog.Row_ID) 197 uniqueColWithIdx := GetUniqueColAndIdxFromTableDef(tableDef) 198 uniqueColCheckExpr, err := GenUniqueColCheckExpr(ctx.GetContext(), tableDef, uniqueColWithIdx, int(insertColCount)) 199 if err != nil { 200 return nil, err 201 } 202 uniqueCol := make([]string, len(uniqueColWithIdx)) 203 for i := range uniqueColWithIdx { 204 keys := make([]string, 0) 205 for k := range uniqueColWithIdx[i] { 206 keys = append(keys, k) 207 } 208 uniqueCol[i] = strings.Join(keys, ",") 209 } 210 onDuplicateKeyNode := &Node{ 211 NodeType: plan.Node_ON_DUPLICATE_KEY, 212 Children: []int32{lastNodeId}, 213 ProjectList: dupProjection, 214 OnDuplicateKey: &plan.OnDuplicateKeyCtx{ 215 Attrs: attrs, 216 InsertColCount: insertColCount, 217 UniqueColCheckExpr: uniqueColCheckExpr, 218 UniqueCols: uniqueCol, 219 OnDuplicateIdx: rewriteInfo.onDuplicateIdx, 220 OnDuplicateExpr: rewriteInfo.onDuplicateExpr, 221 IsIgnore: rewriteInfo.onDuplicateIsIgnore, 222 TableName: tableDef.Name, 223 TableId: tableDef.TblId, 224 TableVersion: tableDef.Version, 225 }, 226 } 227 lastNodeId = builder.appendNode(onDuplicateKeyNode, bindCtx) 228 229 // append project node to make batch like update logic, not insert 230 updateColLength := 0 231 updateColPosMap := make(map[string]int) 232 var insertColPos []int 233 var projectProjection []*Expr 234 tableDef = DeepCopyTableDef(tableDef, true) 235 tableDef.Cols = append(tableDef.Cols, MakeRowIdColDef()) 236 colLength := len(tableDef.Cols) 237 rowIdPos := colLength - 1 238 for _, col := range tableDef.Cols { 239 if col.Hidden && col.Name != catalog.FakePrimaryKeyColName { 240 continue 241 } 242 updateColLength++ 243 } 244 for i, col := range tableDef.Cols { 245 projectProjection = append(projectProjection, &plan.Expr{ 246 Typ: col.Typ, 247 Expr: &plan.Expr_Col{ 248 Col: &plan.ColRef{ 249 ColPos: int32(i + updateColLength), 250 Name: col.Name, 251 }, 252 }, 253 }) 254 } 255 for i := 0; i < updateColLength; i++ { 256 col := tableDef.Cols[i] 257 projectProjection = append(projectProjection, &plan.Expr{ 258 Typ: col.Typ, 259 Expr: &plan.Expr_Col{ 260 Col: &plan.ColRef{ 261 ColPos: int32(i), 262 Name: col.Name, 263 }, 264 }, 265 }) 266 updateColPosMap[col.Name] = colLength + i 267 insertColPos = append(insertColPos, colLength+i) 268 } 269 projectNode := &Node{ 270 NodeType: plan.Node_PROJECT, 271 Children: []int32{lastNodeId}, 272 ProjectList: projectProjection, 273 } 274 lastNodeId = builder.appendNode(projectNode, bindCtx) 275 276 // append sink node 277 lastNodeId = appendSinkNode(builder, bindCtx, lastNodeId) 278 sourceStep = builder.appendStep(lastNodeId) 279 280 // append plans like update 281 updateBindCtx := NewBindContext(builder, nil) 282 upPlanCtx := getDmlPlanCtx() 283 upPlanCtx.objRef = objRef 284 upPlanCtx.tableDef = tableDef 285 upPlanCtx.beginIdx = 0 286 upPlanCtx.sourceStep = sourceStep 287 upPlanCtx.isMulti = false 288 upPlanCtx.updateColLength = updateColLength 289 upPlanCtx.rowIdPos = rowIdPos 290 upPlanCtx.insertColPos = insertColPos 291 upPlanCtx.updateColPosMap = updateColPosMap 292 293 err = buildUpdatePlans(ctx, builder, updateBindCtx, upPlanCtx, true) 294 if err != nil { 295 return nil, err 296 } 297 putDmlPlanCtx(upPlanCtx) 298 299 query.StmtType = plan.Query_UPDATE 300 } else { 301 err = buildInsertPlans(ctx, builder, bindCtx, stmt, objRef, tableDef, rewriteInfo.rootId, ifExistAutoPkCol, insertWithoutUniqueKeyMap) 302 if err != nil { 303 return nil, err 304 } 305 query.StmtType = plan.Query_INSERT 306 } 307 sqls, err := genSqlsForCheckFKSelfRefer(ctx.GetContext(), 308 dbName, tableDef.Name, tableDef.Cols, tableDef.Fkeys) 309 if err != nil { 310 return nil, err 311 } 312 query.DetectSqls = sqls 313 reduceSinkSinkScanNodes(query) 314 ReCalcQueryStats(builder, query) 315 reCheckifNeedLockWholeTable(builder) 316 return &Plan{ 317 Plan: &plan.Plan_Query{ 318 Query: query, 319 }, 320 }, err 321 } 322 323 // ------------------- pk filter relatived ------------------- 324 325 // getInsertColsFromStmt retrieves the list of column names to be inserted into a table 326 // based on the given INSERT statement and table definition. 327 // If the INSERT statement does not specify the columns, all columns except the fake primary key column 328 // will be included in the list. 329 // If the INSERT statement specifies the columns, it validates the column names against the table definition 330 // and returns an error if any of the column names are invalid. 331 // The function returns the list of insert columns and an error, if any. 332 func getInsertColsFromStmt(ctx context.Context, stmt *tree.Insert, tableDef *TableDef) ([]string, error) { 333 var insertColsName []string 334 colToIdx := make(map[string]int) 335 for i, col := range tableDef.Cols { 336 colToIdx[col.Name] = i 337 } 338 if stmt.Columns == nil { 339 for _, col := range tableDef.Cols { 340 if col.Name != catalog.FakePrimaryKeyColName { 341 insertColsName = append(insertColsName, col.Name) 342 } 343 } 344 } else { 345 for _, column := range stmt.Columns { 346 colName := string(column) 347 if _, ok := colToIdx[colName]; !ok { 348 return nil, moerr.NewBadFieldError(ctx, colName, tableDef.Name) 349 } 350 insertColsName = append(insertColsName, colName) 351 } 352 } 353 return insertColsName, nil 354 } 355 356 // canUsePkFilter checks if the primary key filter can be used for the given insert statement. 357 // It returns true if the primary key filter can be used, otherwise it returns false. 358 // The primary key filter can be used if the following conditions are met: 359 // NOTE : For hidden tables created by UNIQUE INDEX, the situation is more subtle. 360 // 0. CNPrimaryCheck is true. 361 // 1. The insert statement is INSERT VALUES type 362 // 2. table contains primary key 363 // 3. for auto-incr primary key, must contain corresponding columns, and values must not contain nil. 364 // 4. performance constraints: (maybe outdated) 365 // 4.1 for single priamry key and the type of pk is number type, the number of rows being inserted is less than or equal to 20_000 366 // 4.2 otherwise : the number of rows being inserted is less than or equal to defaultmaxRowThenUnusePkFilterExpr 367 // 368 // NOTE : For hidden tables created by UNIQUE INDEX, the situation is more subtle. 369 // 5. for hidden table created by unique index, need to contain the inserted data column 370 // 371 // Otherwise, the primary key filter cannot be used. 372 func canUsePkFilter(builder *QueryBuilder, ctx CompilerContext, stmt *tree.Insert, tableDef *TableDef, insertColsName []string, uniqueIndexDef *IndexDef) bool { 373 var isCompound bool 374 var used4UniqueIndex bool // mark if this pkfilter is used for hidden table created by unique index 375 376 if uniqueIndexDef != nil { 377 if !uniqueIndexDef.Unique { 378 panic("should never happen") 379 } 380 used4UniqueIndex = true 381 } 382 383 if used4UniqueIndex { 384 isCompound = len(uniqueIndexDef.Parts) > 1 385 } else { 386 isCompound = len(tableDef.Pkey.Names) > 1 387 } 388 389 if !config.CNPrimaryCheck { 390 return false // break condition 0 391 } 392 393 if builder.qry.Nodes[0].NodeType != plan.Node_VALUE_SCAN { 394 return false // break condition 1 395 } 396 397 // hack, should be removed soon 398 if builder.qry.Nodes[0].NodeType == plan.Node_VALUE_SCAN && builder.qry.Nodes[1].NodeType == plan.Node_FUNCTION_SCAN { 399 return false // break condition 1 400 } 401 402 if used4UniqueIndex { 403 // verify that all cols that make up the unique index exist and no value is null 404 uSet := make(map[string]bool) 405 for _, n := range uniqueIndexDef.Parts { 406 uSet[n] = true 407 } 408 uCnt := len(uSet) 409 410 var bat *batch.Batch 411 proc := ctx.GetProcess() 412 node := builder.qry.Nodes[0] 413 if node.Uuid == nil { 414 return false // TODO(jensenojs): issue14726 415 } 416 417 if builder.isPrepareStatement { 418 bat = proc.GetPrepareBatch() 419 } else { 420 bat = proc.GetValueScanBatch(uuid.UUID(node.Uuid)) 421 } 422 423 for i, n := range insertColsName { 424 if _, ok := uSet[n]; ok { 425 uCnt-- 426 uniqueVec := bat.Vecs[i] 427 if nulls.Any(uniqueVec.GetNulls()) { 428 // has at least one values is null, then can not use pk filter, break conditon 5 429 return false 430 } 431 } 432 } 433 if uCnt != 0 { 434 return false // at least one column that make up the unique index is NOT exist , break condtion 5 435 } 436 } else { 437 // check for auto increment primary key 438 pkPos, pkTyp := getPkPos(tableDef, true) 439 if pkPos == -1 { 440 if tableDef.Pkey.PkeyColName != catalog.CPrimaryKeyColName { 441 return false // break condition 2 442 } 443 444 pkNameMap := make(map[string]int) 445 for pkIdx, pkName := range tableDef.Pkey.Names { 446 pkNameMap[pkName] = pkIdx 447 } 448 449 autoIncIdx := -1 450 for _, col := range tableDef.Cols { 451 if _, ok := pkNameMap[col.Name]; ok { 452 if col.Typ.AutoIncr { 453 foundInStmt := false 454 for i, name := range insertColsName { 455 if name == col.Name { 456 foundInStmt = true 457 autoIncIdx = i 458 break 459 } 460 } 461 if !foundInStmt { 462 // one of pk cols is auto incr col and this col was not in values, break condition 3 463 return false 464 } 465 } 466 } 467 } 468 469 if autoIncIdx != -1 { 470 var bat *batch.Batch 471 proc := ctx.GetProcess() 472 node := builder.qry.Nodes[0] 473 if node.Uuid == nil { 474 return false // TODO(jensenojs): issue14726 475 } 476 if builder.isPrepareStatement { 477 bat = proc.GetPrepareBatch() 478 } else { 479 bat = proc.GetValueScanBatch(uuid.UUID(node.Uuid)) 480 } 481 autoPkVec := bat.Vecs[autoIncIdx] 482 if nulls.Any(autoPkVec.GetNulls()) { 483 // has at least one values is null, then can not use pk filter, break conditon 2 484 return false 485 } 486 } 487 } else if pkTyp.AutoIncr { // single auto incr primary key 488 var bat *batch.Batch 489 490 autoIncIdx := -1 491 for i, name := range insertColsName { 492 if tableDef.Pkey.PkeyColName == name { 493 autoIncIdx = i 494 break 495 } 496 } 497 498 if autoIncIdx == -1 { 499 // have no auto pk col in values, break condition 2 500 return false 501 } else { 502 proc := ctx.GetProcess() 503 node := builder.qry.Nodes[0] 504 if node.Uuid == nil { 505 return false // TODO(jensenojs): issue14726 506 } 507 if builder.isPrepareStatement { 508 bat = proc.GetPrepareBatch() 509 } else { 510 bat = proc.GetValueScanBatch(uuid.UUID(node.Uuid)) 511 } 512 513 autoPkVec := bat.Vecs[autoIncIdx] 514 if nulls.Any(autoPkVec.GetNulls()) { 515 // has at least one values is null, then can not use pk filter, break conditon 2 516 return false 517 } 518 } 519 } 520 } 521 522 switch slt := stmt.Rows.Select.(type) { 523 case *tree.ValuesClause: 524 if !isCompound { 525 526 var toCheckColName string 527 if !used4UniqueIndex { 528 toCheckColName = tableDef.Pkey.PkeyColName 529 } else { 530 toCheckColName = uniqueIndexDef.Parts[0] 531 } 532 533 for i, col := range tableDef.Cols { 534 if col.Name == toCheckColName { 535 typ := tableDef.Cols[i].Typ 536 switch typ.Id { 537 case int32(types.T_int8), int32(types.T_int16), int32(types.T_int32), int32(types.T_int64), int32(types.T_int128): 538 if len(slt.Rows) > 20_000 { 539 return false // break condition 4.1 540 } 541 case int32(types.T_uint8), int32(types.T_uint16), int32(types.T_uint32), int32(types.T_uint64), int32(types.T_uint128), int32(types.T_bit): 542 if len(slt.Rows) > 20_000 { 543 return false // break condition 4.1 544 } 545 default: 546 if len(slt.Rows) > defaultmaxRowThenUnusePkFilterExpr { 547 return false // break condition 4.2 548 } 549 } 550 } 551 } 552 } else { 553 if len(slt.Rows) > defaultmaxRowThenUnusePkFilterExpr { 554 return false // break condition 4.2 555 } 556 } 557 default: 558 // TODO(jensenojs):need to support more type, such as load or update ? 559 return false 560 } 561 562 return true 563 } 564 565 type orderAndIdx struct { 566 order int // pkOrder is the order(ignore non-pk cols) in tableDef.Pkey.Names 567 index int // pkIndex is the index of the primary key columns in tableDef.Cols 568 } 569 570 type locationMap struct { 571 m map[string]orderAndIdx 572 isUnique bool 573 } 574 575 // getPkOrderInValues returns a map, that 576 // 577 // The key of this map is the order(ignore non-pk cols) in which the primary key columns are inserted in INSERT VALUE SQL 578 // The value of this map is the order(ignore non-pk cols) in which the primary key columns are inserted intableDef.Pkey.Names(NOT TableDef.Cols!) 579 // 580 // e.g 581 // 582 // create table t1 (a int, b int, c int, d int, primary key(a, c, b)); 583 // insert into t1(a, b, c, d) value (1, 2, 3, 4) ; 584 // (a, b, c) -> (a, c, b) => pkOrderInValues[0] = 0, pkOrderInValues[1] = 2, pkOrderInValues[2] = 1 585 // insert into t1(d, a, b, c) value (4, 1, 2, 3) ; 586 // (a, b, c) -> (a, c, b) => pkOrderInValues[0] = 0, pkOrderInValues[1] = 2, pkOrderInValues[2] = 1 587 // insert into t1(b, d, a, c) value (2, 4, 1, 3) ; 588 // (b, a, c) -> (a, c, b) => pkOrderInValues[0] = 2, pkOrderInValues[1] = 0, pkOrderInValues[2] = 1 589 // insert into t1(c, b, d, a) value (3, 2, 4, 1) ; 590 // (c, b, a) -> (a, c, b) => pkOrderInValues[0] = 2, pkOrderInValues[1] = 1, pkOrderInValues[2] = 0 591 func (p *locationMap) getPkOrderInValues(insertColsNameFromStmt []string) map[int]int { 592 pkOrderInValues := make(map[int]int) 593 i := 0 594 for _, name := range insertColsNameFromStmt { 595 if pkInfo, ok := p.m[name]; ok { 596 pkOrderInValues[i] = pkInfo.order 597 i++ 598 } 599 } 600 return pkOrderInValues 601 } 602 603 // need to check if the primary key filter can be used before calling this function. 604 // also need to consider both origin table and hidden table for unique key 605 func newLocationMap(tableDef *TableDef, uniqueIndexDef *IndexDef) *locationMap { 606 if uniqueIndexDef != nil && !uniqueIndexDef.Unique { 607 panic("uniqueIndexDef.Unique must be true") 608 } 609 610 m := make(map[string]orderAndIdx) 611 name2Order := make(map[string]int) 612 name2Indx := make(map[string]int) 613 614 if uniqueIndexDef != nil { 615 for o, n := range uniqueIndexDef.Parts { 616 name2Order[n] = o 617 } 618 } else { 619 for o, n := range tableDef.Pkey.Names { 620 name2Order[n] = o 621 } 622 } 623 624 for i, col := range tableDef.Cols { 625 if _, ok := name2Order[col.Name]; ok { 626 name2Indx[col.Name] = i 627 } 628 } 629 for name := range name2Indx { 630 m[name] = orderAndIdx{name2Order[name], name2Indx[name]} 631 } 632 return &locationMap{ 633 m: m, 634 isUnique: uniqueIndexDef != nil, 635 } 636 } 637 638 func getPkValueExpr(builder *QueryBuilder, ctx CompilerContext, tableDef *TableDef, lmap *locationMap, insertColsNameFromStmt []string) (pkFilterExprs []*Expr, err error) { 639 var bat *batch.Batch 640 var pkLocationInfo orderAndIdx 641 var ok bool 642 var colTyp Type 643 proc := ctx.GetProcess() 644 node := builder.qry.Nodes[0] 645 isCompound := len(lmap.m) > 1 646 forUniqueHiddenTable := lmap.isUnique 647 648 if builder.isPrepareStatement { 649 bat = proc.GetPrepareBatch() 650 } else { 651 bat = proc.GetValueScanBatch(uuid.UUID(node.Uuid)) 652 } 653 rowsCount := bat.RowCount() 654 655 // colExprs will store the constant value expressions (or UUID value) for each primary key column by the order in insert value SQL 656 // that is, the key part of pkPosInValues, more info see the comment of func getPkOrderInValues 657 colExprs := make([][]*Expr, len(lmap.m)) 658 // If the expression is nil, it creates a constant expression with either the UUID value or a constant value. 659 for idx, name := range insertColsNameFromStmt { 660 var varcharTyp Type 661 if pkLocationInfo, ok = lmap.m[name]; !ok { 662 continue 663 } 664 665 valExprs := make([]*Expr, rowsCount) 666 rowTyp := bat.Vecs[idx].GetType() 667 colTyp = makePlan2Type(rowTyp) 668 669 if rowTyp.Oid == types.T_uuid { 670 typ := types.T_varchar.ToType() 671 varcharTyp = MakePlan2Type(&typ) 672 } 673 674 for _, data := range node.RowsetData.Cols[idx].Data { 675 rowExpr := DeepCopyExpr(data.Expr) 676 e, err := forceCastExpr(builder.GetContext(), rowExpr, colTyp) 677 if err != nil { 678 return nil, err 679 } 680 valExprs[data.RowPos] = e 681 } 682 683 for i := 0; i < rowsCount; i++ { 684 if valExprs[i] == nil { 685 // handles UUID types specifically by creating a VARCHAR type and casting the UUID to a string. 686 if bat.Vecs[idx].GetType().Oid == types.T_uuid { 687 // we have not uuid type in plan.Const. so use string & cast string to uuid 688 val := vector.MustFixedCol[types.Uuid](bat.Vecs[idx])[i] 689 constExpr := &plan.Expr{ 690 Typ: varcharTyp, 691 Expr: &plan.Expr_Lit{ 692 Lit: &plan.Literal{ 693 Value: &plan.Literal_Sval{ 694 Sval: val.ToString(), 695 }, 696 }, 697 }, 698 } 699 valExprs[i], err = appendCastBeforeExpr(proc.Ctx, constExpr, colTyp, false) 700 if err != nil { 701 return nil, err 702 } 703 } else { 704 constExpr := rule.GetConstantValue(bat.Vecs[idx], true, uint64(i)) 705 if constExpr == nil { 706 return nil, err 707 } 708 valExprs[i] = &plan.Expr{ 709 Typ: colTyp, 710 Expr: &plan.Expr_Lit{ 711 Lit: constExpr, 712 }, 713 } 714 } 715 } 716 } 717 colExprs[pkLocationInfo.order] = valExprs 718 } 719 720 if !isCompound { 721 var colName string 722 for n := range lmap.m { 723 colName = n 724 break 725 } 726 if forUniqueHiddenTable { 727 colName = catalog.IndexTableIndexColName 728 } 729 730 if rowsCount <= 3 { 731 // pk = a1 or pk = a2 or pk = a3 732 var orExpr *Expr 733 for i := 0; i < rowsCount; i++ { 734 expr, err := BindFuncExprImplByPlanExpr(builder.GetContext(), "=", []*Expr{{ 735 Typ: colTyp, 736 Expr: &plan.Expr_Col{ 737 Col: &ColRef{ 738 // ColPos: int32(pkOrderInTableDef), 739 ColPos: 0, 740 Name: colName, 741 }, 742 }, 743 }, colExprs[0][i]}) 744 if err != nil { 745 return nil, err 746 } 747 748 if i == 0 { 749 orExpr = expr 750 } else { 751 orExpr, err = BindFuncExprImplByPlanExpr(builder.GetContext(), "or", []*Expr{orExpr, expr}) 752 if err != nil { 753 return nil, err 754 } 755 } 756 } 757 return []*Expr{orExpr}, err 758 } else { 759 // pk in (a1, a2, a3) 760 // args in list must be constant 761 expr, err := BindFuncExprImplByPlanExpr(builder.GetContext(), "in", []*Expr{{ 762 Typ: colTyp, 763 Expr: &plan.Expr_Col{ 764 Col: &ColRef{ 765 // ColPos: int32(pkOrderInTableDef), 766 ColPos: 0, 767 Name: colName, 768 }, 769 }, 770 }, { 771 Expr: &plan.Expr_List{ 772 List: &plan.ExprList{ 773 List: colExprs[0], 774 }, 775 }, 776 Typ: plan.Type{ 777 Id: int32(types.T_tuple), 778 }, 779 }}) 780 if err != nil { 781 return nil, err 782 } 783 expr, err = ConstantFold(batch.EmptyForConstFoldBatch, expr, proc, false) 784 if err != nil { 785 return nil, err 786 } 787 return []*Expr{expr}, err 788 } 789 } else { 790 if rowsCount <= 3 && !forUniqueHiddenTable { 791 // ppk1 = a1 and ppk2 = a2 or ppk1 = b1 and ppk2 = b2 or ppk1 = c1 and ppk2 = c2 792 var orExpr *Expr 793 var andExpr *Expr 794 for i := 0; i < rowsCount; i++ { 795 for _, pkLocationInfo = range lmap.m { 796 pkOrder := pkLocationInfo.order 797 pkColIdx := pkLocationInfo.index 798 eqExpr, err := BindFuncExprImplByPlanExpr(builder.GetContext(), "=", []*Expr{ 799 { 800 Typ: tableDef.Cols[pkColIdx].Typ, 801 Expr: &plan.Expr_Col{ 802 Col: &ColRef{ 803 ColPos: int32(pkOrder), 804 Name: tableDef.Cols[pkColIdx].Name, 805 }, 806 }, 807 }, 808 colExprs[pkOrder][i], 809 }, 810 ) 811 if err != nil { 812 return nil, err 813 } 814 if andExpr == nil { 815 andExpr = eqExpr 816 } else { 817 andExpr, err = BindFuncExprImplByPlanExpr(builder.GetContext(), "and", []*Expr{andExpr, eqExpr}) 818 if err != nil { 819 return nil, err 820 } 821 } 822 } 823 if i == 0 { 824 orExpr = andExpr 825 } else { 826 orExpr, err = BindFuncExprImplByPlanExpr(builder.GetContext(), "or", []*Expr{orExpr, andExpr}) 827 if err != nil { 828 return nil, err 829 } 830 } 831 andExpr = nil 832 } 833 return []*Expr{orExpr}, nil 834 } else { 835 var colName string 836 var colPos int32 837 if forUniqueHiddenTable { 838 colName = catalog.IndexTableIndexColName 839 colPos = 0 840 } else { 841 colName = catalog.CPrimaryKeyColName 842 colPos = int32(len(tableDef.Pkey.Names)) 843 } 844 845 names := make([]string, len(lmap.m)) 846 for n, p := range lmap.m { 847 names[p.order] = n 848 } 849 toSerialBatch := bat.GetSubBatch(names) 850 // serialize 851 // __cpkey__ in (serial(a1,b1,c1,d1),serial(a2,b2,c2,d2),xxx) 852 // processing composite primary key 853 vec, err := function.RunFunctionDirectly(proc, function.SerialFunctionEncodeID, 854 toSerialBatch.Vecs, 855 toSerialBatch.RowCount()) 856 if err != nil { 857 return nil, err 858 } 859 vec.InplaceSort() 860 data, err := vec.MarshalBinary() 861 if err != nil { 862 return nil, err 863 } 864 inExpr, err := BindFuncExprImplByPlanExpr(builder.GetContext(), "in", []*Expr{ 865 { 866 Typ: makeHiddenColTyp(), 867 Expr: &plan.Expr_Col{ 868 Col: &ColRef{ 869 ColPos: colPos, 870 Name: colName, 871 }, 872 }, 873 }, 874 { 875 Typ: plan.Type{ 876 Id: int32(types.T_tuple), 877 }, 878 Expr: &plan.Expr_Vec{ 879 Vec: &plan.LiteralVec{ 880 Len: int32(vec.Length()), 881 Data: data, 882 }, 883 }, 884 }, 885 }) 886 if err != nil { 887 return nil, err 888 } 889 890 filterExpr, err := ConstantFold(batch.EmptyForConstFoldBatch, inExpr, proc, false) 891 if err != nil { 892 return nil, nil 893 } 894 895 return []*Expr{filterExpr}, nil 896 } 897 } 898 } 899 900 // ------------------- partition relatived ------------------- 901 902 // remapPartitionExpr Remap partition expression column references 903 func remapPartitionExpr(builder *QueryBuilder, tableDef *TableDef, pkPosInValues map[int]int) *Expr { 904 if builder.qry.Nodes[0].NodeType != plan.Node_VALUE_SCAN { 905 return nil 906 } 907 908 if tableDef.Partition == nil { 909 return nil 910 } else { 911 partitionExpr := DeepCopyExpr(tableDef.Partition.PartitionExpression) 912 if remapPartExprColRef(partitionExpr, pkPosInValues, tableDef) { 913 return partitionExpr 914 } 915 return nil 916 } 917 } 918 919 // remapPartExprColRef Remap partition expression column references 920 func remapPartExprColRef(expr *Expr, colMap map[int]int, tableDef *TableDef) bool { 921 switch ne := expr.Expr.(type) { 922 case *plan.Expr_Col: 923 cPos := ne.Col.ColPos 924 if ids, ok := colMap[int(cPos)]; ok { 925 ne.Col.RelPos = 0 926 ne.Col.ColPos = int32(ids) 927 ne.Col.Name = tableDef.Cols[cPos].Name 928 } else { 929 return false 930 } 931 932 case *plan.Expr_F: 933 for _, arg := range ne.F.GetArgs() { 934 if res := remapPartExprColRef(arg, colMap, tableDef); !res { 935 return false 936 } 937 } 938 939 case *plan.Expr_W: 940 if res := remapPartExprColRef(ne.W.WindowFunc, colMap, tableDef); !res { 941 return false 942 } 943 944 for _, arg := range ne.W.PartitionBy { 945 if res := remapPartExprColRef(arg, colMap, tableDef); !res { 946 return false 947 } 948 } 949 for _, order := range ne.W.OrderBy { 950 if res := remapPartExprColRef(order.Expr, colMap, tableDef); !res { 951 return false 952 } 953 } 954 } 955 return true 956 }