func (b *planBuilder) buildSelect(sel *ast.SelectStmt) Plan { var aggFuncs []*ast.AggregateFuncExpr hasAgg := b.detectSelectAgg(sel) if hasAgg { aggFuncs = b.extractSelectAgg(sel) } var p Plan if sel.From != nil { p = b.buildJoin(sel.From.TableRefs) if b.err != nil { return nil } if sel.Where != nil { p = b.buildFilter(p, sel.Where) if b.err != nil { return nil } } if sel.LockTp != ast.SelectLockNone { p = b.buildSelectLock(p, sel.LockTp) if b.err != nil { return nil } } if hasAgg { p = b.buildAggregate(p, aggFuncs, sel.GroupBy) } p = b.buildSelectFields(p, sel.GetResultFields()) if b.err != nil { return nil } } else { if hasAgg { p = b.buildAggregate(p, aggFuncs, nil) } p = b.buildSelectFields(p, sel.GetResultFields()) if b.err != nil { return nil } if sel.Where != nil { p = b.buildFilter(p, sel.Where) if b.err != nil { return nil } } } if sel.OrderBy != nil { p = b.buildSort(p, sel.OrderBy.Items) if b.err != nil { return nil } } if sel.Limit != nil { p = b.buildLimit(p, sel.Limit) if b.err != nil { return nil } } return p }
func (b *planBuilder) buildSelect(sel *ast.SelectStmt) Plan { var aggFuncs []*ast.AggregateFuncExpr hasAgg := b.detectSelectAgg(sel) if hasAgg { aggFuncs = b.extractSelectAgg(sel) } // Build subquery // Convert subquery to expr with plan b.buildSubquery(sel) var p Plan if sel.From != nil { p = b.buildFrom(sel) if b.err != nil { return nil } if sel.LockTp != ast.SelectLockNone { p = b.buildSelectLock(p, sel.LockTp) if b.err != nil { return nil } } if hasAgg { p = b.buildAggregate(p, aggFuncs, sel.GroupBy) } p = b.buildSelectFields(p, sel.GetResultFields()) if b.err != nil { return nil } } else { if hasAgg { p = b.buildAggregate(p, aggFuncs, nil) } p = b.buildSelectFields(p, sel.GetResultFields()) if b.err != nil { return nil } } if sel.Having != nil { p = b.buildHaving(p, sel.Having) if b.err != nil { return nil } } if sel.OrderBy != nil && !matchOrder(p, sel.OrderBy.Items) { p = b.buildSort(p, sel.OrderBy.Items) if b.err != nil { return nil } } if sel.Limit != nil { p = b.buildLimit(p, sel.Limit) if b.err != nil { return nil } } return p }
func (v *typeInferrer) selectStmt(x *ast.SelectStmt) { rf := x.GetResultFields() for _, val := range rf { // column ID is 0 means it is not a real column from table, but a temporary column, // so its type is not pre-defined, we need to set it. if val.Column.ID == 0 && val.Expr.GetType() != nil { val.Column.FieldType = *(val.Expr.GetType()) } } }
// Detect aggregate function or groupby clause. func (b *planBuilder) detectSelectAgg(sel *ast.SelectStmt) bool { if sel.GroupBy != nil { return true } for _, f := range sel.GetResultFields() { if ast.HasAggFlag(f.Expr) { return true } } return false }
// extractSelectAgg extracts aggregate functions and converts ColumnNameExpr to aggregate function. func (b *planBuilder) extractSelectAgg(sel *ast.SelectStmt) []*ast.AggregateFuncExpr { extractor := &ast.AggregateFuncExtractor{AggFuncs: make([]*ast.AggregateFuncExpr, 0)} res := make([]*ast.ResultField, 0, len(sel.GetResultFields())) for _, f := range sel.GetResultFields() { n, ok := f.Expr.Accept(extractor) if !ok { b.err = errors.New("Failed to extract agg expr!") return nil } ve, ok := f.Expr.(*ast.ValueExpr) if ok && len(f.Column.Name.O) > 0 { agg := &ast.AggregateFuncExpr{ F: ast.AggFuncFirstRow, Args: []ast.ExprNode{ve}, } extractor.AggFuncs = append(extractor.AggFuncs, agg) n = agg } // Clone the ResultField. // For "select c from t group by c;" both "c"s in select field and grouby clause refer to the same ResultField. // So we should not affact the "c" in groupby clause. nf := &ast.ResultField{ ColumnAsName: f.ColumnAsName, Column: f.Column, Table: f.Table, DBName: f.DBName, Expr: n.(ast.ExprNode), } res = append(res, nf) } sel.SetResultFields(res) // Extract agg funcs from having clause. if sel.Having != nil { n, ok := sel.Having.Expr.Accept(extractor) if !ok { b.err = errors.New("Failed to extract agg expr from having clause") return nil } sel.Having.Expr = n.(ast.ExprNode) } // Extract agg funcs from orderby clause. if sel.OrderBy != nil { for _, item := range sel.OrderBy.Items { n, ok := item.Expr.Accept(extractor) if !ok { b.err = errors.New("Failed to extract agg expr from orderby clause") return nil } item.Expr = n.(ast.ExprNode) // If item is PositionExpr, we need to rebind it. // For PositionExpr will refer to a ResultField in fieldlist. // After extract AggExpr from fieldlist, it may be changed (See the code above). if pe, ok := item.Expr.(*ast.PositionExpr); ok { pe.Refer = sel.GetResultFields()[pe.N-1] } } } return extractor.AggFuncs }
func (b *planBuilder) buildSelect(sel *ast.SelectStmt) Plan { var p Plan if sel.From != nil { p = b.buildJoin(sel.From.TableRefs) if b.err != nil { return nil } if sel.Where != nil { p = b.buildFilter(p, sel.Where) if b.err != nil { return nil } } if sel.LockTp != ast.SelectLockNone { p = b.buildSelectLock(p, sel.LockTp) if b.err != nil { return nil } } p = b.buildSelectFields(p, sel.GetResultFields()) if b.err != nil { return nil } } else { p = b.buildSelectFields(p, sel.GetResultFields()) if b.err != nil { return nil } if sel.Where != nil { p = b.buildFilter(p, sel.Where) if b.err != nil { return nil } } } if sel.OrderBy != nil { p = b.buildSort(p, sel.OrderBy.Items) if b.err != nil { return nil } } if sel.Limit != nil { p = b.buildLimit(p, sel.Limit) if b.err != nil { return nil } } return p }
// extractSelectAgg extracts aggregate functions and converts ColumnNameExpr to aggregate function. func (b *planBuilder) extractSelectAgg(sel *ast.SelectStmt) []*ast.AggregateFuncExpr { extractor := &ast.AggregateFuncExtractor{AggFuncs: make([]*ast.AggregateFuncExpr, 0)} for _, f := range sel.GetResultFields() { n, ok := f.Expr.Accept(extractor) if !ok { b.err = errors.New("Failed to extract agg expr!") return nil } ve, ok := f.Expr.(*ast.ValueExpr) if ok && len(f.Column.Name.O) > 0 { agg := &ast.AggregateFuncExpr{ F: ast.AggFuncFirstRow, Args: []ast.ExprNode{ve}, } agg.SetType(ve.GetType()) extractor.AggFuncs = append(extractor.AggFuncs, agg) n = agg } f.Expr = n.(ast.ExprNode) } // Extract agg funcs from having clause. if sel.Having != nil { n, ok := sel.Having.Expr.Accept(extractor) if !ok { b.err = errors.New("Failed to extract agg expr from having clause") return nil } sel.Having.Expr = n.(ast.ExprNode) } // Extract agg funcs from orderby clause. if sel.OrderBy != nil { for _, item := range sel.OrderBy.Items { n, ok := item.Expr.Accept(extractor) if !ok { b.err = errors.New("Failed to extract agg expr from orderby clause") return nil } item.Expr = n.(ast.ExprNode) // If item is PositionExpr, we need to rebind it. // For PositionExpr will refer to a ResultField in fieldlist. // After extract AggExpr from fieldlist, it may be changed (See the code above). if pe, ok := item.Expr.(*ast.PositionExpr); ok { pe.Refer = sel.GetResultFields()[pe.N-1] } } } return extractor.AggFuncs }
// Detect aggregate function or groupby clause. func (b *planBuilder) detectSelectAgg(sel *ast.SelectStmt) bool { if sel.GroupBy != nil { return true } for _, f := range sel.GetResultFields() { if ast.HasAggFlag(f.Expr) { return true } } if sel.Having != nil { if ast.HasAggFlag(sel.Having.Expr) { return true } } if sel.OrderBy != nil { for _, item := range sel.OrderBy.Items { if ast.HasAggFlag(item.Expr) { return true } } } return false }
// extractSelectAgg extracts aggregate functions and converts ColumnNameExpr to aggregate function. func (b *planBuilder) extractSelectAgg(sel *ast.SelectStmt) []*ast.AggregateFuncExpr { extractor := &ast.AggregateFuncExtractor{AggFuncs: make([]*ast.AggregateFuncExpr, 0)} res := make([]*ast.ResultField, 0, len(sel.GetResultFields())) for _, f := range sel.GetResultFields() { n, ok := f.Expr.Accept(extractor) if !ok { b.err = errors.New("Failed to extract agg expr!") return nil } ve, ok := f.Expr.(*ast.ValueExpr) if ok && len(f.Column.Name.O) > 0 { agg := &ast.AggregateFuncExpr{ F: ast.AggFuncFirstRow, Args: []ast.ExprNode{ve}, } extractor.AggFuncs = append(extractor.AggFuncs, agg) n = agg } // Clone the ResultField. // For "select c from t group by c;" both "c"s in select field and grouby clause refer to the same ResultField. // So we should not affact the "c" in groupby clause. nf := &ast.ResultField{ ColumnAsName: f.ColumnAsName, Column: f.Column, Table: f.Table, DBName: f.DBName, Expr: n.(ast.ExprNode), } res = append(res, nf) } sel.SetResultFields(res) // Extract agg funcs from orderby clause. if sel.OrderBy != nil { for _, item := range sel.OrderBy.Items { n, ok := item.Expr.Accept(extractor) if !ok { b.err = errors.New("Failed to extract agg expr from orderby clause") return nil } item.Expr = n.(ast.ExprNode) } } // TODO: extract aggfuncs from having clause. return extractor.AggFuncs }
func convertSelect(converter *expressionConverter, s *ast.SelectStmt) (*stmts.SelectStmt, error) { oldSelect := &stmts.SelectStmt{ Distinct: s.Distinct, Text: s.Text(), } oldSelect.Fields = make([]*field.Field, len(s.Fields.Fields)) for i, val := range s.Fields.Fields { oldField := &field.Field{} oldField.AsName = val.AsName.O var err error if val.Expr != nil { oldField.Expr, err = convertExpr(converter, val.Expr) if err != nil { return nil, errors.Trace(err) } if oldField.AsName == "" { innerExpr := getInnerFromParentheses(val.Expr) switch innerExpr.(type) { case *ast.ColumnNameExpr: // Do not set column name as name and remove parentheses. oldField.Expr = converter.exprMap[innerExpr] case *ast.ValueExpr: if innerExpr.Text() != "" { oldField.AsName = innerExpr.Text() } else { oldField.AsName = val.Text() } default: oldField.AsName = val.Text() } } } else if val.WildCard != nil { str := "*" if val.WildCard.Table.O != "" { str = val.WildCard.Table.O + ".*" if val.WildCard.Schema.O != "" { str = val.WildCard.Schema.O + "." + str } } oldField.Expr = &expression.Ident{CIStr: model.NewCIStr(str)} } oldSelect.Fields[i] = oldField } var err error if s.From != nil { oldSelect.From, err = convertJoin(converter, s.From.TableRefs) if err != nil { return nil, errors.Trace(err) } } if s.Where != nil { oldSelect.Where = &rsets.WhereRset{} oldSelect.Where.Expr, err = convertExpr(converter, s.Where) if err != nil { return nil, errors.Trace(err) } } if s.GroupBy != nil { oldSelect.GroupBy, err = convertGroupBy(converter, s.GroupBy) if err != nil { return nil, errors.Trace(err) } } if s.Having != nil { oldSelect.Having, err = convertHaving(converter, s.Having) if err != nil { return nil, errors.Trace(err) } } if s.OrderBy != nil { oldSelect.OrderBy, err = convertOrderBy(converter, s.OrderBy) if err != nil { return nil, errors.Trace(err) } } if s.Limit != nil { if s.Limit.Offset > 0 { oldSelect.Offset = &rsets.OffsetRset{Count: s.Limit.Offset} } if s.Limit.Count > 0 { oldSelect.Limit = &rsets.LimitRset{Count: s.Limit.Count} } } switch s.LockTp { case ast.SelectLockForUpdate: oldSelect.Lock = coldef.SelectLockForUpdate case ast.SelectLockInShareMode: oldSelect.Lock = coldef.SelectLockInShareMode case ast.SelectLockNone: oldSelect.Lock = coldef.SelectLockNone } return oldSelect, nil }
func (b *planBuilder) buildSelect(sel *ast.SelectStmt) Plan { // Detect aggregate function or groupby clause. aggDetetor := &ast.AggFuncDetector{} sel.Accept(aggDetetor) var aggFuncs []*ast.AggregateFuncExpr if aggDetetor.HasAggFunc { extractor := &ast.AggregateFuncExtractor{AggFuncs: make([]*ast.AggregateFuncExpr, 0)} // TODO: extract aggfuncs from having clause. for _, f := range sel.GetResultFields() { f.Expr.Accept(extractor) // TODO: check error } aggFuncs = extractor.AggFuncs // TODO: extract aggfuncs from having clause. } var p Plan if sel.From != nil { p = b.buildJoin(sel.From.TableRefs) if b.err != nil { return nil } if sel.Where != nil { p = b.buildFilter(p, sel.Where) if b.err != nil { return nil } } if sel.LockTp != ast.SelectLockNone { p = b.buildSelectLock(p, sel.LockTp) if b.err != nil { return nil } } if len(aggFuncs) > 0 { p = b.buildAggregate(p, aggFuncs) } p = b.buildSelectFields(p, sel.GetResultFields()) if b.err != nil { return nil } } else { if len(aggFuncs) > 0 { p = b.buildAggregate(p, aggFuncs) } p = b.buildSelectFields(p, sel.GetResultFields()) if b.err != nil { return nil } if sel.Where != nil { p = b.buildFilter(p, sel.Where) if b.err != nil { return nil } } } if sel.OrderBy != nil { p = b.buildSort(p, sel.OrderBy.Items) if b.err != nil { return nil } } if sel.Limit != nil { p = b.buildLimit(p, sel.Limit) if b.err != nil { return nil } } return p }
func convertSelect(converter *expressionConverter, s *ast.SelectStmt) (*stmts.SelectStmt, error) { oldSelect := &stmts.SelectStmt{ Distinct: s.Distinct, Text: s.Text(), } oldSelect.Fields = make([]*field.Field, len(s.Fields.Fields)) for i, val := range s.Fields.Fields { oldField := &field.Field{} oldField.AsName = val.AsName.O var err error if val.Expr != nil { oldField.Expr, err = convertExpr(converter, val.Expr) if err != nil { return nil, errors.Trace(err) } // TODO: handle parenthesesed column name expression, which should not set AsName. if _, ok := oldField.Expr.(*expression.Ident); !ok && oldField.AsName == "" { oldField.AsName = val.Text() } } else if val.WildCard != nil { str := "*" if val.WildCard.Table.O != "" { str = val.WildCard.Table.O + ".*" if val.WildCard.Schema.O != "" { str = val.WildCard.Schema.O + "." + str } } oldField.Expr = &expression.Ident{CIStr: model.NewCIStr(str)} } oldSelect.Fields[i] = oldField } var err error if s.From != nil { oldSelect.From, err = convertJoin(converter, s.From.TableRefs) if err != nil { return nil, errors.Trace(err) } } if s.Where != nil { oldSelect.Where = &rsets.WhereRset{} oldSelect.Where.Expr, err = convertExpr(converter, s.Where) if err != nil { return nil, errors.Trace(err) } } if s.GroupBy != nil { oldSelect.GroupBy, err = convertGroupBy(converter, s.GroupBy) if err != nil { return nil, errors.Trace(err) } } if s.Having != nil { oldSelect.Having, err = convertHaving(converter, s.Having) if err != nil { return nil, errors.Trace(err) } } if s.OrderBy != nil { oldSelect.OrderBy, err = convertOrderBy(converter, s.OrderBy) if err != nil { return nil, errors.Trace(err) } } if s.Limit != nil { if s.Limit.Offset > 0 { oldSelect.Offset = &rsets.OffsetRset{Count: s.Limit.Offset} } if s.Limit.Count > 0 { oldSelect.Limit = &rsets.LimitRset{Count: s.Limit.Count} } } switch s.LockTp { case ast.SelectLockForUpdate: oldSelect.Lock = coldef.SelectLockForUpdate case ast.SelectLockInShareMode: oldSelect.Lock = coldef.SelectLockInShareMode case ast.SelectLockNone: oldSelect.Lock = coldef.SelectLockNone } return oldSelect, nil }