github.com/matrixorigin/matrixone@v0.7.0/pkg/sql/plan/partition.go (about)

     1  // Copyright 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  	"fmt"
    19  	"go/constant"
    20  	"strconv"
    21  	"strings"
    22  
    23  	"github.com/matrixorigin/matrixone/pkg/sql/plan/rule"
    24  	"github.com/matrixorigin/matrixone/pkg/sql/util"
    25  
    26  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    27  	"github.com/matrixorigin/matrixone/pkg/container/types"
    28  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    29  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect"
    30  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
    31  )
    32  
    33  const (
    34  	// Reference link https://dev.mysql.com/doc/mysql-reslimits-excerpt/5.6/en/partitioning-limitations.html
    35  	PartitionNumberLimit = 8192
    36  )
    37  
    38  // buildHashPartition handle Hash Partitioning
    39  func buildHashPartition(partitionBinder *PartitionBinder, stmt *tree.CreateTable, tableDef *TableDef) error {
    40  	partitionOp := stmt.PartitionOption
    41  	if partitionOp.SubPartBy != nil {
    42  		return moerr.NewInvalidInput(partitionBinder.GetContext(), "no subpartition")
    43  	}
    44  	partitionsNum := partitionOp.PartBy.Num
    45  	// If you do not include a PARTITIONS clause, the number of partitions defaults to 1.
    46  	if partitionsNum <= 0 {
    47  		partitionsNum = 1
    48  	}
    49  	// check partition number
    50  	if err := checkPartitionsNumber(partitionBinder, partitionsNum); err != nil {
    51  		return err
    52  	}
    53  
    54  	partitionType := partitionOp.PartBy.PType.(*tree.HashType)
    55  	partitionInfo := &plan.PartitionByDef{
    56  		Partitions:     make([]*plan.PartitionItem, partitionsNum),
    57  		PartitionNum:   partitionsNum,
    58  		IsSubPartition: partitionOp.PartBy.IsSubPartition,
    59  	}
    60  
    61  	if partitionType.Linear {
    62  		partitionInfo.Type = plan.PartitionType_LINEAR_HASH
    63  	} else {
    64  		partitionInfo.Type = plan.PartitionType_HASH
    65  	}
    66  
    67  	planExpr, err := partitionBinder.BindExpr(partitionType.Expr, 0, true)
    68  	if err != nil {
    69  		return err
    70  	}
    71  	partitionInfo.PartitionExpr = &plan.PartitionExpr{
    72  		Expr:    planExpr,
    73  		ExprStr: tree.String(partitionType.Expr, dialect.MYSQL),
    74  	}
    75  
    76  	err = buildPartitionDefinitionsInfo(partitionBinder, partitionInfo, partitionOp.Partitions)
    77  	if err != nil {
    78  		return err
    79  	}
    80  	err = checkTableDefPartition(partitionBinder, tableDef, partitionInfo)
    81  	if err != nil {
    82  		return err
    83  	}
    84  	err = buildEvalPartitionExpression(partitionBinder, stmt, partitionInfo)
    85  	if err != nil {
    86  		return err
    87  	}
    88  
    89  	partitionInfo.PartitionMsg = tree.String(partitionOp, dialect.MYSQL)
    90  	tableDef.Partition = partitionInfo
    91  	return nil
    92  }
    93  
    94  // buildKeyPartition handle KEY Partitioning
    95  func buildKeyPartition(partitionBinder *PartitionBinder, stmt *tree.CreateTable, tableDef *TableDef) error {
    96  	partitionOp := stmt.PartitionOption
    97  	if partitionOp.SubPartBy != nil {
    98  		return moerr.NewInvalidInput(partitionBinder.GetContext(), "no subpartition")
    99  	}
   100  
   101  	// if you do not include a PARTITIONS clause, the number of partitions defaults to 1.
   102  	partitionsNum := partitionOp.PartBy.Num
   103  	if partitionsNum <= 0 {
   104  		partitionsNum = 1
   105  	}
   106  	// check partition number
   107  	if err := checkPartitionsNumber(partitionBinder, partitionsNum); err != nil {
   108  		return err
   109  	}
   110  
   111  	partitionType := partitionOp.PartBy.PType.(*tree.KeyType)
   112  	// check the algorithm option
   113  	if partitionType.Algorithm != 1 && partitionType.Algorithm != 2 {
   114  		return moerr.NewInvalidInput(partitionBinder.GetContext(), "the 'ALGORITHM' option has too many values")
   115  	}
   116  
   117  	partitionInfo := &plan.PartitionByDef{
   118  		Partitions:     make([]*plan.PartitionItem, partitionsNum),
   119  		PartitionNum:   partitionsNum,
   120  		Algorithm:      partitionType.Algorithm,
   121  		IsSubPartition: partitionOp.PartBy.IsSubPartition,
   122  	}
   123  
   124  	if partitionType.Linear {
   125  		partitionInfo.Type = plan.PartitionType_LINEAR_KEY
   126  	} else {
   127  		partitionInfo.Type = plan.PartitionType_KEY
   128  	}
   129  	err := buildPartitionColumns(partitionBinder, partitionInfo, partitionType.ColumnList)
   130  	if err != nil {
   131  		return err
   132  	}
   133  
   134  	err = buildPartitionDefinitionsInfo(partitionBinder, partitionInfo, partitionOp.Partitions)
   135  	if err != nil {
   136  		return err
   137  	}
   138  	err = checkTableDefPartition(partitionBinder, tableDef, partitionInfo)
   139  	if err != nil {
   140  		return err
   141  	}
   142  	err = buildEvalPartitionExpression(partitionBinder, stmt, partitionInfo)
   143  	if err != nil {
   144  		return err
   145  	}
   146  
   147  	partitionInfo.PartitionMsg = tree.String(partitionOp, dialect.MYSQL)
   148  	tableDef.Partition = partitionInfo
   149  	return nil
   150  }
   151  
   152  // buildRangePartition handle Range Partitioning and Range columns partitioning
   153  func buildRangePartition(partitionBinder *PartitionBinder, stmt *tree.CreateTable, tableDef *TableDef) error {
   154  	partitionOp := stmt.PartitionOption
   155  	partitionType := partitionOp.PartBy.PType.(*tree.RangeType)
   156  
   157  	partitionNum := len(partitionOp.Partitions)
   158  	if partitionOp.PartBy.Num != 0 && uint64(partitionNum) != partitionOp.PartBy.Num {
   159  		return moerr.NewParseError(partitionBinder.GetContext(), "build range partition")
   160  	}
   161  
   162  	partitionInfo := &plan.PartitionByDef{
   163  		IsSubPartition: partitionOp.PartBy.IsSubPartition,
   164  		Partitions:     make([]*plan.PartitionItem, partitionNum),
   165  		PartitionNum:   uint64(partitionNum),
   166  	}
   167  
   168  	// RANGE Partitioning
   169  	if len(partitionType.ColumnList) == 0 {
   170  		partitionInfo.Type = plan.PartitionType_RANGE
   171  		planExpr, err := partitionBinder.BindExpr(partitionType.Expr, 0, true)
   172  		if err != nil {
   173  			return err
   174  		}
   175  		partitionInfo.PartitionExpr = &plan.PartitionExpr{
   176  			Expr:    planExpr,
   177  			ExprStr: tree.String(partitionType.Expr, dialect.MYSQL),
   178  		}
   179  	} else {
   180  		// RANGE COLUMNS partitioning
   181  		partitionInfo.Type = plan.PartitionType_RANGE_COLUMNS
   182  		err := buildPartitionColumns(partitionBinder, partitionInfo, partitionType.ColumnList)
   183  		if err != nil {
   184  			return err
   185  		}
   186  	}
   187  
   188  	err := buildPartitionDefinitionsInfo(partitionBinder, partitionInfo, partitionOp.Partitions)
   189  	if err != nil {
   190  		return err
   191  	}
   192  
   193  	err = checkTableDefPartition(partitionBinder, tableDef, partitionInfo)
   194  	if err != nil {
   195  		return err
   196  	}
   197  
   198  	err = buildEvalPartitionExpression(partitionBinder, stmt, partitionInfo)
   199  	if err != nil {
   200  		return err
   201  	}
   202  
   203  	partitionInfo.PartitionMsg = tree.String(partitionOp, dialect.MYSQL)
   204  	tableDef.Partition = partitionInfo
   205  	return nil
   206  }
   207  
   208  // buildListPartitiion handle List Partitioning and List columns partitioning
   209  func buildListPartitiion(partitionBinder *PartitionBinder, stmt *tree.CreateTable, tableDef *TableDef) error {
   210  	partitionOp := stmt.PartitionOption
   211  	partitionType := partitionOp.PartBy.PType.(*tree.ListType)
   212  
   213  	partitionNum := len(partitionOp.Partitions)
   214  	if partitionOp.PartBy.Num != 0 && uint64(partitionNum) != partitionOp.PartBy.Num {
   215  		return moerr.NewParseError(partitionBinder.GetContext(), "build list partition")
   216  	}
   217  
   218  	partitionInfo := &plan.PartitionByDef{
   219  		IsSubPartition: partitionOp.PartBy.IsSubPartition,
   220  		Partitions:     make([]*plan.PartitionItem, partitionNum),
   221  		PartitionNum:   uint64(partitionNum),
   222  	}
   223  
   224  	if len(partitionType.ColumnList) == 0 {
   225  		partitionInfo.Type = plan.PartitionType_LIST
   226  		planExpr, err := partitionBinder.BindExpr(partitionType.Expr, 0, true)
   227  		if err != nil {
   228  			return err
   229  		}
   230  		partitionInfo.PartitionExpr = &plan.PartitionExpr{
   231  			Expr:    planExpr,
   232  			ExprStr: tree.String(partitionType.Expr, dialect.MYSQL),
   233  		}
   234  	} else {
   235  		partitionInfo.Type = plan.PartitionType_LIST_COLUMNS
   236  		err := buildPartitionColumns(partitionBinder, partitionInfo, partitionType.ColumnList)
   237  		if err != nil {
   238  			return err
   239  		}
   240  	}
   241  
   242  	err := buildPartitionDefinitionsInfo(partitionBinder, partitionInfo, partitionOp.Partitions)
   243  	if err != nil {
   244  		return err
   245  	}
   246  
   247  	err = checkTableDefPartition(partitionBinder, tableDef, partitionInfo)
   248  	if err != nil {
   249  		return err
   250  	}
   251  
   252  	err = buildEvalPartitionExpression(partitionBinder, stmt, partitionInfo)
   253  	if err != nil {
   254  		return err
   255  	}
   256  
   257  	partitionInfo.PartitionMsg = tree.String(partitionOp, dialect.MYSQL)
   258  	tableDef.Partition = partitionInfo
   259  	return nil
   260  }
   261  
   262  // buildPartitionColumns COLUMNS partitioning enables the use of multiple columns in partitioning keys
   263  func buildPartitionColumns(partitionBinder *PartitionBinder, partitionInfo *plan.PartitionByDef, columnList []*tree.UnresolvedName) error {
   264  	columnsExpr := make([]*plan.Expr, len(columnList))
   265  	partitionColumns := make([]string, len(columnList))
   266  
   267  	// partition COLUMNS does not accept expressions, only names of columns.
   268  	for i, column := range columnList {
   269  		colExpr, err := partitionBinder.BindColRef(column, 0, true)
   270  		if err != nil {
   271  			return moerr.NewParseError(partitionBinder.GetContext(), "build partition columns")
   272  		}
   273  		columnsExpr[i] = colExpr
   274  		partitionColumns[i] = tree.String(column, dialect.MYSQL)
   275  	}
   276  	// check whether the columns partitioning type is legal
   277  	if err := checkColumnsPartitionType(partitionBinder, partitionColumns, columnsExpr); err != nil {
   278  		return err
   279  	}
   280  	partitionInfo.PartitionColumns = &plan.PartitionColumns{
   281  		Columns:          columnsExpr,
   282  		PartitionColumns: partitionColumns,
   283  	}
   284  	return nil
   285  }
   286  
   287  func getPrimaryKeyAndUniqueKey(defs tree.TableDefs) (primaryKeys []*tree.UnresolvedName, uniqueIndexs []*tree.UniqueIndex) {
   288  	for _, item := range defs {
   289  		switch def := item.(type) {
   290  		case *tree.ColumnTableDef:
   291  			for _, attr := range def.Attributes {
   292  				if _, ok := attr.(*tree.AttributePrimaryKey); ok {
   293  					primaryKeys = append(primaryKeys, def.Name)
   294  				}
   295  
   296  				if _, ok := attr.(*tree.AttributeUniqueKey); ok {
   297  					part := &tree.KeyPart{
   298  						ColName: def.Name,
   299  					}
   300  					uniqueKey := &tree.UniqueIndex{
   301  						KeyParts: []*tree.KeyPart{part},
   302  						Name:     "",
   303  						Empty:    true,
   304  					}
   305  					uniqueIndexs = append(uniqueIndexs, uniqueKey)
   306  				}
   307  			}
   308  		case *tree.PrimaryKeyIndex:
   309  			for _, key := range def.KeyParts {
   310  				primaryKeys = append(primaryKeys, key.ColName)
   311  			}
   312  		case *tree.UniqueIndex:
   313  			uniqueIndexs = append(uniqueIndexs, def)
   314  		}
   315  	}
   316  	return
   317  }
   318  
   319  // This method is used to generate partition ast for key partition and hash partition
   320  // For example: abs (hash_value (col3))% 4
   321  func genPartitionAst(exprs tree.Exprs, partNum int64) tree.Expr {
   322  	hashFuncName := tree.SetUnresolvedName(strings.ToLower("hash_value"))
   323  	hashfuncExpr := &tree.FuncExpr{
   324  		Func:  tree.FuncName2ResolvableFunctionReference(hashFuncName),
   325  		Exprs: exprs,
   326  	}
   327  
   328  	absFuncName := tree.SetUnresolvedName(strings.ToLower("abs"))
   329  	absFuncExpr := &tree.FuncExpr{
   330  		Func:  tree.FuncName2ResolvableFunctionReference(absFuncName),
   331  		Exprs: tree.Exprs{hashfuncExpr},
   332  	}
   333  
   334  	numstr := fmt.Sprintf("%v", partNum)
   335  	divExpr := tree.NewNumValWithType(constant.MakeInt64(partNum), numstr, false, tree.P_int64)
   336  	modOpExpr := tree.NewBinaryExpr(tree.MOD, absFuncExpr, divExpr)
   337  	return modOpExpr
   338  }
   339  
   340  // This method is used to convert different types of partition structures into plan.Expr
   341  func buildEvalPartitionExpression(partitionBinder *PartitionBinder, stmt *tree.CreateTable, partitionInfo *plan.PartitionByDef) error {
   342  	partitionOp := stmt.PartitionOption
   343  	switch partitionType := partitionOp.PartBy.PType.(type) {
   344  	case *tree.KeyType:
   345  		// For the Key partition, convert the partition information into the expression,such as : abs (hash_value (expr)) % partitionNum
   346  		var astExprs []tree.Expr
   347  		if partitionInfo.PartitionColumns == nil {
   348  			// Any columns used as the partitioning key must comprise part or all of the table's primary key, if the table has one.
   349  			// Where no column name is specified as the partitioning key, the table's primary key is used, if there is one.
   350  			// If there is no primary key but there is a unique key, then the unique key is used for the partitioning key
   351  			primaryKeys, uniqueIndexs := getPrimaryKeyAndUniqueKey(stmt.Defs)
   352  			if len(primaryKeys) != 0 {
   353  				astExprs = make([]tree.Expr, len(primaryKeys))
   354  				for i, kexpr := range primaryKeys {
   355  					astExprs[i] = kexpr
   356  				}
   357  			} else if len(uniqueIndexs) != 0 {
   358  				uniqueKey := uniqueIndexs[0]
   359  				astExprs = make([]tree.Expr, len(uniqueKey.KeyParts))
   360  				for i, keyPart := range uniqueKey.KeyParts {
   361  					astExprs[i] = keyPart.ColName
   362  				}
   363  			} else {
   364  				return moerr.NewInvalidInput(partitionBinder.GetContext(), "Field in list of fields for partition function not found in table")
   365  			}
   366  		} else {
   367  			keyList := partitionType.ColumnList
   368  			astExprs = make([]tree.Expr, len(keyList))
   369  			for i, expr := range keyList {
   370  				astExprs[i] = expr
   371  			}
   372  		}
   373  
   374  		partitionAst := genPartitionAst(astExprs, int64(partitionInfo.PartitionNum))
   375  		partitionExpression, err := partitionBinder.baseBindExpr(partitionAst, 0, true)
   376  		if err != nil {
   377  			return err
   378  		}
   379  		partitionInfo.PartitionExpression = partitionExpression
   380  	case *tree.HashType:
   381  		// For the Hash partition, convert the partition information into the expression,such as: abs (hash_value (expr)) % partitionNum
   382  		hashExpr := partitionType.Expr
   383  		partitionAst := genPartitionAst(tree.Exprs{hashExpr}, int64(partitionInfo.PartitionNum))
   384  
   385  		partitionExpression, err := partitionBinder.baseBindExpr(partitionAst, 0, true)
   386  		if err != nil {
   387  			return err
   388  		}
   389  		partitionInfo.PartitionExpression = partitionExpression
   390  	case *tree.RangeType:
   391  		// For the Range partition, convert the partition information into the expression,such as:
   392  		// case when expr < 6 then 0 when expr < 11 then 1 when true then 3 else -1 end
   393  		if partitionType.ColumnList == nil {
   394  			rangeExpr := partitionType.Expr
   395  			partitionExprAst, err := buildRangeCaseWhenExpr(rangeExpr, partitionOp.Partitions)
   396  			if err != nil {
   397  				return err
   398  			}
   399  			partitionExpression, err := partitionBinder.baseBindExpr(partitionExprAst, 0, true)
   400  			if err != nil {
   401  				return err
   402  			}
   403  			partitionInfo.PartitionExpression = partitionExpression
   404  		} else {
   405  			// For the Range Columns partition, convert the partition information into the expression, such as:
   406  			// (a, b, c) < (x0, x1, x2) -->  a < x0 || (a = x0 && (b < x1 || b = x1 && c < x2))
   407  			columnsExpr := partitionType.ColumnList
   408  			partitionExprAst, err := buildRangeColumnsCaseWhenExpr(columnsExpr, partitionOp.Partitions)
   409  			if err != nil {
   410  				return err
   411  			}
   412  			partitionExpression, err := partitionBinder.baseBindExpr(partitionExprAst, 0, true)
   413  			if err != nil {
   414  				return err
   415  			}
   416  			partitionInfo.PartitionExpression = partitionExpression
   417  		}
   418  
   419  	case *tree.ListType:
   420  		// For the List partition, convert the partition information into the expression, such as:
   421  		// case when expr in (1, 5, 9, 13, 17) then 0 when expr in (2, 6, 10, 14, 18) then 1 else -1 end
   422  		if partitionType.ColumnList == nil {
   423  			listExpr := partitionType.Expr
   424  			partitionExprAst, err := buildListCaseWhenExpr(listExpr, partitionOp.Partitions)
   425  			if err != nil {
   426  				return err
   427  			}
   428  			partitionExpression, err := partitionBinder.baseBindExpr(partitionExprAst, 0, true)
   429  			if err != nil {
   430  				return err
   431  			}
   432  			partitionInfo.PartitionExpression = partitionExpression
   433  		} else {
   434  			// For the List Columns partition, convert the partition information into the expression, such as:
   435  			// case when col1 = 0 and col2 = 0 or col1 = null and col2 = null then 0
   436  			// when col1 = 0 and col2 = 1 or col1 = 0 and col2 = 2 or col1 = 0 and col2 = 3 then 1
   437  			// when col1 = 1 and col2 = 0 or col1 = 2 and col2 = 0 or col1 = 2 and col2 = 1 then 2
   438  			// else -1 end
   439  			columnsExpr := partitionType.ColumnList
   440  			partitionExprAst, err := buildListColumnsCaseWhenExpr(columnsExpr, partitionOp.Partitions)
   441  			if err != nil {
   442  				return err
   443  			}
   444  			partitionExpression, err := partitionBinder.baseBindExpr(partitionExprAst, 0, true)
   445  			if err != nil {
   446  				return err
   447  			}
   448  			partitionInfo.PartitionExpression = partitionExpression
   449  		}
   450  	}
   451  	return nil
   452  }
   453  
   454  // This method is used to convert the list columns partition into case when expression,such as:
   455  // PARTITION BY LIST COLUMNS(a,b) (
   456  // PARTITION p0 VALUES IN( (0,0), (NULL,NULL) ),
   457  // PARTITION p1 VALUES IN( (0,1), (0,2) ),
   458  // PARTITION p2 VALUES IN( (1,0), (2,0) )
   459  // );-->
   460  // case
   461  // when a = 0 and b = 0 or a = null and b = null then 0
   462  // when a = 0 and b = 1 or a = 0 and b = 2 then 1
   463  // when a = 1 and b = 0 or a = 2 and b = 0 then 2
   464  // else -1
   465  // end
   466  func buildListColumnsCaseWhenExpr(columnsExpr []*tree.UnresolvedName, defs []*tree.Partition) (*tree.CaseExpr, error) {
   467  	whens := make([]*tree.When, len(defs))
   468  
   469  	for i, partition := range defs {
   470  		valuesIn := partition.Values.(*tree.ValuesIn)
   471  
   472  		elements := make([]tree.Expr, len(valuesIn.ValueList))
   473  		for j, value := range valuesIn.ValueList {
   474  			if tuple, ok := value.(*tree.Tuple); ok {
   475  				exprs := tuple.Exprs
   476  				if len(exprs) != len(columnsExpr) {
   477  					panic("the number of IN expression parameters does not match")
   478  				}
   479  
   480  				if len(columnsExpr) == 1 {
   481  					newExpr := tree.NewComparisonExpr(tree.EQUAL, columnsExpr[0], exprs[0])
   482  					elements[j] = newExpr
   483  					continue
   484  				}
   485  
   486  				if len(columnsExpr) >= 2 {
   487  					var andExpr tree.Expr
   488  
   489  					first := true
   490  					for k, lexpr := range columnsExpr {
   491  						if first {
   492  							andExpr = tree.NewComparisonExpr(tree.EQUAL, lexpr, exprs[k])
   493  							first = false
   494  							continue
   495  						}
   496  						newExpr := tree.NewComparisonExpr(tree.EQUAL, lexpr, exprs[k])
   497  						andExpr = tree.NewAndExpr(andExpr, newExpr)
   498  					}
   499  					elements[j] = andExpr
   500  					continue
   501  				}
   502  			} else {
   503  				if len(columnsExpr) != 1 {
   504  					panic("the number of IN expression parameters does not match")
   505  				}
   506  				newExpr := tree.NewComparisonExpr(tree.EQUAL, columnsExpr[0], value)
   507  				elements[j] = newExpr
   508  				continue
   509  			}
   510  		}
   511  
   512  		var conditionExpr tree.Expr
   513  		if len(valuesIn.ValueList) == 1 {
   514  			conditionExpr = elements[0]
   515  		}
   516  
   517  		if len(valuesIn.ValueList) > 1 {
   518  			for m := 1; m < len(elements); m++ {
   519  				if m == 1 {
   520  					conditionExpr = tree.NewOrExpr(elements[m-1], elements[m])
   521  				} else {
   522  					conditionExpr = tree.NewOrExpr(conditionExpr, elements[m])
   523  				}
   524  			}
   525  		}
   526  
   527  		when := &tree.When{
   528  			Cond: conditionExpr,
   529  			Val:  tree.NewNumValWithType(constant.MakeInt64(int64(i)), fmt.Sprintf("%v", i), false, tree.P_int64),
   530  		}
   531  		whens[i] = when
   532  	}
   533  	caseWhenExpr := &tree.CaseExpr{
   534  		Expr:  nil,
   535  		Whens: whens,
   536  		Else:  tree.NewNumValWithType(constant.MakeInt64(int64(-1)), fmt.Sprintf("%v", -1), false, tree.P_int64),
   537  	}
   538  	return caseWhenExpr, nil
   539  }
   540  
   541  // This method is used to convert the range partition into case when expression,such as:
   542  // PARTITION BY RANGE (code + 5) (
   543  // PARTITION p0 VALUES LESS THAN (6),
   544  // PARTITION p1 VALUES LESS THAN (11),
   545  // PARTITION p2 VALUES LESS THAN (MAXVALUE),
   546  // ); -->
   547  // case when (code + 5) < 6 then 0 when (code + 5) < 11 then 1 when true then 3 else -1 end
   548  func buildRangeCaseWhenExpr(pexpr tree.Expr, defs []*tree.Partition) (*tree.CaseExpr, error) {
   549  	whens := make([]*tree.When, len(defs))
   550  	for i, partition := range defs {
   551  		valuesLessThan := partition.Values.(*tree.ValuesLessThan)
   552  		if len(valuesLessThan.ValueList) != 1 {
   553  			panic("range partition less than expression should have one element")
   554  		}
   555  		valueExpr := valuesLessThan.ValueList[0]
   556  
   557  		var conditionExpr tree.Expr
   558  		if _, ok := valueExpr.(*tree.MaxValue); ok {
   559  			conditionExpr = tree.NewNumValWithType(constant.MakeBool(true), "true", false, tree.P_bool)
   560  		} else {
   561  			LessThanExpr := tree.NewComparisonExpr(tree.LESS_THAN, pexpr, valueExpr)
   562  			conditionExpr = LessThanExpr
   563  		}
   564  
   565  		when := &tree.When{
   566  			Cond: conditionExpr,
   567  			Val:  tree.NewNumValWithType(constant.MakeInt64(int64(i)), fmt.Sprintf("%v", i), false, tree.P_int64),
   568  		}
   569  		whens[i] = when
   570  	}
   571  
   572  	caseWhenExpr := &tree.CaseExpr{
   573  		Expr:  nil,
   574  		Whens: whens,
   575  		Else:  tree.NewNumValWithType(constant.MakeInt64(int64(-1)), fmt.Sprintf("%v", -1), false, tree.P_int64),
   576  	}
   577  	return caseWhenExpr, nil
   578  }
   579  
   580  // This method is used to optimize the row constructor expression in range columns partition item into a common logical operation expression,
   581  // such as: (a, b, c) < (x0, x1, x2) ->  a < x0 || (a = x0 && (b < x1 || b = x1 && c < x2))
   582  func buildRangeColumnsCaseWhenExpr(columnsExpr []*tree.UnresolvedName, defs []*tree.Partition) (*tree.CaseExpr, error) {
   583  	whens := make([]*tree.When, len(defs))
   584  	for i, partition := range defs {
   585  		valuesLessThan := partition.Values.(*tree.ValuesLessThan)
   586  
   587  		if len(valuesLessThan.ValueList) != len(columnsExpr) {
   588  			panic("the number of less value expression parameters does not match")
   589  		}
   590  
   591  		var tempExpr tree.Expr
   592  		for j := len(valuesLessThan.ValueList) - 1; j >= 0; j-- {
   593  			valueExpr := valuesLessThan.ValueList[j]
   594  			if j == len(valuesLessThan.ValueList)-1 {
   595  				if _, ok := valueExpr.(*tree.MaxValue); ok {
   596  					trueExpr := tree.NewNumValWithType(constant.MakeBool(true), "true", false, tree.P_bool)
   597  					tempExpr = trueExpr
   598  				} else {
   599  					lessThanExpr := tree.NewComparisonExpr(tree.LESS_THAN, columnsExpr[j], valueExpr)
   600  					tempExpr = lessThanExpr
   601  				}
   602  				continue
   603  			} else {
   604  				var firstExpr tree.Expr
   605  				if _, ok := valueExpr.(*tree.MaxValue); ok {
   606  					trueExpr := tree.NewNumValWithType(constant.MakeBool(true), "true", false, tree.P_bool)
   607  					firstExpr = trueExpr
   608  				} else {
   609  					lessThanExpr := tree.NewComparisonExpr(tree.LESS_THAN, columnsExpr[j], valueExpr)
   610  					firstExpr = lessThanExpr
   611  				}
   612  
   613  				var middleExpr tree.Expr
   614  				if _, ok := valueExpr.(*tree.MaxValue); ok {
   615  					trueExpr := tree.NewNumValWithType(constant.MakeBool(true), "true", false, tree.P_bool)
   616  					middleExpr = trueExpr
   617  				} else {
   618  					equalExpr := tree.NewComparisonExpr(tree.EQUAL, columnsExpr[j], valueExpr)
   619  					middleExpr = equalExpr
   620  				}
   621  				secondExpr := tree.NewAndExpr(middleExpr, tempExpr)
   622  				tempExpr = tree.NewOrExpr(firstExpr, secondExpr)
   623  			}
   624  		}
   625  
   626  		when := &tree.When{
   627  			Cond: tempExpr,
   628  			Val:  tree.NewNumValWithType(constant.MakeInt64(int64(i)), fmt.Sprintf("%v", i), false, tree.P_int64),
   629  		}
   630  		whens[i] = when
   631  	}
   632  	caseWhenExpr := &tree.CaseExpr{
   633  		Expr:  nil,
   634  		Whens: whens,
   635  		Else:  tree.NewNumValWithType(constant.MakeInt64(int64(-1)), fmt.Sprintf("%v", -1), false, tree.P_int64),
   636  	}
   637  	return caseWhenExpr, nil
   638  }
   639  
   640  // This method is used to convert the list columns partition into an case when expression,such as:
   641  // PARTITION BY LIST (expr) (
   642  // PARTITION p0 VALUES IN(1, 5, 9, 13, 17),
   643  // PARTITION p1 VALUES IN (2, 6, 10, 14, 18)
   644  // );-->
   645  // case when expr in (1, 5, 9, 13, 17) then 0 when expr in (2, 6, 10, 14, 18) then 1 else -1 end
   646  func buildListCaseWhenExpr(listExpr tree.Expr, defs []*tree.Partition) (*tree.CaseExpr, error) {
   647  	whens := make([]*tree.When, len(defs))
   648  	for i, partition := range defs {
   649  		valuesIn := partition.Values.(*tree.ValuesIn)
   650  
   651  		tuple := tree.NewTuple(valuesIn.ValueList)
   652  		inExpr := tree.NewComparisonExpr(tree.IN, listExpr, tuple)
   653  
   654  		when := &tree.When{
   655  			Cond: inExpr,
   656  			Val:  tree.NewNumValWithType(constant.MakeInt64(int64(i)), fmt.Sprintf("%v", i), false, tree.P_int64),
   657  		}
   658  		whens[i] = when
   659  	}
   660  	caseWhenExpr := &tree.CaseExpr{
   661  		Expr:  nil,
   662  		Whens: whens,
   663  		Else:  tree.NewNumValWithType(constant.MakeInt64(int64(-1)), fmt.Sprintf("%v", -1), false, tree.P_int64),
   664  	}
   665  	return caseWhenExpr, nil
   666  }
   667  
   668  // buildPartitionDefinitionsInfo build partition definitions info without assign partition id.
   669  func buildPartitionDefinitionsInfo(partitionBinder *PartitionBinder, partitionInfo *plan.PartitionByDef, defs []*tree.Partition) (err error) {
   670  	switch partitionInfo.Type {
   671  	case plan.PartitionType_HASH, plan.PartitionType_LINEAR_HASH:
   672  		err = buildHashPartitionDefinitions(partitionBinder, defs, partitionInfo)
   673  	case plan.PartitionType_KEY, plan.PartitionType_LINEAR_KEY:
   674  		err = buildKeyPartitionDefinitions(partitionBinder, defs, partitionInfo)
   675  	case plan.PartitionType_RANGE, plan.PartitionType_RANGE_COLUMNS:
   676  		err = buildRangePartitionDefinitions(partitionBinder, defs, partitionInfo)
   677  	case plan.PartitionType_LIST, plan.PartitionType_LIST_COLUMNS:
   678  		err = buildListPartitionDefinitions(partitionBinder, defs, partitionInfo)
   679  	}
   680  	return err
   681  }
   682  
   683  func buildRangePartitionDefinitions(partitionBinder *PartitionBinder, defs []*tree.Partition, partitionInfo *plan.PartitionByDef) error {
   684  	// VALUES LESS THAN value must be strictly increasing for each partition
   685  	for i, partition := range defs {
   686  		partitionItem := &plan.PartitionItem{
   687  			PartitionName:   string(partition.Name),
   688  			OrdinalPosition: uint32(i + 1),
   689  		}
   690  
   691  		if valuesLessThan, ok := partition.Values.(*tree.ValuesLessThan); ok {
   692  			planExprs := make([]*plan.Expr, len(valuesLessThan.ValueList))
   693  			binder := NewPartitionBinder(nil, nil)
   694  
   695  			for j, valueExpr := range valuesLessThan.ValueList {
   696  				// value must be able to evaluate the expression's return value
   697  				planExpr, err := binder.BindExpr(valueExpr, 0, false)
   698  				if err != nil {
   699  					return err
   700  				}
   701  				planExprs[j] = planExpr
   702  			}
   703  
   704  			partitionItem.LessThan = planExprs
   705  			partitionItem.Description = tree.String(valuesLessThan.ValueList, dialect.MYSQL)
   706  		} else {
   707  			return moerr.NewInternalError(partitionBinder.GetContext(), "RANGE PARTITIONING can only use VALUES LESS THAN definition")
   708  		}
   709  
   710  		for _, tableOption := range partition.Options {
   711  			if opComment, ok := tableOption.(*tree.TableOptionComment); ok {
   712  				partitionItem.Comment = opComment.Comment
   713  			}
   714  		}
   715  		partitionInfo.Partitions[i] = partitionItem
   716  	}
   717  	return buildRangePartitionItem(partitionBinder, partitionInfo, defs)
   718  }
   719  
   720  func buildListPartitionDefinitions(partitionBinder *PartitionBinder, defs []*tree.Partition, partitionInfo *plan.PartitionByDef) error {
   721  	for i, partition := range defs {
   722  		partitionItem := &plan.PartitionItem{
   723  			PartitionName:   string(partition.Name),
   724  			OrdinalPosition: uint32(i + 1),
   725  		}
   726  
   727  		if valuesIn, ok := partition.Values.(*tree.ValuesIn); ok {
   728  			binder := NewPartitionBinder(nil, nil)
   729  			inValues := make([]*plan.Expr, len(valuesIn.ValueList))
   730  
   731  			for j, value := range valuesIn.ValueList {
   732  				tuple, err := binder.BindExpr(value, 0, false)
   733  				if err != nil {
   734  					return err
   735  				}
   736  				inValues[j] = tuple
   737  			}
   738  			partitionItem.InValues = inValues
   739  			partitionItem.Description = tree.String(valuesIn, dialect.MYSQL)
   740  		} else {
   741  			return moerr.NewInternalError(partitionBinder.GetContext(), "LIST PARTITIONING can only use VALUES IN definition")
   742  		}
   743  		partitionInfo.Partitions[i] = partitionItem
   744  	}
   745  	return buildListPartitionItem(partitionBinder, partitionInfo, defs)
   746  }
   747  
   748  func buildHashPartitionDefinitions(partitionBinder *PartitionBinder, defs []*tree.Partition, partitionInfo *plan.PartitionByDef) error {
   749  	for i := uint64(0); i < partitionInfo.PartitionNum; i++ {
   750  		partition := &plan.PartitionItem{
   751  			PartitionName:   "p" + strconv.FormatUint(i, 10),
   752  			OrdinalPosition: uint32(i + 1),
   753  		}
   754  		partitionInfo.Partitions[i] = partition
   755  	}
   756  	return nil
   757  }
   758  
   759  func buildKeyPartitionDefinitions(partitionBinder *PartitionBinder, defs []*tree.Partition, partitionInfo *plan.PartitionByDef) error {
   760  	for i := uint64(0); i < partitionInfo.PartitionNum; i++ {
   761  		partition := &plan.PartitionItem{
   762  			PartitionName:   "p" + strconv.FormatUint(i, 10),
   763  			OrdinalPosition: uint32(i + 1),
   764  		}
   765  		partitionInfo.Partitions[i] = partition
   766  	}
   767  	return nil
   768  }
   769  
   770  // The permitted data types are shown in the following list:
   771  // All integer types
   772  // DATE and DATETIME
   773  // CHAR, VARCHAR, BINARY, and VARBINARY
   774  // See https://dev.mysql.com/doc/mysql-partitioning-excerpt/5.7/en/partitioning-columns.html
   775  func checkColumnsPartitionType(partitionBinder *PartitionBinder, columnNames []string, columnPlanExprs []*plan.Expr) error {
   776  	for i, planexpr := range columnPlanExprs {
   777  		t := types.T(planexpr.Typ.Id)
   778  		if !types.IsInteger(t) && !types.IsString(t) && !types.IsDateRelate(t) {
   779  			return moerr.NewSyntaxError(partitionBinder.GetContext(), "type %s of column %s not allowd in partition clause", t.String(), columnNames[i])
   780  		}
   781  	}
   782  	return nil
   783  }
   784  
   785  // checkTableDefPartition Perform integrity constraint check on partitions of create table statement
   786  func checkTableDefPartition(partitionBinder *PartitionBinder, tableDef *TableDef, partitionInfo *plan.PartitionByDef) error {
   787  	if err := checkPartitionFuncType(partitionBinder, tableDef, partitionInfo); err != nil {
   788  		return err
   789  	}
   790  	if err := checkPartitionDefinitionConstraints(partitionBinder, partitionInfo, tableDef); err != nil {
   791  		return err
   792  	}
   793  	if err := checkPartitionKeysConstraints(partitionBinder, tableDef, partitionInfo); err != nil {
   794  		return err
   795  	}
   796  	if partitionInfo.Type == plan.PartitionType_KEY || partitionInfo.Type == plan.PartitionType_LINEAR_KEY {
   797  		//if len(partitionInfo.Columns) == 0 {
   798  		if len(partitionInfo.PartitionColumns.Columns) == 0 {
   799  			return handleEmptyKeyPartition(partitionBinder, tableDef, partitionInfo)
   800  		}
   801  	}
   802  	return nil
   803  }
   804  
   805  // check partition expression type
   806  func checkPartitionFuncType(partitionBinder *PartitionBinder, tableDef *TableDef, partitionInfo *plan.PartitionByDef) error {
   807  	//if partitionInfo.Expr == nil {
   808  	if partitionInfo.PartitionExpr == nil {
   809  		return nil
   810  	} else {
   811  		//expr := partitionInfo.Expr
   812  		expr := partitionInfo.PartitionExpr.Expr
   813  		// expr must return a nonconstant, nonrandom integer value
   814  		if rule.IsConstant(expr) {
   815  			return moerr.NewInvalidInput(partitionBinder.GetContext(), "partition functin is not const")
   816  		}
   817  
   818  		t := types.T(expr.Typ.Id)
   819  		if !types.IsInteger(t) {
   820  			return moerr.NewSyntaxError(partitionBinder.GetContext(), "type %s not allowed in partition clause", t.String())
   821  		}
   822  	}
   823  	return nil
   824  }
   825  
   826  // checkPartitionKeysConstraints checks the partitioning key is included in the table constraint.
   827  func checkPartitionKeysConstraints(partitionBinder *PartitionBinder, tableDef *TableDef, partitionInfo *plan.PartitionByDef) error {
   828  	hasPrimaryKey := false
   829  	var primaryKey *plan.PrimaryKeyDef
   830  	if tableDef.Pkey != nil {
   831  		hasPrimaryKey = true
   832  		primaryKey = tableDef.Pkey
   833  	}
   834  
   835  	hasUniqueKey := false
   836  	if tableDef.Indexes != nil {
   837  		for _, indexdef := range tableDef.Indexes {
   838  			if indexdef.Unique {
   839  				hasUniqueKey = true
   840  				break
   841  			}
   842  		}
   843  	}
   844  
   845  	if hasPrimaryKey {
   846  		var pkcols []string
   847  		if len(primaryKey.Names) > 0 && util.JudgeIsCompositePrimaryKeyColumn(primaryKey.Names[0]) {
   848  			pkcols = util.SplitCompositePrimaryKeyColumnName(primaryKey.Names[0])
   849  		} else {
   850  			pkcols = primaryKey.Names
   851  		}
   852  
   853  		if partitionInfo.PartitionColumns != nil {
   854  			if !checkUniqueKeyIncludePartKey(partitionInfo.PartitionColumns.PartitionColumns, pkcols) {
   855  				return moerr.NewInvalidInput(partitionBinder.GetContext(), "partition key is not part of primary key")
   856  			}
   857  		} else {
   858  			extractCols := extractColFromExpr(partitionBinder, partitionInfo.PartitionExpr.Expr)
   859  			if !checkUniqueKeyIncludePartKey(extractCols, pkcols) {
   860  				return moerr.NewInvalidInput(partitionBinder.GetContext(), "partition key is not part of primary key")
   861  			}
   862  		}
   863  	}
   864  
   865  	if hasUniqueKey {
   866  		for _, indexdef := range tableDef.Indexes {
   867  			if indexdef.Unique {
   868  				uniqueKeyCols := indexdef.Parts
   869  				if partitionInfo.PartitionColumns != nil {
   870  					if !checkUniqueKeyIncludePartKey(partitionInfo.PartitionColumns.PartitionColumns, uniqueKeyCols) {
   871  						return moerr.NewInvalidInput(partitionBinder.GetContext(), "partition key is not part of primary key")
   872  					}
   873  				} else {
   874  					extractCols := extractColFromExpr(partitionBinder, partitionInfo.PartitionExpr.Expr)
   875  					if !checkUniqueKeyIncludePartKey(extractCols, uniqueKeyCols) {
   876  						return moerr.NewInvalidInput(partitionBinder.GetContext(), "partition key is not part of primary key")
   877  					}
   878  				}
   879  			} else {
   880  				continue
   881  			}
   882  		}
   883  	}
   884  
   885  	if partitionInfo.Type == plan.PartitionType_KEY {
   886  		if len(partitionInfo.PartitionColumns.Columns) == 0 && !hasUniqueKey && !hasPrimaryKey {
   887  			return moerr.NewInvalidInput(partitionBinder.GetContext(), "Field in list of fields for partition function not found in table")
   888  		}
   889  	}
   890  
   891  	return nil
   892  }
   893  
   894  // checkUniqueKeyIncludePartKey checks the partitioning key is included in the constraint(primary key and unique key).
   895  func checkUniqueKeyIncludePartKey(partitionKeys []string, uqkeys []string) bool {
   896  	for i := 0; i < len(partitionKeys); i++ {
   897  		partitionKey := partitionKeys[i]
   898  		if !findColumnInIndexCols(partitionKey, uqkeys) {
   899  			return false
   900  		}
   901  	}
   902  	return true
   903  }
   904  
   905  func findColumnInIndexCols(c string, pkcols []string) bool {
   906  	for _, c1 := range pkcols {
   907  		if strings.EqualFold(c, c1) {
   908  			return true
   909  		}
   910  	}
   911  	return false
   912  }
   913  
   914  func checkPartitionDefinitionConstraints(partitionBinder *PartitionBinder, partitionInfo *plan.PartitionByDef, tableDef *TableDef) error {
   915  	var err error
   916  	if err = checkPartitionNameUnique(partitionBinder, partitionInfo); err != nil {
   917  		return err
   918  	}
   919  	if err = checkPartitionsNumber(partitionBinder, uint64(len(partitionInfo.Partitions))); err != nil {
   920  		return err
   921  	}
   922  	if err = checkPartitionColumnsUnique(partitionBinder, partitionInfo); err != nil {
   923  		return err
   924  	}
   925  
   926  	if len(partitionInfo.Partitions) == 0 {
   927  		if partitionInfo.Type == plan.PartitionType_RANGE || partitionInfo.Type == plan.PartitionType_RANGE_COLUMNS {
   928  			return moerr.NewInvalidInput(partitionBinder.GetContext(), "range partition cannot be empty")
   929  		} else if partitionInfo.Type == plan.PartitionType_LIST || partitionInfo.Type == plan.PartitionType_LIST_COLUMNS {
   930  			return moerr.NewInvalidInput(partitionBinder.GetContext(), "list partition cannot be empty")
   931  		}
   932  	}
   933  
   934  	switch partitionInfo.Type {
   935  	case plan.PartitionType_RANGE:
   936  		// TODO
   937  	case plan.PartitionType_HASH:
   938  		// TODO
   939  	case plan.PartitionType_LIST:
   940  		err = checkPartitionByList(partitionBinder, partitionInfo, tableDef)
   941  	}
   942  	return err
   943  }
   944  
   945  // checkPartitionColumnsUnique check partition columns for duplicate columns
   946  func checkPartitionColumnsUnique(partitionBinder *PartitionBinder, partitionInfo *plan.PartitionByDef) error {
   947  	if partitionInfo.PartitionColumns == nil || len(partitionInfo.PartitionColumns.PartitionColumns) <= 1 {
   948  		return nil
   949  	}
   950  	var columnsMap = make(map[string]byte)
   951  	for _, column := range partitionInfo.PartitionColumns.PartitionColumns {
   952  		if _, ok := columnsMap[column]; ok {
   953  			return moerr.NewSyntaxError(partitionBinder.GetContext(), "duplicate partition column %s", column)
   954  		}
   955  		columnsMap[column] = 1
   956  	}
   957  	return nil
   958  }
   959  
   960  // checkPartitionsNumber: check whether check partition number exceeds the limit
   961  func checkPartitionsNumber(partitionBinder *PartitionBinder, partNum uint64) error {
   962  	if partNum > uint64(PartitionNumberLimit) {
   963  		return moerr.NewInvalidInput(partitionBinder.GetContext(), "too many (%d) partitions", partNum)
   964  	}
   965  	return nil
   966  }
   967  
   968  // Check whether the partition name is duplicate
   969  func checkPartitionNameUnique(partitionBinder *PartitionBinder, pd *plan.PartitionByDef) error {
   970  	partitions := pd.Partitions
   971  
   972  	partNames := make(map[string]byte, len(partitions))
   973  	for _, par := range partitions {
   974  		if _, ok := partNames[par.PartitionName]; ok {
   975  			return moerr.NewSyntaxError(partitionBinder.GetContext(), "duplicate partition name %s", par.PartitionName)
   976  		}
   977  		partNames[par.PartitionName] = 1
   978  	}
   979  	return nil
   980  }
   981  
   982  // extractColFromExpr: extract column names from partition expression
   983  func extractColFromExpr(partitionBinder *PartitionBinder, expr *Expr) []string {
   984  	result := make([]string, 0)
   985  	switch exprImpl := expr.Expr.(type) {
   986  	case *plan.Expr_Col:
   987  		builder := partitionBinder.builder
   988  		tableColName := builder.nameByColRef[[2]int32{exprImpl.Col.RelPos, exprImpl.Col.ColPos}]
   989  		split := strings.Split(tableColName, ".")
   990  		colName := split[len(split)-1]
   991  		result = append(result, colName)
   992  	case *plan.Expr_F:
   993  		tmpcols := extractColFromFunc(partitionBinder, exprImpl)
   994  		result = append(result, tmpcols...)
   995  	}
   996  	return result
   997  }
   998  
   999  // extractColFromFunc extract column names from function expression
  1000  func extractColFromFunc(partitionBinder *PartitionBinder, funcExpr *plan.Expr_F) []string {
  1001  	result := make([]string, 0)
  1002  	for _, arg := range funcExpr.F.Args {
  1003  		tmpcols := extractColFromExpr(partitionBinder, arg)
  1004  		result = append(result, tmpcols...)
  1005  	}
  1006  	return result
  1007  }
  1008  
  1009  func handleEmptyKeyPartition(partitionBinder *PartitionBinder, tableDef *TableDef, partitionInfo *plan.PartitionByDef) error {
  1010  	hasPrimaryKey := false
  1011  	hasUniqueKey := false
  1012  	var primaryKey *plan.PrimaryKeyDef
  1013  
  1014  	if tableDef.Pkey != nil {
  1015  		hasPrimaryKey = true
  1016  		primaryKey = tableDef.Pkey
  1017  	}
  1018  
  1019  	uniqueIndexCount := 0
  1020  	if tableDef.Indexes != nil {
  1021  		for _, indexdef := range tableDef.Indexes {
  1022  			if indexdef.Unique {
  1023  				hasUniqueKey = true
  1024  				uniqueIndexCount++
  1025  			}
  1026  		}
  1027  	}
  1028  
  1029  	if hasPrimaryKey {
  1030  		//  Any columns used as the partitioning key must comprise part or all of the table's primary key, if the table has one.
  1031  		// Where no column name is specified as the partitioning key, the table's primary key is used, if there is one.
  1032  		pkcols := primaryKey.Names
  1033  
  1034  		if hasUniqueKey {
  1035  			for _, indexdef := range tableDef.Indexes {
  1036  				if indexdef.Unique {
  1037  					// A UNIQUE INDEX must include all columns in the table's partitioning function
  1038  					if !checkUniqueKeyIncludePartKey(pkcols, indexdef.Parts) {
  1039  						return moerr.NewInvalidInput(partitionBinder.GetContext(), "partition key is not part of primary key")
  1040  					}
  1041  				} else {
  1042  					continue
  1043  				}
  1044  			}
  1045  		}
  1046  	} else if hasUniqueKey {
  1047  		// If there is no primary key but there is a unique key, then the unique key is used for the partitioning key
  1048  		if uniqueIndexCount >= 2 {
  1049  			var firstUniqueKeyCols []string
  1050  			for _, indexdef := range tableDef.Indexes {
  1051  				firstUniqueKeyCols = indexdef.Parts
  1052  				break
  1053  			}
  1054  			for _, indexdef := range tableDef.Indexes {
  1055  				if !checkUniqueKeyIncludePartKey(firstUniqueKeyCols, indexdef.Parts) {
  1056  					return moerr.NewInvalidInput(partitionBinder.GetContext(), "partition key is not part of primary key")
  1057  				}
  1058  			}
  1059  		}
  1060  	} else {
  1061  		return moerr.NewInvalidInput(partitionBinder.GetContext(), "Field in list of fields for partition function not found in table")
  1062  	}
  1063  	return nil
  1064  }