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: &timestamp.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  }