1450 lines
36 KiB
Go
1450 lines
36 KiB
Go
// Copyright 2018 PingCAP, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package aggfuncs
|
|
|
|
import (
|
|
"container/heap"
|
|
"unsafe"
|
|
|
|
"github.com/pingcap/tidb/sessionctx"
|
|
"github.com/pingcap/tidb/types"
|
|
"github.com/pingcap/tidb/types/json"
|
|
"github.com/pingcap/tidb/util/chunk"
|
|
"github.com/pingcap/tidb/util/stringutil"
|
|
)
|
|
|
|
type maxMinHeap struct {
|
|
data []interface{}
|
|
h heap.Interface
|
|
varSet map[interface{}]int64
|
|
isMax bool
|
|
cmpFunc func(i, j interface{}) int
|
|
}
|
|
|
|
func newMaxMinHeap(isMax bool, cmpFunc func(i, j interface{}) int) *maxMinHeap {
|
|
h := &maxMinHeap{
|
|
data: make([]interface{}, 0),
|
|
varSet: make(map[interface{}]int64),
|
|
isMax: isMax,
|
|
cmpFunc: cmpFunc,
|
|
}
|
|
return h
|
|
}
|
|
|
|
func (h *maxMinHeap) Len() int { return len(h.data) }
|
|
func (h *maxMinHeap) Less(i, j int) bool {
|
|
if h.isMax {
|
|
return h.cmpFunc(h.data[i], h.data[j]) > 0
|
|
}
|
|
return h.cmpFunc(h.data[i], h.data[j]) < 0
|
|
}
|
|
func (h *maxMinHeap) Swap(i, j int) { h.data[i], h.data[j] = h.data[j], h.data[i] }
|
|
|
|
func (h *maxMinHeap) Push(x interface{}) {
|
|
h.data = append(h.data, x)
|
|
}
|
|
func (h *maxMinHeap) Pop() interface{} {
|
|
old := h.data
|
|
n := len(old)
|
|
x := old[n-1]
|
|
h.data = old[0 : n-1]
|
|
return x
|
|
}
|
|
|
|
func (h *maxMinHeap) Reset() {
|
|
h.data = h.data[:0]
|
|
h.varSet = make(map[interface{}]int64)
|
|
}
|
|
func (h *maxMinHeap) Append(val interface{}) {
|
|
h.varSet[val]++
|
|
if h.varSet[val] == 1 {
|
|
heap.Push(h, val)
|
|
}
|
|
}
|
|
func (h *maxMinHeap) Remove(val interface{}) {
|
|
if h.varSet[val] > 0 {
|
|
h.varSet[val]--
|
|
} else {
|
|
panic("remove a not exist value")
|
|
}
|
|
}
|
|
func (h *maxMinHeap) Top() (val interface{}, isEmpty bool) {
|
|
retry:
|
|
if h.Len() == 0 {
|
|
return nil, true
|
|
}
|
|
top := h.data[0]
|
|
if h.varSet[top] == 0 {
|
|
_ = heap.Pop(h)
|
|
goto retry
|
|
}
|
|
return top, false
|
|
}
|
|
|
|
func (h *maxMinHeap) AppendMyDecimal(val types.MyDecimal) error {
|
|
key, err := val.ToHashKey()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
h.varSet[string(key)]++
|
|
if h.varSet[string(key)] == 1 {
|
|
heap.Push(h, val)
|
|
}
|
|
return nil
|
|
}
|
|
func (h *maxMinHeap) RemoveMyDecimal(val types.MyDecimal) error {
|
|
key, err := val.ToHashKey()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if h.varSet[string(key)] > 0 {
|
|
h.varSet[string(key)]--
|
|
} else {
|
|
panic("remove a not exist value")
|
|
}
|
|
return nil
|
|
}
|
|
func (h *maxMinHeap) TopDecimal() (val types.MyDecimal, isEmpty bool) {
|
|
retry:
|
|
if h.Len() == 0 {
|
|
return types.MyDecimal{}, true
|
|
}
|
|
top := h.data[0].(types.MyDecimal)
|
|
key, err := top.ToHashKey()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
if h.varSet[string(key)] == 0 {
|
|
_ = heap.Pop(h)
|
|
goto retry
|
|
}
|
|
return top, false
|
|
}
|
|
|
|
const (
|
|
// DefPartialResult4MaxMinIntSize is the size of partialResult4MaxMinInt
|
|
DefPartialResult4MaxMinIntSize = int64(unsafe.Sizeof(partialResult4MaxMinInt{}))
|
|
// DefPartialResult4MaxMinUintSize is the size of partialResult4MaxMinUint
|
|
DefPartialResult4MaxMinUintSize = int64(unsafe.Sizeof(partialResult4MaxMinUint{}))
|
|
// DefPartialResult4MaxMinDecimalSize is the size of partialResult4MaxMinDecimal
|
|
DefPartialResult4MaxMinDecimalSize = int64(unsafe.Sizeof(partialResult4MaxMinDecimal{}))
|
|
// DefPartialResult4MaxMinFloat32Size is the size of partialResult4MaxMinFloat32
|
|
DefPartialResult4MaxMinFloat32Size = int64(unsafe.Sizeof(partialResult4MaxMinFloat32{}))
|
|
// DefPartialResult4MaxMinFloat64Size is the size of partialResult4MaxMinFloat64
|
|
DefPartialResult4MaxMinFloat64Size = int64(unsafe.Sizeof(partialResult4MaxMinFloat64{}))
|
|
// DefPartialResult4TimeSize is the size of partialResult4Time
|
|
DefPartialResult4TimeSize = int64(unsafe.Sizeof(partialResult4Time{}))
|
|
// DefPartialResult4MaxMinDurationSize is the size of partialResult4MaxMinDuration
|
|
DefPartialResult4MaxMinDurationSize = int64(unsafe.Sizeof(partialResult4MaxMinDuration{}))
|
|
// DefPartialResult4MaxMinStringSize is the size of partialResult4MaxMinString
|
|
DefPartialResult4MaxMinStringSize = int64(unsafe.Sizeof(partialResult4MaxMinString{}))
|
|
// DefPartialResult4MaxMinJSONSize is the size of partialResult4MaxMinJSON
|
|
DefPartialResult4MaxMinJSONSize = int64(unsafe.Sizeof(partialResult4MaxMinJSON{}))
|
|
// DefPartialResult4MaxMinEnumSize is the size of partialResult4MaxMinEnum
|
|
DefPartialResult4MaxMinEnumSize = int64(unsafe.Sizeof(partialResult4MaxMinEnum{}))
|
|
// DefPartialResult4MaxMinSetSize is the size of partialResult4MaxMinSet
|
|
DefPartialResult4MaxMinSetSize = int64(unsafe.Sizeof(partialResult4MaxMinSet{}))
|
|
)
|
|
|
|
type partialResult4MaxMinInt struct {
|
|
val int64
|
|
// isNull is used to indicates:
|
|
// 1. whether the partial result is the initialization value which should not be compared during evaluation;
|
|
// 2. whether all the values of arg are all null, if so, we should return null as the default value for MAX/MIN.
|
|
isNull bool
|
|
// maxMinHeap is an ordered queue, using to evaluate the maximum or minimum value in a sliding window.
|
|
heap *maxMinHeap
|
|
}
|
|
|
|
type partialResult4MaxMinUint struct {
|
|
val uint64
|
|
isNull bool
|
|
heap *maxMinHeap
|
|
}
|
|
|
|
type partialResult4MaxMinDecimal struct {
|
|
val types.MyDecimal
|
|
isNull bool
|
|
heap *maxMinHeap
|
|
}
|
|
|
|
type partialResult4MaxMinFloat32 struct {
|
|
val float32
|
|
isNull bool
|
|
heap *maxMinHeap
|
|
}
|
|
|
|
type partialResult4MaxMinFloat64 struct {
|
|
val float64
|
|
isNull bool
|
|
heap *maxMinHeap
|
|
}
|
|
|
|
type partialResult4Time struct {
|
|
val types.Time
|
|
isNull bool
|
|
heap *maxMinHeap
|
|
}
|
|
|
|
type partialResult4MaxMinDuration struct {
|
|
val types.Duration
|
|
isNull bool
|
|
heap *maxMinHeap
|
|
}
|
|
|
|
type partialResult4MaxMinString struct {
|
|
val string
|
|
isNull bool
|
|
heap *maxMinHeap
|
|
}
|
|
|
|
type partialResult4MaxMinJSON struct {
|
|
val json.BinaryJSON
|
|
isNull bool
|
|
}
|
|
|
|
type partialResult4MaxMinEnum struct {
|
|
val types.Enum
|
|
isNull bool
|
|
}
|
|
|
|
type partialResult4MaxMinSet struct {
|
|
val types.Set
|
|
isNull bool
|
|
}
|
|
|
|
type baseMaxMinAggFunc struct {
|
|
baseAggFunc
|
|
|
|
isMax bool
|
|
}
|
|
|
|
type maxMin4Int struct {
|
|
baseMaxMinAggFunc
|
|
}
|
|
|
|
func (e *maxMin4Int) AllocPartialResult() (pr PartialResult, memDelta int64) {
|
|
p := new(partialResult4MaxMinInt)
|
|
p.isNull = true
|
|
p.heap = newMaxMinHeap(e.isMax, func(i, j interface{}) int {
|
|
return types.CompareInt64(i.(int64), j.(int64))
|
|
})
|
|
return PartialResult(p), DefPartialResult4MaxMinIntSize
|
|
}
|
|
|
|
func (e *maxMin4Int) ResetPartialResult(pr PartialResult) {
|
|
p := (*partialResult4MaxMinInt)(pr)
|
|
p.val = 0
|
|
p.isNull = true
|
|
p.heap.Reset()
|
|
}
|
|
|
|
func (e *maxMin4Int) AppendFinalResult2Chunk(sctx sessionctx.Context, pr PartialResult, chk *chunk.Chunk) error {
|
|
p := (*partialResult4MaxMinInt)(pr)
|
|
if p.isNull {
|
|
chk.AppendNull(e.ordinal)
|
|
return nil
|
|
}
|
|
chk.AppendInt64(e.ordinal, p.val)
|
|
return nil
|
|
}
|
|
|
|
func (e *maxMin4Int) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4MaxMinInt)(pr)
|
|
for _, row := range rowsInGroup {
|
|
input, isNull, err := e.args[0].EvalInt(sctx, row)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
if p.isNull {
|
|
p.val = input
|
|
p.isNull = false
|
|
continue
|
|
}
|
|
if e.isMax && input > p.val || !e.isMax && input < p.val {
|
|
p.val = input
|
|
}
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
func (e *maxMin4Int) MergePartialResult(sctx sessionctx.Context, src, dst PartialResult) (memDelta int64, err error) {
|
|
p1, p2 := (*partialResult4MaxMinInt)(src), (*partialResult4MaxMinInt)(dst)
|
|
if p1.isNull {
|
|
return 0, nil
|
|
}
|
|
if p2.isNull {
|
|
*p2 = *p1
|
|
return 0, nil
|
|
}
|
|
if e.isMax && p1.val > p2.val || !e.isMax && p1.val < p2.val {
|
|
p2.val, p2.isNull = p1.val, false
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
type maxMin4IntSliding struct {
|
|
maxMin4Int
|
|
}
|
|
|
|
func (e *maxMin4IntSliding) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4MaxMinInt)(pr)
|
|
for _, row := range rowsInGroup {
|
|
input, isNull, err := e.args[0].EvalInt(sctx, row)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Append(input)
|
|
}
|
|
if val, isEmpty := p.heap.Top(); !isEmpty {
|
|
p.val = val.(int64)
|
|
p.isNull = false
|
|
} else {
|
|
p.isNull = true
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
func (e *maxMin4IntSliding) Slide(sctx sessionctx.Context, rows []chunk.Row, lastStart, lastEnd uint64, shiftStart, shiftEnd uint64, pr PartialResult) error {
|
|
p := (*partialResult4MaxMinInt)(pr)
|
|
for i := uint64(0); i < shiftEnd; i++ {
|
|
input, isNull, err := e.args[0].EvalInt(sctx, rows[lastEnd+i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Append(input)
|
|
}
|
|
for i := uint64(0); i < shiftStart; i++ {
|
|
input, isNull, err := e.args[0].EvalInt(sctx, rows[lastStart+i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Remove(input)
|
|
}
|
|
if val, isEmpty := p.heap.Top(); !isEmpty {
|
|
p.val = val.(int64)
|
|
p.isNull = false
|
|
} else {
|
|
p.isNull = true
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type maxMin4Uint struct {
|
|
baseMaxMinAggFunc
|
|
}
|
|
|
|
func (e *maxMin4Uint) AllocPartialResult() (pr PartialResult, memDelta int64) {
|
|
p := new(partialResult4MaxMinUint)
|
|
p.isNull = true
|
|
p.heap = newMaxMinHeap(e.isMax, func(i, j interface{}) int {
|
|
return types.CompareUint64(i.(uint64), j.(uint64))
|
|
})
|
|
return PartialResult(p), DefPartialResult4MaxMinUintSize
|
|
}
|
|
|
|
func (e *maxMin4Uint) ResetPartialResult(pr PartialResult) {
|
|
p := (*partialResult4MaxMinUint)(pr)
|
|
p.val = 0
|
|
p.isNull = true
|
|
p.heap.Reset()
|
|
}
|
|
|
|
func (e *maxMin4Uint) AppendFinalResult2Chunk(sctx sessionctx.Context, pr PartialResult, chk *chunk.Chunk) error {
|
|
p := (*partialResult4MaxMinUint)(pr)
|
|
if p.isNull {
|
|
chk.AppendNull(e.ordinal)
|
|
return nil
|
|
}
|
|
chk.AppendUint64(e.ordinal, p.val)
|
|
return nil
|
|
}
|
|
|
|
func (e *maxMin4Uint) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4MaxMinUint)(pr)
|
|
for _, row := range rowsInGroup {
|
|
input, isNull, err := e.args[0].EvalInt(sctx, row)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
uintVal := uint64(input)
|
|
if p.isNull {
|
|
p.val = uintVal
|
|
p.isNull = false
|
|
continue
|
|
}
|
|
if e.isMax && uintVal > p.val || !e.isMax && uintVal < p.val {
|
|
p.val = uintVal
|
|
}
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
func (e *maxMin4Uint) MergePartialResult(sctx sessionctx.Context, src, dst PartialResult) (memDelta int64, err error) {
|
|
p1, p2 := (*partialResult4MaxMinUint)(src), (*partialResult4MaxMinUint)(dst)
|
|
if p1.isNull {
|
|
return 0, nil
|
|
}
|
|
if p2.isNull {
|
|
*p2 = *p1
|
|
return 0, nil
|
|
}
|
|
if e.isMax && p1.val > p2.val || !e.isMax && p1.val < p2.val {
|
|
p2.val, p2.isNull = p1.val, false
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
type maxMin4UintSliding struct {
|
|
maxMin4Uint
|
|
}
|
|
|
|
func (e *maxMin4UintSliding) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4MaxMinUint)(pr)
|
|
for _, row := range rowsInGroup {
|
|
input, isNull, err := e.args[0].EvalInt(sctx, row)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Append(uint64(input))
|
|
}
|
|
if val, isEmpty := p.heap.Top(); !isEmpty {
|
|
p.val = val.(uint64)
|
|
p.isNull = false
|
|
} else {
|
|
p.isNull = true
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
func (e *maxMin4UintSliding) Slide(sctx sessionctx.Context, rows []chunk.Row, lastStart, lastEnd uint64, shiftStart, shiftEnd uint64, pr PartialResult) error {
|
|
p := (*partialResult4MaxMinUint)(pr)
|
|
for i := uint64(0); i < shiftEnd; i++ {
|
|
input, isNull, err := e.args[0].EvalInt(sctx, rows[lastEnd+i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Append(uint64(input))
|
|
}
|
|
for i := uint64(0); i < shiftStart; i++ {
|
|
input, isNull, err := e.args[0].EvalInt(sctx, rows[lastStart+i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Remove(uint64(input))
|
|
}
|
|
if val, isEmpty := p.heap.Top(); !isEmpty {
|
|
p.val = val.(uint64)
|
|
p.isNull = false
|
|
} else {
|
|
p.isNull = true
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// maxMin4Float32 gets a float32 input and returns a float32 result.
|
|
type maxMin4Float32 struct {
|
|
baseMaxMinAggFunc
|
|
}
|
|
|
|
func (e *maxMin4Float32) AllocPartialResult() (pr PartialResult, memDelta int64) {
|
|
p := new(partialResult4MaxMinFloat32)
|
|
p.isNull = true
|
|
p.heap = newMaxMinHeap(e.isMax, func(i, j interface{}) int {
|
|
return types.CompareFloat64(float64(i.(float32)), float64(j.(float32)))
|
|
})
|
|
return PartialResult(p), DefPartialResult4MaxMinFloat32Size
|
|
}
|
|
|
|
func (e *maxMin4Float32) ResetPartialResult(pr PartialResult) {
|
|
p := (*partialResult4MaxMinFloat32)(pr)
|
|
p.val = 0
|
|
p.isNull = true
|
|
p.heap.Reset()
|
|
}
|
|
|
|
func (e *maxMin4Float32) AppendFinalResult2Chunk(sctx sessionctx.Context, pr PartialResult, chk *chunk.Chunk) error {
|
|
p := (*partialResult4MaxMinFloat32)(pr)
|
|
if p.isNull {
|
|
chk.AppendNull(e.ordinal)
|
|
return nil
|
|
}
|
|
chk.AppendFloat32(e.ordinal, p.val)
|
|
return nil
|
|
}
|
|
|
|
func (e *maxMin4Float32) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4MaxMinFloat32)(pr)
|
|
for _, row := range rowsInGroup {
|
|
input, isNull, err := e.args[0].EvalReal(sctx, row)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
f := float32(input)
|
|
if p.isNull {
|
|
p.val = f
|
|
p.isNull = false
|
|
continue
|
|
}
|
|
if e.isMax && f > p.val || !e.isMax && f < p.val {
|
|
p.val = f
|
|
}
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
func (e *maxMin4Float32) MergePartialResult(sctx sessionctx.Context, src, dst PartialResult) (memDelta int64, err error) {
|
|
p1, p2 := (*partialResult4MaxMinFloat32)(src), (*partialResult4MaxMinFloat32)(dst)
|
|
if p1.isNull {
|
|
return 0, nil
|
|
}
|
|
if p2.isNull {
|
|
*p2 = *p1
|
|
return 0, nil
|
|
}
|
|
if e.isMax && p1.val > p2.val || !e.isMax && p1.val < p2.val {
|
|
p2.val, p2.isNull = p1.val, false
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
type maxMin4Float32Sliding struct {
|
|
maxMin4Float32
|
|
}
|
|
|
|
func (e *maxMin4Float32Sliding) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4MaxMinFloat32)(pr)
|
|
for _, row := range rowsInGroup {
|
|
input, isNull, err := e.args[0].EvalReal(sctx, row)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Append(float32(input))
|
|
}
|
|
if val, isEmpty := p.heap.Top(); !isEmpty {
|
|
p.val = val.(float32)
|
|
p.isNull = false
|
|
} else {
|
|
p.isNull = true
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
func (e *maxMin4Float32Sliding) Slide(sctx sessionctx.Context, rows []chunk.Row, lastStart, lastEnd uint64, shiftStart, shiftEnd uint64, pr PartialResult) error {
|
|
p := (*partialResult4MaxMinFloat32)(pr)
|
|
for i := uint64(0); i < shiftEnd; i++ {
|
|
input, isNull, err := e.args[0].EvalReal(sctx, rows[lastEnd+i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Append(float32(input))
|
|
}
|
|
for i := uint64(0); i < shiftStart; i++ {
|
|
input, isNull, err := e.args[0].EvalReal(sctx, rows[lastStart+i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Remove(float32(input))
|
|
}
|
|
if val, isEmpty := p.heap.Top(); !isEmpty {
|
|
p.val = val.(float32)
|
|
p.isNull = false
|
|
} else {
|
|
p.isNull = true
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type maxMin4Float64 struct {
|
|
baseMaxMinAggFunc
|
|
}
|
|
|
|
func (e *maxMin4Float64) AllocPartialResult() (pr PartialResult, memDelta int64) {
|
|
p := new(partialResult4MaxMinFloat64)
|
|
p.isNull = true
|
|
p.heap = newMaxMinHeap(e.isMax, func(i, j interface{}) int {
|
|
return types.CompareFloat64(i.(float64), j.(float64))
|
|
})
|
|
return PartialResult(p), DefPartialResult4MaxMinFloat64Size
|
|
}
|
|
|
|
func (e *maxMin4Float64) ResetPartialResult(pr PartialResult) {
|
|
p := (*partialResult4MaxMinFloat64)(pr)
|
|
p.val = 0
|
|
p.isNull = true
|
|
p.heap.Reset()
|
|
}
|
|
|
|
func (e *maxMin4Float64) AppendFinalResult2Chunk(sctx sessionctx.Context, pr PartialResult, chk *chunk.Chunk) error {
|
|
p := (*partialResult4MaxMinFloat64)(pr)
|
|
if p.isNull {
|
|
chk.AppendNull(e.ordinal)
|
|
return nil
|
|
}
|
|
chk.AppendFloat64(e.ordinal, p.val)
|
|
return nil
|
|
}
|
|
|
|
func (e *maxMin4Float64) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4MaxMinFloat64)(pr)
|
|
for _, row := range rowsInGroup {
|
|
input, isNull, err := e.args[0].EvalReal(sctx, row)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
if p.isNull {
|
|
p.val = input
|
|
p.isNull = false
|
|
continue
|
|
}
|
|
if e.isMax && input > p.val || !e.isMax && input < p.val {
|
|
p.val = input
|
|
}
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
func (e *maxMin4Float64) MergePartialResult(sctx sessionctx.Context, src, dst PartialResult) (memDelta int64, err error) {
|
|
p1, p2 := (*partialResult4MaxMinFloat64)(src), (*partialResult4MaxMinFloat64)(dst)
|
|
if p1.isNull {
|
|
return 0, nil
|
|
}
|
|
if p2.isNull {
|
|
*p2 = *p1
|
|
return 0, nil
|
|
}
|
|
if e.isMax && p1.val > p2.val || !e.isMax && p1.val < p2.val {
|
|
p2.val, p2.isNull = p1.val, false
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
type maxMin4Float64Sliding struct {
|
|
maxMin4Float64
|
|
}
|
|
|
|
func (e *maxMin4Float64Sliding) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4MaxMinFloat64)(pr)
|
|
for _, row := range rowsInGroup {
|
|
input, isNull, err := e.args[0].EvalReal(sctx, row)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Append(input)
|
|
}
|
|
if val, isEmpty := p.heap.Top(); !isEmpty {
|
|
p.val = val.(float64)
|
|
p.isNull = false
|
|
} else {
|
|
p.isNull = true
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
func (e *maxMin4Float64Sliding) Slide(sctx sessionctx.Context, rows []chunk.Row, lastStart, lastEnd uint64, shiftStart, shiftEnd uint64, pr PartialResult) error {
|
|
p := (*partialResult4MaxMinFloat64)(pr)
|
|
for i := uint64(0); i < shiftEnd; i++ {
|
|
input, isNull, err := e.args[0].EvalReal(sctx, rows[lastEnd+i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Append(input)
|
|
}
|
|
for i := uint64(0); i < shiftStart; i++ {
|
|
input, isNull, err := e.args[0].EvalReal(sctx, rows[lastStart+i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Remove(input)
|
|
}
|
|
if val, isEmpty := p.heap.Top(); !isEmpty {
|
|
p.val = val.(float64)
|
|
p.isNull = false
|
|
} else {
|
|
p.isNull = true
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type maxMin4Decimal struct {
|
|
baseMaxMinAggFunc
|
|
}
|
|
|
|
func (e *maxMin4Decimal) AllocPartialResult() (pr PartialResult, memDelta int64) {
|
|
p := new(partialResult4MaxMinDecimal)
|
|
p.isNull = true
|
|
p.heap = newMaxMinHeap(e.isMax, func(i, j interface{}) int {
|
|
src := i.(types.MyDecimal)
|
|
dst := j.(types.MyDecimal)
|
|
return src.Compare(&dst)
|
|
})
|
|
return PartialResult(p), DefPartialResult4MaxMinDecimalSize
|
|
}
|
|
|
|
func (e *maxMin4Decimal) ResetPartialResult(pr PartialResult) {
|
|
p := (*partialResult4MaxMinDecimal)(pr)
|
|
p.isNull = true
|
|
p.heap.Reset()
|
|
}
|
|
|
|
func (e *maxMin4Decimal) AppendFinalResult2Chunk(sctx sessionctx.Context, pr PartialResult, chk *chunk.Chunk) error {
|
|
p := (*partialResult4MaxMinDecimal)(pr)
|
|
if p.isNull {
|
|
chk.AppendNull(e.ordinal)
|
|
return nil
|
|
}
|
|
chk.AppendMyDecimal(e.ordinal, &p.val)
|
|
return nil
|
|
}
|
|
|
|
func (e *maxMin4Decimal) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4MaxMinDecimal)(pr)
|
|
for _, row := range rowsInGroup {
|
|
input, isNull, err := e.args[0].EvalDecimal(sctx, row)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
if p.isNull {
|
|
p.val = *input
|
|
p.isNull = false
|
|
continue
|
|
}
|
|
cmp := input.Compare(&p.val)
|
|
if e.isMax && cmp > 0 || !e.isMax && cmp < 0 {
|
|
p.val = *input
|
|
}
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
func (e *maxMin4Decimal) MergePartialResult(sctx sessionctx.Context, src, dst PartialResult) (memDelta int64, err error) {
|
|
p1, p2 := (*partialResult4MaxMinDecimal)(src), (*partialResult4MaxMinDecimal)(dst)
|
|
if p1.isNull {
|
|
return 0, nil
|
|
}
|
|
if p2.isNull {
|
|
*p2 = *p1
|
|
return 0, nil
|
|
}
|
|
cmp := (&p1.val).Compare(&p2.val)
|
|
if e.isMax && cmp > 0 || !e.isMax && cmp < 0 {
|
|
p2.val, p2.isNull = p1.val, false
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
type maxMin4DecimalSliding struct {
|
|
maxMin4Decimal
|
|
}
|
|
|
|
func (e *maxMin4DecimalSliding) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4MaxMinDecimal)(pr)
|
|
for _, row := range rowsInGroup {
|
|
input, isNull, err := e.args[0].EvalDecimal(sctx, row)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
if err := p.heap.AppendMyDecimal(*input); err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
if val, isEmpty := p.heap.TopDecimal(); !isEmpty {
|
|
p.val = val
|
|
p.isNull = false
|
|
} else {
|
|
p.isNull = true
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
func (e *maxMin4DecimalSliding) Slide(sctx sessionctx.Context, rows []chunk.Row, lastStart, lastEnd uint64, shiftStart, shiftEnd uint64, pr PartialResult) error {
|
|
p := (*partialResult4MaxMinDecimal)(pr)
|
|
for i := uint64(0); i < shiftEnd; i++ {
|
|
input, isNull, err := e.args[0].EvalDecimal(sctx, rows[lastEnd+i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
if err := p.heap.AppendMyDecimal(*input); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
for i := uint64(0); i < shiftStart; i++ {
|
|
input, isNull, err := e.args[0].EvalDecimal(sctx, rows[lastStart+i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
if err := p.heap.RemoveMyDecimal(*input); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if val, isEmpty := p.heap.TopDecimal(); !isEmpty {
|
|
p.val = val
|
|
p.isNull = false
|
|
} else {
|
|
p.isNull = true
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type maxMin4String struct {
|
|
baseMaxMinAggFunc
|
|
retTp *types.FieldType
|
|
}
|
|
|
|
func (e *maxMin4String) AllocPartialResult() (pr PartialResult, memDelta int64) {
|
|
p := new(partialResult4MaxMinString)
|
|
p.isNull = true
|
|
tp := e.args[0].GetType()
|
|
p.heap = newMaxMinHeap(e.isMax, func(i, j interface{}) int {
|
|
return types.CompareString(i.(string), j.(string), tp.Collate)
|
|
})
|
|
return PartialResult(p), DefPartialResult4MaxMinStringSize
|
|
}
|
|
|
|
func (e *maxMin4String) ResetPartialResult(pr PartialResult) {
|
|
p := (*partialResult4MaxMinString)(pr)
|
|
p.isNull = true
|
|
p.heap.Reset()
|
|
}
|
|
|
|
func (e *maxMin4String) AppendFinalResult2Chunk(sctx sessionctx.Context, pr PartialResult, chk *chunk.Chunk) error {
|
|
p := (*partialResult4MaxMinString)(pr)
|
|
if p.isNull {
|
|
chk.AppendNull(e.ordinal)
|
|
return nil
|
|
}
|
|
chk.AppendString(e.ordinal, p.val)
|
|
return nil
|
|
}
|
|
|
|
func (e *maxMin4String) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4MaxMinString)(pr)
|
|
tp := e.args[0].GetType()
|
|
for _, row := range rowsInGroup {
|
|
input, isNull, err := e.args[0].EvalString(sctx, row)
|
|
if err != nil {
|
|
return memDelta, err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
if p.isNull {
|
|
// The string returned by `EvalString` may be referenced to an underlying buffer,
|
|
// for example ‘Chunk’, which could be reset and reused multiply times.
|
|
// We have to deep copy that string to avoid some potential risks
|
|
// when the content of that underlying buffer changed.
|
|
p.val = stringutil.Copy(input)
|
|
memDelta += int64(len(input))
|
|
p.isNull = false
|
|
continue
|
|
}
|
|
cmp := types.CompareString(input, p.val, tp.Collate)
|
|
if e.isMax && cmp == 1 || !e.isMax && cmp == -1 {
|
|
oldMem := len(p.val)
|
|
newMem := len(input)
|
|
memDelta += int64(newMem - oldMem)
|
|
p.val = stringutil.Copy(input)
|
|
}
|
|
}
|
|
return memDelta, nil
|
|
}
|
|
|
|
func (e *maxMin4String) MergePartialResult(sctx sessionctx.Context, src, dst PartialResult) (memDelta int64, err error) {
|
|
p1, p2 := (*partialResult4MaxMinString)(src), (*partialResult4MaxMinString)(dst)
|
|
if p1.isNull {
|
|
return 0, nil
|
|
}
|
|
if p2.isNull {
|
|
*p2 = *p1
|
|
return 0, nil
|
|
}
|
|
tp := e.args[0].GetType()
|
|
cmp := types.CompareString(p1.val, p2.val, tp.Collate)
|
|
if e.isMax && cmp > 0 || !e.isMax && cmp < 0 {
|
|
p2.val, p2.isNull = p1.val, false
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
type maxMin4StringSliding struct {
|
|
maxMin4String
|
|
}
|
|
|
|
func (e *maxMin4StringSliding) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4MaxMinString)(pr)
|
|
for _, row := range rowsInGroup {
|
|
input, isNull, err := e.args[0].EvalString(sctx, row)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Append(input)
|
|
}
|
|
if val, isEmpty := p.heap.Top(); !isEmpty {
|
|
p.val = val.(string)
|
|
p.isNull = false
|
|
} else {
|
|
p.isNull = true
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
func (e *maxMin4StringSliding) Slide(sctx sessionctx.Context, rows []chunk.Row, lastStart, lastEnd uint64, shiftStart, shiftEnd uint64, pr PartialResult) error {
|
|
p := (*partialResult4MaxMinString)(pr)
|
|
for i := uint64(0); i < shiftEnd; i++ {
|
|
input, isNull, err := e.args[0].EvalString(sctx, rows[lastEnd+i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Append(input)
|
|
}
|
|
for i := uint64(0); i < shiftStart; i++ {
|
|
input, isNull, err := e.args[0].EvalString(sctx, rows[lastStart+i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Remove(input)
|
|
}
|
|
if val, isEmpty := p.heap.Top(); !isEmpty {
|
|
p.val = val.(string)
|
|
p.isNull = false
|
|
} else {
|
|
p.isNull = true
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type maxMin4Time struct {
|
|
baseMaxMinAggFunc
|
|
}
|
|
|
|
func (e *maxMin4Time) AllocPartialResult() (pr PartialResult, memDelta int64) {
|
|
p := new(partialResult4Time)
|
|
p.isNull = true
|
|
p.heap = newMaxMinHeap(e.isMax, func(i, j interface{}) int {
|
|
src := i.(types.Time)
|
|
dst := j.(types.Time)
|
|
return src.Compare(dst)
|
|
})
|
|
return PartialResult(p), DefPartialResult4TimeSize
|
|
}
|
|
|
|
func (e *maxMin4Time) ResetPartialResult(pr PartialResult) {
|
|
p := (*partialResult4Time)(pr)
|
|
p.isNull = true
|
|
p.heap.Reset()
|
|
}
|
|
|
|
func (e *maxMin4Time) AppendFinalResult2Chunk(sctx sessionctx.Context, pr PartialResult, chk *chunk.Chunk) error {
|
|
p := (*partialResult4Time)(pr)
|
|
if p.isNull {
|
|
chk.AppendNull(e.ordinal)
|
|
return nil
|
|
}
|
|
chk.AppendTime(e.ordinal, p.val)
|
|
return nil
|
|
}
|
|
|
|
func (e *maxMin4Time) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4Time)(pr)
|
|
for _, row := range rowsInGroup {
|
|
input, isNull, err := e.args[0].EvalTime(sctx, row)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
if p.isNull {
|
|
p.val = input
|
|
p.isNull = false
|
|
continue
|
|
}
|
|
cmp := input.Compare(p.val)
|
|
if e.isMax && cmp == 1 || !e.isMax && cmp == -1 {
|
|
p.val = input
|
|
}
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
func (e *maxMin4Time) MergePartialResult(sctx sessionctx.Context, src, dst PartialResult) (memDelta int64, err error) {
|
|
p1, p2 := (*partialResult4Time)(src), (*partialResult4Time)(dst)
|
|
if p1.isNull {
|
|
return 0, nil
|
|
}
|
|
if p2.isNull {
|
|
*p2 = *p1
|
|
return 0, nil
|
|
}
|
|
cmp := p1.val.Compare(p2.val)
|
|
if e.isMax && cmp == 1 || !e.isMax && cmp == -1 {
|
|
p2.val, p2.isNull = p1.val, false
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
type maxMin4TimeSliding struct {
|
|
maxMin4Time
|
|
}
|
|
|
|
func (e *maxMin4TimeSliding) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4Time)(pr)
|
|
for _, row := range rowsInGroup {
|
|
input, isNull, err := e.args[0].EvalTime(sctx, row)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Append(input)
|
|
}
|
|
if val, isEmpty := p.heap.Top(); !isEmpty {
|
|
p.val = val.(types.Time)
|
|
p.isNull = false
|
|
} else {
|
|
p.isNull = true
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
func (e *maxMin4TimeSliding) Slide(sctx sessionctx.Context, rows []chunk.Row, lastStart, lastEnd uint64, shiftStart, shiftEnd uint64, pr PartialResult) error {
|
|
p := (*partialResult4Time)(pr)
|
|
for i := uint64(0); i < shiftEnd; i++ {
|
|
input, isNull, err := e.args[0].EvalTime(sctx, rows[lastEnd+i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Append(input)
|
|
}
|
|
for i := uint64(0); i < shiftStart; i++ {
|
|
input, isNull, err := e.args[0].EvalTime(sctx, rows[lastStart+i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Remove(input)
|
|
}
|
|
if val, isEmpty := p.heap.Top(); !isEmpty {
|
|
p.val = val.(types.Time)
|
|
p.isNull = false
|
|
} else {
|
|
p.isNull = true
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type maxMin4Duration struct {
|
|
baseMaxMinAggFunc
|
|
}
|
|
|
|
func (e *maxMin4Duration) AllocPartialResult() (pr PartialResult, memDelta int64) {
|
|
p := new(partialResult4MaxMinDuration)
|
|
p.isNull = true
|
|
p.heap = newMaxMinHeap(e.isMax, func(i, j interface{}) int {
|
|
src := i.(types.Duration)
|
|
dst := j.(types.Duration)
|
|
return src.Compare(dst)
|
|
})
|
|
return PartialResult(p), DefPartialResult4MaxMinDurationSize
|
|
}
|
|
|
|
func (e *maxMin4Duration) ResetPartialResult(pr PartialResult) {
|
|
p := (*partialResult4MaxMinDuration)(pr)
|
|
p.isNull = true
|
|
p.heap.Reset()
|
|
}
|
|
|
|
func (e *maxMin4Duration) AppendFinalResult2Chunk(sctx sessionctx.Context, pr PartialResult, chk *chunk.Chunk) error {
|
|
p := (*partialResult4MaxMinDuration)(pr)
|
|
if p.isNull {
|
|
chk.AppendNull(e.ordinal)
|
|
return nil
|
|
}
|
|
chk.AppendDuration(e.ordinal, p.val)
|
|
return nil
|
|
}
|
|
|
|
func (e *maxMin4Duration) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4MaxMinDuration)(pr)
|
|
for _, row := range rowsInGroup {
|
|
input, isNull, err := e.args[0].EvalDuration(sctx, row)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
if p.isNull {
|
|
p.val = input
|
|
p.isNull = false
|
|
continue
|
|
}
|
|
cmp := input.Compare(p.val)
|
|
if e.isMax && cmp == 1 || !e.isMax && cmp == -1 {
|
|
p.val = input
|
|
}
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
func (e *maxMin4Duration) MergePartialResult(sctx sessionctx.Context, src, dst PartialResult) (memDelta int64, err error) {
|
|
p1, p2 := (*partialResult4MaxMinDuration)(src), (*partialResult4MaxMinDuration)(dst)
|
|
if p1.isNull {
|
|
return 0, nil
|
|
}
|
|
if p2.isNull {
|
|
*p2 = *p1
|
|
return 0, nil
|
|
}
|
|
cmp := p1.val.Compare(p2.val)
|
|
if e.isMax && cmp == 1 || !e.isMax && cmp == -1 {
|
|
p2.val, p2.isNull = p1.val, false
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
type maxMin4DurationSliding struct {
|
|
maxMin4Duration
|
|
}
|
|
|
|
func (e *maxMin4DurationSliding) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4MaxMinDuration)(pr)
|
|
for _, row := range rowsInGroup {
|
|
input, isNull, err := e.args[0].EvalDuration(sctx, row)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Append(input)
|
|
}
|
|
if val, isEmpty := p.heap.Top(); !isEmpty {
|
|
p.val = val.(types.Duration)
|
|
p.isNull = false
|
|
} else {
|
|
p.isNull = true
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
func (e *maxMin4DurationSliding) Slide(sctx sessionctx.Context, rows []chunk.Row, lastStart, lastEnd uint64, shiftStart, shiftEnd uint64, pr PartialResult) error {
|
|
p := (*partialResult4MaxMinDuration)(pr)
|
|
for i := uint64(0); i < shiftEnd; i++ {
|
|
input, isNull, err := e.args[0].EvalDuration(sctx, rows[lastEnd+i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Append(input)
|
|
}
|
|
for i := uint64(0); i < shiftStart; i++ {
|
|
input, isNull, err := e.args[0].EvalDuration(sctx, rows[lastStart+i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
p.heap.Remove(input)
|
|
}
|
|
if val, isEmpty := p.heap.Top(); !isEmpty {
|
|
p.val = val.(types.Duration)
|
|
p.isNull = false
|
|
} else {
|
|
p.isNull = true
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type maxMin4JSON struct {
|
|
baseMaxMinAggFunc
|
|
}
|
|
|
|
func (e *maxMin4JSON) AllocPartialResult() (pr PartialResult, memDelta int64) {
|
|
p := new(partialResult4MaxMinJSON)
|
|
p.isNull = true
|
|
return PartialResult(p), DefPartialResult4MaxMinJSONSize
|
|
}
|
|
|
|
func (e *maxMin4JSON) ResetPartialResult(pr PartialResult) {
|
|
p := (*partialResult4MaxMinJSON)(pr)
|
|
p.isNull = true
|
|
}
|
|
|
|
func (e *maxMin4JSON) AppendFinalResult2Chunk(sctx sessionctx.Context, pr PartialResult, chk *chunk.Chunk) error {
|
|
p := (*partialResult4MaxMinJSON)(pr)
|
|
if p.isNull {
|
|
chk.AppendNull(e.ordinal)
|
|
return nil
|
|
}
|
|
chk.AppendJSON(e.ordinal, p.val)
|
|
return nil
|
|
}
|
|
|
|
func (e *maxMin4JSON) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4MaxMinJSON)(pr)
|
|
for _, row := range rowsInGroup {
|
|
input, isNull, err := e.args[0].EvalJSON(sctx, row)
|
|
if err != nil {
|
|
return memDelta, err
|
|
}
|
|
if isNull {
|
|
continue
|
|
}
|
|
if p.isNull {
|
|
p.val = input.Copy()
|
|
memDelta += int64(len(input.Value))
|
|
p.isNull = false
|
|
continue
|
|
}
|
|
cmp := json.CompareBinary(input, p.val)
|
|
if e.isMax && cmp > 0 || !e.isMax && cmp < 0 {
|
|
oldMem := len(p.val.Value)
|
|
newMem := len(input.Value)
|
|
memDelta += int64(newMem - oldMem)
|
|
p.val = input.Copy()
|
|
}
|
|
}
|
|
return memDelta, nil
|
|
}
|
|
|
|
func (e *maxMin4JSON) MergePartialResult(sctx sessionctx.Context, src, dst PartialResult) (memDelta int64, err error) {
|
|
p1, p2 := (*partialResult4MaxMinJSON)(src), (*partialResult4MaxMinJSON)(dst)
|
|
if p1.isNull {
|
|
return 0, nil
|
|
}
|
|
if p2.isNull {
|
|
*p2 = *p1
|
|
return 0, nil
|
|
}
|
|
cmp := json.CompareBinary(p1.val, p2.val)
|
|
if e.isMax && cmp > 0 || !e.isMax && cmp < 0 {
|
|
p2.val = p1.val
|
|
p2.isNull = false
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
type maxMin4Enum struct {
|
|
baseMaxMinAggFunc
|
|
}
|
|
|
|
func (e *maxMin4Enum) AllocPartialResult() (pr PartialResult, memDelta int64) {
|
|
p := new(partialResult4MaxMinEnum)
|
|
p.isNull = true
|
|
return PartialResult(p), DefPartialResult4MaxMinEnumSize
|
|
}
|
|
|
|
func (e *maxMin4Enum) ResetPartialResult(pr PartialResult) {
|
|
p := (*partialResult4MaxMinEnum)(pr)
|
|
p.isNull = true
|
|
}
|
|
|
|
func (e *maxMin4Enum) AppendFinalResult2Chunk(sctx sessionctx.Context, pr PartialResult, chk *chunk.Chunk) error {
|
|
p := (*partialResult4MaxMinEnum)(pr)
|
|
if p.isNull {
|
|
chk.AppendNull(e.ordinal)
|
|
return nil
|
|
}
|
|
chk.AppendEnum(e.ordinal, p.val)
|
|
return nil
|
|
}
|
|
|
|
func (e *maxMin4Enum) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4MaxMinEnum)(pr)
|
|
for _, row := range rowsInGroup {
|
|
d, err := e.args[0].Eval(row)
|
|
if err != nil {
|
|
return memDelta, err
|
|
}
|
|
if d.IsNull() {
|
|
continue
|
|
}
|
|
if p.isNull {
|
|
p.val = d.GetMysqlEnum().Copy()
|
|
memDelta += int64(len(d.GetMysqlEnum().Name))
|
|
p.isNull = false
|
|
continue
|
|
}
|
|
en := d.GetMysqlEnum()
|
|
if e.isMax && en.Value > p.val.Value || !e.isMax && en.Value < p.val.Value {
|
|
oldMem := len(p.val.Name)
|
|
newMem := len(en.Name)
|
|
memDelta += int64(newMem - oldMem)
|
|
p.val = en.Copy()
|
|
}
|
|
}
|
|
return memDelta, nil
|
|
}
|
|
|
|
func (e *maxMin4Enum) MergePartialResult(sctx sessionctx.Context, src, dst PartialResult) (memDelta int64, err error) {
|
|
p1, p2 := (*partialResult4MaxMinEnum)(src), (*partialResult4MaxMinEnum)(dst)
|
|
if p1.isNull {
|
|
return 0, nil
|
|
}
|
|
if p2.isNull {
|
|
*p2 = *p1
|
|
return 0, nil
|
|
}
|
|
if e.isMax && p1.val.Value > p2.val.Value || !e.isMax && p1.val.Value < p2.val.Value {
|
|
p2.val, p2.isNull = p1.val, false
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
type maxMin4Set struct {
|
|
baseMaxMinAggFunc
|
|
}
|
|
|
|
func (e *maxMin4Set) AllocPartialResult() (pr PartialResult, memDelta int64) {
|
|
p := new(partialResult4MaxMinSet)
|
|
p.isNull = true
|
|
return PartialResult(p), DefPartialResult4MaxMinSetSize
|
|
}
|
|
|
|
func (e *maxMin4Set) ResetPartialResult(pr PartialResult) {
|
|
p := (*partialResult4MaxMinSet)(pr)
|
|
p.isNull = true
|
|
}
|
|
|
|
func (e *maxMin4Set) AppendFinalResult2Chunk(sctx sessionctx.Context, pr PartialResult, chk *chunk.Chunk) error {
|
|
p := (*partialResult4MaxMinSet)(pr)
|
|
if p.isNull {
|
|
chk.AppendNull(e.ordinal)
|
|
return nil
|
|
}
|
|
chk.AppendSet(e.ordinal, p.val)
|
|
return nil
|
|
}
|
|
|
|
func (e *maxMin4Set) UpdatePartialResult(sctx sessionctx.Context, rowsInGroup []chunk.Row, pr PartialResult) (memDelta int64, err error) {
|
|
p := (*partialResult4MaxMinSet)(pr)
|
|
for _, row := range rowsInGroup {
|
|
d, err := e.args[0].Eval(row)
|
|
if err != nil {
|
|
return memDelta, err
|
|
}
|
|
if d.IsNull() {
|
|
continue
|
|
}
|
|
if p.isNull {
|
|
p.val = d.GetMysqlSet().Copy()
|
|
memDelta += int64(len(d.GetMysqlSet().Name))
|
|
p.isNull = false
|
|
continue
|
|
}
|
|
s := d.GetMysqlSet()
|
|
if e.isMax && s.Value > p.val.Value || !e.isMax && s.Value < p.val.Value {
|
|
oldMem := len(p.val.Name)
|
|
newMem := len(s.Name)
|
|
memDelta += int64(newMem - oldMem)
|
|
p.val = s.Copy()
|
|
}
|
|
}
|
|
return memDelta, nil
|
|
}
|
|
|
|
func (e *maxMin4Set) MergePartialResult(sctx sessionctx.Context, src, dst PartialResult) (memDelta int64, err error) {
|
|
p1, p2 := (*partialResult4MaxMinSet)(src), (*partialResult4MaxMinSet)(dst)
|
|
if p1.isNull {
|
|
return 0, nil
|
|
}
|
|
if p2.isNull {
|
|
*p2 = *p1
|
|
return 0, nil
|
|
}
|
|
if e.isMax && p1.val.Value > p2.val.Value || !e.isMax && p1.val.Value < p2.val.Value {
|
|
p2.val, p2.isNull = p1.val, false
|
|
}
|
|
return 0, nil
|
|
}
|