github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/partition_util.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  
    21  	"github.com/matrixorigin/matrixone/pkg/catalog"
    22  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    23  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    24  	"github.com/matrixorigin/matrixone/pkg/container/types"
    25  	"github.com/matrixorigin/matrixone/pkg/container/vector"
    26  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    27  	"github.com/matrixorigin/matrixone/pkg/sql/colexec"
    28  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
    29  	"github.com/matrixorigin/matrixone/pkg/sql/plan/function"
    30  	"github.com/matrixorigin/matrixone/pkg/sql/plan/rule"
    31  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    32  )
    33  
    34  // add this code in buildListPartitionItem
    35  // return buildListPartitionItem(partitionBinder, partitionDef, defs)
    36  func buildListPartitionItem(binder *PartitionBinder, partitionDef *plan.PartitionByDef, defs []*tree.Partition) error {
    37  	for _, def := range defs {
    38  		if partitionDef.PartitionColumns != nil {
    39  			if err := checkListColumnsTypeAndValuesMatch(binder, partitionDef, def); err != nil {
    40  				return err
    41  			}
    42  		} else {
    43  			if err := checkListPartitionValuesIsInt(binder, def, partitionDef); err != nil {
    44  				return err
    45  			}
    46  		}
    47  	}
    48  	return nil
    49  }
    50  
    51  // checkPartitionExprAllowed Check whether the ast expression or sub ast expression of partition expression is used legally
    52  func checkPartitionExprAllowed(ctx context.Context, tb *plan.TableDef, e tree.Expr) error {
    53  	switch v := e.(type) {
    54  	case *tree.FuncExpr:
    55  		funcRef, ok := v.Func.FunctionReference.(*tree.UnresolvedName)
    56  		if !ok {
    57  			return moerr.NewNYI(ctx, "invalid function expr '%v'", v)
    58  		}
    59  		funcName := strings.ToLower(funcRef.Parts[0])
    60  		if _, ok := AllowedPartitionFuncMap[funcName]; ok {
    61  			return nil
    62  		}
    63  
    64  	case *tree.BinaryExpr:
    65  		if _, ok := AllowedPartitionBinaryOpMap[v.Op]; ok {
    66  			return checkNoTimestampArgs(ctx, tb, v.Left, v.Right)
    67  		}
    68  	case *tree.UnaryExpr:
    69  		if _, ok := AllowedPartitionUnaryOpMap[v.Op]; ok {
    70  			return checkNoTimestampArgs(ctx, tb, v.Expr)
    71  		}
    72  	case *tree.ParenExpr, *tree.NumVal, *tree.UnresolvedName, *tree.MaxValue:
    73  		return nil
    74  	}
    75  	return moerr.NewPartitionFunctionIsNotAllowed(ctx)
    76  }
    77  
    78  // checkPartitionExprArgs Check whether the parameters of the partition function are allowed
    79  // see link: https://dev.mysql.com/doc/refman/8.0/en/partitioning-limitations-functions.html
    80  func checkPartitionExprArgs(ctx context.Context, tblInfo *plan.TableDef, e tree.Expr) error {
    81  	expr, ok := e.(*tree.FuncExpr)
    82  	if !ok {
    83  		return nil
    84  	}
    85  
    86  	funcRef, ok := expr.Func.FunctionReference.(*tree.UnresolvedName)
    87  	if !ok {
    88  		return moerr.NewNYI(ctx, "invalid function expr '%v'", expr)
    89  	}
    90  	funcName := strings.ToLower(funcRef.Parts[0])
    91  
    92  	argsType, err := collectArgsType(ctx, tblInfo, expr.Exprs...)
    93  	if err != nil {
    94  		return err
    95  	}
    96  
    97  	switch funcName {
    98  	case "to_days", "to_seconds", "dayofmonth", "month", "dayofyear", "quarter", "yearweek",
    99  		"year", "weekday", "dayofweek", "day":
   100  		return checkResultOK(ctx, hasDateArgs(argsType...))
   101  	case "hour", "minute", "second", "time_to_sec", "microsecond":
   102  		return checkResultOK(ctx, hasTimeArgs(argsType...))
   103  	case "unix_timestamp":
   104  		return checkResultOK(ctx, hasTimestampArgs(argsType...))
   105  	case "from_days":
   106  		return checkResultOK(ctx, hasDateArgs(argsType...) || hasTimeArgs(argsType...))
   107  	case "extract":
   108  		// see link: https://dev.mysql.com/doc/refman/8.0/en/expressions.html#temporal-intervals
   109  		switch strings.ToUpper(expr.Exprs[0].String()) {
   110  		case INTERVAL_YEAR, INTERVAL_YEAR_MONTH, INTERVAL_QUARTER, INTERVAL_MONTH, INTERVAL_DAY:
   111  			return checkResultOK(ctx, hasDateArgs(argsType...))
   112  		case INTERVAL_DAY_MICROSECOND, INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE, INTERVAL_DAY_SECOND:
   113  			return checkResultOK(ctx, hasDatetimeArgs(argsType...))
   114  		case INTERVAL_HOUR, INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND, INTERVAL_MINUTE,
   115  			INTERVAL_MINUTE_SECOND, INTERVAL_SECOND, INTERVAL_MICROSECOND, INTERVAL_HOUR_MICROSECOND,
   116  			INTERVAL_MINUTE_MICROSECOND, INTERVAL_SECOND_MICROSECOND:
   117  			return checkResultOK(ctx, hasTimeArgs(argsType...))
   118  		default:
   119  			// EXTRACT() function with WEEK specifier. The value returned by the EXTRACT() function,
   120  			// when used as EXTRACT(WEEK FROM col), depends on the value of the default_week_format system variable.
   121  			// For this reason, EXTRACT() is not permitted as a partitioning function when it specifies the unit as WEEK.
   122  			return moerr.NewWrongExprInPartitionFunc(ctx)
   123  		}
   124  	case "datediff":
   125  		return checkResultOK(ctx, hasDateArgs(argsType...))
   126  
   127  	case "abs", "ceiling", "floor", "mod":
   128  		has := hasTimestampArgs(argsType...)
   129  		if has {
   130  			return moerr.NewWrongExprInPartitionFunc(ctx)
   131  		}
   132  	}
   133  	return nil
   134  }
   135  
   136  // Collect the types of columns which used as the partition function parameter
   137  func collectArgsType(ctx context.Context, tblInfo *plan.TableDef, exprs ...tree.Expr) ([]int32, error) {
   138  	types := make([]int32, 0, len(exprs))
   139  	for _, arg := range exprs {
   140  		col, ok := arg.(*tree.UnresolvedName)
   141  		if !ok {
   142  			continue
   143  		}
   144  
   145  		// Check whether column name exist in the table
   146  		column := findColumnByName(col.Parts[0], tblInfo)
   147  		if column == nil {
   148  			return nil, moerr.NewBadFieldError(ctx, col.Parts[0], "partition function")
   149  		}
   150  		types = append(types, column.GetTyp().Id)
   151  	}
   152  	return types, nil
   153  }
   154  
   155  // hasDateArgs Check if the arguments contains date or datetime type
   156  func hasDateArgs(argsType ...int32) bool {
   157  	for _, typeId := range argsType {
   158  		if typeId == int32(types.T_date) || typeId == int32(types.T_datetime) {
   159  			return true
   160  		}
   161  	}
   162  	return false
   163  }
   164  
   165  // hasTimeArgs Check if the arguments contains time or datetime type
   166  func hasTimeArgs(argsType ...int32) bool {
   167  	for _, typeId := range argsType {
   168  		return typeId == int32(types.T_time) || typeId == int32(types.T_datetime)
   169  	}
   170  	return false
   171  }
   172  
   173  // hasTimestampArgs Check if the arguments contains timestamp(time zone) type
   174  func hasTimestampArgs(argsType ...int32) bool {
   175  	for _, typeId := range argsType {
   176  		return typeId == int32(types.T_timestamp)
   177  	}
   178  	return false
   179  }
   180  
   181  // hasTimestampArgs Check if the arguments contains datetime type
   182  func hasDatetimeArgs(argsType ...int32) bool {
   183  	for _, typeId := range argsType {
   184  		return typeId == int32(types.T_datetime)
   185  	}
   186  	return false
   187  
   188  }
   189  
   190  // checkNoTimestampArgs Check to confirm that there are no timestamp type arguments in the partition expression
   191  func checkNoTimestampArgs(ctx context.Context, tbInfo *plan.TableDef, exprs ...tree.Expr) error {
   192  	argsType, err := collectArgsType(ctx, tbInfo, exprs...)
   193  	if err != nil {
   194  		return err
   195  	}
   196  	if hasTimestampArgs(argsType...) {
   197  		return moerr.NewWrongExprInPartitionFunc(ctx)
   198  	}
   199  	return nil
   200  }
   201  
   202  // checkResultOK For partition table in mysql, Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed
   203  func checkResultOK(ctx context.Context, ok bool) error {
   204  	if !ok {
   205  		return moerr.NewWrongExprInPartitionFunc(ctx)
   206  	}
   207  	return nil
   208  }
   209  
   210  func checkListColumnsTypeAndValuesMatch(binder *PartitionBinder, partitionDef *plan.PartitionByDef, partition *tree.Partition) error {
   211  	colTypes := collectColumnsType(partitionDef)
   212  
   213  	inClause := partition.Values.(*tree.ValuesIn)
   214  	for _, inValue := range inClause.ValueList {
   215  		expr, err := binder.BindExpr(inValue, 0, true)
   216  		if err != nil {
   217  			return err
   218  		}
   219  
   220  		switch expr.Expr.(type) {
   221  		case *plan.Expr_List:
   222  			tuple := expr.Expr.(*plan.Expr_List)
   223  			if len(colTypes) != len(tuple.List.List) {
   224  				return moerr.NewErrPartitionColumnList(binder.GetContext())
   225  			}
   226  
   227  			for i, colExpr := range tuple.List.List {
   228  				if err := checkPartitionColumnValue(binder, colTypes[i], colExpr); err != nil {
   229  					return err
   230  				}
   231  			}
   232  		case *plan.Expr_Lit, *plan.Expr_F:
   233  			if len(colTypes) != 1 {
   234  				return moerr.NewErrPartitionColumnList(binder.GetContext())
   235  			}
   236  
   237  			if err := checkPartitionColumnValue(binder, colTypes[0], expr); err != nil {
   238  				return err
   239  			}
   240  		case *plan.Expr_Max:
   241  			return moerr.NewErrMaxvalueInValuesIn(binder.GetContext())
   242  		default:
   243  			return moerr.NewPartitionFunctionIsNotAllowed(binder.GetContext())
   244  		}
   245  	}
   246  	return nil
   247  }
   248  
   249  // checkPartitionColumnValue check whether the types of partition column and partition value match
   250  func checkPartitionColumnValue(binder *PartitionBinder, colType Type, colExpr *plan.Expr) error {
   251  	val, err := EvalPlanExpr(binder.GetContext(), colExpr, binder.builder.compCtx.GetProcess())
   252  	if err != nil {
   253  		return err
   254  	}
   255  
   256  	vkind := types.T(val.Typ.Id)
   257  
   258  	switch types.T(colType.Id) {
   259  	case types.T_date, types.T_datetime, types.T_time:
   260  		switch vkind {
   261  		case types.T_varchar, types.T_char, types.T_any:
   262  		default:
   263  			return moerr.NewWrongTypeColumnValue(binder.GetContext())
   264  		}
   265  	case types.T_int8, types.T_int16, types.T_int32, types.T_int64, types.T_uint8, types.T_uint16, types.T_uint32, types.T_uint64, types.T_bit:
   266  		switch vkind {
   267  		case types.T_int8, types.T_int16, types.T_int32, types.T_int64, types.T_uint8, types.T_uint16, types.T_uint32, types.T_uint64, types.T_bit, types.T_any:
   268  		default:
   269  			return moerr.NewWrongTypeColumnValue(binder.GetContext())
   270  		}
   271  	case types.T_float32, types.T_float64:
   272  		switch vkind {
   273  		case types.T_float32, types.T_float64, types.T_any:
   274  		default:
   275  			return moerr.NewWrongTypeColumnValue(binder.GetContext())
   276  		}
   277  	case types.T_varchar, types.T_char:
   278  		switch vkind {
   279  		case types.T_varchar, types.T_char, types.T_any:
   280  		default:
   281  			return moerr.NewWrongTypeColumnValue(binder.GetContext())
   282  		}
   283  	}
   284  
   285  	if castExpr, err := forceCastExpr(binder.GetContext(), val, colType); err != nil {
   286  		return err
   287  	} else {
   288  		if castVal, err := EvalPlanExpr(binder.GetContext(), castExpr, binder.builder.compCtx.GetProcess()); err != nil {
   289  			return moerr.NewWrongTypeColumnValue(binder.GetContext())
   290  		} else {
   291  			if _, ok := castVal.Expr.(*plan.Expr_Lit); !ok {
   292  				return moerr.NewPartitionFunctionIsNotAllowed(binder.GetContext())
   293  			}
   294  		}
   295  	}
   296  	return nil
   297  }
   298  
   299  func checkListPartitionValuesIsInt(binder *PartitionBinder, partition *tree.Partition, info *plan.PartitionByDef) error {
   300  	unsignedFlag := types.T(info.PartitionExpr.Expr.Typ.Id).IsUnsignedInt()
   301  	inClause := partition.Values.(*tree.ValuesIn)
   302  	for _, inValue := range inClause.ValueList {
   303  		expr, err := binder.BindExpr(inValue, 0, true)
   304  		if err != nil {
   305  			return err
   306  		}
   307  		switch expr.Expr.(type) {
   308  		case *plan.Expr_Lit, *plan.Expr_F:
   309  			evalExpr, err := EvalPlanExpr(binder.GetContext(), expr, binder.builder.compCtx.GetProcess())
   310  			if err != nil {
   311  				return err
   312  			}
   313  
   314  			cval, ok1 := evalExpr.Expr.(*plan.Expr_Lit)
   315  			if !ok1 {
   316  				return moerr.NewPartitionFunctionIsNotAllowed(binder.GetContext())
   317  			}
   318  
   319  			switch types.T(evalExpr.Typ.Id) {
   320  			case types.T_uint8, types.T_uint16, types.T_uint32, types.T_uint64, types.T_bit, types.T_any:
   321  			case types.T_int8, types.T_int16, types.T_int32, types.T_int64:
   322  				switch value := cval.Lit.Value.(type) {
   323  				case *plan.Literal_I8Val:
   324  					if value.I8Val < 0 && unsignedFlag {
   325  						//return moerr.NewInternalError(binder.GetContext(), "Partition constant is out of partition function domain")
   326  						return moerr.NewPartitionConstDomain(binder.GetContext())
   327  					}
   328  				case *plan.Literal_I16Val:
   329  					if value.I16Val < 0 && unsignedFlag {
   330  						//return moerr.NewInternalError(binder.GetContext(), "Partition constant is out of partition function domain")
   331  						return moerr.NewPartitionConstDomain(binder.GetContext())
   332  					}
   333  				case *plan.Literal_I32Val:
   334  					if value.I32Val < 0 && unsignedFlag {
   335  						//return moerr.NewInternalError(binder.GetContext(), "Partition constant is out of partition function domain")
   336  						return moerr.NewPartitionConstDomain(binder.GetContext())
   337  					}
   338  				case *plan.Literal_I64Val:
   339  					if value.I64Val < 0 && unsignedFlag {
   340  						//return moerr.NewInternalError(binder.GetContext(), "Partition constant is out of partition function domain")
   341  						return moerr.NewPartitionConstDomain(binder.GetContext())
   342  					}
   343  				default:
   344  					return moerr.NewValuesIsNotIntType(binder.GetContext(), partition.Name)
   345  				}
   346  			default:
   347  				return moerr.NewValuesIsNotIntType(binder.GetContext(), partition.Name)
   348  			}
   349  		case *plan.Expr_List:
   350  			return moerr.NewErrRowSinglePartitionField(binder.GetContext())
   351  		case *plan.Expr_Max:
   352  			return moerr.NewErrMaxvalueInValuesIn(binder.GetContext())
   353  		default:
   354  			return moerr.NewPartitionFunctionIsNotAllowed(binder.GetContext())
   355  		}
   356  	}
   357  	return nil
   358  }
   359  
   360  // add this code in buildRangePartitionDefinitions
   361  // return buildRangePartitionDefinitionItem(partitionBinder, partitionDef, defs)
   362  func buildRangePartitionItem(binder *PartitionBinder, partitionDef *plan.PartitionByDef, defs []*tree.Partition) error {
   363  	for _, def := range defs {
   364  		if partitionDef.PartitionColumns != nil && len(partitionDef.PartitionColumns.Columns) > 0 {
   365  			if err := checkRangeColumnsTypeAndValuesMatch(binder, partitionDef, def); err != nil {
   366  				return err
   367  			}
   368  		} else {
   369  			if err := checkPartitionValuesIsInt(binder, def, partitionDef); err != nil {
   370  				return err
   371  			}
   372  		}
   373  	}
   374  	return nil
   375  }
   376  
   377  // 我认为这里的PartitionBinder是一个独立的binder,不需要表的上下文信息,可以单独实例化
   378  func checkRangeColumnsTypeAndValuesMatch(binder *PartitionBinder, partitionDef *plan.PartitionByDef, partition *tree.Partition) error {
   379  	if valuesLessThan, ok := partition.Values.(*tree.ValuesLessThan); ok {
   380  		exprs := valuesLessThan.ValueList
   381  		// Validate() has already checked len(colNames) = len(exprs)
   382  		// create table ... partition by range columns (cols)
   383  		// partition p0 values less than (expr)
   384  		// check the type of cols[i] and expr is consistent.
   385  		colTypes := collectColumnsType(partitionDef)
   386  		for i, colExpr := range exprs {
   387  			if _, ok1 := colExpr.(*tree.MaxValue); ok1 {
   388  				continue
   389  			}
   390  			colType := colTypes[i]
   391  			val, err := binder.BindExpr(colExpr, 0, true)
   392  			if err != nil {
   393  				return err
   394  			}
   395  			switch val.Expr.(type) {
   396  			case *plan.Expr_Lit, *plan.Expr_Max:
   397  			case *plan.Expr_F:
   398  			default:
   399  				//return moerr.NewInternalError(binder.GetContext(), "This partition function is not allowed")
   400  				return moerr.NewPartitionFunctionIsNotAllowed(binder.GetContext())
   401  			}
   402  
   403  			// Check val.ConvertTo(colType) doesn't work, so we need this case by case check.
   404  			vkind := val.Typ
   405  			switch types.T(colType.Id) {
   406  			case types.T_date, types.T_datetime:
   407  				switch types.T(vkind.Id) {
   408  				case types.T_varchar, types.T_char:
   409  				default:
   410  					//return moerr.NewInternalError(binder.GetContext(), "Partition column values of incorrect type")
   411  					return moerr.NewWrongTypeColumnValue(binder.GetContext())
   412  				}
   413  			case types.T_int8, types.T_int16, types.T_int32, types.T_int64, types.T_uint8, types.T_uint16, types.T_uint32, types.T_uint64, types.T_bit:
   414  				switch types.T(vkind.Id) {
   415  				case types.T_int8, types.T_int16, types.T_int32, types.T_int64, types.T_uint8, types.T_uint16, types.T_uint32, types.T_uint64, types.T_bit: //+types.T_null:
   416  				default:
   417  					//return moerr.NewInternalError(binder.GetContext(), "Partition column values of incorrect type")
   418  					return moerr.NewWrongTypeColumnValue(binder.GetContext())
   419  				}
   420  			case types.T_float32, types.T_float64:
   421  				switch types.T(vkind.Id) {
   422  				case types.T_float32, types.T_float64: //+types.T_null:
   423  				default:
   424  					//return moerr.NewInternalError(binder.GetContext(), "Partition column values of incorrect type")
   425  					return moerr.NewWrongTypeColumnValue(binder.GetContext())
   426  				}
   427  			case types.T_varchar, types.T_char:
   428  				switch types.T(vkind.Id) {
   429  				case types.T_varchar, types.T_char: //+types.T_null:
   430  				default:
   431  					//return moerr.NewInternalError(binder.GetContext(), "Partition column values of incorrect type")
   432  					return moerr.NewWrongTypeColumnValue(binder.GetContext())
   433  				}
   434  			}
   435  		}
   436  		return nil
   437  	} else {
   438  		return moerr.NewInternalError(binder.GetContext(), "list partition function is not values in expression")
   439  	}
   440  }
   441  
   442  func checkPartitionValuesIsInt(binder *PartitionBinder, partition *tree.Partition, info *plan.PartitionByDef) error {
   443  	unsignedFlag := types.T(info.PartitionExpr.Expr.Typ.Id).IsUnsignedInt()
   444  	if valuesLess, ok := partition.Values.(*tree.ValuesLessThan); ok {
   445  		exprs := valuesLess.ValueList
   446  		for _, exp := range exprs {
   447  			if _, ok := exp.(*tree.MaxValue); ok {
   448  				continue
   449  			}
   450  			val, err := binder.BindExpr(exp, 0, true)
   451  			if err != nil {
   452  				return err
   453  			}
   454  
   455  			compilerContext := binder.builder.compCtx
   456  			evalExpr, err := EvalPlanExpr(binder.GetContext(), val, compilerContext.GetProcess())
   457  			if err != nil {
   458  				return err
   459  			}
   460  
   461  			cval, ok1 := evalExpr.Expr.(*plan.Expr_Lit)
   462  			if !ok1 {
   463  				//return moerr.NewInternalError(binder.GetContext(), "This partition function is not allowed")
   464  				return moerr.NewPartitionFunctionIsNotAllowed(binder.GetContext())
   465  			}
   466  
   467  			switch types.T(evalExpr.Typ.Id) {
   468  			case types.T_uint8, types.T_uint16, types.T_uint32, types.T_uint64, types.T_bit, types.T_any:
   469  			case types.T_int8, types.T_int16, types.T_int32, types.T_int64:
   470  				switch value := cval.Lit.Value.(type) {
   471  				case *plan.Literal_I8Val:
   472  					if value.I8Val < 0 && unsignedFlag {
   473  						//return moerr.NewInternalError(binder.GetContext(), "Partition constant is out of partition function domain")
   474  						return moerr.NewPartitionConstDomain(binder.GetContext())
   475  					}
   476  				case *plan.Literal_I16Val:
   477  					if value.I16Val < 0 && unsignedFlag {
   478  						//return moerr.NewInternalError(binder.GetContext(), "Partition constant is out of partition function domain")
   479  						return moerr.NewPartitionConstDomain(binder.GetContext())
   480  					}
   481  				case *plan.Literal_I32Val:
   482  					if value.I32Val < 0 && unsignedFlag {
   483  						//return moerr.NewInternalError(binder.GetContext(), "Partition constant is out of partition function domain")
   484  						return moerr.NewPartitionConstDomain(binder.GetContext())
   485  					}
   486  				case *plan.Literal_I64Val:
   487  					if value.I64Val < 0 && unsignedFlag {
   488  						//return moerr.NewInternalError(binder.GetContext(), "Partition constant is out of partition function domain")
   489  						return moerr.NewPartitionConstDomain(binder.GetContext())
   490  					}
   491  				default:
   492  					//return moerr.NewInternalError(binder.GetContext(), "VALUES value for partition '%-.64s' must have type INT", partition.Name)
   493  					return moerr.NewValuesIsNotIntType(binder.GetContext(), partition.Name)
   494  				}
   495  			default:
   496  				//return moerr.NewInternalError(binder.GetContext(), "VALUES value for partition '%-.64s' must have type INT", partition.Name)
   497  				return moerr.NewValuesIsNotIntType(binder.GetContext(), partition.Name)
   498  			}
   499  		}
   500  	}
   501  	return nil
   502  }
   503  
   504  // checkPartitionByList checks validity of list partition.
   505  func checkPartitionByList(partitionBinder *PartitionBinder, partitionDef *plan.PartitionByDef, tableDef *TableDef) error {
   506  	return checkListPartitionValue(partitionBinder, partitionDef, tableDef)
   507  }
   508  
   509  // checkListPartitionValue Check if the definition of the list partition entry is correct
   510  func checkListPartitionValue(partitionBinder *PartitionBinder, partitionDef *plan.PartitionByDef, tableDef *TableDef) error {
   511  	ctx := partitionBinder.GetContext()
   512  	if len(partitionDef.Partitions) == 0 {
   513  		return moerr.NewPartitionsMustBeDefined(ctx, "LIST")
   514  	}
   515  
   516  	expStrs, err := formatListPartitionValue(partitionBinder, tableDef, partitionDef)
   517  	if err != nil {
   518  		return err
   519  	}
   520  
   521  	partitionsValuesMap := make(map[string]struct{})
   522  	for _, str := range expStrs {
   523  		if _, ok := partitionsValuesMap[str]; ok {
   524  			return moerr.NewMultipleDefConstInListPart(ctx)
   525  		}
   526  		partitionsValuesMap[str] = struct{}{}
   527  	}
   528  	return nil
   529  }
   530  
   531  func formatListPartitionValue(binder *PartitionBinder, tblInfo *TableDef, pi *plan.PartitionByDef) ([]string, error) {
   532  	defs := pi.Partitions
   533  	var colTps []Type
   534  	if pi.PartitionExpr != nil {
   535  		tp := types.T_int64
   536  		if isPartExprUnsigned(pi) {
   537  			tp = types.T_uint64
   538  		}
   539  		toType := tp.ToType()
   540  		makePlan2Type(&toType)
   541  		colTps = []Type{makePlan2Type(&toType)}
   542  	} else {
   543  		colTps = make([]Type, 0, len(pi.PartitionColumns.PartitionColumns))
   544  		for _, colName := range pi.PartitionColumns.PartitionColumns {
   545  			colInfo := findColumnByName(colName, tblInfo)
   546  			if colInfo == nil {
   547  				return nil, moerr.NewFieldNotFoundPart(binder.GetContext())
   548  			}
   549  			colTps = append(colTps, colInfo.Typ)
   550  		}
   551  	}
   552  
   553  	exprStrs := make([]string, 0)
   554  	inValueStrs := make([]string, 0)
   555  	compilerContext := binder.builder.compCtx
   556  	for _, def := range defs {
   557  		for _, val := range def.InValues {
   558  			inValueStrs = inValueStrs[:0]
   559  			switch val.Expr.(type) {
   560  			case *plan.Expr_List:
   561  				temp := ""
   562  				expr := val.Expr.(*plan.Expr_List)
   563  				for k, elem := range expr.List.List {
   564  					if elemStr, err := evalPartitionFieldExpr(binder.GetContext(), compilerContext.GetProcess(), colTps[k], elem); err != nil {
   565  						return nil, err
   566  					} else {
   567  						if k == 0 {
   568  							temp += "(" + elemStr
   569  						} else {
   570  							temp += "," + elemStr
   571  						}
   572  					}
   573  				}
   574  				temp += ")"
   575  				inValueStrs = append(inValueStrs, temp)
   576  			default:
   577  				if exprStr, err := evalPartitionFieldExpr(binder.GetContext(), compilerContext.GetProcess(), colTps[0], val); err != nil {
   578  					return nil, err
   579  				} else {
   580  					inValueStrs = append(inValueStrs, exprStr)
   581  				}
   582  			}
   583  			exprStrs = append(exprStrs, strings.Join(inValueStrs, ","))
   584  		}
   585  	}
   586  	return exprStrs, nil
   587  }
   588  
   589  func isPartExprUnsigned(pi *plan.PartitionByDef) bool {
   590  	return types.T(pi.PartitionExpr.Expr.Typ.Id).IsUnsignedInt()
   591  }
   592  
   593  func evalPartitionFieldExpr(ctx context.Context, process *process.Process, colType Type, colExpr *plan.Expr) (string, error) {
   594  	evalExpr, err := EvalPlanExpr(ctx, colExpr, process)
   595  	if err != nil {
   596  		return "", err
   597  	}
   598  
   599  	castExpr, err := forceCastExpr(ctx, evalExpr, colType)
   600  	if err != nil {
   601  		return "", err
   602  	}
   603  
   604  	castVal, err := EvalPlanExpr(ctx, castExpr, process)
   605  	if err != nil {
   606  		return "", moerr.NewWrongTypeColumnValue(ctx)
   607  	}
   608  
   609  	if cval, ok := castVal.Expr.(*plan.Expr_Lit); ok {
   610  		return cval.Lit.String(), nil
   611  	} else {
   612  		return "", moerr.NewPartitionFunctionIsNotAllowed(ctx)
   613  	}
   614  }
   615  
   616  // collectPartitionColumnsType
   617  func collectColumnsType(partitionDef *plan.PartitionByDef) []Type {
   618  	if len(partitionDef.PartitionColumns.Columns) > 0 {
   619  		colTypes := make([]Type, 0, len(partitionDef.PartitionColumns.Columns))
   620  		for _, col := range partitionDef.PartitionColumns.Columns {
   621  			colTypes = append(colTypes, col.Typ)
   622  		}
   623  		return colTypes
   624  	}
   625  	return nil
   626  }
   627  
   628  func findColumnByName(colName string, tbdef *TableDef) *ColDef {
   629  	if tbdef == nil {
   630  		return nil
   631  	}
   632  	for _, colDef := range tbdef.Cols {
   633  		if colDef.Name == colName {
   634  			return colDef
   635  		}
   636  	}
   637  	return nil
   638  }
   639  
   640  func EvalPlanExpr(ctx context.Context, expr *plan.Expr, process *process.Process) (*plan.Expr, error) {
   641  	switch expr.Expr.(type) {
   642  	case *plan.Expr_Lit:
   643  		return expr, nil
   644  	default:
   645  		// try to calculate default value, return err if fails
   646  		newExpr, err := PartitionFuncConstantFold(batch.EmptyForConstFoldBatch, expr, process)
   647  		if err != nil {
   648  			return nil, err
   649  		}
   650  		if _, ok := newExpr.Expr.(*plan.Expr_Lit); ok {
   651  			return newExpr, nil
   652  		} else {
   653  			//return nil, moerr.NewInternalError(ctx, "This partition function is not allowed")
   654  			return nil, moerr.NewPartitionFunctionIsNotAllowed(ctx)
   655  		}
   656  
   657  	}
   658  }
   659  
   660  func PartitionFuncConstantFold(bat *batch.Batch, e *plan.Expr, proc *process.Process) (*plan.Expr, error) {
   661  	// If it is Expr_List, perform constant folding on its elements
   662  	if exprImpl, ok := e.Expr.(*plan.Expr_List); ok {
   663  		exprList := exprImpl.List.List
   664  		for i := range exprList {
   665  			foldExpr, err := PartitionFuncConstantFold(bat, exprList[i], proc)
   666  			if err != nil {
   667  				return e, nil
   668  			}
   669  			exprList[i] = foldExpr
   670  		}
   671  
   672  		vec, err := colexec.GenerateConstListExpressionExecutor(proc, exprList)
   673  		if err != nil {
   674  			return nil, err
   675  		}
   676  		defer vec.Free(proc.Mp())
   677  
   678  		vec.InplaceSortAndCompact()
   679  		data, err := vec.MarshalBinary()
   680  		if err != nil {
   681  			return nil, err
   682  		}
   683  
   684  		return &plan.Expr{
   685  			Typ: e.Typ,
   686  			Expr: &plan.Expr_Vec{
   687  				Vec: &plan.LiteralVec{
   688  					Len:  int32(vec.Length()),
   689  					Data: data,
   690  				},
   691  			},
   692  		}, nil
   693  	}
   694  
   695  	ef, ok := e.Expr.(*plan.Expr_F)
   696  	if !ok || proc == nil {
   697  		return e, nil
   698  	}
   699  
   700  	overloadID := ef.F.Func.GetObj()
   701  	f, err := function.GetFunctionById(proc.Ctx, overloadID)
   702  	if err != nil {
   703  		return nil, err
   704  	}
   705  	if ef.F.Func.ObjName != "cast" && f.CannotFold() { // function cannot be fold
   706  		return e, nil
   707  	}
   708  	for i := range ef.F.Args {
   709  		if ef.F.Args[i], err = PartitionFuncConstantFold(bat, ef.F.Args[i], proc); err != nil {
   710  			return nil, err
   711  		}
   712  	}
   713  	if !rule.IsConstant(e, false) {
   714  		return e, nil
   715  	}
   716  
   717  	vec, err := colexec.EvalExpressionOnce(proc, e, []*batch.Batch{bat})
   718  	if err != nil {
   719  		return nil, err
   720  	}
   721  	defer vec.Free(proc.Mp())
   722  	c := rule.GetConstantValue(vec, true, 0)
   723  	if c == nil {
   724  		return e, nil
   725  	}
   726  	e.Expr = &plan.Expr_Lit{
   727  		Lit: c,
   728  	}
   729  	return e, nil
   730  }
   731  
   732  // AllowedPartitionFuncMap stores functions which can be used in the partition expression.
   733  // See Link: https://dev.mysql.com/doc/refman/8.0/en/partitioning-limitations-functions.html
   734  var AllowedPartitionFuncMap = map[string]int{
   735  	"to_days":        1,
   736  	"to_seconds":     1,
   737  	"dayofmonth":     1,
   738  	"month":          1,
   739  	"dayofyear":      1,
   740  	"quarter":        1,
   741  	"yearweek":       1,
   742  	"year":           1,
   743  	"weekday":        1,
   744  	"dayofweek":      1,
   745  	"day":            1,
   746  	"hour":           1,
   747  	"minute":         1,
   748  	"second":         1,
   749  	"time_to_sec":    1,
   750  	"microsecond":    1,
   751  	"unix_timestamp": 1,
   752  	"from_days":      1,
   753  	"extract":        1,
   754  	"abs":            1,
   755  	"ceiling":        1,
   756  	"ceil":           1,
   757  	"datediff":       1,
   758  	"floor":          1,
   759  	"mod":            1,
   760  }
   761  
   762  // AllowedPartitionBinaryOpMap store the operators of Binary operation expression
   763  // link ref:https://dev.mysql.com/doc/refman/8.0/en/partitioning-limitations.html
   764  var AllowedPartitionBinaryOpMap = map[tree.BinaryOp]string{
   765  	tree.PLUS:        "+",
   766  	tree.MINUS:       "-",
   767  	tree.MULTI:       "*",
   768  	tree.INTEGER_DIV: "div",
   769  	tree.MOD:         "%",
   770  }
   771  
   772  // AllowedPartitionUnaryOpMap store the operators of Unary expression
   773  // link ref:https://dev.mysql.com/doc/refman/8.0/en/partitioning-limitations.html
   774  var AllowedPartitionUnaryOpMap = map[tree.UnaryOp]string{
   775  	tree.UNARY_PLUS:  "+",
   776  	tree.UNARY_MINUS: "-",
   777  }
   778  
   779  // The following code shows the expected form of the expr argument for each unit value.
   780  // see link: https://dev.mysql.com/doc/refman/8.0/en/expressions.html#temporal-intervals
   781  const (
   782  	// INTERVAL_MICROSECOND is the time or timestamp unit MICROSECOND.
   783  	INTERVAL_MICROSECOND = "MICROSECOND"
   784  	// INTERVAL_SECOND is the time or timestamp unit SECOND.
   785  	INTERVAL_SECOND = "SECOND"
   786  	// INTERVAL_MINUTE is the time or timestamp unit MINUTE.
   787  	INTERVAL_MINUTE = "MINUTE"
   788  	// INTERVAL_HOUR is the time or timestamp unit HOUR.
   789  	INTERVAL_HOUR = "HOUR"
   790  	// INTERVAL_DAY is the time or timestamp unit DAY.
   791  	INTERVAL_DAY = "DAY"
   792  	// INTERVAL_WEEK is the time or timestamp unit WEEK.
   793  	INTERVAL_WEEK = "WEEK"
   794  	// INTERVAL_MONTH is the time or timestamp unit MONTH.
   795  	INTERVAL_MONTH = "MONTH"
   796  	// INTERVAL_QUARTER is the time or timestamp unit QUARTER.
   797  	INTERVAL_QUARTER = "QUARTER"
   798  	// INTERVAL_YEAR is the time or timestamp unit YEAR.
   799  	INTERVAL_YEAR = "YEAR"
   800  	// INTERVAL_SECOND_MICROSECOND is the time unit SECOND_MICROSECOND.
   801  	INTERVAL_SECOND_MICROSECOND = "SECOND_MICROSECOND"
   802  	// INTERVAL_MINUTE_MICROSECOND is the time unit MINUTE_MICROSECOND.
   803  	INTERVAL_MINUTE_MICROSECOND = "MINUTE_MICROSECOND"
   804  	// INTERVAL_MINUTE_SECOND is the time unit MINUTE_SECOND.
   805  	INTERVAL_MINUTE_SECOND = "MINUTE_SECOND"
   806  	// INTERVAL_HOUR_MICROSECOND is the time unit HOUR_MICROSECOND.
   807  	INTERVAL_HOUR_MICROSECOND = "HOUR_MICROSECOND"
   808  	// INTERVAL_HOUR_SECOND is the time unit HOUR_SECOND.
   809  	INTERVAL_HOUR_SECOND = "HOUR_SECOND"
   810  	// INTERVAL_HOUR_MINUTE is the time unit HOUR_MINUTE.
   811  	INTERVAL_HOUR_MINUTE = "HOUR_MINUTE"
   812  	// INTERVAL_DAY_MICROSECOND is the time unit DAY_MICROSECOND.
   813  	INTERVAL_DAY_MICROSECOND = "DAY_MICROSECOND"
   814  	// INTERVAL_DAY_SECOND is the time unit DAY_SECOND.
   815  	INTERVAL_DAY_SECOND = "DAY_SECOND"
   816  	// INTERVAL_DAY_MINUTE is the time unit DAY_MINUTE.
   817  	INTERVAL_DAY_MINUTE = "DAY_MINUTE"
   818  	// INTERVAL_DAY_HOUR is the time unit DAY_HOUR.
   819  	INTERVAL_DAY_HOUR = "DAY_HOUR"
   820  	// INTERVAL_YEAR_MONTH is the time unit YEAR_MONTH.
   821  	INTERVAL_YEAR_MONTH = "YEAR_MONTH"
   822  )
   823  
   824  // onlyHasHiddenPrimaryKey checks the primary key is hidden or not
   825  func onlyHasHiddenPrimaryKey(tableDef *TableDef) bool {
   826  	if tableDef == nil {
   827  		return false
   828  	}
   829  	pk := tableDef.GetPkey()
   830  	return pk != nil && pk.GetPkeyColName() == catalog.FakePrimaryKeyColName
   831  }
   832  
   833  // checkPartitionByRange Check the validity of each partition definition in range partition.
   834  func checkPartitionByRange(partitionBinder *PartitionBinder, partitionDef *plan.PartitionByDef, tbInfo *TableDef) error {
   835  	if partitionDef.PartitionColumns != nil {
   836  		return checkRangeColumnsPartitionValue(partitionBinder, partitionDef, tbInfo)
   837  	}
   838  	return checkRangePartitionValue(partitionBinder, partitionDef, tbInfo)
   839  }
   840  
   841  // checkRangePartitionValue check if the 'less than value' for each partition is strictly monotonically increasing.
   842  func checkRangePartitionValue(partitionBinder *PartitionBinder, partitionDef *plan.PartitionByDef, tbInfo *TableDef) error {
   843  	ctx := partitionBinder.GetContext()
   844  
   845  	partdefs := partitionDef.Partitions
   846  	if len(partdefs) == 0 {
   847  		return nil
   848  	}
   849  
   850  	if _, ok := partdefs[len(partdefs)-1].LessThan[0].Expr.(*plan.Expr_Max); ok {
   851  		partdefs = partdefs[:len(partdefs)-1]
   852  	}
   853  	isUnsigned := types.T(partitionDef.PartitionExpr.Expr.Typ.Id).IsUnsignedInt()
   854  	var prevRangeValue interface{}
   855  	for i := 0; i < len(partdefs); i++ {
   856  		if _, isMaxVal := partdefs[i].LessThan[0].Expr.(*plan.Expr_Max); isMaxVal {
   857  			return moerr.NewErrPartitionMaxvalue(ctx)
   858  		}
   859  		currentRangeValue, err := getRangeValue(ctx, partitionDef, partdefs[i].LessThan[0], isUnsigned, partitionBinder.builder.compCtx.GetProcess())
   860  		if err != nil {
   861  			return err
   862  		}
   863  
   864  		if i == 0 {
   865  			prevRangeValue = currentRangeValue
   866  			continue
   867  		}
   868  
   869  		if isUnsigned {
   870  			if currentRangeValue.(uint64) <= prevRangeValue.(uint64) {
   871  				return moerr.NewErrRangeNotIncreasing(ctx)
   872  			}
   873  		} else {
   874  			if currentRangeValue.(int64) <= prevRangeValue.(int64) {
   875  				return moerr.NewErrRangeNotIncreasing(ctx)
   876  			}
   877  		}
   878  		prevRangeValue = currentRangeValue
   879  	}
   880  	return nil
   881  }
   882  
   883  // checkRangeColumnsPartitionValue check whether "less than value" of each partition is strictly increased in Lexicographic order order.
   884  func checkRangeColumnsPartitionValue(partitionBinder *PartitionBinder, partitionDef *plan.PartitionByDef, tbInfo *TableDef) error {
   885  	ctx := partitionBinder.GetContext()
   886  	partdefs := partitionDef.Partitions
   887  	if len(partdefs) < 1 {
   888  		return moerr.NewPartitionsMustBeDefined(ctx, "RANGE")
   889  	}
   890  
   891  	curr := partdefs[0]
   892  	if len(curr.LessThan) != len(partitionDef.PartitionColumns.PartitionColumns) {
   893  		return moerr.NewErrPartitionColumnList(ctx)
   894  	}
   895  
   896  	var prev *plan.PartitionItem
   897  	for i := 1; i < len(partdefs); i++ {
   898  		prev, curr = curr, partdefs[i]
   899  		res, err := compareTwoRangeColumns(ctx, curr, prev, partitionDef, tbInfo, partitionBinder)
   900  		if err != nil {
   901  			return err
   902  		}
   903  		if !res {
   904  			return moerr.NewErrRangeNotIncreasing(ctx)
   905  		}
   906  	}
   907  	return nil
   908  }
   909  
   910  // getRangeValue gets an integer value from range value expression
   911  // The second returned boolean value indicates whether the input string is a constant expression.
   912  func getRangeValue(ctx context.Context, partitionDef *plan.PartitionByDef, expr *Expr, unsigned bool, process *process.Process) (interface{}, error) {
   913  	// Unsigned integer was converted to uint64
   914  	if unsigned {
   915  		if cExpr, ok := expr.Expr.(*plan.Expr_Lit); ok {
   916  			return getIntConstVal[uint64](cExpr), nil
   917  		}
   918  		evalExpr, err := EvalPlanExpr(ctx, expr, process)
   919  		if err != nil {
   920  			return 0, err
   921  		}
   922  		cVal, ok := evalExpr.Expr.(*plan.Expr_Lit)
   923  		if ok {
   924  			return getIntConstVal[uint64](cVal), nil
   925  		}
   926  	} else {
   927  		// signed integer was converted to int64
   928  		if cExpr, ok := expr.Expr.(*plan.Expr_Lit); ok {
   929  			return getIntConstVal[int64](cExpr), nil
   930  		}
   931  
   932  		// The range partition `less than value` may be not an integer, it could be a constant expression.
   933  		evalExpr, err := EvalPlanExpr(ctx, expr, process)
   934  		if err != nil {
   935  			return 0, err
   936  		}
   937  		cVal, ok := evalExpr.Expr.(*plan.Expr_Lit)
   938  		if ok {
   939  			return getIntConstVal[int64](cVal), nil
   940  		}
   941  	}
   942  	return 0, moerr.NewFieldTypeNotAllowedAsPartitionField(ctx, partitionDef.PartitionExpr.ExprStr)
   943  }
   944  
   945  // compareTwoRangeColumns Check whether the two range columns partition definition values increase in Lexicographic order order
   946  func compareTwoRangeColumns(ctx context.Context, curr, prev *plan.PartitionItem, partitionDef *plan.PartitionByDef, tbldef *TableDef, binder *PartitionBinder) (bool, error) {
   947  	if len(curr.LessThan) != len(partitionDef.PartitionColumns.PartitionColumns) {
   948  		return false, moerr.NewErrPartitionColumnList(ctx)
   949  	}
   950  
   951  	for i := 0; i < len(partitionDef.PartitionColumns.Columns); i++ {
   952  		// handling `MAXVALUE` in partition less than value
   953  		_, ok1 := curr.LessThan[i].Expr.(*plan.Expr_Max)
   954  		_, ok2 := prev.LessThan[i].Expr.(*plan.Expr_Max)
   955  		if ok1 && !ok2 {
   956  			// If current is maxvalue, then it must be greater than previous, so previous cannot be maxvalue
   957  			return true, nil
   958  		}
   959  
   960  		if ok2 {
   961  			// Current is not maxvalue, and  the previous cannot be maxvalue
   962  			return false, nil
   963  		}
   964  
   965  		// The range columns tuples values are strictly increasing in dictionary order
   966  		colInfo := findColumnByName(partitionDef.PartitionColumns.PartitionColumns[i], tbldef)
   967  		res, err := evalPartitionBoolExpr(ctx, curr.LessThan[i], prev.LessThan[i], colInfo, binder)
   968  		if err != nil {
   969  			return false, err
   970  		}
   971  
   972  		if res {
   973  			return true, nil
   974  		}
   975  	}
   976  	return false, nil
   977  }
   978  
   979  // evalPartitionBoolExpr Calculate the bool result of comparing the values of two range partition `less than value`
   980  func evalPartitionBoolExpr(ctx context.Context, lOriExpr *Expr, rOriExpr *Expr, colInfo *plan.ColDef, binder *PartitionBinder) (bool, error) {
   981  	lexpr, err := makePlan2CastExpr(ctx, lOriExpr, colInfo.Typ)
   982  	if err != nil {
   983  		return false, err
   984  	}
   985  
   986  	rexpr, err := makePlan2CastExpr(ctx, rOriExpr, colInfo.Typ)
   987  	if err != nil {
   988  		return false, err
   989  	}
   990  
   991  	retExpr, err := BindFuncExprImplByPlanExpr(ctx, ">", []*Expr{lexpr, rexpr})
   992  	if err != nil {
   993  		return false, err
   994  	}
   995  
   996  	vec, err := colexec.EvalExpressionOnce(binder.builder.compCtx.GetProcess(), retExpr, []*batch.Batch{batch.EmptyForConstFoldBatch, batch.EmptyForConstFoldBatch})
   997  	if err != nil {
   998  		return false, err
   999  	}
  1000  	fixedCol := vector.MustFixedCol[bool](vec)
  1001  	return fixedCol[0], nil
  1002  }
  1003  
  1004  // getIntConstVal Get an integer constant value, the `cExpr` must be integral constant expression
  1005  func getIntConstVal[T uint64 | int64](cExpr *plan.Expr_Lit) T {
  1006  	switch value := cExpr.Lit.Value.(type) {
  1007  	case *plan.Literal_U8Val:
  1008  		return T(value.U8Val)
  1009  	case *plan.Literal_U16Val:
  1010  		return T(value.U16Val)
  1011  	case *plan.Literal_U32Val:
  1012  		return T(value.U32Val)
  1013  	case *plan.Literal_U64Val:
  1014  		return T(value.U64Val)
  1015  	case *plan.Literal_I8Val:
  1016  		return T(value.I8Val)
  1017  	case *plan.Literal_I16Val:
  1018  		return T(value.I16Val)
  1019  	case *plan.Literal_I32Val:
  1020  		return T(value.I32Val)
  1021  	case *plan.Literal_I64Val:
  1022  		return T(value.I64Val)
  1023  	default:
  1024  		panic("the `expr` must be integral constant expression")
  1025  	}
  1026  }
  1027  
  1028  // deepCopyTableCols Deeply copy table's column definition information
  1029  // Cols: Table column definitions
  1030  // ignoreRowId: Whether to ignore the rowId column
  1031  func deepCopyTableCols(Cols []*ColDef, ignoreRowId bool) []*ColDef {
  1032  	if Cols == nil {
  1033  		return nil
  1034  	}
  1035  	newCols := make([]*plan.ColDef, 0)
  1036  	for _, col := range Cols {
  1037  		if ignoreRowId && col.Name == catalog.Row_ID {
  1038  			continue
  1039  		}
  1040  		newCols = append(newCols, DeepCopyColDef(col))
  1041  	}
  1042  	return newCols
  1043  }