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 }