github.com/matrixorigin/matrixone@v0.7.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  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    20  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    21  	"github.com/matrixorigin/matrixone/pkg/container/types"
    22  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    23  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
    24  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    25  )
    26  
    27  // add this code in buildListPartitionItem
    28  // return buildListPartitionItem(partitionBinder, partitionInfo, defs)
    29  func buildListPartitionItem(binder *PartitionBinder, partitionInfo *plan.PartitionByDef, defs []*tree.Partition) error {
    30  	for _, def := range defs {
    31  		if partitionInfo.PartitionColumns != nil {
    32  			if err := checkListColumnsTypeAndValuesMatch(binder, partitionInfo, def); err != nil {
    33  				return err
    34  			}
    35  		} else {
    36  			if err := checkListPartitionValuesIsInt(binder, def, partitionInfo); err != nil {
    37  				return err
    38  			}
    39  		}
    40  	}
    41  	return nil
    42  }
    43  
    44  func checkListColumnsTypeAndValuesMatch(binder *PartitionBinder, partitionInfo *plan.PartitionByDef, partition *tree.Partition) error {
    45  	if valuesIn, ok := partition.Values.(*tree.ValuesIn); ok {
    46  		exprs := valuesIn.ValueList
    47  
    48  		// Validate() has already checked len(colNames) = len(exprs)
    49  		// create table ... partition by range columns (cols)
    50  		// partition p0 values less than (expr)
    51  		// check the type of cols[i] and expr is consistent.
    52  		colTypes := collectColumnsType(partitionInfo)
    53  		for _, colExpr := range exprs {
    54  			val, err := binder.BindExpr(colExpr, 0, true)
    55  			if err != nil {
    56  				return err
    57  			}
    58  
    59  			switch tuple := val.Expr.(type) {
    60  			case *plan.Expr_List:
    61  				if len(colTypes) != len(tuple.List.List) {
    62  					return moerr.NewInternalError(binder.GetContext(), "Inconsistency in usage of column lists for partitioning")
    63  				}
    64  				for i, elem := range tuple.List.List {
    65  					switch elem.Expr.(type) {
    66  					case *plan.Expr_C:
    67  					case *plan.Expr_F:
    68  					default:
    69  						return moerr.NewInternalError(binder.GetContext(), "This partition function is not allowed")
    70  					}
    71  
    72  					colType := colTypes[i]
    73  					// Check val.ConvertTo(colType) doesn't work, so we need this case by case check.
    74  					err = partitionValueTypeCheck(binder.GetContext(), colType, elem.Typ)
    75  					if err != nil {
    76  						return err
    77  					}
    78  				}
    79  			case *plan.Expr_C, *plan.Expr_F:
    80  				if len(colTypes) != 1 {
    81  					return moerr.NewInternalError(binder.GetContext(), "Inconsistency in usage of column lists for partitioning")
    82  				} else {
    83  					err = partitionValueTypeCheck(binder.GetContext(), colTypes[0], val.Typ)
    84  					if err != nil {
    85  						return err
    86  					}
    87  				}
    88  			default:
    89  				return moerr.NewInternalError(binder.GetContext(), "This partition function is not allowed")
    90  			}
    91  		}
    92  		return nil
    93  	} else {
    94  		return moerr.NewInternalError(binder.GetContext(), "list partition function is not values in expression")
    95  	}
    96  }
    97  
    98  // check whether the types of partition functions and partition values match
    99  func partitionValueTypeCheck(ctx context.Context, funcTyp *Type, valueTyp *Type) error {
   100  	switch types.T(funcTyp.Id) {
   101  	case types.T_date, types.T_datetime:
   102  		switch types.T(valueTyp.Id) {
   103  		case types.T_varchar, types.T_char:
   104  		default:
   105  			return moerr.NewInternalError(ctx, "Partition column values of incorrect type")
   106  		}
   107  	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:
   108  		switch types.T(valueTyp.Id) {
   109  		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_any:
   110  		default:
   111  			return moerr.NewInternalError(ctx, "Partition column values of incorrect type")
   112  		}
   113  	case types.T_float32, types.T_float64:
   114  		switch types.T(valueTyp.Id) {
   115  		case types.T_float32, types.T_float64, types.T_any:
   116  		default:
   117  			return moerr.NewInternalError(ctx, "Partition column values of incorrect type")
   118  		}
   119  	case types.T_varchar, types.T_char:
   120  		switch types.T(valueTyp.Id) {
   121  		case types.T_varchar, types.T_char, types.T_any:
   122  		default:
   123  			return moerr.NewInternalError(ctx, "Partition column values of incorrect type")
   124  		}
   125  	}
   126  	return nil
   127  }
   128  
   129  func checkListPartitionValuesIsInt(binder *PartitionBinder, partition *tree.Partition, info *plan.PartitionByDef) error {
   130  	unsignedFlag := types.IsUnsignedInt(types.T(info.PartitionExpr.Expr.Typ.Id))
   131  	if valuesIn, ok := partition.Values.(*tree.ValuesIn); ok {
   132  		exprs := valuesIn.ValueList
   133  		for _, exp := range exprs {
   134  			if _, ok := exp.(*tree.MaxValue); ok {
   135  				continue
   136  			}
   137  			val, err := binder.BindExpr(exp, 0, true)
   138  			if err != nil {
   139  				return err
   140  			}
   141  
   142  			compilerContext := binder.builder.compCtx
   143  			evalExpr, err := EvalPlanExpr(binder.GetContext(), val, compilerContext.GetProcess())
   144  			if err != nil {
   145  				return err
   146  			}
   147  
   148  			cval, ok1 := evalExpr.Expr.(*plan.Expr_C)
   149  			if !ok1 {
   150  				return moerr.NewInternalError(binder.GetContext(), "This partition function is not allowed")
   151  			}
   152  
   153  			switch types.T(evalExpr.Typ.Id) {
   154  			case types.T_uint8, types.T_uint16, types.T_uint32, types.T_uint64, types.T_any:
   155  			case types.T_int8, types.T_int16, types.T_int32, types.T_int64:
   156  				switch value := cval.C.Value.(type) {
   157  				case *plan.Const_I8Val:
   158  					if value.I8Val < 0 && unsignedFlag {
   159  						return moerr.NewInternalError(binder.GetContext(), "Partition constant is out of partition function domain")
   160  					}
   161  				case *plan.Const_I16Val:
   162  					if value.I16Val < 0 && unsignedFlag {
   163  						return moerr.NewInternalError(binder.GetContext(), "Partition constant is out of partition function domain")
   164  					}
   165  				case *plan.Const_I32Val:
   166  					if value.I32Val < 0 && unsignedFlag {
   167  						return moerr.NewInternalError(binder.GetContext(), "Partition constant is out of partition function domain")
   168  					}
   169  				case *plan.Const_I64Val:
   170  					if value.I64Val < 0 && unsignedFlag {
   171  						return moerr.NewInternalError(binder.GetContext(), "Partition constant is out of partition function domain")
   172  					}
   173  				default:
   174  					return moerr.NewInternalError(binder.GetContext(), "VALUES value for partition '%-.64s' must have type INT", partition.Name)
   175  				}
   176  			default:
   177  				return moerr.NewInternalError(binder.GetContext(), "VALUES value for partition '%-.64s' must have type INT", partition.Name)
   178  			}
   179  		}
   180  	}
   181  	return nil
   182  }
   183  
   184  // add this code in buildRangePartitionDefinitions
   185  // return buildRangePartitionDefinitionItem(partitionBinder, partitionInfo, defs)
   186  func buildRangePartitionItem(binder *PartitionBinder, partitionInfo *plan.PartitionByDef, defs []*tree.Partition) error {
   187  	for _, def := range defs {
   188  		if partitionInfo.PartitionColumns != nil && len(partitionInfo.PartitionColumns.Columns) > 0 {
   189  			if err := checkRangeColumnsTypeAndValuesMatch(binder, partitionInfo, def); err != nil {
   190  				return err
   191  			}
   192  		} else {
   193  			if err := checkPartitionValuesIsInt(binder, def, partitionInfo); err != nil {
   194  				return err
   195  			}
   196  		}
   197  	}
   198  	return nil
   199  }
   200  
   201  func checkRangeColumnsTypeAndValuesMatch(binder *PartitionBinder, partitionInfo *plan.PartitionByDef, partition *tree.Partition) error {
   202  	if valuesLessThan, ok := partition.Values.(*tree.ValuesLessThan); ok {
   203  		exprs := valuesLessThan.ValueList
   204  		// Validate() has already checked len(colNames) = len(exprs)
   205  		// create table ... partition by range columns (cols)
   206  		// partition p0 values less than (expr)
   207  		// check the type of cols[i] and expr is consistent.
   208  		colTypes := collectColumnsType(partitionInfo)
   209  		for i, colExpr := range exprs {
   210  			if _, ok1 := colExpr.(*tree.MaxValue); ok1 {
   211  				continue
   212  			}
   213  			colType := colTypes[i]
   214  			val, err := binder.BindExpr(colExpr, 0, true)
   215  			if err != nil {
   216  				return err
   217  			}
   218  			switch val.Expr.(type) {
   219  			case *plan.Expr_C, *plan.Expr_Max:
   220  			case *plan.Expr_F:
   221  			default:
   222  				return moerr.NewInternalError(binder.GetContext(), "This partition function is not allowed")
   223  			}
   224  
   225  			// Check val.ConvertTo(colType) doesn't work, so we need this case by case check.
   226  			vkind := val.Typ
   227  			switch types.T(colType.Id) {
   228  			case types.T_date, types.T_datetime:
   229  				switch types.T(vkind.Id) {
   230  				case types.T_varchar, types.T_char:
   231  				default:
   232  					return moerr.NewInternalError(binder.GetContext(), "Partition column values of incorrect type")
   233  				}
   234  			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:
   235  				switch types.T(vkind.Id) {
   236  				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_null:
   237  				default:
   238  					return moerr.NewInternalError(binder.GetContext(), "Partition column values of incorrect type")
   239  				}
   240  			case types.T_float32, types.T_float64:
   241  				switch types.T(vkind.Id) {
   242  				case types.T_float32, types.T_float64: //+types.T_null:
   243  				default:
   244  					return moerr.NewInternalError(binder.GetContext(), "Partition column values of incorrect type")
   245  				}
   246  			case types.T_varchar, types.T_char:
   247  				switch types.T(vkind.Id) {
   248  				case types.T_varchar, types.T_char: //+types.T_null:
   249  				default:
   250  					return moerr.NewInternalError(binder.GetContext(), "Partition column values of incorrect type")
   251  				}
   252  			}
   253  		}
   254  		return nil
   255  	} else {
   256  		return moerr.NewInternalError(binder.GetContext(), "list partition function is not values in expression")
   257  	}
   258  }
   259  
   260  func checkPartitionValuesIsInt(binder *PartitionBinder, partition *tree.Partition, info *plan.PartitionByDef) error {
   261  	unsignedFlag := types.IsUnsignedInt(types.T(info.PartitionExpr.Expr.Typ.Id))
   262  	if valuesLess, ok := partition.Values.(*tree.ValuesLessThan); ok {
   263  		exprs := valuesLess.ValueList
   264  		for _, exp := range exprs {
   265  			if _, ok := exp.(*tree.MaxValue); ok {
   266  				continue
   267  			}
   268  			val, err := binder.BindExpr(exp, 0, true)
   269  			if err != nil {
   270  				return err
   271  			}
   272  
   273  			compilerContext := binder.builder.compCtx
   274  			evalExpr, err := EvalPlanExpr(binder.GetContext(), val, compilerContext.GetProcess())
   275  			if err != nil {
   276  				return err
   277  			}
   278  
   279  			cval, ok1 := evalExpr.Expr.(*plan.Expr_C)
   280  			if !ok1 {
   281  				return moerr.NewInternalError(binder.GetContext(), "This partition function is not allowed")
   282  			}
   283  
   284  			switch types.T(evalExpr.Typ.Id) {
   285  			case types.T_uint8, types.T_uint16, types.T_uint32, types.T_uint64, types.T_any:
   286  			case types.T_int8, types.T_int16, types.T_int32, types.T_int64:
   287  				switch value := cval.C.Value.(type) {
   288  				case *plan.Const_I8Val:
   289  					if value.I8Val < 0 && unsignedFlag {
   290  						return moerr.NewInternalError(binder.GetContext(), "Partition constant is out of partition function domain")
   291  					}
   292  				case *plan.Const_I16Val:
   293  					if value.I16Val < 0 && unsignedFlag {
   294  						return moerr.NewInternalError(binder.GetContext(), "Partition constant is out of partition function domain")
   295  					}
   296  				case *plan.Const_I32Val:
   297  					if value.I32Val < 0 && unsignedFlag {
   298  						return moerr.NewInternalError(binder.GetContext(), "Partition constant is out of partition function domain")
   299  					}
   300  				case *plan.Const_I64Val:
   301  					if value.I64Val < 0 && unsignedFlag {
   302  						return moerr.NewInternalError(binder.GetContext(), "Partition constant is out of partition function domain")
   303  					}
   304  				default:
   305  					return moerr.NewInternalError(binder.GetContext(), "VALUES value for partition '%-.64s' must have type INT", partition.Name)
   306  				}
   307  			default:
   308  				return moerr.NewInternalError(binder.GetContext(), "VALUES value for partition '%-.64s' must have type INT", partition.Name)
   309  			}
   310  		}
   311  	}
   312  	return nil
   313  }
   314  
   315  // checkPartitionByList checks validity of list partition.
   316  func checkPartitionByList(partitionBinder *PartitionBinder, partitionInfo *plan.PartitionByDef, tableDef *TableDef) error {
   317  	return checkListPartitionValue(partitionBinder, partitionInfo, tableDef)
   318  }
   319  
   320  func checkListPartitionValue(partitionBinder *PartitionBinder, partitionInfo *plan.PartitionByDef, tableDef *TableDef) error {
   321  	//pi := tblInfo.Partition
   322  	ctx := partitionBinder.GetContext()
   323  	if len(partitionInfo.Partitions) == 0 {
   324  		return moerr.NewInternalError(ctx, "For %-.64s partitions each partition must be defined", "LIST")
   325  	}
   326  	expStrs, err := formatListPartitionValue(partitionBinder, partitionInfo, tableDef)
   327  	if err != nil {
   328  		return err
   329  	}
   330  
   331  	partitionsValuesMap := make(map[string]struct{})
   332  	for _, str := range expStrs {
   333  		if _, ok := partitionsValuesMap[str]; ok {
   334  			return moerr.NewInternalError(ctx, "Multiple definition of same constant in list partitioning")
   335  		}
   336  		partitionsValuesMap[str] = struct{}{}
   337  	}
   338  	return nil
   339  }
   340  
   341  func formatListPartitionValue(binder *PartitionBinder, partitionInfo *plan.PartitionByDef, tableDef *TableDef) ([]string, error) {
   342  	pi := partitionInfo
   343  	defs := partitionInfo.Partitions
   344  	if pi.PartitionColumns != nil {
   345  		for _, column := range pi.PartitionColumns.PartitionColumns {
   346  			colInfo := findColumnByName(column, tableDef)
   347  			if colInfo == nil {
   348  				return nil, moerr.NewInternalError(binder.GetContext(), "Field in list of fields for partition function not found in table")
   349  			}
   350  		}
   351  	}
   352  
   353  	exprStrs := make([]string, 0)
   354  	inValueStrs := make([]string, 0)
   355  	for i := range defs {
   356  		inValueStrs = inValueStrs[:0]
   357  		for _, val := range defs[i].InValues {
   358  			compilerContext := binder.builder.compCtx
   359  			evalExpr, err := EvalPlanExpr(binder.GetContext(), val, compilerContext.GetProcess())
   360  			if err != nil {
   361  				return nil, err
   362  			}
   363  
   364  			cval, ok1 := evalExpr.Expr.(*plan.Expr_C)
   365  			if !ok1 {
   366  				return nil, moerr.NewInternalError(binder.GetContext(), "This partition function is not allowed")
   367  			}
   368  			s := cval.C.String()
   369  			inValueStrs = append(inValueStrs, s)
   370  		}
   371  		exprStrs = append(exprStrs, inValueStrs...)
   372  	}
   373  	return exprStrs, nil
   374  }
   375  
   376  func collectColumnsType(partitionInfo *plan.PartitionByDef) []*Type {
   377  	if len(partitionInfo.PartitionColumns.Columns) > 0 {
   378  		colTypes := make([]*Type, 0, len(partitionInfo.PartitionColumns.Columns))
   379  		for _, col := range partitionInfo.PartitionColumns.Columns {
   380  			colTypes = append(colTypes, col.Typ)
   381  		}
   382  		return colTypes
   383  	}
   384  	return nil
   385  }
   386  
   387  func findColumnByName(colName string, tbdef *TableDef) *ColDef {
   388  	if tbdef == nil {
   389  		return nil
   390  	}
   391  	for _, colDef := range tbdef.Cols {
   392  		if colDef.Name == colName {
   393  			return colDef
   394  		}
   395  	}
   396  	return nil
   397  }
   398  
   399  func EvalPlanExpr(ctx context.Context, expr *plan.Expr, process *process.Process) (*plan.Expr, error) {
   400  	switch expr.Expr.(type) {
   401  	case *plan.Expr_C:
   402  		return expr, nil
   403  	default:
   404  		// try to calculate default value, return err if fails
   405  		bat := batch.NewWithSize(0)
   406  		bat.Zs = []int64{1}
   407  		newExpr, err := ConstantFold(bat, expr, process)
   408  		if err != nil {
   409  			return nil, err
   410  		}
   411  		if _, ok := newExpr.Expr.(*plan.Expr_C); ok {
   412  			return newExpr, nil
   413  		} else {
   414  			return nil, moerr.NewInternalError(ctx, "This partition function is not allowed")
   415  		}
   416  
   417  	}
   418  }
   419  
   420  // Continue to use this function in the future. Do not delete this function temporarily. Please call @qingxinhome
   421  /*
   422  // checkPartitionFuncValid checks partition function validly.
   423  func checkPartitionFuncValid(ctx context.Context, tbdef *TableDef, partby tree.PartitionBy) error {
   424  	if partby.PType == nil {
   425  		return nil
   426  	}
   427  
   428  	checker := &partitionExprChecker{
   429  		processors: []partitionExprProcessor{checkPartitionExprAllowed},
   430  		tbdef:      tbdef,
   431  		err:        nil,
   432  	}
   433  
   434  	switch partitionType := partby.PType.(type) {
   435  	case *tree.KeyType:
   436  		if partitionType.ColumnList != nil {
   437  			for _, expr := range partitionType.ColumnList {
   438  				PartitionExprSemanticCheck(ctx, tbdef, expr, checker)
   439  				if checker.err != nil {
   440  					return checker.err
   441  				}
   442  			}
   443  		}
   444  	case *tree.HashType:
   445  		PartitionExprSemanticCheck(ctx, tbdef, partitionType.Expr, checker)
   446  		if checker.err != nil {
   447  			return checker.err
   448  		}
   449  	case *tree.RangeType:
   450  		if partitionType.ColumnList != nil {
   451  			for _, expr := range partitionType.ColumnList {
   452  				PartitionExprSemanticCheck(ctx, tbdef, expr, checker)
   453  				if checker.err != nil {
   454  					return checker.err
   455  				}
   456  			}
   457  		} else {
   458  			PartitionExprSemanticCheck(ctx, tbdef, partitionType.Expr, checker)
   459  			if checker.err != nil {
   460  				return checker.err
   461  			}
   462  		}
   463  	case *tree.ListType:
   464  		if partitionType.ColumnList != nil {
   465  			for _, expr := range partitionType.ColumnList {
   466  				PartitionExprSemanticCheck(ctx, tbdef, expr, checker)
   467  				if checker.err != nil {
   468  					return checker.err
   469  				}
   470  			}
   471  		} else {
   472  			PartitionExprSemanticCheck(ctx, tbdef, partitionType.Expr, checker)
   473  			if checker.err != nil {
   474  				return checker.err
   475  			}
   476  		}
   477  	}
   478  	return nil
   479  }
   480  
   481  type partitionExprProcessor func(ctx context.Context, def *TableDef, expr tree.Expr) error
   482  type partitionExprChecker struct {
   483  	processors []partitionExprProcessor
   484  	tbdef      *TableDef
   485  	err        error
   486  }
   487  
   488  func PartitionExprSemanticCheck(ctx context.Context, tbdef *TableDef, expr tree.Expr, checker *partitionExprChecker) (canNext bool) {
   489  	for _, processor := range checker.processors {
   490  		if err := processor(ctx, tbdef, expr); err != nil {
   491  			checker.err = err
   492  			return false
   493  		}
   494  	}
   495  
   496  	switch v := expr.(type) {
   497  	case *tree.FuncExpr:
   498  		for _, e := range v.Exprs {
   499  			next := PartitionExprSemanticCheck(ctx, tbdef, e, checker)
   500  			if !next {
   501  				return next
   502  			}
   503  		}
   504  	case *tree.BinaryExpr:
   505  		next := PartitionExprSemanticCheck(ctx, tbdef, v.Left, checker)
   506  		if !next {
   507  			return next
   508  		}
   509  
   510  		next = PartitionExprSemanticCheck(ctx, tbdef, v.Right, checker)
   511  		if !next {
   512  			return next
   513  		}
   514  	case *tree.UnaryExpr:
   515  		next := PartitionExprSemanticCheck(ctx, tbdef, v.Expr, checker)
   516  		if !next {
   517  			return next
   518  		}
   519  	case *tree.ParenExpr:
   520  		next := PartitionExprSemanticCheck(ctx, tbdef, v.Expr, checker)
   521  		if !next {
   522  			return next
   523  		}
   524  	case *tree.UnresolvedName:
   525  		return false
   526  	case *tree.MaxValue:
   527  		return false
   528  	default:
   529  		checker.err = moerr.NewInternalError(ctx, "This partition function is not allowed")
   530  		return false
   531  	}
   532  	return true
   533  }
   534  
   535  func checkPartitionExprAllowed(ctx context.Context, tb *TableDef, e tree.Expr) error {
   536  	switch v := e.(type) {
   537  	case *tree.FuncExpr:
   538  		funcRef, ok := v.Func.FunctionReference.(*tree.UnresolvedName)
   539  		if !ok {
   540  			return moerr.NewNYI(ctx, "function expr '%v'", v)
   541  		}
   542  		funcName := funcRef.Parts[0]
   543  		if _, ok = AllowedPartitionFuncMap[funcName]; ok {
   544  			return nil
   545  		}
   546  	case *tree.BinaryExpr:
   547  		if _, ok := AllowedPartition4BinaryOpMap[v.Op]; ok {
   548  			return checkNoTimestampArgs(ctx, tb, v.Left, v.Right)
   549  		}
   550  	case *tree.UnaryExpr:
   551  		if _, ok := AllowedPartition4UnaryOpMap[v.Op]; ok {
   552  			return checkNoTimestampArgs(ctx, tb, v.Expr)
   553  		}
   554  	case *tree.ParenExpr, *tree.MaxValue, *tree.UnresolvedName:
   555  		return nil
   556  	}
   557  	return moerr.NewInternalError(ctx, "This partition function is not allowed")
   558  }
   559  
   560  func checkNoTimestampArgs(ctx context.Context, tbInfo *TableDef, exprs ...tree.Expr) error {
   561  	argsType, err := collectArgsType(ctx, tbInfo, exprs...)
   562  	if err != nil {
   563  		return err
   564  	}
   565  	if hasTimestampArgs(argsType...) {
   566  		return moerr.NewInternalError(ctx, "Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed")
   567  	}
   568  	return nil
   569  }
   570  
   571  func collectArgsType(ctx context.Context, tblInfo *TableDef, exprs ...tree.Expr) ([]*Type, error) {
   572  	ts := make([]*Type, 0, len(exprs))
   573  	for _, arg := range exprs {
   574  		col, ok := arg.(*tree.UnresolvedName)
   575  		if !ok {
   576  			continue
   577  		}
   578  		columnInfo := findColumnByName(col.Parts[0], tblInfo)
   579  		if columnInfo == nil {
   580  			return nil, moerr.NewInternalError(ctx, "Unknown column '%-.192s' in '%-.192s'", col.Parts[0], "partition function")
   581  		}
   582  		ts = append(ts, columnInfo.GetTyp())
   583  	}
   584  	return ts, nil
   585  }
   586  
   587  func hasDateArgs(argsType ...*Type) bool {
   588  	for _, t := range argsType {
   589  		return t.Id == int32(types.T_date) || t.Id == int32(types.T_datetime)
   590  	}
   591  	return false
   592  }
   593  
   594  func hasTimeArgs(argsType ...*Type) bool {
   595  	for _, t := range argsType {
   596  		return t.Id == int32(types.T_time) || t.Id == int32(types.T_datetime)
   597  	}
   598  	return false
   599  }
   600  
   601  func hasTimestampArgs(argsType ...*Type) bool {
   602  	for _, t := range argsType {
   603  		return t.Id == int32(types.T_timestamp)
   604  	}
   605  	return false
   606  }
   607  
   608  func hasDatetimeArgs(argsType ...*Type) bool {
   609  	for _, t := range argsType {
   610  		return t.Id == int32(types.T_datetime)
   611  	}
   612  	return false
   613  }
   614  */
   615  // AllowedPartitionFuncMap stores functions which can be used in the partition expression.
   616  var AllowedPartitionFuncMap = map[string]int{
   617  	"to_days":        1,
   618  	"to_seconds":     1,
   619  	"dayofmonth":     1,
   620  	"month":          1,
   621  	"dayofyear":      1,
   622  	"quarter":        1,
   623  	"yearweek":       1,
   624  	"year":           1,
   625  	"weekday":        1,
   626  	"dayofweek":      1,
   627  	"day":            1,
   628  	"hour":           1,
   629  	"minute":         1,
   630  	"second":         1,
   631  	"time_to_sec":    1,
   632  	"microsecond":    1,
   633  	"unix_timestamp": 1,
   634  	"from_days":      1,
   635  	"extract":        1,
   636  	"abs":            1,
   637  	"ceiling":        1,
   638  	"ceil":           1,
   639  	"datediff":       1,
   640  	"floor":          1,
   641  	"mod":            1,
   642  }
   643  
   644  // AllowedPartition4BinaryOpMap store the operator for Binary Expr
   645  // link ref:https://dev.mysql.com/doc/refman/8.0/en/partitioning-limitations.html
   646  var AllowedPartition4BinaryOpMap = map[tree.BinaryOp]string{
   647  	tree.PLUS:        "+",
   648  	tree.MINUS:       "-",
   649  	tree.MULTI:       "*",
   650  	tree.INTEGER_DIV: "div",
   651  	tree.MOD:         "%",
   652  }
   653  
   654  // AllowedPartition4UnaryOpMap store the operator for Unary Expr
   655  var AllowedPartition4UnaryOpMap = map[tree.UnaryOp]string{
   656  	tree.UNARY_PLUS:  "+",
   657  	tree.UNARY_MINUS: "-",
   658  }