github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/build_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  	"bytes"
    19  	"context"
    20  	"fmt"
    21  	"strings"
    22  
    23  	"github.com/matrixorigin/matrixone/pkg/catalog"
    24  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    25  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    26  	"github.com/matrixorigin/matrixone/pkg/container/types"
    27  	"github.com/matrixorigin/matrixone/pkg/defines"
    28  	"github.com/matrixorigin/matrixone/pkg/logutil"
    29  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    30  	"github.com/matrixorigin/matrixone/pkg/pb/timestamp"
    31  	"github.com/matrixorigin/matrixone/pkg/sql/colexec"
    32  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect"
    33  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
    34  	"github.com/matrixorigin/matrixone/pkg/sql/util"
    35  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    36  )
    37  
    38  // func appendQueryNode(query *Query, node *Node) int32 {
    39  // 	nodeID := int32(len(query.Nodes))
    40  // 	node.NodeId = nodeID
    41  // 	query.Nodes = append(query.Nodes, node)
    42  
    43  // 	return nodeID
    44  // }
    45  
    46  // reCheckifNeedLockWholeTable checks if the whole table needs to be locked based on the last node's statistics.
    47  // It returns true if the out count of the last node is greater than the maximum lock count, otherwise it returns false.
    48  func reCheckifNeedLockWholeTable(builder *QueryBuilder) {
    49  	lockService := builder.compCtx.GetProcess().LockService
    50  	if lockService == nil {
    51  		// MockCompilerContext
    52  		return
    53  	}
    54  	lockconfig := lockService.GetConfig()
    55  
    56  	for _, n := range builder.qry.Nodes {
    57  		if n.NodeType != plan.Node_LOCK_OP {
    58  			continue
    59  		}
    60  		if !n.LockTargets[0].LockTable {
    61  			reCheckIfNeed := n.Stats.Outcnt > float64(lockconfig.MaxLockRowCount)
    62  			if reCheckIfNeed {
    63  				logutil.Infof("Row lock upgraded to table lock for SQL : %s", builder.compCtx.GetRootSql())
    64  				logutil.Infof("the outcnt stats is %f", n.Stats.Outcnt)
    65  				n.LockTargets[0].LockTable = reCheckIfNeed
    66  			}
    67  		}
    68  	}
    69  }
    70  
    71  // GetFunctionArgTypeStrFromAst function arg type do not have scale and width, it depends on the data that it process
    72  func GetFunctionArgTypeStrFromAst(arg tree.FunctionArg) (string, error) {
    73  	argDecl := arg.(*tree.FunctionArgDecl)
    74  	return GetFunctionTypeStrFromAst(argDecl.Type)
    75  }
    76  
    77  func GetFunctionTypeStrFromAst(typRef tree.ResolvableTypeReference) (string, error) {
    78  	typ, err := getTypeFromAst(moerr.Context(), typRef)
    79  	if err != nil {
    80  		return "", err
    81  	}
    82  	ret := strings.ToLower(types.T(typ.Id).String())
    83  	// do not display precision, because the choice of decimal64 or decimal128 is not exposed to user
    84  	if strings.HasPrefix(ret, "decimal") {
    85  		return "decimal", nil
    86  	}
    87  	return ret, nil
    88  }
    89  
    90  func getTypeFromAst(ctx context.Context, typ tree.ResolvableTypeReference) (plan.Type, error) {
    91  	if n, ok := typ.(*tree.T); ok {
    92  		switch defines.MysqlType(n.InternalType.Oid) {
    93  		case defines.MYSQL_TYPE_BIT:
    94  			return plan.Type{Id: int32(types.T_bit), Width: n.InternalType.DisplayWith, Scale: -1}, nil
    95  		case defines.MYSQL_TYPE_TINY:
    96  			if n.InternalType.Unsigned {
    97  				return plan.Type{Id: int32(types.T_uint8), Width: n.InternalType.Width, Scale: -1}, nil
    98  			}
    99  			return plan.Type{Id: int32(types.T_int8), Width: n.InternalType.Width, Scale: -1}, nil
   100  		case defines.MYSQL_TYPE_SHORT:
   101  			if n.InternalType.Unsigned {
   102  				return plan.Type{Id: int32(types.T_uint16), Width: n.InternalType.Width, Scale: -1}, nil
   103  			}
   104  			return plan.Type{Id: int32(types.T_int16), Width: n.InternalType.Width, Scale: -1}, nil
   105  		case defines.MYSQL_TYPE_LONG, defines.MYSQL_TYPE_INT24:
   106  			if n.InternalType.Unsigned {
   107  				return plan.Type{Id: int32(types.T_uint32), Width: n.InternalType.Width, Scale: -1}, nil
   108  			}
   109  			return plan.Type{Id: int32(types.T_int32), Width: n.InternalType.Width, Scale: -1}, nil
   110  		case defines.MYSQL_TYPE_LONGLONG:
   111  			if n.InternalType.Unsigned {
   112  				return plan.Type{Id: int32(types.T_uint64), Width: n.InternalType.Width, Scale: -1}, nil
   113  			}
   114  			return plan.Type{Id: int32(types.T_int64), Width: n.InternalType.Width, Scale: -1}, nil
   115  		case defines.MYSQL_TYPE_FLOAT:
   116  			return plan.Type{Id: int32(types.T_float32), Width: n.InternalType.DisplayWith, Scale: n.InternalType.Scale}, nil
   117  		case defines.MYSQL_TYPE_DOUBLE:
   118  			return plan.Type{Id: int32(types.T_float64), Width: n.InternalType.DisplayWith, Scale: n.InternalType.Scale}, nil
   119  		case defines.MYSQL_TYPE_STRING:
   120  			width := n.InternalType.DisplayWith
   121  			// for char type,if we didn't specify the length,
   122  			// the default width should be 1, and for varchar,it's
   123  			// the defaultMaxLength
   124  			fstr := strings.ToLower(n.InternalType.FamilyString)
   125  			if width == -1 {
   126  				// create table t1(a char) -> DisplayWith = -1;but get width=1 in MySQL and PgSQL
   127  				if fstr == "char" {
   128  					width = 1
   129  				} else {
   130  					width = types.MaxVarcharLen
   131  				}
   132  			}
   133  			if fstr == "char" && width > types.MaxCharLen {
   134  				return plan.Type{}, moerr.NewOutOfRange(ctx, "char", " typeLen is over the MaxCharLen: %v", types.MaxCharLen)
   135  			} else if fstr == "varchar" && width > types.MaxVarcharLen {
   136  				return plan.Type{}, moerr.NewOutOfRange(ctx, "varchar", " typeLen is over the MaxVarcharLen: %v", types.MaxVarcharLen)
   137  			}
   138  			if fstr == "char" { // type char
   139  				return plan.Type{Id: int32(types.T_char), Width: width}, nil
   140  			}
   141  			return plan.Type{Id: int32(types.T_varchar), Width: width}, nil
   142  		case defines.MYSQL_TYPE_VAR_STRING, defines.MYSQL_TYPE_VARCHAR:
   143  			width := n.InternalType.DisplayWith
   144  			// for char type,if we didn't specify the length,
   145  			// the default width should be 1, and for varchar,it's
   146  			// the defaultMaxLength
   147  			// Should always specify length to varbinary.
   148  			fstr := strings.ToLower(n.InternalType.FamilyString)
   149  			// Check explicit casting.
   150  			if fstr == "binary" && n.InternalType.Scale == -1 {
   151  				r := plan.Type{Id: int32(types.T_binary), Width: width}
   152  				r.Scale = -1
   153  				return r, nil
   154  			}
   155  			if width == -1 {
   156  				// create table t1(a char) -> DisplayWith = -1;but get width=1 in MySQL and PgSQL
   157  				if fstr == "char" || fstr == "binary" {
   158  					width = 1
   159  				} else if fstr == "vecf32" || fstr == "vecf64" {
   160  					width = types.MaxArrayDimension
   161  				} else {
   162  					width = types.MaxVarcharLen
   163  				}
   164  			}
   165  
   166  			if (fstr == "char" || fstr == "binary") && width > types.MaxCharLen {
   167  				return plan.Type{}, moerr.NewOutOfRange(ctx, fstr, " typeLen is over the MaxCharLen: %v", types.MaxCharLen)
   168  			} else if (fstr == "varchar" || fstr == "varbinary") && width > types.MaxVarcharLen {
   169  				return plan.Type{}, moerr.NewOutOfRange(ctx, fstr, " typeLen is over the MaxVarcharLen: %v", types.MaxVarcharLen)
   170  			} else if fstr == "vecf32" || fstr == "vecf64" {
   171  				if width > types.MaxArrayDimension {
   172  					return plan.Type{}, moerr.NewOutOfRange(ctx, fstr, " typeLen is over the MaxVectorLen : %v", types.MaxArrayDimension)
   173  				}
   174  				if width < 1 {
   175  					return plan.Type{}, moerr.NewOutOfRange(ctx, fstr, " typeLen cannot be less than 1")
   176  				}
   177  			}
   178  			switch fstr {
   179  			case "char":
   180  				return plan.Type{Id: int32(types.T_char), Width: width}, nil
   181  			case "binary":
   182  				return plan.Type{Id: int32(types.T_binary), Width: width}, nil
   183  			case "varchar":
   184  				return plan.Type{Id: int32(types.T_varchar), Width: width}, nil
   185  			case "vecf32":
   186  				return plan.Type{Id: int32(types.T_array_float32), Width: width}, nil
   187  			case "vecf64":
   188  				return plan.Type{Id: int32(types.T_array_float64), Width: width}, nil
   189  			}
   190  			// varbinary
   191  			return plan.Type{Id: int32(types.T_varbinary), Width: width}, nil
   192  		case defines.MYSQL_TYPE_DATE:
   193  			return plan.Type{Id: int32(types.T_date)}, nil
   194  		case defines.MYSQL_TYPE_TIME:
   195  			return plan.Type{Id: int32(types.T_time), Width: n.InternalType.DisplayWith, Scale: n.InternalType.Scale}, nil
   196  		case defines.MYSQL_TYPE_DATETIME:
   197  			// currently the ast's width for datetime's is 26, this is not accurate and may need revise, not important though, as we don't need it anywhere else except to differentiate empty vector.Typ.
   198  			return plan.Type{Id: int32(types.T_datetime), Width: n.InternalType.DisplayWith, Scale: n.InternalType.Scale}, nil
   199  		case defines.MYSQL_TYPE_TIMESTAMP:
   200  			return plan.Type{Id: int32(types.T_timestamp), Width: n.InternalType.DisplayWith, Scale: n.InternalType.Scale}, nil
   201  		case defines.MYSQL_TYPE_DECIMAL:
   202  			if n.InternalType.DisplayWith > 16 {
   203  				return plan.Type{Id: int32(types.T_decimal128), Width: n.InternalType.DisplayWith, Scale: n.InternalType.Scale}, nil
   204  			}
   205  			return plan.Type{Id: int32(types.T_decimal64), Width: n.InternalType.DisplayWith, Scale: n.InternalType.Scale}, nil
   206  		case defines.MYSQL_TYPE_BOOL:
   207  			return plan.Type{Id: int32(types.T_bool)}, nil
   208  		case defines.MYSQL_TYPE_BLOB:
   209  			return plan.Type{Id: int32(types.T_blob)}, nil
   210  		case defines.MYSQL_TYPE_TEXT:
   211  			return plan.Type{Id: int32(types.T_text)}, nil
   212  		case defines.MYSQL_TYPE_JSON:
   213  			return plan.Type{Id: int32(types.T_json)}, nil
   214  		case defines.MYSQL_TYPE_UUID:
   215  			return plan.Type{Id: int32(types.T_uuid)}, nil
   216  		case defines.MYSQL_TYPE_TINY_BLOB:
   217  			return plan.Type{Id: int32(types.T_blob)}, nil
   218  		case defines.MYSQL_TYPE_MEDIUM_BLOB:
   219  			return plan.Type{Id: int32(types.T_blob)}, nil
   220  		case defines.MYSQL_TYPE_LONG_BLOB:
   221  			return plan.Type{Id: int32(types.T_blob)}, nil
   222  		case defines.MYSQL_TYPE_ENUM:
   223  			if len(n.InternalType.EnumValues) > types.MaxEnumLen {
   224  				return plan.Type{}, moerr.NewNYI(ctx, "enum type out of max length")
   225  			}
   226  			if len(n.InternalType.EnumValues) == 0 {
   227  				return plan.Type{}, moerr.NewNYI(ctx, "enum type length err")
   228  			}
   229  
   230  			return plan.Type{Id: int32(types.T_enum), Enumvalues: strings.Join(n.InternalType.EnumValues, ",")}, nil
   231  		default:
   232  			return plan.Type{}, moerr.NewNYI(ctx, "data type: '%s'", tree.String(&n.InternalType, dialect.MYSQL))
   233  		}
   234  	}
   235  	return plan.Type{}, moerr.NewInternalError(ctx, "unknown data type")
   236  }
   237  
   238  func buildDefaultExpr(col *tree.ColumnTableDef, typ plan.Type, proc *process.Process) (*plan.Default, error) {
   239  	nullAbility := true
   240  	var expr tree.Expr = nil
   241  	for _, attr := range col.Attributes {
   242  		if s, ok := attr.(*tree.AttributeNull); ok {
   243  			nullAbility = s.Is
   244  			break
   245  		}
   246  	}
   247  
   248  	for _, attr := range col.Attributes {
   249  		if s, ok := attr.(*tree.AttributeDefault); ok {
   250  			expr = s.Expr
   251  			break
   252  		}
   253  	}
   254  
   255  	if typ.Id == int32(types.T_json) {
   256  		if expr != nil && !isNullAstExpr(expr) {
   257  			return nil, moerr.NewNotSupported(proc.Ctx, fmt.Sprintf("JSON column '%s' cannot have default value", col.Name.Parts[0]))
   258  		}
   259  	}
   260  	if !nullAbility && isNullAstExpr(expr) {
   261  		return nil, moerr.NewInvalidInput(proc.Ctx, "invalid default value for column '%s'", col.Name.Parts[0])
   262  	}
   263  
   264  	if expr == nil {
   265  		return &plan.Default{
   266  			NullAbility:  nullAbility,
   267  			Expr:         nil,
   268  			OriginString: "",
   269  		}, nil
   270  	}
   271  
   272  	binder := NewDefaultBinder(proc.Ctx, nil, nil, typ, nil)
   273  	planExpr, err := binder.BindExpr(expr, 0, false)
   274  	if err != nil {
   275  		return nil, err
   276  	}
   277  
   278  	if defaultFunc := planExpr.GetF(); defaultFunc != nil {
   279  		if int(typ.Id) != int(types.T_uuid) && defaultFunc.Func.ObjName == "uuid" {
   280  			return nil, moerr.NewInvalidInput(proc.Ctx, "invalid default value for column '%s'", col.Name.Parts[0])
   281  		}
   282  	}
   283  
   284  	defaultExpr, err := makePlan2CastExpr(proc.Ctx, planExpr, typ)
   285  	if err != nil {
   286  		return nil, err
   287  	}
   288  
   289  	// try to calculate default value, return err if fails
   290  	newExpr, err := ConstantFold(batch.EmptyForConstFoldBatch, DeepCopyExpr(defaultExpr), proc, false)
   291  	if err != nil {
   292  		return nil, err
   293  	}
   294  
   295  	fmtCtx := tree.NewFmtCtx(dialect.MYSQL, tree.WithSingleQuoteString())
   296  	fmtCtx.PrintExpr(expr, expr, false)
   297  	return &plan.Default{
   298  		NullAbility:  nullAbility,
   299  		Expr:         newExpr,
   300  		OriginString: fmtCtx.String(),
   301  	}, nil
   302  }
   303  
   304  func buildOnUpdate(col *tree.ColumnTableDef, typ plan.Type, proc *process.Process) (*plan.OnUpdate, error) {
   305  	var expr tree.Expr = nil
   306  
   307  	for _, attr := range col.Attributes {
   308  		if s, ok := attr.(*tree.AttributeOnUpdate); ok {
   309  			expr = s.Expr
   310  			break
   311  		}
   312  	}
   313  
   314  	if expr == nil {
   315  		return nil, nil
   316  	}
   317  
   318  	binder := NewDefaultBinder(proc.Ctx, nil, nil, typ, nil)
   319  	planExpr, err := binder.BindExpr(expr, 0, false)
   320  	if err != nil {
   321  		return nil, err
   322  	}
   323  
   324  	onUpdateExpr, err := makePlan2CastExpr(proc.Ctx, planExpr, typ)
   325  	if err != nil {
   326  		return nil, err
   327  	}
   328  
   329  	// try to calculate on update value, return err if fails
   330  	executor, err := colexec.NewExpressionExecutor(proc, onUpdateExpr)
   331  	if err != nil {
   332  		return nil, err
   333  	}
   334  	defer executor.Free()
   335  	_, err = executor.Eval(proc, []*batch.Batch{batch.EmptyForConstFoldBatch})
   336  	if err != nil {
   337  		return nil, err
   338  	}
   339  
   340  	ret := &plan.OnUpdate{
   341  		Expr:         onUpdateExpr,
   342  		OriginString: tree.String(expr, dialect.MYSQL),
   343  	}
   344  	return ret, nil
   345  }
   346  
   347  func isNullExpr(expr *plan.Expr) bool {
   348  	if expr == nil {
   349  		return false
   350  	}
   351  	switch ef := expr.Expr.(type) {
   352  	case *plan.Expr_Lit:
   353  		return expr.Typ.Id == int32(types.T_any) && ef.Lit.Isnull
   354  	default:
   355  		return false
   356  	}
   357  }
   358  
   359  func isNullAstExpr(expr tree.Expr) bool {
   360  	if expr == nil {
   361  		return false
   362  	}
   363  	v, ok := expr.(*tree.NumVal)
   364  	return ok && v.ValType == tree.P_null
   365  }
   366  
   367  func convertValueIntoBool(name string, args []*Expr, isLogic bool) error {
   368  	if !isLogic && (len(args) != 2 || (args[0].Typ.Id != int32(types.T_bool) && args[1].Typ.Id != int32(types.T_bool))) {
   369  		return nil
   370  	}
   371  	for _, arg := range args {
   372  		if arg.Typ.Id == int32(types.T_bool) {
   373  			continue
   374  		}
   375  		switch ex := arg.Expr.(type) {
   376  		case *plan.Expr_Lit:
   377  			switch value := ex.Lit.Value.(type) {
   378  			case *plan.Literal_I64Val:
   379  				if value.I64Val == 0 {
   380  					ex.Lit.Value = &plan.Literal_Bval{Bval: false}
   381  				} else {
   382  					ex.Lit.Value = &plan.Literal_Bval{Bval: true}
   383  				}
   384  				arg.Typ.Id = int32(types.T_bool)
   385  			}
   386  		}
   387  	}
   388  	return nil
   389  }
   390  
   391  func getFunctionObjRef(funcID int64, name string) *ObjectRef {
   392  	return &ObjectRef{
   393  		Obj:     funcID,
   394  		ObjName: name,
   395  	}
   396  }
   397  
   398  // getAccountIds transforms the account names into account ids.
   399  // if accounts is nil, return the id of the sys account.
   400  // func getAccountIds(ctx CompilerContext, accounts tree.IdentifierList) ([]uint32, error) {
   401  // 	var accountIds []uint32
   402  // 	var err error
   403  // 	if len(accounts) != 0 {
   404  // 		accountNames := make([]string, len(accounts))
   405  // 		for i, account := range accounts {
   406  // 			accountNames[i] = string(account)
   407  // 		}
   408  // 		accountIds, err = ctx.ResolveAccountIds(accountNames)
   409  // 		if err != nil {
   410  // 			return nil, err
   411  // 		}
   412  // 	} else {
   413  // 		accountIds = []uint32{catalog.System_Account}
   414  // 	}
   415  // 	if len(accountIds) == 0 {
   416  // 		return nil, moerr.NewInternalError(ctx.GetContext(), "need specify account for the cluster tables")
   417  // 	}
   418  // 	return accountIds, err
   419  // }
   420  
   421  // func getAccountInfoOfClusterTable(ctx CompilerContext, accounts tree.IdentifierList, tableDef *TableDef, isClusterTable bool) (*plan.ClusterTable, error) {
   422  // 	var accountIds []uint32
   423  // 	var columnIndexOfAccountId int32 = -1
   424  // 	var err error
   425  // 	if isClusterTable {
   426  // 		accountIds, err = getAccountIds(ctx, accounts)
   427  // 		if err != nil {
   428  // 			return nil, err
   429  // 		}
   430  // 		for i, col := range tableDef.GetCols() {
   431  // 			if util.IsClusterTableAttribute(col.Name) {
   432  // 				if columnIndexOfAccountId >= 0 {
   433  // 					return nil, moerr.NewInternalError(ctx.GetContext(), "there are two account_ids in the cluster table")
   434  // 				} else {
   435  // 					columnIndexOfAccountId = int32(i)
   436  // 				}
   437  // 			}
   438  // 		}
   439  
   440  // 		if columnIndexOfAccountId == -1 {
   441  // 			return nil, moerr.NewInternalError(ctx.GetContext(), "there is no account_id in the cluster table")
   442  // 		} else if columnIndexOfAccountId >= int32(len(tableDef.GetCols())) {
   443  // 			return nil, moerr.NewInternalError(ctx.GetContext(), "the index of the account_id in the cluster table is invalid")
   444  // 		}
   445  // 	} else {
   446  // 		if len(accounts) != 0 {
   447  // 			return nil, moerr.NewInvalidInput(ctx.GetContext(), "can not specify the accounts for the non cluster table")
   448  // 		}
   449  // 	}
   450  // 	return &plan.ClusterTable{
   451  // 		IsClusterTable:         isClusterTable,
   452  // 		AccountIDs:             accountIds,
   453  // 		ColumnIndexOfAccountId: columnIndexOfAccountId,
   454  // 	}, nil
   455  // }
   456  
   457  func getDefaultExpr(ctx context.Context, d *plan.ColDef) (*Expr, error) {
   458  	if !d.Default.NullAbility && d.Default.Expr == nil && !d.Typ.AutoIncr {
   459  		return nil, moerr.NewInvalidInput(ctx, "invalid default value for column '%s'", d.Name)
   460  	}
   461  	if d.Default.Expr == nil {
   462  		return &Expr{
   463  			Expr: &plan.Expr_Lit{
   464  				Lit: &Const{
   465  					Isnull: true,
   466  				},
   467  			},
   468  			Typ: plan.Type{
   469  				Id:          d.Typ.Id,
   470  				NotNullable: false,
   471  			},
   472  		}, nil
   473  	}
   474  	return d.Default.Expr, nil
   475  }
   476  
   477  func judgeUnixTimestampReturnType(timestr string) types.T {
   478  	retDecimal := 0
   479  	if dotIdx := strings.LastIndex(timestr, "."); dotIdx >= 0 {
   480  		retDecimal = len(timestr) - dotIdx - 1
   481  	}
   482  
   483  	if retDecimal > 6 || retDecimal == -1 {
   484  		retDecimal = 6
   485  	}
   486  
   487  	if retDecimal == 0 {
   488  		return types.T_int64
   489  	} else {
   490  		return types.T_decimal128
   491  	}
   492  }
   493  
   494  // Get the primary key name of the table
   495  func getTablePriKeyName(priKeyDef *plan.PrimaryKeyDef) string {
   496  	if priKeyDef == nil {
   497  		return ""
   498  	} else {
   499  		return priKeyDef.PkeyColName
   500  	}
   501  }
   502  
   503  // Check whether the table column name is an internal key
   504  func checkTableColumnNameValid(name string) bool {
   505  	if name == catalog.Row_ID || name == catalog.CPrimaryKeyColName ||
   506  		name == catalog.TableTailAttrCommitTs || name == catalog.TableTailAttrAborted || name == catalog.TableTailAttrPKVal {
   507  		return false
   508  	}
   509  	return true
   510  }
   511  
   512  // Check the expr has paramExpr
   513  func checkExprHasParamExpr(exprs []tree.Expr) bool {
   514  	for _, expr := range exprs {
   515  		if _, ok := expr.(*tree.ParamExpr); ok {
   516  			return true
   517  		} else if e, ok := expr.(*tree.FuncExpr); ok {
   518  			return checkExprHasParamExpr(e.Exprs)
   519  		}
   520  	}
   521  	return false
   522  }
   523  
   524  // makeSelectList forms SELECT Clause "Select t.a,t.b,... "
   525  func makeSelectList(table string, strs []string) string {
   526  	bb := strings.Builder{}
   527  	for i, str := range strs {
   528  		if i > 0 {
   529  			bb.WriteByte(',')
   530  		}
   531  		//table
   532  		bb.WriteByte('`')
   533  		bb.WriteString(table)
   534  		bb.WriteByte('`')
   535  		bb.WriteByte('.')
   536  		//column
   537  		bb.WriteByte('`')
   538  		bb.WriteString(str)
   539  		bb.WriteByte('`')
   540  	}
   541  	return bb.String()
   542  }
   543  
   544  // makeWhere forms WHERE Clause "Where t.a is not null and ..."
   545  func makeWhere(table string, strs []string) string {
   546  	bb := strings.Builder{}
   547  	for i, str := range strs {
   548  		if i > 0 {
   549  			bb.WriteString(" and ")
   550  		}
   551  		//table
   552  		bb.WriteByte('`')
   553  		bb.WriteString(table)
   554  		bb.WriteByte('`')
   555  		bb.WriteByte('.')
   556  		//column
   557  		bb.WriteByte('`')
   558  		bb.WriteString(str)
   559  		bb.WriteByte('`')
   560  		//is not null
   561  		bb.WriteString(" is not null")
   562  	}
   563  	bb.WriteByte(' ')
   564  	return bb.String()
   565  }
   566  
   567  // colIdsToNames convert the colId to the col name
   568  func colIdsToNames(ctx context.Context, colIds []uint64, colDefs []*plan.ColDef) ([]string, error) {
   569  	colId2Name := make(map[uint64]string)
   570  	for _, def := range colDefs {
   571  		colId2Name[def.ColId] = def.Name
   572  	}
   573  	names := make([]string, 0)
   574  	for _, colId := range colIds {
   575  		if name, has := colId2Name[colId]; !has {
   576  			return nil, moerr.NewInternalError(ctx, fmt.Sprintf("colId %d does exist", colId))
   577  		} else {
   578  			names = append(names, name)
   579  		}
   580  	}
   581  	return names, nil
   582  }
   583  
   584  /*
   585  genSqlForCheckFKConstraints generates the fk constraint checking sql.
   586  
   587  basic logic of fk constraint check.
   588  
   589  	parent table:
   590  		T(a)
   591  	child table:
   592  		S(b)
   593  		foreign key (b) references T(a)
   594  
   595  
   596  	generated sql :
   597  		select count(*) == 0 from (
   598  			select distinct S.b from S where S.b is not null
   599  			except
   600  			select distinct T.a from T
   601  		)
   602  	if the result is true, then the fk constraint confirmed.
   603  */
   604  func genSqlForCheckFKConstraints(ctx context.Context,
   605  	fkey *plan.ForeignKeyDef,
   606  	childDbName, childTblName string, colsOfChild []*plan.ColDef,
   607  	parentDbName, parentTblName string, colsOfParent []*plan.ColDef) (string, error) {
   608  
   609  	//fk column names
   610  	fkCols, err := colIdsToNames(ctx, fkey.Cols, colsOfChild)
   611  	if err != nil {
   612  		return "", err
   613  	}
   614  	//referred column names
   615  	referCols, err := colIdsToNames(ctx, fkey.ForeignCols, colsOfParent)
   616  	if err != nil {
   617  		return "", err
   618  	}
   619  
   620  	childTableClause := fmt.Sprintf("`%s`.`%s`", childDbName, childTblName)
   621  	parentTableClause := fmt.Sprintf("`%s`.`%s`", parentDbName, parentTblName)
   622  	where := fmt.Sprintf("where %s", makeWhere(childTblName, fkCols))
   623  	except := fmt.Sprintf("select distinct %s from %s %s except select distinct %s from %s",
   624  		makeSelectList(childTblName, fkCols),
   625  		childTableClause,
   626  		where,
   627  		makeSelectList(parentTblName, referCols),
   628  		parentTableClause,
   629  	)
   630  
   631  	//make detect sql
   632  	sql := strings.Join([]string{
   633  		"select count(*) = 0 from (",
   634  		except,
   635  		")",
   636  	}, " ")
   637  	return sql, nil
   638  }
   639  
   640  // genSqlsForCheckFKSelfRefer generates the fk constraint checking sql.
   641  // the only difference between genSqlsForCheckFKSelfRefer and genSqlForCheckFKConstraints
   642  // is the parent table and child table are same in the fk self refer.
   643  func genSqlsForCheckFKSelfRefer(ctx context.Context,
   644  	dbName, tblName string,
   645  	cols []*plan.ColDef, fkeys []*plan.ForeignKeyDef) ([]string, error) {
   646  	ret := make([]string, 0)
   647  	for _, fkey := range fkeys {
   648  		if fkey.ForeignTbl != 0 {
   649  			continue
   650  		}
   651  		sql, err := genSqlForCheckFKConstraints(ctx, fkey, dbName, tblName, cols, dbName, tblName, cols)
   652  		if err != nil {
   653  			return nil, err
   654  		}
   655  		ret = append(ret, sql)
   656  	}
   657  	return ret, nil
   658  }
   659  
   660  func rewriteForCreateTableLike(stmt *tree.CreateTable, ctx CompilerContext) (newStmt tree.Statement, err error) {
   661  	oldTable := stmt.LikeTableName
   662  	newTable := stmt.Table
   663  
   664  	tblName := formatStr(string(oldTable.ObjectName))
   665  	dbName := formatStr(string(oldTable.SchemaName))
   666  	dbName, err = databaseIsValid(getSuitableDBName(dbName, ""), ctx, Snapshot{TS: &timestamp.Timestamp{}})
   667  	if err != nil {
   668  		return nil, err
   669  	}
   670  
   671  	_, tableDef := ctx.Resolve(dbName, tblName, Snapshot{TS: &timestamp.Timestamp{}})
   672  	if tableDef == nil {
   673  		return nil, moerr.NewNoSuchTable(ctx.GetContext(), dbName, tblName)
   674  	}
   675  	if tableDef.TableType == catalog.SystemViewRel || tableDef.TableType == catalog.SystemExternalRel || tableDef.TableType == catalog.SystemClusterRel {
   676  		return nil, moerr.NewInternalError(ctx.GetContext(), "%s.%s is not BASE TABLE", dbName, tblName)
   677  	}
   678  
   679  	var createStr string
   680  	if tableDef.TableType == catalog.SystemOrdinaryRel {
   681  		createStr = fmt.Sprintf("CREATE TABLE `%s` (", formatStr(string(newTable.ObjectName)))
   682  	} else if tblName == catalog.MO_DATABASE || tblName == catalog.MO_TABLES || tblName == catalog.MO_COLUMNS {
   683  		createStr = fmt.Sprintf("CREATE TABLE `%s` (", formatStr(string(newTable.ObjectName)))
   684  	}
   685  
   686  	rowCount := 0
   687  	var pkDefs []string
   688  	colIdToName := make(map[uint64]string)
   689  	for _, col := range tableDef.Cols {
   690  		if col.Hidden {
   691  			continue
   692  		}
   693  		colName := col.Name
   694  		colIdToName[col.ColId] = col.Name
   695  		if colName == catalog.Row_ID {
   696  			continue
   697  		}
   698  
   699  		nullOrNot := "NOT NULL"
   700  		// col.Default must be not nil
   701  		if len(col.Default.OriginString) > 0 {
   702  			if !col.Primary {
   703  				nullOrNot = "DEFAULT " + formatStr(col.Default.OriginString)
   704  			}
   705  		} else if col.Default.NullAbility {
   706  			nullOrNot = "DEFAULT NULL"
   707  		}
   708  
   709  		if col.Typ.AutoIncr {
   710  			nullOrNot = "NOT NULL AUTO_INCREMENT"
   711  		}
   712  
   713  		var hasAttrComment string
   714  		if col.Comment != "" {
   715  			hasAttrComment = " COMMENT '" + col.Comment + "'"
   716  		}
   717  
   718  		if rowCount == 0 {
   719  			createStr += "\n"
   720  		} else {
   721  			createStr += ",\n"
   722  		}
   723  		typ := types.T(col.Typ.Id).ToType()
   724  		typeStr := typ.String()
   725  		if typ.Oid.IsDecimal() { //after decimal fix,remove this
   726  			typeStr = fmt.Sprintf("DECIMAL(%d,%d)", col.Typ.Width, col.Typ.Scale)
   727  		}
   728  		if typ.Oid == types.T_varchar || typ.Oid == types.T_char ||
   729  			typ.Oid == types.T_binary || typ.Oid == types.T_varbinary ||
   730  			typ.Oid.IsArrayRelate() || typ.Oid == types.T_bit {
   731  			typeStr += fmt.Sprintf("(%d)", col.Typ.Width)
   732  		}
   733  		if typ.Oid.IsFloat() && col.Typ.Scale != -1 {
   734  			typeStr += fmt.Sprintf("(%d,%d)", col.Typ.Width, col.Typ.Scale)
   735  		}
   736  
   737  		if typ.Oid.IsEnum() {
   738  			enums := strings.Split(col.Typ.GetEnumvalues(), ",")
   739  			typeStr += "("
   740  			for i, enum := range enums {
   741  				typeStr += fmt.Sprintf("'%s'", enum)
   742  				if i < len(enums)-1 {
   743  					typeStr += ","
   744  				}
   745  			}
   746  			typeStr += ")"
   747  		}
   748  
   749  		updateOpt := ""
   750  		if col.OnUpdate != nil && col.OnUpdate.Expr != nil {
   751  			updateOpt = " ON UPDATE " + col.OnUpdate.OriginString
   752  		}
   753  		createStr += fmt.Sprintf("`%s` %s %s%s%s", formatStr(colName), typeStr, nullOrNot, updateOpt, hasAttrComment)
   754  		rowCount++
   755  		if col.Primary {
   756  			pkDefs = append(pkDefs, colName)
   757  		}
   758  	}
   759  
   760  	// If it is a composite primary key, get the component columns of the composite primary key
   761  	if tableDef.Pkey != nil && len(tableDef.Pkey.Names) > 1 {
   762  		pkDefs = append(pkDefs, tableDef.Pkey.Names...)
   763  	}
   764  
   765  	if len(pkDefs) != 0 {
   766  		pkStr := "PRIMARY KEY ("
   767  		for i, def := range pkDefs {
   768  			if i == len(pkDefs)-1 {
   769  				pkStr += fmt.Sprintf("`%s`", formatStr(def))
   770  			} else {
   771  				pkStr += fmt.Sprintf("`%s`,", formatStr(def))
   772  			}
   773  		}
   774  		pkStr += ")"
   775  		if rowCount != 0 {
   776  			createStr += ",\n"
   777  		}
   778  		createStr += pkStr
   779  	}
   780  
   781  	if tableDef.Indexes != nil {
   782  
   783  		// We only print distinct index names. This is used to avoid printing the same index multiple times for IVFFLAT or
   784  		// other multi-table indexes.
   785  		indexNames := make(map[string]bool)
   786  
   787  		for _, indexdef := range tableDef.Indexes {
   788  			if _, ok := indexNames[indexdef.IndexName]; ok {
   789  				continue
   790  			} else {
   791  				indexNames[indexdef.IndexName] = true
   792  			}
   793  
   794  			var indexStr string
   795  			if indexdef.Unique {
   796  				indexStr = "UNIQUE KEY "
   797  			} else {
   798  				indexStr = "KEY "
   799  			}
   800  			indexStr += fmt.Sprintf("`%s` ", formatStr(indexdef.IndexName))
   801  			if !catalog.IsNullIndexAlgo(indexdef.IndexAlgo) {
   802  				indexStr += fmt.Sprintf("USING %s ", indexdef.IndexAlgo)
   803  			}
   804  			indexStr += "("
   805  			i := 0
   806  			for _, part := range indexdef.Parts {
   807  				if catalog.IsAlias(part) {
   808  					continue
   809  				}
   810  				if i > 0 {
   811  					indexStr += ","
   812  				}
   813  
   814  				indexStr += fmt.Sprintf("`%s`", formatStr(part))
   815  				i++
   816  			}
   817  
   818  			indexStr += ")"
   819  			if indexdef.IndexAlgoParams != "" {
   820  				var paramList string
   821  				paramList, err = catalog.IndexParamsToStringList(indexdef.IndexAlgoParams)
   822  				if err != nil {
   823  					return nil, err
   824  				}
   825  				indexStr += paramList
   826  			}
   827  			if indexdef.Comment != "" {
   828  				indexdef.Comment = strings.Replace(indexdef.Comment, "'", "\\'", -1)
   829  				indexStr += fmt.Sprintf(" COMMENT '%s'", formatStr(indexdef.Comment))
   830  			}
   831  			if rowCount != 0 {
   832  				createStr += ",\n"
   833  			}
   834  			createStr += indexStr
   835  		}
   836  	}
   837  
   838  	for _, fk := range tableDef.Fkeys {
   839  		colNames := make([]string, len(fk.Cols))
   840  		for i, colId := range fk.Cols {
   841  			colNames[i] = colIdToName[colId]
   842  		}
   843  
   844  		var fkTableDef *TableDef
   845  
   846  		//fk self reference
   847  		if fk.ForeignTbl == 0 {
   848  			fkTableDef = tableDef
   849  		} else {
   850  			_, fkTableDef = ctx.ResolveById(fk.ForeignTbl, Snapshot{TS: &timestamp.Timestamp{}})
   851  		}
   852  
   853  		fkColIdToName := make(map[uint64]string)
   854  		for _, col := range fkTableDef.Cols {
   855  			fkColIdToName[col.ColId] = col.Name
   856  		}
   857  		fkColNames := make([]string, len(fk.ForeignCols))
   858  		for i, colId := range fk.ForeignCols {
   859  			fkColNames[i] = fkColIdToName[colId]
   860  		}
   861  
   862  		if rowCount != 0 {
   863  			createStr += ",\n"
   864  		}
   865  		createStr += fmt.Sprintf("CONSTRAINT `%s` FOREIGN KEY (`%s`) REFERENCES `%s` (`%s`) ON DELETE %s ON UPDATE %s",
   866  			formatStr(fk.Name), strings.Join(colNames, "`,`"), formatStr(fkTableDef.Name), strings.Join(fkColNames, "`,`"), fk.OnDelete.String(), fk.OnUpdate.String())
   867  	}
   868  
   869  	if rowCount != 0 {
   870  		createStr += "\n"
   871  	}
   872  	createStr += ")"
   873  
   874  	var comment string
   875  	var partition string
   876  	for _, def := range tableDef.Defs {
   877  		if proDef, ok := def.Def.(*plan.TableDef_DefType_Properties); ok {
   878  			for _, kv := range proDef.Properties.Properties {
   879  				if kv.Key == catalog.SystemRelAttr_Comment {
   880  					comment = " COMMENT='" + kv.Value + "'"
   881  				}
   882  			}
   883  		}
   884  	}
   885  
   886  	if tableDef.Partition != nil {
   887  		partition = ` ` + tableDef.Partition.PartitionMsg
   888  	}
   889  
   890  	createStr += comment
   891  	createStr += partition
   892  
   893  	if tableDef.ClusterBy != nil {
   894  		clusterby := " CLUSTER BY ("
   895  		if util.JudgeIsCompositeClusterByColumn(tableDef.ClusterBy.Name) {
   896  			//multi column clusterby
   897  			cbNames := util.SplitCompositeClusterByColumnName(tableDef.ClusterBy.Name)
   898  			for i, cbName := range cbNames {
   899  				if i != 0 {
   900  					clusterby += fmt.Sprintf(", `%s`", formatStr(cbName))
   901  				} else {
   902  					clusterby += fmt.Sprintf("`%s`", formatStr(cbName))
   903  				}
   904  			}
   905  		} else {
   906  			//single column cluster by
   907  			clusterby += fmt.Sprintf("`%s`", formatStr(tableDef.ClusterBy.Name))
   908  		}
   909  		clusterby += ")"
   910  		createStr += clusterby
   911  	}
   912  
   913  	var buf bytes.Buffer
   914  	for _, ch := range createStr {
   915  		if ch == '"' {
   916  			buf.WriteRune('"')
   917  		}
   918  		buf.WriteRune(ch)
   919  	}
   920  	sql := buf.String()
   921  	return getRewriteSQLStmt(ctx, sql)
   922  }