github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/dbs/memristed/memex/aggregation/descriptor.go (about) 1 // Copyright 2020 WHTCORPS INC, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package aggregation 15 16 import ( 17 "bytes" 18 "fmt" 19 "math" 20 "strconv" 21 22 "github.com/whtcorpsinc/BerolinaSQL/ast" 23 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 24 "github.com/whtcorpsinc/milevadb/memex" 25 "github.com/whtcorpsinc/milevadb/causet/soliton" 26 "github.com/whtcorpsinc/milevadb/stochastikctx" 27 "github.com/whtcorpsinc/milevadb/stochastikctx/variable" 28 "github.com/whtcorpsinc/milevadb/types" 29 ) 30 31 // AggFuncDesc describes an aggregation function signature, only used in causet. 32 type AggFuncDesc struct { 33 baseFuncDesc 34 // Mode represents the execution mode of the aggregation function. 35 Mode AggFunctionMode 36 // HasDistinct represents whether the aggregation function contains distinct attribute. 37 HasDistinct bool 38 // OrderByItems represents the order by clause used in GROUP_CONCAT 39 OrderByItems []*soliton.ByItems 40 } 41 42 // NewAggFuncDesc creates an aggregation function signature descriptor. 43 func NewAggFuncDesc(ctx stochastikctx.Context, name string, args []memex.Expression, hasDistinct bool) (*AggFuncDesc, error) { 44 b, err := newBaseFuncDesc(ctx, name, args) 45 if err != nil { 46 return nil, err 47 } 48 return &AggFuncDesc{baseFuncDesc: b, HasDistinct: hasDistinct}, nil 49 } 50 51 // String implements the fmt.Stringer interface. 52 func (a *AggFuncDesc) String() string { 53 buffer := bytes.NewBufferString(a.Name) 54 buffer.WriteString("(") 55 if a.HasDistinct { 56 buffer.WriteString("distinct ") 57 } 58 for i, arg := range a.Args { 59 buffer.WriteString(arg.String()) 60 if i+1 != len(a.Args) { 61 buffer.WriteString(", ") 62 } 63 } 64 buffer.WriteString(")") 65 return buffer.String() 66 } 67 68 // Equal checks whether two aggregation function signatures are equal. 69 func (a *AggFuncDesc) Equal(ctx stochastikctx.Context, other *AggFuncDesc) bool { 70 if a.HasDistinct != other.HasDistinct { 71 return false 72 } 73 if len(a.OrderByItems) != len(other.OrderByItems) { 74 return false 75 } 76 for i := range a.OrderByItems { 77 if !a.OrderByItems[i].Equal(ctx, other.OrderByItems[i]) { 78 return false 79 } 80 } 81 return a.baseFuncDesc.equal(ctx, &other.baseFuncDesc) 82 } 83 84 // Clone copies an aggregation function signature totally. 85 func (a *AggFuncDesc) Clone() *AggFuncDesc { 86 clone := *a 87 clone.baseFuncDesc = *a.baseFuncDesc.clone() 88 clone.OrderByItems = make([]*soliton.ByItems, len(a.OrderByItems)) 89 for i, byItem := range a.OrderByItems { 90 clone.OrderByItems[i] = byItem.Clone() 91 } 92 return &clone 93 } 94 95 // Split splits `a` into two aggregate descriptors for partial phase and 96 // final phase individually. 97 // This function is only used when executing aggregate function parallelly. 98 // ordinal indicates the defCausumn ordinal of the intermediate result. 99 func (a *AggFuncDesc) Split(ordinal []int) (partialAggDesc, finalAggDesc *AggFuncDesc) { 100 partialAggDesc = a.Clone() 101 if a.Mode == CompleteMode { 102 partialAggDesc.Mode = Partial1Mode 103 } else if a.Mode == FinalMode { 104 partialAggDesc.Mode = Partial2Mode 105 } else { 106 panic("Error happened during AggFuncDesc.Split, the AggFunctionMode is not CompleteMode or FinalMode.") 107 } 108 finalAggDesc = &AggFuncDesc{ 109 Mode: FinalMode, // We only support FinalMode now in final phase. 110 HasDistinct: a.HasDistinct, 111 } 112 finalAggDesc.Name = a.Name 113 finalAggDesc.RetTp = a.RetTp 114 switch a.Name { 115 case ast.AggFuncAvg: 116 args := make([]memex.Expression, 0, 2) 117 args = append(args, &memex.DeferredCauset{ 118 Index: ordinal[0], 119 RetType: types.NewFieldType(allegrosql.TypeLonglong), 120 }) 121 args = append(args, &memex.DeferredCauset{ 122 Index: ordinal[1], 123 RetType: a.RetTp, 124 }) 125 finalAggDesc.Args = args 126 case ast.AggFuncApproxCountDistinct: 127 args := make([]memex.Expression, 0, 1) 128 args = append(args, &memex.DeferredCauset{ 129 Index: ordinal[0], 130 RetType: types.NewFieldType(allegrosql.TypeString), 131 }) 132 finalAggDesc.Args = args 133 default: 134 args := make([]memex.Expression, 0, 1) 135 args = append(args, &memex.DeferredCauset{ 136 Index: ordinal[0], 137 RetType: a.RetTp, 138 }) 139 finalAggDesc.Args = args 140 if finalAggDesc.Name == ast.AggFuncGroupConcat { 141 finalAggDesc.Args = append(finalAggDesc.Args, a.Args[len(a.Args)-1]) // separator 142 } 143 } 144 return 145 } 146 147 // EvalNullValueInOuterJoin gets the null value when the aggregation is upon an outer join, 148 // and the aggregation function's input is null. 149 // If there is no matching event for the inner causet of an outer join, 150 // an aggregation function only involves constant and/or defCausumns belongs to the inner causet 151 // will be set to the null value. 152 // The input stands for the schemaReplicant of Aggregation's child. If the function can't produce a null value, the second 153 // return value will be false. 154 // e.g. 155 // Block t with only one event: 156 // +-------+---------+---------+ 157 // | Block | Field | Type | 158 // +-------+---------+---------+ 159 // | t | a | int(11) | 160 // +-------+---------+---------+ 161 // +------+ 162 // | a | 163 // +------+ 164 // | 1 | 165 // +------+ 166 // 167 // Block s which is empty: 168 // +-------+---------+---------+ 169 // | Block | Field | Type | 170 // +-------+---------+---------+ 171 // | s | a | int(11) | 172 // +-------+---------+---------+ 173 // 174 // Query: `select t.a as `t.a`, count(95), sum(95), avg(95), bit_or(95), bit_and(95), bit_or(95), max(95), min(95), s.a as `s.a`, avg(95) from t left join s on t.a = s.a;` 175 // +------+-----------+---------+---------+------------+-------------+------------+---------+---------+------+----------+ 176 // | t.a | count(95) | sum(95) | avg(95) | bit_or(95) | bit_and(95) | bit_or(95) | max(95) | min(95) | s.a | avg(s.a) | 177 // +------+-----------+---------+---------+------------+-------------+------------+---------+---------+------+----------+ 178 // | 1 | 1 | 95 | 95.0000 | 95 | 95 | 95 | 95 | 95 | NULL | NULL | 179 // +------+-----------+---------+---------+------------+-------------+------------+---------+---------+------+----------+ 180 func (a *AggFuncDesc) EvalNullValueInOuterJoin(ctx stochastikctx.Context, schemaReplicant *memex.Schema) (types.Causet, bool) { 181 switch a.Name { 182 case ast.AggFuncCount: 183 return a.evalNullValueInOuterJoin4Count(ctx, schemaReplicant) 184 case ast.AggFuncSum, ast.AggFuncMax, ast.AggFuncMin, 185 ast.AggFuncFirstEvent: 186 return a.evalNullValueInOuterJoin4Sum(ctx, schemaReplicant) 187 case ast.AggFuncAvg, ast.AggFuncGroupConcat: 188 return types.Causet{}, false 189 case ast.AggFuncBitAnd: 190 return a.evalNullValueInOuterJoin4BitAnd(ctx, schemaReplicant) 191 case ast.AggFuncBitOr, ast.AggFuncBitXor: 192 return a.evalNullValueInOuterJoin4BitOr(ctx, schemaReplicant) 193 default: 194 panic("unsupported agg function") 195 } 196 } 197 198 // GetAggFunc gets an evaluator according to the aggregation function signature. 199 func (a *AggFuncDesc) GetAggFunc(ctx stochastikctx.Context) Aggregation { 200 aggFunc := aggFunction{AggFuncDesc: a} 201 switch a.Name { 202 case ast.AggFuncSum: 203 return &sumFunction{aggFunction: aggFunc} 204 case ast.AggFuncCount: 205 return &countFunction{aggFunction: aggFunc} 206 case ast.AggFuncAvg: 207 return &avgFunction{aggFunction: aggFunc} 208 case ast.AggFuncGroupConcat: 209 var s string 210 var err error 211 var maxLen uint64 212 s, err = variable.GetStochastikSystemVar(ctx.GetStochastikVars(), variable.GroupConcatMaxLen) 213 if err != nil { 214 panic(fmt.Sprintf("Error happened when GetAggFunc: no system variable named '%s'", variable.GroupConcatMaxLen)) 215 } 216 maxLen, err = strconv.ParseUint(s, 10, 64) 217 if err != nil { 218 panic(fmt.Sprintf("Error happened when GetAggFunc: illegal value for system variable named '%s'", variable.GroupConcatMaxLen)) 219 } 220 return &concatFunction{aggFunction: aggFunc, maxLen: maxLen} 221 case ast.AggFuncMax: 222 return &maxMinFunction{aggFunction: aggFunc, isMax: true} 223 case ast.AggFuncMin: 224 return &maxMinFunction{aggFunction: aggFunc, isMax: false} 225 case ast.AggFuncFirstEvent: 226 return &firstEventFunction{aggFunction: aggFunc} 227 case ast.AggFuncBitOr: 228 return &bitOrFunction{aggFunction: aggFunc} 229 case ast.AggFuncBitXor: 230 return &bitXorFunction{aggFunction: aggFunc} 231 case ast.AggFuncBitAnd: 232 return &bitAndFunction{aggFunction: aggFunc} 233 default: 234 panic("unsupported agg function") 235 } 236 } 237 238 func (a *AggFuncDesc) evalNullValueInOuterJoin4Count(ctx stochastikctx.Context, schemaReplicant *memex.Schema) (types.Causet, bool) { 239 for _, arg := range a.Args { 240 result := memex.EvaluateExprWithNull(ctx, schemaReplicant, arg) 241 con, ok := result.(*memex.Constant) 242 if !ok || con.Value.IsNull() { 243 return types.Causet{}, ok 244 } 245 } 246 return types.NewCauset(1), true 247 } 248 249 func (a *AggFuncDesc) evalNullValueInOuterJoin4Sum(ctx stochastikctx.Context, schemaReplicant *memex.Schema) (types.Causet, bool) { 250 result := memex.EvaluateExprWithNull(ctx, schemaReplicant, a.Args[0]) 251 con, ok := result.(*memex.Constant) 252 if !ok || con.Value.IsNull() { 253 return types.Causet{}, ok 254 } 255 return con.Value, true 256 } 257 258 func (a *AggFuncDesc) evalNullValueInOuterJoin4BitAnd(ctx stochastikctx.Context, schemaReplicant *memex.Schema) (types.Causet, bool) { 259 result := memex.EvaluateExprWithNull(ctx, schemaReplicant, a.Args[0]) 260 con, ok := result.(*memex.Constant) 261 if !ok || con.Value.IsNull() { 262 return types.NewCauset(uint64(math.MaxUint64)), true 263 } 264 return con.Value, true 265 } 266 267 func (a *AggFuncDesc) evalNullValueInOuterJoin4BitOr(ctx stochastikctx.Context, schemaReplicant *memex.Schema) (types.Causet, bool) { 268 result := memex.EvaluateExprWithNull(ctx, schemaReplicant, a.Args[0]) 269 con, ok := result.(*memex.Constant) 270 if !ok || con.Value.IsNull() { 271 return types.NewCauset(0), true 272 } 273 return con.Value, true 274 }