github.com/matrixorigin/matrixone@v0.7.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  	"context"
    19  	"fmt"
    20  	"strings"
    21  
    22  	"github.com/matrixorigin/matrixone/pkg/catalog"
    23  	"github.com/matrixorigin/matrixone/pkg/sql/util"
    24  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    25  
    26  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    27  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    28  	"github.com/matrixorigin/matrixone/pkg/container/types"
    29  	"github.com/matrixorigin/matrixone/pkg/defines"
    30  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    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  )
    35  
    36  // func appendQueryNode(query *Query, node *Node) int32 {
    37  // 	nodeID := int32(len(query.Nodes))
    38  // 	node.NodeId = nodeID
    39  // 	query.Nodes = append(query.Nodes, node)
    40  
    41  // 	return nodeID
    42  // }
    43  
    44  func getTypeFromAst(ctx context.Context, typ tree.ResolvableTypeReference) (*plan.Type, error) {
    45  	if n, ok := typ.(*tree.T); ok {
    46  		switch defines.MysqlType(n.InternalType.Oid) {
    47  		case defines.MYSQL_TYPE_TINY:
    48  			if n.InternalType.Unsigned {
    49  				return &plan.Type{Id: int32(types.T_uint8), Width: n.InternalType.Width, Size: 1}, nil
    50  			}
    51  			return &plan.Type{Id: int32(types.T_int8), Width: n.InternalType.Width, Size: 1}, nil
    52  		case defines.MYSQL_TYPE_SHORT:
    53  			if n.InternalType.Unsigned {
    54  				return &plan.Type{Id: int32(types.T_uint16), Width: n.InternalType.Width, Size: 2}, nil
    55  			}
    56  			return &plan.Type{Id: int32(types.T_int16), Width: n.InternalType.Width, Size: 2}, nil
    57  		case defines.MYSQL_TYPE_LONG:
    58  			if n.InternalType.Unsigned {
    59  				return &plan.Type{Id: int32(types.T_uint32), Width: n.InternalType.Width, Size: 4}, nil
    60  			}
    61  			return &plan.Type{Id: int32(types.T_int32), Width: n.InternalType.Width, Size: 4}, nil
    62  		case defines.MYSQL_TYPE_LONGLONG:
    63  			if n.InternalType.Unsigned {
    64  				return &plan.Type{Id: int32(types.T_uint64), Width: n.InternalType.Width, Size: 8}, nil
    65  			}
    66  			return &plan.Type{Id: int32(types.T_int64), Width: n.InternalType.Width, Size: 8}, nil
    67  		case defines.MYSQL_TYPE_FLOAT:
    68  			return &plan.Type{Id: int32(types.T_float32), Width: n.InternalType.DisplayWith, Size: 4, Precision: n.InternalType.Precision}, nil
    69  		case defines.MYSQL_TYPE_DOUBLE:
    70  			return &plan.Type{Id: int32(types.T_float64), Width: n.InternalType.DisplayWith, Size: 8, Precision: n.InternalType.Precision}, nil
    71  		case defines.MYSQL_TYPE_STRING:
    72  			width := n.InternalType.DisplayWith
    73  			// for char type,if we didn't specify the length,
    74  			// the default width should be 1, and for varchar,it's
    75  			// the defaultMaxLength
    76  			if width == -1 {
    77  				// create table t1(a char) -> DisplayWith = -1;but get width=1 in MySQL and PgSQL
    78  				if n.InternalType.FamilyString == "char" {
    79  					width = 1
    80  				} else {
    81  					width = types.MaxVarcharLen
    82  				}
    83  			}
    84  			if n.InternalType.FamilyString == "char" && width > types.MaxCharLen {
    85  				return nil, moerr.NewOutOfRange(ctx, "char", " typeLen is over the MaxCharLen: %v", types.MaxCharLen)
    86  			} else if n.InternalType.FamilyString == "varchar" && width > types.MaxVarcharLen {
    87  				return nil, moerr.NewOutOfRange(ctx, "varchar", " typeLen is over the MaxVarcharLen: %v", types.MaxVarcharLen)
    88  			}
    89  			if n.InternalType.FamilyString == "char" { // type char
    90  				return &plan.Type{Id: int32(types.T_char), Size: 24, Width: width}, nil
    91  			}
    92  			return &plan.Type{Id: int32(types.T_varchar), Size: 24, Width: width}, nil
    93  		case defines.MYSQL_TYPE_VAR_STRING, defines.MYSQL_TYPE_VARCHAR:
    94  			width := n.InternalType.DisplayWith
    95  			// for char type,if we didn't specify the length,
    96  			// the default width should be 1, and for varchar,it's
    97  			// the defaultMaxLength
    98  			if width == -1 {
    99  				// create table t1(a char) -> DisplayWith = -1;but get width=1 in MySQL and PgSQL
   100  				if n.InternalType.FamilyString == "char" {
   101  					width = 1
   102  				} else {
   103  					width = types.MaxVarcharLen
   104  				}
   105  			}
   106  			if n.InternalType.FamilyString == "char" && width > types.MaxCharLen {
   107  				return nil, moerr.NewOutOfRange(ctx, "char", " typeLen is over the MaxCharLen: %v", types.MaxCharLen)
   108  			} else if n.InternalType.FamilyString == "varchar" && width > types.MaxVarcharLen {
   109  				return nil, moerr.NewOutOfRange(ctx, "varchar", " typeLen is over the MaxVarcharLen: %v", types.MaxVarcharLen)
   110  			}
   111  			if n.InternalType.FamilyString == "char" { // type char
   112  				return &plan.Type{Id: int32(types.T_char), Size: 24, Width: width}, nil
   113  			}
   114  			return &plan.Type{Id: int32(types.T_varchar), Size: 24, Width: width}, nil
   115  		case defines.MYSQL_TYPE_DATE:
   116  			return &plan.Type{Id: int32(types.T_date), Size: 4}, nil
   117  		case defines.MYSQL_TYPE_TIME:
   118  			return &plan.Type{Id: int32(types.T_time), Size: 8, Width: n.InternalType.Width, Precision: n.InternalType.Precision}, nil
   119  		case defines.MYSQL_TYPE_DATETIME:
   120  			// 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.
   121  			return &plan.Type{Id: int32(types.T_datetime), Size: 8, Width: n.InternalType.Width, Precision: n.InternalType.Precision}, nil
   122  		case defines.MYSQL_TYPE_TIMESTAMP:
   123  			return &plan.Type{Id: int32(types.T_timestamp), Size: 8, Width: n.InternalType.Width, Precision: n.InternalType.Precision}, nil
   124  		case defines.MYSQL_TYPE_DECIMAL:
   125  			if n.InternalType.DisplayWith > 15 {
   126  				return &plan.Type{Id: int32(types.T_decimal128), Size: 16, Width: n.InternalType.DisplayWith, Scale: n.InternalType.Precision}, nil
   127  			}
   128  			return &plan.Type{Id: int32(types.T_decimal64), Size: 8, Width: n.InternalType.DisplayWith, Scale: n.InternalType.Precision}, nil
   129  		case defines.MYSQL_TYPE_BOOL:
   130  			return &plan.Type{Id: int32(types.T_bool), Size: 1}, nil
   131  		case defines.MYSQL_TYPE_BLOB:
   132  			return &plan.Type{Id: int32(types.T_blob), Size: 24}, nil
   133  		case defines.MYSQL_TYPE_TEXT:
   134  			return &plan.Type{Id: int32(types.T_text), Size: 24}, nil
   135  		case defines.MYSQL_TYPE_JSON:
   136  			return &plan.Type{Id: int32(types.T_json), Size: types.VarlenaSize}, nil
   137  		case defines.MYSQL_TYPE_UUID:
   138  			return &plan.Type{Id: int32(types.T_uuid), Size: 16}, nil
   139  		case defines.MYSQL_TYPE_TINY_BLOB:
   140  			return &plan.Type{Id: int32(types.T_blob), Size: types.VarlenaSize}, nil
   141  		case defines.MYSQL_TYPE_MEDIUM_BLOB:
   142  			return &plan.Type{Id: int32(types.T_blob), Size: types.VarlenaSize}, nil
   143  		case defines.MYSQL_TYPE_LONG_BLOB:
   144  			return &plan.Type{Id: int32(types.T_blob), Size: types.VarlenaSize}, nil
   145  		default:
   146  			return nil, moerr.NewNYI(ctx, "data type: '%s'", tree.String(&n.InternalType, dialect.MYSQL))
   147  		}
   148  	}
   149  	return nil, moerr.NewInternalError(ctx, "unknown data type")
   150  }
   151  
   152  func buildDefaultExpr(col *tree.ColumnTableDef, typ *plan.Type, proc *process.Process) (*plan.Default, error) {
   153  	nullAbility := true
   154  	var expr tree.Expr = nil
   155  	for _, attr := range col.Attributes {
   156  		if s, ok := attr.(*tree.AttributeNull); ok {
   157  			nullAbility = s.Is
   158  			break
   159  		}
   160  	}
   161  
   162  	for _, attr := range col.Attributes {
   163  		if s, ok := attr.(*tree.AttributeDefault); ok {
   164  			expr = s.Expr
   165  			break
   166  		}
   167  	}
   168  
   169  	if typ.Id == int32(types.T_json) {
   170  		if expr != nil && !isNullAstExpr(expr) {
   171  			return nil, moerr.NewNotSupported(proc.Ctx, fmt.Sprintf("JSON column '%s' cannot have default value", col.Name.Parts[0]))
   172  		}
   173  	}
   174  	if !nullAbility && isNullAstExpr(expr) {
   175  		return nil, moerr.NewInvalidInput(proc.Ctx, "invalid default value for column '%s'", col.Name.Parts[0])
   176  	}
   177  
   178  	if expr == nil {
   179  		return &plan.Default{
   180  			NullAbility:  nullAbility,
   181  			Expr:         nil,
   182  			OriginString: "",
   183  		}, nil
   184  	}
   185  
   186  	binder := NewDefaultBinder(proc.Ctx, nil, nil, typ, nil)
   187  	planExpr, err := binder.BindExpr(expr, 0, false)
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  
   192  	if defaultFunc := planExpr.GetF(); defaultFunc != nil {
   193  		if int(typ.Id) != int(types.T_uuid) && defaultFunc.Func.ObjName == "uuid" {
   194  			return nil, moerr.NewInvalidInput(proc.Ctx, "invalid default value for column '%s'", col.Name.Parts[0])
   195  		}
   196  	}
   197  
   198  	defaultExpr, err := makePlan2CastExpr(proc.Ctx, planExpr, typ)
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  
   203  	// try to calculate default value, return err if fails
   204  	bat := batch.NewWithSize(0)
   205  	bat.Zs = []int64{1}
   206  	newExpr, err := ConstantFold(bat, DeepCopyExpr(defaultExpr), proc)
   207  	if err != nil {
   208  		return nil, err
   209  	}
   210  
   211  	fmtCtx := tree.NewFmtCtx(dialect.MYSQL, tree.WithSingleQuoteString())
   212  	fmtCtx.PrintExpr(expr, expr, false)
   213  	return &plan.Default{
   214  		NullAbility:  nullAbility,
   215  		Expr:         newExpr,
   216  		OriginString: fmtCtx.String(),
   217  	}, nil
   218  }
   219  
   220  func buildOnUpdate(col *tree.ColumnTableDef, typ *plan.Type, proc *process.Process) (*plan.OnUpdate, error) {
   221  	var expr tree.Expr = nil
   222  
   223  	for _, attr := range col.Attributes {
   224  		if s, ok := attr.(*tree.AttributeOnUpdate); ok {
   225  			expr = s.Expr
   226  			break
   227  		}
   228  	}
   229  
   230  	if expr == nil {
   231  		return nil, nil
   232  	}
   233  
   234  	binder := NewDefaultBinder(proc.Ctx, nil, nil, typ, nil)
   235  	planExpr, err := binder.BindExpr(expr, 0, false)
   236  	if err != nil {
   237  		return nil, err
   238  	}
   239  
   240  	onUpdateExpr, err := makePlan2CastExpr(proc.Ctx, planExpr, typ)
   241  	if err != nil {
   242  		return nil, err
   243  	}
   244  
   245  	// try to calculate on update value, return err if fails
   246  	bat := batch.NewWithSize(0)
   247  	bat.Zs = []int64{1}
   248  	v, err := colexec.EvalExpr(bat, proc, onUpdateExpr)
   249  	if err != nil {
   250  		return nil, err
   251  	}
   252  	v.Free(proc.Mp())
   253  	ret := &plan.OnUpdate{
   254  		Expr:         onUpdateExpr,
   255  		OriginString: tree.String(expr, dialect.MYSQL),
   256  	}
   257  	return ret, nil
   258  }
   259  
   260  func isNullExpr(expr *plan.Expr) bool {
   261  	if expr == nil {
   262  		return false
   263  	}
   264  	switch ef := expr.Expr.(type) {
   265  	case *plan.Expr_C:
   266  		return expr.Typ.Id == int32(types.T_any) && ef.C.Isnull
   267  	default:
   268  		return false
   269  	}
   270  }
   271  
   272  func isNullAstExpr(expr tree.Expr) bool {
   273  	if expr == nil {
   274  		return false
   275  	}
   276  	v, ok := expr.(*tree.NumVal)
   277  	return ok && v.ValType == tree.P_null
   278  }
   279  
   280  func convertValueIntoBool(name string, args []*Expr, isLogic bool) error {
   281  	if !isLogic && (len(args) != 2 || (args[0].Typ.Id != int32(types.T_bool) && args[1].Typ.Id != int32(types.T_bool))) {
   282  		return nil
   283  	}
   284  	for _, arg := range args {
   285  		if arg.Typ.Id == int32(types.T_bool) {
   286  			continue
   287  		}
   288  		switch ex := arg.Expr.(type) {
   289  		case *plan.Expr_C:
   290  			switch value := ex.C.Value.(type) {
   291  			case *plan.Const_I64Val:
   292  				if value.I64Val == 0 {
   293  					ex.C.Value = &plan.Const_Bval{Bval: false}
   294  				} else {
   295  					ex.C.Value = &plan.Const_Bval{Bval: true}
   296  				}
   297  				arg.Typ.Id = int32(types.T_bool)
   298  			}
   299  		}
   300  	}
   301  	return nil
   302  }
   303  
   304  func getFunctionObjRef(funcID int64, name string) *ObjectRef {
   305  	return &ObjectRef{
   306  		Obj:     funcID,
   307  		ObjName: name,
   308  	}
   309  }
   310  
   311  // getAccountIds transforms the account names into account ids.
   312  // if accounts is nil, return the id of the sys account.
   313  func getAccountIds(ctx CompilerContext, accounts tree.IdentifierList) ([]uint32, error) {
   314  	var accountIds []uint32
   315  	var err error
   316  	if len(accounts) != 0 {
   317  		accountNames := make([]string, len(accounts))
   318  		for i, account := range accounts {
   319  			accountNames[i] = string(account)
   320  		}
   321  		accountIds, err = ctx.ResolveAccountIds(accountNames)
   322  		if err != nil {
   323  			return nil, err
   324  		}
   325  	} else {
   326  		accountIds = []uint32{catalog.System_Account}
   327  	}
   328  	if len(accountIds) == 0 {
   329  		return nil, moerr.NewInternalError(ctx.GetContext(), "need specify account for the cluster tables")
   330  	}
   331  	return accountIds, err
   332  }
   333  
   334  func getAccountInfoOfClusterTable(ctx CompilerContext, accounts tree.IdentifierList, tableDef *TableDef, isClusterTable bool) (*plan.ClusterTable, error) {
   335  	var accountIds []uint32
   336  	var columnIndexOfAccountId int32 = -1
   337  	var err error
   338  	if isClusterTable {
   339  		accountIds, err = getAccountIds(ctx, accounts)
   340  		if err != nil {
   341  			return nil, err
   342  		}
   343  		for i, col := range tableDef.GetCols() {
   344  			if util.IsClusterTableAttribute(col.Name) {
   345  				if columnIndexOfAccountId >= 0 {
   346  					return nil, moerr.NewInternalError(ctx.GetContext(), "there are two account_ids in the cluster table")
   347  				} else {
   348  					columnIndexOfAccountId = int32(i)
   349  				}
   350  			}
   351  		}
   352  
   353  		if columnIndexOfAccountId == -1 {
   354  			return nil, moerr.NewInternalError(ctx.GetContext(), "there is no account_id in the cluster table")
   355  		} else if columnIndexOfAccountId >= int32(len(tableDef.GetCols())) {
   356  			return nil, moerr.NewInternalError(ctx.GetContext(), "the index of the account_id in the cluster table is invalid")
   357  		}
   358  	} else {
   359  		if len(accounts) != 0 {
   360  			return nil, moerr.NewInvalidInput(ctx.GetContext(), "can not specify the accounts for the non cluster table")
   361  		}
   362  	}
   363  	return &plan.ClusterTable{
   364  		IsClusterTable:         isClusterTable,
   365  		AccountIDs:             accountIds,
   366  		ColumnIndexOfAccountId: columnIndexOfAccountId,
   367  	}, nil
   368  }
   369  
   370  func getDefaultExpr(ctx context.Context, d *plan.ColDef) (*Expr, error) {
   371  	if !d.Default.NullAbility && d.Default.Expr == nil && !d.Typ.AutoIncr {
   372  		return nil, moerr.NewInvalidInput(ctx, "invalid default value")
   373  	}
   374  	if d.Default.Expr == nil {
   375  		return &Expr{
   376  			Expr: &plan.Expr_C{
   377  				C: &Const{
   378  					Isnull: true,
   379  				},
   380  			},
   381  			Typ: &plan.Type{
   382  				Id:          d.Typ.Id,
   383  				NotNullable: false,
   384  			},
   385  		}, nil
   386  	}
   387  	return d.Default.Expr, nil
   388  }
   389  
   390  func judgeUnixTimestampReturnType(timestr string) types.T {
   391  	retDecimal := 0
   392  	if dotIdx := strings.LastIndex(timestr, "."); dotIdx >= 0 {
   393  		retDecimal = len(timestr) - dotIdx - 1
   394  	}
   395  
   396  	if retDecimal > 6 || retDecimal == -1 {
   397  		retDecimal = 6
   398  	}
   399  
   400  	if retDecimal == 0 {
   401  		return types.T_int64
   402  	} else {
   403  		return types.T_decimal128
   404  	}
   405  }
   406  
   407  // Get the primary key name of the table
   408  func GetTablePriKeyName(cols []*plan.ColDef, cPkeyCol *plan.ColDef) string {
   409  	for _, col := range cols {
   410  		if col.Name != catalog.Row_ID && col.Primary {
   411  			return col.Name
   412  		}
   413  
   414  	}
   415  
   416  	if cPkeyCol != nil {
   417  		return cPkeyCol.Name
   418  	}
   419  	return ""
   420  }