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  }