func (g *groupConcatBuffer) Dispose() {
}
Dispose implements the Disposable interface.
package aggregation
import (
	"fmt"
	"sort"
	"strings"
	"github.com/dolthub/vitess/go/vt/proto/query"
	"github.com/dolthub/go-mysql-server/sql"
	"github.com/dolthub/go-mysql-server/sql/expression"
)
type GroupConcat struct {
	distinct    string
	sf          sql.SortFields
	separator   string
	selectExprs []sql.Expression
	maxLen      int
	returnType  sql.Type
}
var _ sql.FunctionExpression = &GroupConcat{}
var _ sql.Aggregation = &GroupConcat{}
func NewEmptyGroupConcat() sql.Expression {
	return &GroupConcat{}
}
func NewGroupConcat(distinct string, orderBy sql.SortFields, separator string, selectExprs []sql.Expression, maxLen int) (*GroupConcat, error) {
	return &GroupConcat{distinct: distinct, sf: orderBy, separator: separator, selectExprs: selectExprs, maxLen: maxLen}, nil
}
func (g *GroupConcat) NewBuffer() (sql.AggregationBuffer, error) {
	var rows []sql.Row
	distinctSet := make(map[string]bool)
	return &groupConcatBuffer{g, rows, distinctSet}, nil
}
func (g *GroupConcat) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
	return nil, ErrEvalUnsupportedOnAggregation.New("GroupConcat")
}
func (g *GroupConcat) Resolved() bool {
	for _, se := range g.selectExprs {
		if !se.Resolved() {
			return false
		}
	}
	sfs := g.sf.ToExpressions()
	for _, sf := range sfs {
		if !sf.Resolved() {
			return false
		}
	}
	return true
}
func (g *GroupConcat) String() string {
	sb := strings.Builder{}
	sb.WriteString("group_concat(")
	if g.distinct != "" {
		sb.WriteString(fmt.Sprintf("distinct %s", g.distinct))
	}
	if g.selectExprs != nil {
		var exprs = make([]string, len(g.selectExprs))
		for i, expr := range g.selectExprs {
			exprs[i] = expr.String()
		}
		sb.WriteString(strings.Join(exprs, ", "))
	}
	if len(g.sf) > 0 {
		sb.WriteString(" order by ")
		for i, ob := range g.sf {
			if i > 0 {
				sb.WriteString(", ")
			}
			sb.WriteString(ob.String())
		}
	}
	if g.separator != "," {
		sb.WriteString(" separator ")
		sb.WriteString(fmt.Sprintf("'%s'", g.separator))
	}
	sb.WriteString(")")
	return sb.String()
}
func (g *GroupConcat) Type() sql.Type {
	if g.returnType == sql.Blob {
		if g.maxLen <= 512 {
			return sql.MustCreateString(query.Type_VARBINARY, 512, sql.Collation_binary)
		} else {
			return sql.Blob
		}
	} else {
		if g.maxLen <= 512 {
			return sql.MustCreateString(query.Type_VARCHAR, 512, sql.Collation_Default)
		} else {
			return sql.Text
		}
	}
}
func (g *GroupConcat) IsNullable() bool {
	return false
}
func (g *GroupConcat) Children() []sql.Expression {
	return append(g.sf.ToExpressions(), g.selectExprs...)
}
func (g *GroupConcat) WithChildren(children ...sql.Expression) (sql.Expression, error) {
	if len(children) == 0 {
		return nil, sql.ErrInvalidChildrenNumber.New(GroupConcat{}, len(children), 2)
	}
	sortFieldMarker := len(g.sf)
	orderByExpr := children[:len(g.sf)]
	return NewGroupConcat(g.distinct, g.sf.FromExpressions(orderByExpr), g.separator, children[sortFieldMarker:], g.maxLen)
}
func (g *GroupConcat) FunctionName() string {
	return "group_concat"
}
type groupConcatBuffer struct {
	gc          *GroupConcat
	rows        []sql.Row
	distinctSet map[string]bool
}
func (g *groupConcatBuffer) Update(ctx *sql.Context, originalRow sql.Row) error {
	evalRow, retType, err := evalExprs(ctx, g.gc.selectExprs, originalRow)
	if err != nil {
		return err
	}
	g.gc.returnType = retType
	if evalRow == nil {
		return nil
	}
	var v interface{}
	if retType == sql.Blob {
		v, err = sql.Blob.Convert(evalRow[0])
	} else {
		v, err = sql.LongText.Convert(evalRow[0])
	}
	if err != nil {
		return err
	}
	if v == nil {
		return nil
	}
	vs := v.(string)
	if g.gc.distinct != "" {
		if _, ok := g.distinctSet[vs]; ok {
			return nil
		} else {
			g.distinctSet[vs] = true
		}
	}
	g.rows = append(g.rows, append(originalRow, nil, vs))
	return nil
}
func (g *groupConcatBuffer) Eval(ctx *sql.Context) (interface{}, error) {
	rows := g.rows
	if len(rows) == 0 {
		return nil, nil
	}
	if g.gc.sf != nil {
		sorter := &expression.Sorter{
			SortFields: g.gc.sf,
			Rows:       rows,
			Ctx:        ctx,
		}
		sort.Stable(sorter)
		if sorter.LastError != nil {
			return nil, sorter.LastError
		}
	}
	sb := strings.Builder{}
	for i, row := range rows {
		lastIdx := len(row) - 1
		if i == 0 {
			sb.WriteString(row[lastIdx].(string))
		} else {
			sb.WriteString(g.gc.separator)
			sb.WriteString(row[lastIdx].(string))
		}
		if sb.Len() >= g.gc.maxLen {
			break
		}
	}
	ret := sb.String()
	if len(ret) > g.gc.maxLen {
		ret = ret[:g.gc.maxLen]
	}
	return ret, nil
}