github.com/matrixorigin/matrixone@v1.2.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  	"context"
    19  	"fmt"
    20  	catalog2 "github.com/matrixorigin/matrixone/pkg/catalog"
    21  	"go/constant"
    22  	"strings"
    23  
    24  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    25  	"github.com/matrixorigin/matrixone/pkg/container/types"
    26  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    27  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect"
    28  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
    29  )
    30  
    31  const (
    32  	/*
    33  		https://dev.mysql.com/doc/refman/8.0/en/create-table.html
    34  		PARTITION BY
    35  			If used, a partition_options clause begins with PARTITION BY. This clause contains the function that is used
    36  			to determine the partition; the function returns an integer value ranging from 1 to num, where num is
    37  			the number of partitions. (The maximum number of user-defined partitions which a table may contain is 1024;
    38  			the number of subpartitions—discussed later in this section—is included in this maximum.)
    39  	*/
    40  	PartitionCountLimit = 1024
    41  
    42  	/*
    43  		    https://dev.mysql.com/doc/refman/8.0/en/create-table.html
    44  			1. KEY(column_list): the column_list argument is simply a list of 1 or more table columns (maximum: 16).
    45  			2. RANGE COLUMNS(column_list): The maximum number of columns that can be referenced in the column_list
    46  				and value_list is 16.
    47  			3. LIST COLUMNS(column_list): The maximum number of columns that can be used in the column_list and
    48  				in the elements making up the value_list is 16.
    49  	*/
    50  	PartitionColumnsLimit = 16
    51  )
    52  
    53  type partitionBuilder interface {
    54  	build(ctx context.Context, partitionBinder *PartitionBinder, stmt *tree.CreateTable, tableDef *TableDef) error
    55  
    56  	// buildPartitionDefinitionsInfo build partition definitions info without assign partition id.
    57  	buildPartitionDefs(ctx context.Context, partitionBinder *PartitionBinder, partitionDef *plan.PartitionByDef, defs []*tree.Partition) (err error)
    58  
    59  	// checkTableDefPartition Perform integrity constraint check on partitions of create table statement
    60  	checkPartitionIntegrity(ctx context.Context, partitionBinder *PartitionBinder, tableDef *TableDef, partitionDef *plan.PartitionByDef) error
    61  
    62  	// This method is used to convert different types of partition structures into plan.Expr
    63  	buildEvalPartitionExpression(ctx context.Context, partitionBinder *PartitionBinder, stmt *tree.PartitionOption, partitionDef *plan.PartitionByDef) error
    64  }
    65  
    66  var _ partitionBuilder = &hashPartitionBuilder{}
    67  var _ partitionBuilder = &keyPartitionBuilder{}
    68  var _ partitionBuilder = &rangePartitionBuilder{}
    69  var _ partitionBuilder = &listPartitionBuilder{}
    70  
    71  // visit partition expression and check the correctness of partition expression
    72  type partitionExprProcessor func(ctx context.Context, tbInfo *plan.TableDef, expr tree.Expr) error
    73  
    74  // partitionExprChecker used to check partition expression legitimacy
    75  type partitionExprChecker struct {
    76  	ctx        context.Context
    77  	processors []partitionExprProcessor
    78  	tableInfo  *plan.TableDef
    79  	err        error     // Error occurred during checking partition expression
    80  	columns    []*ColDef // Columns used in partition expressions
    81  }
    82  
    83  func newPartitionExprChecker(ctx context.Context, tbInfo *plan.TableDef, processor ...partitionExprProcessor) *partitionExprChecker {
    84  	p := &partitionExprChecker{
    85  		ctx:        ctx,
    86  		processors: processor,
    87  		tableInfo:  tbInfo,
    88  	}
    89  	p.processors = append(p.processors, p.extractColumns)
    90  	return p
    91  }
    92  
    93  func (p *partitionExprChecker) Enter(n tree.Expr) (node tree.Expr, skipChildren bool) {
    94  	for _, processor := range p.processors {
    95  		if err := processor(p.ctx, p.tableInfo, n); err != nil {
    96  			p.err = err
    97  			return n, true
    98  		}
    99  	}
   100  	return n, false
   101  }
   102  
   103  func (p *partitionExprChecker) Exit(n tree.Expr) (node tree.Expr, ok bool) {
   104  	return n, p.err == nil
   105  }
   106  
   107  func (p *partitionExprChecker) extractColumns(ctx context.Context, _ *plan.TableDef, expr tree.Expr) error {
   108  	columnNameExpr, ok := expr.(*tree.UnresolvedName)
   109  	if !ok {
   110  		return nil
   111  	}
   112  
   113  	colInfo := findColumnByName(columnNameExpr.Parts[0], p.tableInfo)
   114  	if colInfo == nil {
   115  		return moerr.NewBadFieldError(ctx, columnNameExpr.Parts[0], "partition function")
   116  	}
   117  
   118  	p.columns = append(p.columns, colInfo)
   119  	return nil
   120  }
   121  
   122  // checkPartitionExprValid checks partition expression function validly.
   123  func checkPartitionExprValid(ctx context.Context, tblInfo *plan.TableDef, expr tree.Expr) error {
   124  	if expr == nil {
   125  		return nil
   126  	}
   127  	exprChecker := newPartitionExprChecker(ctx, tblInfo, checkPartitionExprArgs, checkPartitionExprAllowed)
   128  	expr.Accept(exprChecker)
   129  	if exprChecker.err != nil {
   130  		return exprChecker.err
   131  	}
   132  	if len(exprChecker.columns) == 0 {
   133  		return moerr.NewWrongExprInPartitionFunc(ctx)
   134  	}
   135  	return nil
   136  }
   137  
   138  // buildPartitionExpr enables the use of multiple columns in partitioning keys
   139  func buildPartitionExpr(ctx context.Context, tblInfo *plan.TableDef, partitionBinder *PartitionBinder, partitionDef *plan.PartitionByDef, pExpr tree.Expr) error {
   140  	if err := checkPartitionExprValid(ctx, tblInfo, pExpr); err != nil {
   141  		return err
   142  	}
   143  	planExpr, err := partitionBinder.BindExpr(pExpr, 0, true)
   144  	if err != nil {
   145  		return err
   146  	}
   147  	//TODO: format partition expression
   148  	//fmtCtx := tree.NewFmtCtxWithFlag(dialect.MYSQL, tree.RestoreNameBackQuotes)
   149  	//pExpr.Format(fmtCtx)
   150  	//exprFmtStr := fmtCtx.ToString()
   151  
   152  	// Temporary operation
   153  	partitionDef.PartitionExpr = &plan.PartitionExpr{
   154  		Expr:    planExpr,
   155  		ExprStr: tree.String(pExpr, dialect.MYSQL),
   156  		//ExprFmtStr: exprFmtStr,
   157  	}
   158  	return nil
   159  }
   160  
   161  // getValidPartitionCount checks the subpartition and adjust the number of the partition
   162  func getValidPartitionCount(ctx context.Context, needPartitionDefs bool, partitionSyntaxDef *tree.PartitionOption) (uint64, error) {
   163  	var err error
   164  	//step 1 : reject subpartition
   165  	if partitionSyntaxDef.SubPartBy != nil {
   166  		return 0, moerr.NewInvalidInput(ctx, "subpartition is unsupported")
   167  	}
   168  
   169  	if needPartitionDefs && len(partitionSyntaxDef.Partitions) == 0 {
   170  		if _, ok := partitionSyntaxDef.PartBy.PType.(*tree.ListType); ok {
   171  			return 0, moerr.NewPartitionsMustBeDefined(ctx, "LIST")
   172  		} else {
   173  			return 0, moerr.NewInvalidInput(ctx, "each partition must be defined")
   174  		}
   175  	}
   176  
   177  	//step 2: verify the partition number [1,1024]
   178  	partitionCount := partitionSyntaxDef.PartBy.Num
   179  	/*
   180  		"partitionCount = 0" only occurs when the PARTITIONS clause is missed.
   181  	*/
   182  	if partitionCount <= 0 {
   183  		if len(partitionSyntaxDef.Partitions) == 0 {
   184  			//if there is no partition definition, the default number for the partitionCount is 1.
   185  			partitionCount = 1
   186  		} else {
   187  			//if there are at lease one partition definitions, the default number for the partitionsNums
   188  			//is designated as the number of the partition definitions.
   189  			partitionCount = uint64(len(partitionSyntaxDef.Partitions))
   190  		}
   191  	} else if len(partitionSyntaxDef.Partitions) != 0 && partitionCount != uint64(len(partitionSyntaxDef.Partitions)) {
   192  		//if partition definitions exists in the syntax, but the count of it is different from
   193  		//the one in PARTITIONS clause, it is wrong.
   194  		return 0, moerr.NewInvalidInput(ctx, "Wrong number of partitions defined")
   195  	}
   196  	// check partition number
   197  	if err = checkPartitionCount(ctx, int(partitionCount)); err != nil {
   198  		return 0, err
   199  	}
   200  	return partitionCount, err
   201  }
   202  
   203  // buildPartitionColumns enables the use of multiple columns in partitioning keys
   204  func buildPartitionColumns(ctx context.Context, tableDef *TableDef, partitionBinder *PartitionBinder, partitionDef *plan.PartitionByDef, columnList []*tree.UnresolvedName) error {
   205  	var err error
   206  	partitionDef.PartitionColumns = &plan.PartitionColumns{
   207  		Columns:          make([]*plan.Expr, len(columnList)),
   208  		PartitionColumns: make([]string, len(columnList)),
   209  	}
   210  
   211  	// 1. First, check if the partition column is legal,
   212  	for i, column := range columnList {
   213  		partitionDef.PartitionColumns.PartitionColumns[i] = tree.String(column, dialect.MYSQL)
   214  	}
   215  	if err = checkColumnsPartitionType(ctx, tableDef, partitionDef); err != nil {
   216  		return err
   217  	}
   218  
   219  	// 2. then construct the expression for the partition column
   220  	for i, column := range columnList {
   221  		partitionDef.PartitionColumns.Columns[i], err = partitionBinder.BindColRef(column, 0, true)
   222  		if err != nil {
   223  			return err
   224  		}
   225  	}
   226  	return nil
   227  }
   228  
   229  // checkColumnsPartitionType Check if the type of the partition column is correct
   230  func checkColumnsPartitionType(ctx context.Context, tbInfo *TableDef, pi *plan.PartitionByDef) error {
   231  	for _, colName := range pi.PartitionColumns.PartitionColumns {
   232  		colInfo := findColumnByName(colName, tbInfo)
   233  		if colInfo == nil {
   234  			return moerr.NewFieldNotFoundPart(ctx)
   235  		}
   236  
   237  		t := types.T(colInfo.Typ.Id)
   238  		if pi.Type == plan.PartitionType_KEY || pi.Type == plan.PartitionType_LINEAR_KEY {
   239  			// When partitioning by [LINEAR] KEY, it is possible to use columns of any valid MySQL data type other than TEXT or BLOB
   240  			// as partitioning keys, because MySQL's internal key-hashing functions produce the correct data type from these types.
   241  			// See https://dev.mysql.com/doc/refman/8.0/en/partitioning-limitations.html
   242  			if t == types.T_blob || t == types.T_text || t == types.T_json {
   243  				return moerr.NewBlobFieldInPartFunc(ctx)
   244  			}
   245  		} else {
   246  			// Both `RANGE COLUMNS` partitioning and `LIST COLUMNS` partitioning support the use of non-integer columns for defining value ranges or list members. The permitted data types are shown in the following list:
   247  			//1. All integer types: TINYINT, SMALLINT, MEDIUMINT, INT (INTEGER), and BIGINT. (This is the same as with partitioning by RANGE and LIST.)
   248  			//  Other numeric data types (such as DECIMAL or FLOAT) are not supported as partitioning columns.
   249  			//2. DATE and DATETIME.
   250  			//	Columns using other data types relating to dates or times are not supported as partitioning columns.
   251  			//3. The following string types: CHAR, VARCHAR, BINARY, and VARBINARY.
   252  			//	TEXT and BLOB columns are not supported as partitioning columns.
   253  			// See https://dev.mysql.com/doc/refman/8.0/en/partitioning-columns.html
   254  			if t == types.T_float32 || t == types.T_float64 || t == types.T_decimal64 || t == types.T_decimal128 ||
   255  				t == types.T_timestamp || t == types.T_blob || t == types.T_text || t == types.T_json || t == types.T_enum {
   256  				return moerr.NewFieldTypeNotAllowedAsPartitionField(ctx, colName)
   257  			}
   258  		}
   259  	}
   260  	return nil
   261  }
   262  
   263  // buildPartitionDefs constructs the partitions
   264  func buildPartitionDefs(ctx context.Context,
   265  	partitionDef *plan.PartitionByDef, syntaxDefs []*tree.Partition) error {
   266  	if len(syntaxDefs) != 0 && len(syntaxDefs) != int(partitionDef.PartitionNum) {
   267  		return moerr.NewInvalidInput(ctx, "Wrong number of partitions defined")
   268  	}
   269  	dedup := make(map[string]bool)
   270  	if len(syntaxDefs) == 0 {
   271  		//complement partition defs missing in syntax
   272  		for i := 0; i < int(partitionDef.PartitionNum); i++ {
   273  			name := fmt.Sprintf("p%d", i)
   274  			if _, ok := dedup[name]; ok {
   275  				//return moerr.NewInvalidInput(ctx, "duplicate partition name %s", name)
   276  				return moerr.NewSameNamePartition(ctx, name)
   277  			}
   278  			dedup[name] = true
   279  			pi := &plan.PartitionItem{
   280  				PartitionName:   name,
   281  				OrdinalPosition: uint32(i + 1),
   282  			}
   283  			partitionDef.Partitions = append(partitionDef.Partitions, pi)
   284  		}
   285  	} else {
   286  		//process defs in syntax
   287  		for i := 0; i < len(syntaxDefs); i++ {
   288  			name := string(syntaxDefs[i].Name)
   289  			if _, ok := dedup[name]; ok {
   290  				//return moerr.NewInvalidInput(ctx, "duplicate partition name %s", name)
   291  				return moerr.NewSameNamePartition(ctx, name)
   292  			}
   293  			dedup[name] = true
   294  
   295  			//get COMMENT option only
   296  			comment := ""
   297  			for _, option := range syntaxDefs[i].Options {
   298  				if commentOpt, ok := option.(*tree.TableOptionComment); ok {
   299  					comment = commentOpt.Comment
   300  				}
   301  			}
   302  
   303  			pi := &plan.PartitionItem{
   304  				PartitionName:   name,
   305  				OrdinalPosition: uint32(i + 1),
   306  				Comment:         comment,
   307  			}
   308  			partitionDef.Partitions = append(partitionDef.Partitions, pi)
   309  		}
   310  	}
   311  
   312  	return nil
   313  }
   314  
   315  func checkPartitionIntegrity(ctx context.Context, partitionBinder *PartitionBinder, tableDef *TableDef, partitionDef *plan.PartitionByDef) error {
   316  	if err := checkPartitionKeys(ctx, partitionBinder.builder.nameByColRef, tableDef, partitionDef); err != nil {
   317  		return err
   318  	}
   319  	if err := checkPartitionExprType(ctx, partitionBinder, tableDef, partitionDef); err != nil {
   320  		return err
   321  	}
   322  	if err := checkPartitionDefines(ctx, partitionBinder, partitionDef, tableDef); err != nil {
   323  		return err
   324  	}
   325  	return nil
   326  }
   327  
   328  func getPrimaryKeyAndUniqueKey(defs tree.TableDefs) (primaryKeys []*tree.UnresolvedName, uniqueIndexs []*tree.UniqueIndex) {
   329  	for _, item := range defs {
   330  		switch def := item.(type) {
   331  		case *tree.ColumnTableDef:
   332  			for _, attr := range def.Attributes {
   333  				if _, ok := attr.(*tree.AttributePrimaryKey); ok {
   334  					primaryKeys = append(primaryKeys, def.Name)
   335  				}
   336  
   337  				if _, ok := attr.(*tree.AttributeUniqueKey); ok {
   338  					part := &tree.KeyPart{
   339  						ColName: def.Name,
   340  					}
   341  					uniqueKey := &tree.UniqueIndex{
   342  						KeyParts: []*tree.KeyPart{part},
   343  						Name:     "",
   344  						Empty:    true,
   345  					}
   346  					uniqueIndexs = append(uniqueIndexs, uniqueKey)
   347  				}
   348  			}
   349  		case *tree.PrimaryKeyIndex:
   350  			for _, key := range def.KeyParts {
   351  				primaryKeys = append(primaryKeys, key.ColName)
   352  			}
   353  		case *tree.UniqueIndex:
   354  			uniqueIndexs = append(uniqueIndexs, def)
   355  		}
   356  	}
   357  	return
   358  }
   359  
   360  // This method is used to generate partition ast for key partition and hash partition
   361  // For example: abs (hash_value (col3))% 4
   362  func genPartitionAst(exprs tree.Exprs, partNum int64) tree.Expr {
   363  	hashFuncName := tree.SetUnresolvedName(strings.ToLower("hash_value"))
   364  	hashfuncExpr := &tree.FuncExpr{
   365  		Func:  tree.FuncName2ResolvableFunctionReference(hashFuncName),
   366  		Exprs: exprs,
   367  	}
   368  
   369  	absFuncName := tree.SetUnresolvedName(strings.ToLower("abs"))
   370  	absFuncExpr := &tree.FuncExpr{
   371  		Func:  tree.FuncName2ResolvableFunctionReference(absFuncName),
   372  		Exprs: tree.Exprs{hashfuncExpr},
   373  	}
   374  
   375  	numstr := fmt.Sprintf("%v", partNum)
   376  	divExpr := tree.NewNumValWithType(constant.MakeInt64(partNum), numstr, false, tree.P_int64)
   377  	modOpExpr := tree.NewBinaryExpr(tree.MOD, absFuncExpr, divExpr)
   378  	return modOpExpr
   379  }
   380  
   381  // This method is used to convert the list columns partition into case when expression,such as:
   382  // PARTITION BY LIST COLUMNS(a,b) (
   383  // PARTITION p0 VALUES IN( (0,0), (NULL,NULL) ),
   384  // PARTITION p1 VALUES IN( (0,1), (0,2) ),
   385  // PARTITION p2 VALUES IN( (1,0), (2,0) )
   386  // );-->
   387  // case
   388  // when a = 0 and b = 0 or a = null and b = null then 0
   389  // when a = 0 and b = 1 or a = 0 and b = 2 then 1
   390  // when a = 1 and b = 0 or a = 2 and b = 0 then 2
   391  // else -1
   392  // end
   393  func buildListColumnsCaseWhenExpr(columnsExpr []*tree.UnresolvedName, defs []*tree.Partition) (*tree.CaseExpr, error) {
   394  	whens := make([]*tree.When, len(defs))
   395  
   396  	for i, partition := range defs {
   397  		valuesIn := partition.Values.(*tree.ValuesIn)
   398  
   399  		elements := make([]tree.Expr, len(valuesIn.ValueList))
   400  		for j, value := range valuesIn.ValueList {
   401  			if tuple, ok := value.(*tree.Tuple); ok {
   402  				exprs := tuple.Exprs
   403  				if len(exprs) != len(columnsExpr) {
   404  					panic("the number of IN expression parameters does not match")
   405  				}
   406  
   407  				if len(columnsExpr) == 1 {
   408  					newExpr := tree.NewComparisonExpr(tree.EQUAL, columnsExpr[0], exprs[0])
   409  					elements[j] = newExpr
   410  					continue
   411  				}
   412  
   413  				if len(columnsExpr) >= 2 {
   414  					var andExpr tree.Expr
   415  
   416  					first := true
   417  					for k, lexpr := range columnsExpr {
   418  						if first {
   419  							andExpr = tree.NewComparisonExpr(tree.EQUAL, lexpr, exprs[k])
   420  							first = false
   421  							continue
   422  						}
   423  						newExpr := tree.NewComparisonExpr(tree.EQUAL, lexpr, exprs[k])
   424  						andExpr = tree.NewAndExpr(andExpr, newExpr)
   425  					}
   426  					elements[j] = andExpr
   427  					continue
   428  				}
   429  			} else {
   430  				if len(columnsExpr) != 1 {
   431  					panic("the number of IN expression parameters does not match")
   432  				}
   433  				newExpr := tree.NewComparisonExpr(tree.EQUAL, columnsExpr[0], value)
   434  				elements[j] = newExpr
   435  				continue
   436  			}
   437  		}
   438  
   439  		var conditionExpr tree.Expr
   440  		if len(valuesIn.ValueList) == 1 {
   441  			conditionExpr = elements[0]
   442  		}
   443  
   444  		if len(valuesIn.ValueList) > 1 {
   445  			for m := 1; m < len(elements); m++ {
   446  				if m == 1 {
   447  					conditionExpr = tree.NewOrExpr(elements[m-1], elements[m])
   448  				} else {
   449  					conditionExpr = tree.NewOrExpr(conditionExpr, elements[m])
   450  				}
   451  			}
   452  		}
   453  
   454  		when := &tree.When{
   455  			Cond: conditionExpr,
   456  			Val:  tree.NewNumValWithType(constant.MakeInt64(int64(i)), fmt.Sprintf("%v", i), false, tree.P_int64),
   457  		}
   458  		whens[i] = when
   459  	}
   460  	caseWhenExpr := &tree.CaseExpr{
   461  		Expr:  nil,
   462  		Whens: whens,
   463  		Else:  tree.NewNumValWithType(constant.MakeInt64(int64(-1)), fmt.Sprintf("%v", -1), false, tree.P_int64),
   464  	}
   465  	return caseWhenExpr, nil
   466  }
   467  
   468  // This method is used to convert the range partition into case when expression,such as:
   469  // PARTITION BY RANGE (code + 5) (
   470  // PARTITION p0 VALUES LESS THAN (6),
   471  // PARTITION p1 VALUES LESS THAN (11),
   472  // PARTITION p2 VALUES LESS THAN (MAXVALUE),
   473  // ); -->
   474  // case when (code + 5) < 6 then 0 when (code + 5) < 11 then 1 when true then 3 else -1 end
   475  func buildRangeCaseWhenExpr(pexpr tree.Expr, defs []*tree.Partition) (*tree.CaseExpr, error) {
   476  	whens := make([]*tree.When, len(defs))
   477  	for i, partition := range defs {
   478  		valuesLessThan := partition.Values.(*tree.ValuesLessThan)
   479  		if len(valuesLessThan.ValueList) != 1 {
   480  			panic("range partition less than expression should have one element")
   481  		}
   482  		valueExpr := valuesLessThan.ValueList[0]
   483  
   484  		var conditionExpr tree.Expr
   485  		if _, ok := valueExpr.(*tree.MaxValue); ok {
   486  			conditionExpr = tree.NewNumValWithType(constant.MakeBool(true), "true", false, tree.P_bool)
   487  		} else {
   488  			LessThanExpr := tree.NewComparisonExpr(tree.LESS_THAN, pexpr, valueExpr)
   489  			conditionExpr = LessThanExpr
   490  		}
   491  
   492  		when := &tree.When{
   493  			Cond: conditionExpr,
   494  			Val:  tree.NewNumValWithType(constant.MakeInt64(int64(i)), fmt.Sprintf("%v", i), false, tree.P_int64),
   495  		}
   496  		whens[i] = when
   497  	}
   498  
   499  	caseWhenExpr := &tree.CaseExpr{
   500  		Expr:  nil,
   501  		Whens: whens,
   502  		Else:  tree.NewNumValWithType(constant.MakeInt64(int64(-1)), fmt.Sprintf("%v", -1), false, tree.P_int64),
   503  	}
   504  	return caseWhenExpr, nil
   505  }
   506  
   507  // This method is used to optimize the row constructor expression in range columns partition item into a common logical operation expression,
   508  // such as: (a, b, c) < (x0, x1, x2) ->  a < x0 || (a = x0 && (b < x1 || b = x1 && c < x2))
   509  func buildRangeColumnsCaseWhenExpr(columnsExpr []*tree.UnresolvedName, defs []*tree.Partition) (*tree.CaseExpr, error) {
   510  	whens := make([]*tree.When, len(defs))
   511  	for i, partition := range defs {
   512  		valuesLessThan := partition.Values.(*tree.ValuesLessThan)
   513  
   514  		if len(valuesLessThan.ValueList) != len(columnsExpr) {
   515  			panic("the number of less value expression parameters does not match")
   516  		}
   517  
   518  		var tempExpr tree.Expr
   519  		for j := len(valuesLessThan.ValueList) - 1; j >= 0; j-- {
   520  			valueExpr := valuesLessThan.ValueList[j]
   521  			if j == len(valuesLessThan.ValueList)-1 {
   522  				if _, ok := valueExpr.(*tree.MaxValue); ok {
   523  					trueExpr := tree.NewNumValWithType(constant.MakeBool(true), "true", false, tree.P_bool)
   524  					tempExpr = trueExpr
   525  				} else {
   526  					lessThanExpr := tree.NewComparisonExpr(tree.LESS_THAN, columnsExpr[j], valueExpr)
   527  					tempExpr = lessThanExpr
   528  				}
   529  				continue
   530  			} else {
   531  				var firstExpr tree.Expr
   532  				if _, ok := valueExpr.(*tree.MaxValue); ok {
   533  					trueExpr := tree.NewNumValWithType(constant.MakeBool(true), "true", false, tree.P_bool)
   534  					firstExpr = trueExpr
   535  				} else {
   536  					lessThanExpr := tree.NewComparisonExpr(tree.LESS_THAN, columnsExpr[j], valueExpr)
   537  					firstExpr = lessThanExpr
   538  				}
   539  
   540  				var middleExpr tree.Expr
   541  				if _, ok := valueExpr.(*tree.MaxValue); ok {
   542  					trueExpr := tree.NewNumValWithType(constant.MakeBool(true), "true", false, tree.P_bool)
   543  					middleExpr = trueExpr
   544  				} else {
   545  					equalExpr := tree.NewComparisonExpr(tree.EQUAL, columnsExpr[j], valueExpr)
   546  					middleExpr = equalExpr
   547  				}
   548  				secondExpr := tree.NewAndExpr(middleExpr, tempExpr)
   549  				tempExpr = tree.NewOrExpr(firstExpr, secondExpr)
   550  			}
   551  		}
   552  
   553  		when := &tree.When{
   554  			Cond: tempExpr,
   555  			Val:  tree.NewNumValWithType(constant.MakeInt64(int64(i)), fmt.Sprintf("%v", i), false, tree.P_int64),
   556  		}
   557  		whens[i] = when
   558  	}
   559  	caseWhenExpr := &tree.CaseExpr{
   560  		Expr:  nil,
   561  		Whens: whens,
   562  		Else:  tree.NewNumValWithType(constant.MakeInt64(int64(-1)), fmt.Sprintf("%v", -1), false, tree.P_int64),
   563  	}
   564  	return caseWhenExpr, nil
   565  }
   566  
   567  // This method is used to convert the list columns partition into an case when expression,such as:
   568  // PARTITION BY LIST (expr) (
   569  // PARTITION p0 VALUES IN(1, 5, 9, 13, 17),
   570  // PARTITION p1 VALUES IN (2, 6, 10, 14, 18)
   571  // );-->
   572  // case when expr in (1, 5, 9, 13, 17) then 0 when expr in (2, 6, 10, 14, 18) then 1 else -1 end
   573  func buildListCaseWhenExpr(listExpr tree.Expr, defs []*tree.Partition) (*tree.CaseExpr, error) {
   574  	whens := make([]*tree.When, len(defs))
   575  	for i, partition := range defs {
   576  		valuesIn := partition.Values.(*tree.ValuesIn)
   577  
   578  		tuple := tree.NewTuple(valuesIn.ValueList)
   579  		inExpr := tree.NewComparisonExpr(tree.IN, listExpr, tuple)
   580  
   581  		when := &tree.When{
   582  			Cond: inExpr,
   583  			Val:  tree.NewNumValWithType(constant.MakeInt64(int64(i)), fmt.Sprintf("%v", i), false, tree.P_int64),
   584  		}
   585  		whens[i] = when
   586  	}
   587  	caseWhenExpr := &tree.CaseExpr{
   588  		Expr:  nil,
   589  		Whens: whens,
   590  		Else:  tree.NewNumValWithType(constant.MakeInt64(int64(-1)), fmt.Sprintf("%v", -1), false, tree.P_int64),
   591  	}
   592  	return caseWhenExpr, nil
   593  }
   594  
   595  // checkPartitionExprType checks partition function return type.
   596  func checkPartitionExprType(ctx context.Context, _ *PartitionBinder, _ *TableDef, partitionDef *plan.PartitionByDef) error {
   597  	if partitionDef.PartitionExpr != nil && partitionDef.PartitionExpr.Expr != nil {
   598  		expr := partitionDef.PartitionExpr.Expr
   599  		t := types.T(expr.Typ.Id)
   600  		if partitionDef.Type == plan.PartitionType_HASH || partitionDef.Type == plan.PartitionType_LINEAR_HASH {
   601  			if !t.IsInteger() {
   602  				if _, ok := expr.Expr.(*plan.Expr_Col); ok {
   603  					return moerr.NewFieldTypeNotAllowedAsPartitionField(ctx, partitionDef.PartitionExpr.ExprStr)
   604  				} else {
   605  					return moerr.NewPartitionFuncNotAllowed(ctx, "PARTITION")
   606  				}
   607  			}
   608  		}
   609  
   610  		if partitionDef.Type == plan.PartitionType_RANGE && !t.IsInteger() {
   611  			return moerr.NewFieldTypeNotAllowedAsPartitionField(ctx, partitionDef.PartitionExpr.ExprStr)
   612  		}
   613  
   614  		if partitionDef.Type == plan.PartitionType_LIST {
   615  			if !t.IsInteger() {
   616  				if _, ok := expr.Expr.(*plan.Expr_Col); ok {
   617  					return moerr.NewFieldTypeNotAllowedAsPartitionField(ctx, partitionDef.PartitionExpr.ExprStr)
   618  				} else {
   619  					return moerr.NewPartitionFuncNotAllowed(ctx, "PARTITION")
   620  				}
   621  			}
   622  		}
   623  	}
   624  	return nil
   625  }
   626  
   627  // stringSliceToMap converts the string slice to the string map
   628  // return true -- has duplicate names
   629  func stringSliceToMap(stringSlice []string, stringMap map[string]int) (bool, string) {
   630  	for _, s := range stringSlice {
   631  		if _, ok := stringMap[s]; ok {
   632  			return true, s
   633  		}
   634  		stringMap[s] = 0
   635  	}
   636  	return false, ""
   637  }
   638  
   639  func stringSliceToMapForIndexParts(stringSlice []string, stringMap map[string]int) (bool, string) {
   640  	for _, s := range stringSlice {
   641  		s = catalog2.ResolveAlias(s)
   642  		if _, ok := stringMap[s]; ok {
   643  			return true, s
   644  		}
   645  		stringMap[s] = 0
   646  	}
   647  	return false, ""
   648  }
   649  
   650  // checkPartitionKeys checks the partitioning key is included in the table constraint.
   651  func checkPartitionKeys(ctx context.Context, nameByColRef map[[2]int32]string,
   652  	tableDef *TableDef, partitionDef *plan.PartitionByDef) error {
   653  	partitionKeys := make(map[string]int)
   654  	if partitionDef.PartitionColumns != nil {
   655  		if dup, dupName := stringSliceToMap(partitionDef.PartitionColumns.PartitionColumns, partitionKeys); dup {
   656  			//return moerr.NewInvalidInput(ctx, "duplicate name %s", dupName)
   657  			return moerr.NewSameNamePartition(ctx, dupName)
   658  		}
   659  	} else if partitionDef.PartitionExpr.Expr != nil {
   660  		extractColFromExpr(nameByColRef, partitionDef.PartitionExpr.Expr, partitionKeys)
   661  	} else {
   662  		return moerr.NewInvalidInput(ctx, "both COLUMNS and EXPR in PARTITION BY are invalid")
   663  	}
   664  
   665  	//do nothing
   666  	if len(partitionKeys) == 0 {
   667  		return nil
   668  	}
   669  
   670  	if tableDef.Pkey != nil && !onlyHasHiddenPrimaryKey(tableDef) {
   671  		pKeys := make(map[string]int)
   672  		if dup, dupName := stringSliceToMap(tableDef.Pkey.Names, pKeys); dup {
   673  			//return moerr.NewInvalidInput(ctx, "duplicate name %s", dupName)
   674  			return moerr.NewSameNamePartition(ctx, dupName)
   675  		}
   676  		if !checkUniqueKeyIncludePartKey(partitionKeys, pKeys) {
   677  			//return moerr.NewInvalidInput(ctx, "partition key is not part of primary key")
   678  			return moerr.NewUniqueKeyNeedAllFieldsInPf(ctx, "PRIMARY KEY")
   679  		}
   680  	}
   681  
   682  	if tableDef.Indexes != nil {
   683  		for _, indexDef := range tableDef.Indexes {
   684  			if indexDef.Unique {
   685  				uniqueKeys := make(map[string]int)
   686  				if dup, dupName := stringSliceToMapForIndexParts(indexDef.Parts, uniqueKeys); dup {
   687  					//return moerr.NewInvalidInput(ctx, "duplicate name %s", dupName)
   688  					return moerr.NewSameNamePartition(ctx, dupName)
   689  				}
   690  				if !checkUniqueKeyIncludePartKey(partitionKeys, uniqueKeys) {
   691  					//return moerr.NewInvalidInput(ctx, "partition key is not part of unique key")
   692  					return moerr.NewUniqueKeyNeedAllFieldsInPf(ctx, "PRIMARY KEY")
   693  				}
   694  			}
   695  		}
   696  	}
   697  
   698  	return nil
   699  }
   700  
   701  // checkUniqueKeyIncludePartKey checks the partitioning key is included in the constraint(primary key and unique key).
   702  func checkUniqueKeyIncludePartKey(partitionKeys map[string]int, uqkeys map[string]int) bool {
   703  	for key := range partitionKeys {
   704  		if !findColumnInIndexCols(key, uqkeys) {
   705  			return false
   706  		}
   707  	}
   708  	return true
   709  }
   710  
   711  func findColumnInIndexCols(c string, pkcols map[string]int) bool {
   712  	for c1 := range pkcols {
   713  		if strings.EqualFold(c, c1) {
   714  			return true
   715  		}
   716  	}
   717  	return false
   718  }
   719  
   720  /*
   721  checkPartitionDefines Check partition definition
   722  
   723  	1.check partition name unique or not
   724  	2.check partition count limitation
   725  	3.check partition columns count limitation
   726  	4.check partition column name uinque
   727  */
   728  func checkPartitionDefines(ctx context.Context, partitionBinder *PartitionBinder, partitionDef *plan.PartitionByDef, tableDef *TableDef) error {
   729  	var err error
   730  	if err = checkPartitionNameUnique(ctx, partitionDef); err != nil {
   731  		return err
   732  	}
   733  
   734  	if err = checkPartitionCount(ctx, len(partitionDef.Partitions)); err != nil {
   735  		return err
   736  	}
   737  
   738  	if err = checkPartitionColumnsCount(ctx, partitionDef); err != nil {
   739  		return err
   740  	}
   741  
   742  	if err = checkPartitionColumnsUnique(ctx, partitionDef); err != nil {
   743  		return err
   744  	}
   745  
   746  	if len(partitionDef.Partitions) == 0 {
   747  		if partitionDef.Type == plan.PartitionType_RANGE || partitionDef.Type == plan.PartitionType_RANGE_COLUMNS {
   748  			return moerr.NewPartitionsMustBeDefined(ctx, "RANGE")
   749  		} else if partitionDef.Type == plan.PartitionType_LIST || partitionDef.Type == plan.PartitionType_LIST_COLUMNS {
   750  			return moerr.NewPartitionsMustBeDefined(ctx, "LIST")
   751  		}
   752  	}
   753  
   754  	switch partitionDef.Type {
   755  	case plan.PartitionType_RANGE, plan.PartitionType_RANGE_COLUMNS:
   756  		err = checkPartitionByRange(partitionBinder, partitionDef, tableDef)
   757  	case plan.PartitionType_LIST, plan.PartitionType_LIST_COLUMNS:
   758  		err = checkPartitionByList(partitionBinder, partitionDef, tableDef)
   759  	}
   760  	return err
   761  }
   762  
   763  // checkPartitionColumnsUnique check duplicate partition columns
   764  func checkPartitionColumnsUnique(ctx context.Context, pi *plan.PartitionByDef) error {
   765  	if pi.PartitionColumns != nil {
   766  		if len(pi.PartitionColumns.PartitionColumns) <= 1 {
   767  			return nil
   768  		}
   769  		var columnsMap = make(map[string]struct{})
   770  		for _, column := range pi.PartitionColumns.PartitionColumns {
   771  			if _, ok := columnsMap[column]; ok {
   772  				return moerr.NewSameNamePartitionField(ctx, column)
   773  			}
   774  			columnsMap[column] = struct{}{}
   775  		}
   776  	}
   777  	return nil
   778  }
   779  
   780  // checkPartitionColumns Check if the number of partition columns exceeds the limit
   781  func checkPartitionColumnsCount(ctx context.Context, pi *plan.PartitionByDef) error {
   782  	if pi.PartitionColumns != nil && len(pi.PartitionColumns.PartitionColumns) > PartitionColumnsLimit {
   783  		return moerr.NewErrTooManyPartitionFuncFields(ctx, "list of partition fields")
   784  	}
   785  	return nil
   786  }
   787  
   788  // checkPartitionCount: check whether check partition number exceeds the limit
   789  func checkPartitionCount(ctx context.Context, partNum int) error {
   790  	if partNum > PartitionCountLimit {
   791  		return moerr.NewErrTooManyPartitions(ctx)
   792  	}
   793  	return nil
   794  }
   795  
   796  // Check whether the partition name is duplicate
   797  func checkPartitionNameUnique(ctx context.Context, pi *plan.PartitionByDef) error {
   798  	partitions := pi.Partitions
   799  	partNames := make(map[string]struct{}, len(partitions))
   800  	for _, partitionItem := range partitions {
   801  		if _, ok := partNames[partitionItem.PartitionName]; ok {
   802  			return moerr.NewSameNamePartition(ctx, partitionItem.PartitionName)
   803  		}
   804  		partNames[partitionItem.PartitionName] = struct{}{}
   805  	}
   806  	return nil
   807  }
   808  
   809  // extractColFromExpr extracts column names from partition expression
   810  func extractColFromExpr(nameByColRef map[[2]int32]string, expr *Expr, result map[string]int) {
   811  	switch exprImpl := expr.Expr.(type) {
   812  	case *plan.Expr_Col:
   813  		colRef := nameByColRef[[2]int32{exprImpl.Col.RelPos, exprImpl.Col.ColPos}]
   814  		split := strings.Split(colRef, ".")
   815  		colName := split[len(split)-1]
   816  		result[colName] = 0
   817  	case *plan.Expr_F:
   818  		for _, arg := range exprImpl.F.Args {
   819  			extractColFromExpr(nameByColRef, arg, result)
   820  		}
   821  	}
   822  }
   823  
   824  func handleEmptyKeyPartition(partitionBinder *PartitionBinder, tableDef *TableDef, partitionDef *plan.PartitionByDef) error {
   825  	hasValidPrimaryKey := false
   826  	hasUniqueKey := false
   827  	var primaryKey *plan.PrimaryKeyDef
   828  
   829  	if tableDef.Pkey != nil && !onlyHasHiddenPrimaryKey(tableDef) {
   830  		hasValidPrimaryKey = true
   831  		primaryKey = tableDef.Pkey
   832  	}
   833  
   834  	uniqueIndexCount := 0
   835  	if tableDef.Indexes != nil {
   836  		for _, indexdef := range tableDef.Indexes {
   837  			if indexdef.Unique {
   838  				hasUniqueKey = true
   839  				uniqueIndexCount++
   840  			}
   841  		}
   842  	}
   843  
   844  	if hasValidPrimaryKey {
   845  		//  Any columns used as the partitioning key must comprise part or all of the table's primary key, if the table has one.
   846  		// Where no column name is specified as the partitioning key, the table's primary key is used, if there is one.
   847  		pkcols := make(map[string]int)
   848  		stringSliceToMap(primaryKey.Names, pkcols)
   849  		if hasUniqueKey {
   850  			for _, indexdef := range tableDef.Indexes {
   851  				if indexdef.Unique {
   852  					// A UNIQUE INDEX must include all columns in the table's partitioning function
   853  					uniqueKeys := make(map[string]int)
   854  					stringSliceToMapForIndexParts(indexdef.Parts, uniqueKeys)
   855  					if !checkUniqueKeyIncludePartKey(pkcols, uniqueKeys) {
   856  						return moerr.NewUniqueKeyNeedAllFieldsInPf(partitionBinder.GetContext(), "PRIMARY KEY")
   857  					}
   858  				} else {
   859  					continue
   860  				}
   861  			}
   862  		}
   863  	} else if hasUniqueKey {
   864  		// If there is no primary key but there is a unique key, then the unique key is used for the partitioning key
   865  		if uniqueIndexCount >= 2 {
   866  			firstUniqueKeyCols := make(map[string]int)
   867  			for _, indexdef := range tableDef.Indexes {
   868  				stringSliceToMapForIndexParts(indexdef.Parts, firstUniqueKeyCols)
   869  				break
   870  			}
   871  
   872  			for _, indexdef := range tableDef.Indexes {
   873  				uniqueKeys := make(map[string]int)
   874  				stringSliceToMapForIndexParts(indexdef.Parts, uniqueKeys)
   875  				if !checkUniqueKeyIncludePartKey(firstUniqueKeyCols, uniqueKeys) {
   876  					return moerr.NewUniqueKeyNeedAllFieldsInPf(partitionBinder.GetContext(), "PRIMARY KEY")
   877  				}
   878  			}
   879  		}
   880  	} else {
   881  		return moerr.NewFieldNotFoundPart(partitionBinder.GetContext())
   882  	}
   883  	return nil
   884  }