From 50b6e4f2454c6f4696702f50948159a40d9c2278 Mon Sep 17 00:00:00 2001 From: bRong Njam Date: Fri, 17 Jan 2025 01:45:04 +0800 Subject: [PATCH] implement REPLACE stmt in new DML plan --- pkg/sql/plan/bind_insert.go | 39 ++- pkg/sql/plan/bind_replace.go | 476 +++++++++++++++++++++++++++++++++++ pkg/sql/plan/build.go | 39 ++- 3 files changed, 527 insertions(+), 27 deletions(-) create mode 100644 pkg/sql/plan/bind_replace.go diff --git a/pkg/sql/plan/bind_insert.go b/pkg/sql/plan/bind_insert.go index cb089cb8f124e..7d6eb5d973853 100644 --- a/pkg/sql/plan/bind_insert.go +++ b/pkg/sql/plan/bind_insert.go @@ -33,14 +33,6 @@ func (builder *QueryBuilder) bindInsert(stmt *tree.Insert, bindCtx *BindContext) return 0, err } - // clusterTable, err := getAccountInfoOfClusterTable(ctx, stmt.Accounts, tableDef, tblInfo.isClusterTable[0]) - // if err != nil { - // return 0, err - // } - // if len(stmt.OnDuplicateUpdate) > 0 && clusterTable.IsClusterTable { - // return 0, moerr.NewNotSupported(builder.compCtx.GetContext(), "INSERT ... ON DUPLICATE KEY UPDATE ... for cluster table") - // } - if stmt.IsRestore { builder.isRestore = true if stmt.IsRestoreByTs { @@ -58,7 +50,7 @@ func (builder *QueryBuilder) bindInsert(stmt *tree.Insert, bindCtx *BindContext) }() } - lastNodeID, colName2Idx, skipUniqueIdx, err := builder.initInsertStmt(bindCtx, stmt, dmlCtx.objRefs[0], dmlCtx.tableDefs[0]) + lastNodeID, colName2Idx, skipUniqueIdx, err := builder.initInsertStmt(bindCtx, stmt.Rows, stmt.Columns, dmlCtx.objRefs[0], dmlCtx.tableDefs[0]) if err != nil { return 0, err } @@ -90,11 +82,6 @@ func (builder *QueryBuilder) appendDedupAndMultiUpdateNodesForBindInsert( skipUniqueIdx []bool, astUpdateExprs tree.UpdateExprs, ) (int32, error) { - var err error - - selectNode := builder.qry.Nodes[lastNodeID] - selectTag := selectNode.BindingTags[0] - tableDef := dmlCtx.tableDefs[0] pkName := tableDef.Pkey.PkeyColName @@ -109,7 +96,13 @@ func (builder *QueryBuilder) appendDedupAndMultiUpdateNodesForBindInsert( } } - var onDupAction plan.Node_OnDuplicateAction + var ( + err error + onDupAction plan.Node_OnDuplicateAction + ) + + selectNode := builder.qry.Nodes[lastNodeID] + selectTag := selectNode.BindingTags[0] scanTag := builder.genNewTag() updateExprs := make(map[string]*plan.Expr) @@ -676,20 +669,20 @@ func (builder *QueryBuilder) appendDedupAndMultiUpdateNodesForBindInsert( // If the INSERT statement specifies the columns, it validates the column names against the table definition // and returns an error if any of the column names are invalid. // The function returns the list of insert columns and an error, if any. -func (builder *QueryBuilder) getInsertColsFromStmt(stmt *tree.Insert, tableDef *TableDef) ([]string, error) { +func (builder *QueryBuilder) getInsertColsFromStmt(astCols tree.IdentifierList, tableDef *TableDef) ([]string, error) { var insertColNames []string colToIdx := make(map[string]int) for i, col := range tableDef.Cols { colToIdx[strings.ToLower(col.Name)] = i } - if stmt.Columns == nil { + if astCols == nil { for _, col := range tableDef.Cols { if !col.Hidden { insertColNames = append(insertColNames, col.Name) } } } else { - for _, column := range stmt.Columns { + for _, column := range astCols { colName := strings.ToLower(string(column)) idx, ok := colToIdx[colName] if !ok { @@ -701,7 +694,7 @@ func (builder *QueryBuilder) getInsertColsFromStmt(stmt *tree.Insert, tableDef * return insertColNames, nil } -func (builder *QueryBuilder) initInsertStmt(bindCtx *BindContext, stmt *tree.Insert, objRef *plan.ObjectRef, tableDef *plan.TableDef) (int32, map[string]int32, []bool, error) { +func (builder *QueryBuilder) initInsertStmt(bindCtx *BindContext, astRows *tree.Select, astCols tree.IdentifierList, objRef *plan.ObjectRef, tableDef *plan.TableDef) (int32, map[string]int32, []bool, error) { var ( lastNodeID int32 err error @@ -711,12 +704,12 @@ func (builder *QueryBuilder) initInsertStmt(bindCtx *BindContext, stmt *tree.Ins var insertColumns []string //var ifInsertFromUniqueColMap map[string]bool - if insertColumns, err = builder.getInsertColsFromStmt(stmt, tableDef); err != nil { + if insertColumns, err = builder.getInsertColsFromStmt(astCols, tableDef); err != nil { return 0, nil, nil, err } var astSelect *tree.Select - switch selectImpl := stmt.Rows.Select.(type) { + switch selectImpl := astRows.Select.(type) { // rewrite 'insert into tbl values (1,1)' to 'insert into tbl select * from (values row(1,1))' case *tree.ValuesClause: isAllDefault := false @@ -741,7 +734,7 @@ func (builder *QueryBuilder) initInsertStmt(bindCtx *BindContext, stmt *tree.Ins // example1:insert into a values (); // but it does not work at the case: // insert into a(a) values (); insert into a values (0),(); - if isAllDefault && stmt.Columns != nil { + if isAllDefault && astCols != nil { return 0, nil, nil, moerr.NewInvalidInput(builder.GetContext(), "insert values does not match the number of columns") } lastNodeID, err = builder.buildValueScan(isAllDefault, bindCtx, tableDef, selectImpl, insertColumns) @@ -750,7 +743,7 @@ func (builder *QueryBuilder) initInsertStmt(bindCtx *BindContext, stmt *tree.Ins } case *tree.SelectClause: - astSelect = stmt.Rows + astSelect = astRows subCtx := NewBindContext(builder, bindCtx) lastNodeID, err = builder.bindSelect(astSelect, subCtx, false) diff --git a/pkg/sql/plan/bind_replace.go b/pkg/sql/plan/bind_replace.go new file mode 100644 index 0000000000000..8d3b7d3d49bf9 --- /dev/null +++ b/pkg/sql/plan/bind_replace.go @@ -0,0 +1,476 @@ +// Copyright 2021 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package plan + +import ( + "fmt" + "strings" + + "github.com/matrixorigin/matrixone/pkg/catalog" + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/pb/plan" + "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" +) + +func (builder *QueryBuilder) bindReplace(stmt *tree.Replace, bindCtx *BindContext) (int32, error) { + dmlCtx := NewDMLContext() + err := dmlCtx.ResolveTables(builder.compCtx, tree.TableExprs{stmt.Table}, nil, nil, true) + if err != nil { + return 0, err + } + + lastNodeID, colName2Idx, skipUniqueIdx, err := builder.initInsertStmt(bindCtx, stmt.Rows, stmt.Columns, dmlCtx.objRefs[0], dmlCtx.tableDefs[0]) + if err != nil { + return 0, err + } + + return builder.appendDedupAndMultiUpdateNodesForBindReplace(bindCtx, dmlCtx, lastNodeID, colName2Idx, skipUniqueIdx) +} + +func (builder *QueryBuilder) appendDedupAndMultiUpdateNodesForBindReplace( + bindCtx *BindContext, + dmlCtx *DMLContext, + lastNodeID int32, + colName2Idx map[string]int32, + skipUniqueIdx []bool, +) (int32, error) { + objRef := dmlCtx.objRefs[0] + tableDef := dmlCtx.tableDefs[0] + pkName := tableDef.Pkey.PkeyColName + + if tableDef.TableType != catalog.SystemOrdinaryRel && + tableDef.TableType != catalog.SystemIndexRel { + return 0, moerr.NewUnsupportedDML(builder.GetContext(), "insert into vector/text index table") + } + + for _, idxDef := range tableDef.Indexes { + if !catalog.IsRegularIndexAlgo(idxDef.IndexAlgo) { + return 0, moerr.NewUnsupportedDML(builder.GetContext(), "have vector index table") + } + } + + if pkName == catalog.FakePrimaryKeyColName { + return builder.appendDedupAndMultiUpdateNodesForBindInsert(bindCtx, dmlCtx, lastNodeID, colName2Idx, skipUniqueIdx, nil) + } + + selectNode := builder.qry.Nodes[lastNodeID] + selectTag := selectNode.BindingTags[0] + + { + scanTag := builder.genNewTag() + + // handle primary/unique key confliction + if pkName != catalog.FakePrimaryKeyColName { + builder.addNameByColRef(scanTag, tableDef) + + scanNodeID := builder.appendNode(&plan.Node{ + NodeType: plan.Node_TABLE_SCAN, + TableDef: tableDef, + ObjRef: objRef, + BindingTags: []int32{scanTag}, + ScanSnapshot: bindCtx.snapshot, + }, bindCtx) + + pkPos := tableDef.Name2ColIndex[pkName] + pkTyp := tableDef.Cols[pkPos].Typ + leftExpr := &plan.Expr{ + Typ: pkTyp, + Expr: &plan.Expr_Col{ + Col: &plan.ColRef{ + RelPos: selectTag, + ColPos: colName2Idx[tableDef.Name+"."+pkName], + }, + }, + } + rightExpr := &plan.Expr{ + Typ: pkTyp, + Expr: &plan.Expr_Col{ + Col: &plan.ColRef{ + RelPos: scanTag, + ColPos: pkPos, + }, + }, + } + + joinCond, _ := BindFuncExprImplByPlanExpr(builder.GetContext(), "=", []*plan.Expr{ + leftExpr, + rightExpr, + }) + + lastNodeID = builder.appendNode(&plan.Node{ + NodeType: plan.Node_JOIN, + Children: []int32{lastNodeID, scanNodeID}, + JoinType: plan.Node_LEFT, + OnList: []*plan.Expr{joinCond}, + }, bindCtx) + } + } + + idxObjRefs := make([]*plan.ObjectRef, len(tableDef.Indexes)) + idxTableDefs := make([]*plan.TableDef, len(tableDef.Indexes)) + + //lock main table + lockTargets := make([]*plan.LockTarget, 0, len(tableDef.Indexes)+1) + for _, col := range tableDef.Cols { + if col.Name == pkName && pkName != catalog.FakePrimaryKeyColName { + lockTarget := &plan.LockTarget{ + TableId: tableDef.TblId, + ObjRef: DeepCopyObjectRef(objRef), + PrimaryColIdxInBat: colName2Idx[tableDef.Name+"."+col.Name], + PrimaryColRelPos: selectTag, + PrimaryColTyp: col.Typ, + } + lockTargets = append(lockTargets, lockTarget) + break + } + } + // lock unique key table + for j, idxDef := range tableDef.Indexes { + if !idxDef.TableExist || skipUniqueIdx[j] || !idxDef.Unique { + continue + } + idxObjRef, idxTableDef := builder.compCtx.ResolveIndexTableByRef(dmlCtx.objRefs[0], idxDef.IndexTableName, bindCtx.snapshot) + var pkIdxInBat int32 + + if len(idxDef.Parts) == 1 { + pkIdxInBat = colName2Idx[tableDef.Name+"."+idxDef.Parts[0]] + } else { + pkIdxInBat = colName2Idx[idxTableDef.Name+"."+catalog.IndexTableIndexColName] + } + lockTarget := &plan.LockTarget{ + TableId: idxTableDef.TblId, + ObjRef: idxObjRef, + PrimaryColIdxInBat: pkIdxInBat, + PrimaryColRelPos: selectTag, + PrimaryColTyp: selectNode.ProjectList[int(pkIdxInBat)].Typ, + } + lockTargets = append(lockTargets, lockTarget) + } + if len(lockTargets) > 0 { + lastNodeID = builder.appendNode(&plan.Node{ + NodeType: plan.Node_LOCK_OP, + Children: []int32{lastNodeID}, + TableDef: tableDef, + BindingTags: []int32{builder.genNewTag()}, + LockTargets: lockTargets, + }, bindCtx) + reCheckifNeedLockWholeTable(builder) + } + + scanTag := builder.genNewTag() + + // handle primary/unique key confliction + if pkName != catalog.FakePrimaryKeyColName { + builder.addNameByColRef(scanTag, tableDef) + + scanNodeID := builder.appendNode(&plan.Node{ + NodeType: plan.Node_TABLE_SCAN, + TableDef: tableDef, + ObjRef: objRef, + BindingTags: []int32{scanTag}, + ScanSnapshot: bindCtx.snapshot, + }, bindCtx) + + pkPos := tableDef.Name2ColIndex[pkName] + pkTyp := tableDef.Cols[pkPos].Typ + leftExpr := &plan.Expr{ + Typ: pkTyp, + Expr: &plan.Expr_Col{ + Col: &plan.ColRef{ + RelPos: scanTag, + ColPos: pkPos, + }, + }, + } + + rightExpr := &plan.Expr{ + Typ: pkTyp, + Expr: &plan.Expr_Col{ + Col: &plan.ColRef{ + RelPos: selectTag, + ColPos: colName2Idx[tableDef.Name+"."+pkName], + }, + }, + } + + joinCond, _ := BindFuncExprImplByPlanExpr(builder.GetContext(), "=", []*plan.Expr{ + leftExpr, + rightExpr, + }) + + var dedupColName string + dedupColTypes := make([]plan.Type, len(tableDef.Pkey.Names)) + + if len(tableDef.Pkey.Names) == 1 { + dedupColName = tableDef.Pkey.Names[0] + } else { + dedupColName = "(" + strings.Join(tableDef.Pkey.Names, ",") + ")" + } + + for j, part := range tableDef.Pkey.Names { + dedupColTypes[j] = tableDef.Cols[tableDef.Name2ColIndex[part]].Typ + } + + dedupJoinNode := &plan.Node{ + NodeType: plan.Node_JOIN, + Children: []int32{scanNodeID, lastNodeID}, + JoinType: plan.Node_DEDUP, + OnList: []*plan.Expr{joinCond}, + OnDuplicateAction: plan.Node_FAIL, + DedupColName: dedupColName, + DedupColTypes: dedupColTypes, + } + + lastNodeID = builder.appendNode(dedupJoinNode, bindCtx) + } + + for i, idxDef := range tableDef.Indexes { + if !idxDef.TableExist || skipUniqueIdx[i] { + continue + } + + idxObjRefs[i], idxTableDefs[i] = builder.compCtx.ResolveIndexTableByRef(objRef, idxDef.IndexTableName, bindCtx.snapshot) + + if !idxDef.Unique { + continue + } + + idxTag := builder.genNewTag() + builder.addNameByColRef(idxTag, idxTableDefs[i]) + + idxScanNode := &plan.Node{ + NodeType: plan.Node_TABLE_SCAN, + TableDef: idxTableDefs[i], + ObjRef: idxObjRefs[i], + BindingTags: []int32{idxTag}, + ScanSnapshot: bindCtx.snapshot, + } + idxTableNodeID := builder.appendNode(idxScanNode, bindCtx) + + idxPkPos := idxTableDefs[i].Name2ColIndex[catalog.IndexTableIndexColName] + pkTyp := idxTableDefs[i].Cols[idxPkPos].Typ + + leftExpr := &plan.Expr{ + Typ: pkTyp, + Expr: &plan.Expr_Col{ + Col: &plan.ColRef{ + RelPos: idxTag, + ColPos: idxPkPos, + }, + }, + } + + rightExpr := &plan.Expr{ + Typ: pkTyp, + Expr: &plan.Expr_Col{ + Col: &plan.ColRef{ + RelPos: selectTag, + ColPos: colName2Idx[idxTableDefs[i].Name+"."+catalog.IndexTableIndexColName], + }, + }, + } + + joinCond, _ := BindFuncExprImplByPlanExpr(builder.GetContext(), "=", []*plan.Expr{ + leftExpr, + rightExpr, + }) + + var dedupColName string + dedupColTypes := make([]plan.Type, len(idxDef.Parts)) + + if len(idxDef.Parts) == 1 { + dedupColName = idxDef.Parts[0] + } else { + dedupColName = "(" + for j, part := range idxDef.Parts { + if j == 0 { + dedupColName += catalog.ResolveAlias(part) + } else { + dedupColName += "," + catalog.ResolveAlias(part) + } + } + dedupColName += ")" + } + + for j, part := range idxDef.Parts { + dedupColTypes[j] = tableDef.Cols[tableDef.Name2ColIndex[catalog.ResolveAlias(part)]].Typ + } + + lastNodeID = builder.appendNode(&plan.Node{ + NodeType: plan.Node_JOIN, + Children: []int32{idxTableNodeID, lastNodeID}, + JoinType: plan.Node_DEDUP, + OnList: []*plan.Expr{joinCond}, + OnDuplicateAction: plan.Node_FAIL, + DedupColName: dedupColName, + DedupColTypes: dedupColTypes, + }, bindCtx) + } + + newProjLen := len(selectNode.ProjectList) + for _, idxDef := range tableDef.Indexes { + if idxDef.TableExist && !idxDef.Unique { + newProjLen++ + } + } + + delColName2Idx := make(map[string][2]int32) + + if newProjLen > len(selectNode.ProjectList) { + newProjList := make([]*plan.Expr, 0, newProjLen) + finalProjTag := builder.genNewTag() + pkPos := colName2Idx[tableDef.Name+"."+tableDef.Pkey.PkeyColName] + + for i, expr := range selectNode.ProjectList { + newProjList = append(newProjList, &plan.Expr{ + Typ: expr.Typ, + Expr: &plan.Expr_Col{ + Col: &plan.ColRef{ + RelPos: selectTag, + ColPos: int32(i), + }, + }, + }) + } + + for _, idxDef := range tableDef.Indexes { + if !idxDef.TableExist || idxDef.Unique { + continue + } + + idxTableName := idxDef.IndexTableName + colName2Idx[idxTableName+"."+catalog.IndexTablePrimaryColName] = pkPos + argsLen := len(idxDef.Parts) // argsLen is alwarys greater than 1 for secondary index + args := make([]*plan.Expr, argsLen) + + var colPos int32 + var ok bool + for k := 0; k < argsLen; k++ { + if colPos, ok = colName2Idx[tableDef.Name+"."+catalog.ResolveAlias(idxDef.Parts[k])]; !ok { + errMsg := fmt.Sprintf("bind insert err, can not find colName = %s", idxDef.Parts[k]) + return 0, moerr.NewInternalError(builder.GetContext(), errMsg) + } + + args[k] = &plan.Expr{ + Typ: selectNode.ProjectList[colPos].Typ, + Expr: &plan.Expr_Col{ + Col: &plan.ColRef{ + RelPos: selectTag, + ColPos: colPos, + }, + }, + } + } + + idxExpr, _ := BindFuncExprImplByPlanExpr(builder.GetContext(), "serial_full", args) + colName2Idx[idxTableName+"."+catalog.IndexTableIndexColName] = int32(len(newProjList)) + newProjList = append(newProjList, idxExpr) + + delArgs := make([]*plan.Expr, argsLen) + + for k := 0; k < argsLen; k++ { + if colPos, ok = tableDef.Name2ColIndex[catalog.ResolveAlias(idxDef.Parts[k])]; !ok { + errMsg := fmt.Sprintf("bind insert err, can not find colName = %s", idxDef.Parts[k]) + return 0, moerr.NewInternalError(builder.GetContext(), errMsg) + } + + delArgs[k] = &plan.Expr{ + Typ: selectNode.ProjectList[colPos].Typ, + Expr: &plan.Expr_Col{ + Col: &plan.ColRef{ + RelPos: scanTag, + ColPos: colPos, + }, + }, + } + } + + delIdxExpr, _ := BindFuncExprImplByPlanExpr(builder.GetContext(), "serial_full", delArgs) + delColName2Idx[idxTableName+"."+catalog.IndexTableIndexColName] = [2]int32{finalProjTag, int32(len(newProjList))} + newProjList = append(newProjList, delIdxExpr) + } + + selectTag = finalProjTag + lastNodeID = builder.appendNode(&plan.Node{ + NodeType: plan.Node_PROJECT, + ProjectList: newProjList, + Children: []int32{lastNodeID}, + BindingTags: []int32{selectTag}, + }, bindCtx) + } + + dmlNode := &plan.Node{ + NodeType: plan.Node_MULTI_UPDATE, + BindingTags: []int32{builder.genNewTag()}, + } + + insertCols := make([]plan.ColRef, len(tableDef.Cols)-1) + updateCtx := &plan.UpdateCtx{ + ObjRef: objRef, + TableDef: tableDef, + InsertCols: insertCols, + } + + for i, col := range tableDef.Cols { + if col.Name == catalog.Row_ID { + continue + } + + insertCols[i].RelPos = selectTag + insertCols[i].ColPos = colName2Idx[tableDef.Name+"."+col.Name] + } + + dmlNode.UpdateCtxList = append(dmlNode.UpdateCtxList, updateCtx) + + for i, idxTableDef := range idxTableDefs { + if idxTableDef == nil { + continue + } + + idxInsertCols := make([]plan.ColRef, len(idxTableDef.Cols)-1) + updateCtx := &plan.UpdateCtx{ + ObjRef: idxObjRefs[i], + TableDef: idxTableDef, + InsertCols: idxInsertCols, + } + + for j, col := range idxTableDef.Cols { + if col.Name == catalog.Row_ID { + continue + } + + idxInsertCols[j].RelPos = selectTag + idxInsertCols[j].ColPos = int32(colName2Idx[idxTableDef.Name+"."+col.Name]) + } + + deleteCols := make([]plan.ColRef, 2) + updateCtx.DeleteCols = deleteCols + + delRowIDIdx := delColName2Idx[idxTableDef.Name+"."+catalog.Row_ID] + deleteCols[0].RelPos = delRowIDIdx[0] + deleteCols[0].ColPos = delRowIDIdx[1] + + delPkIdx := delColName2Idx[idxTableDef.Name+"."+catalog.IndexTableIndexColName] + deleteCols[1].RelPos = delPkIdx[0] + deleteCols[1].ColPos = delPkIdx[1] + + dmlNode.UpdateCtxList = append(dmlNode.UpdateCtxList, updateCtx) + } + + dmlNode.Children = append(dmlNode.Children, lastNodeID) + lastNodeID = builder.appendNode(dmlNode, bindCtx) + + return lastNodeID, nil +} diff --git a/pkg/sql/plan/build.go b/pkg/sql/plan/build.go index 8361aa32f5c58..8cf60ed1e30e5 100644 --- a/pkg/sql/plan/build.go +++ b/pkg/sql/plan/build.go @@ -93,6 +93,41 @@ func bindAndOptimizeInsertQuery(ctx CompilerContext, stmt *tree.Insert, isPrepar }, err } +func bindAndOptimizeReplaceQuery(ctx CompilerContext, stmt *tree.Replace, isPrepareStmt bool, skipStats bool) (*Plan, error) { + start := time.Now() + defer func() { + v2.TxnStatementBuildInsertHistogram.Observe(time.Since(start).Seconds()) + }() + + builder := NewQueryBuilder(plan.Query_INSERT, ctx, isPrepareStmt, true) + builder.parseOptimizeHints() + bindCtx := NewBindContext(builder, nil) + if IsSnapshotValid(ctx.GetSnapshot()) { + bindCtx.snapshot = ctx.GetSnapshot() + } + + rootId, err := builder.bindReplace(stmt, bindCtx) + if err != nil { + if err.(*moerr.Error).ErrorCode() == moerr.ErrUnsupportedDML { + return buildReplace(stmt, ctx, false, isPrepareStmt) + } + return nil, err + } + ctx.SetViews(bindCtx.views) + + builder.qry.Steps = append(builder.qry.Steps, rootId) + builder.skipStats = skipStats + query, err := builder.createQuery() + if err != nil { + return nil, err + } + return &Plan{ + Plan: &plan.Plan_Query{ + Query: query, + }, + }, err +} + func bindAndOptimizeLoadQuery(ctx CompilerContext, stmt *tree.Load, isPrepareStmt bool, skipStats bool) (*Plan, error) { // return buildLoad(stmt, ctx, isPrepareStmt) start := time.Now() @@ -163,10 +198,6 @@ func bindAndOptimizeDeleteQuery(ctx CompilerContext, stmt *tree.Delete, isPrepar } func bindAndOptimizeUpdateQuery(ctx CompilerContext, stmt *tree.Update, isPrepareStmt bool, skipStats bool) (*Plan, error) { - // if !isExplain { - // return buildTableUpdate(stmt, ctx, isPrepareStmt) - // } - start := time.Now() defer func() { v2.TxnStatementBuildDeleteHistogram.Observe(time.Since(start).Seconds())