func (nr *nameResolver) resolveColumnInResultFields(cn *ast.ColumnNameExpr, rfs []*ast.ResultField) bool { if cn.Name.Table.L != "" { // Skip result fields, resolve the column in table source. return false } var matched *ast.ResultField for _, rf := range rfs { matchAsName := cn.Name.Name.L == rf.ColumnAsName.L matchColumnName := rf.ColumnAsName.L == "" && cn.Name.Name.L == rf.Column.Name.L if matchAsName || matchColumnName { if rf.Column.Name.L == "" { // This is not a real table column, resolve it directly. cn.Refer = rf return true } if matched == nil { matched = rf } else { sameColumn := matched.Table.Name.L == rf.Table.Name.L && matched.Column.Name.L == rf.Column.Name.L if !sameColumn { nr.Err = errors.Errorf("column %s is ambiguous.", cn.Name.Name.O) return true } } } } if matched != nil { // Bind column. cn.Refer = matched return true } return false }
func (nr *nameResolver) resolveColumnInResultFields(ctx *resolverContext, cn *ast.ColumnNameExpr, rfs []*ast.ResultField) bool { var matched *ast.ResultField for _, rf := range rfs { if cn.Name.Table.L != "" { // Check table name if rf.TableAsName.L != "" { if cn.Name.Table.L != rf.TableAsName.L { continue } } else if cn.Name.Table.L != rf.Table.Name.L { continue } } matchAsName := cn.Name.Name.L == rf.ColumnAsName.L var matchColumnName bool if ctx.inHaving { matchColumnName = cn.Name.Name.L == rf.Column.Name.L } else { matchColumnName = rf.ColumnAsName.L == "" && cn.Name.Name.L == rf.Column.Name.L } if matchAsName || matchColumnName { if rf.Column.Name.L == "" { // This is not a real table column, resolve it directly. cn.Refer = rf rf.Referenced = true return true } if matched == nil { matched = rf } else { sameColumn := matched.TableName == rf.TableName && matched.Column.Name.L == rf.Column.Name.L if !sameColumn { nr.Err = errors.Errorf("column %s is ambiguous.", cn.Name.Name.O) return true } } } } if matched != nil { // If in GroupBy, we clone the ResultField if ctx.inGroupBy || ctx.inHaving || ctx.inOrderBy { nf := *matched expr := matched.Expr if cexpr, ok := expr.(*ast.ColumnNameExpr); ok { expr = cexpr.Refer.Expr } nf.Expr = expr matched = &nf } // Bind column. cn.Refer = matched matched.Referenced = true return true } return false }
func (nr *nameResolver) resolveColumnInTableSources(cn *ast.ColumnNameExpr, tableSources []*ast.TableSource) (done bool) { var matchedResultField *ast.ResultField tableNameL := cn.Name.Table.L columnNameL := cn.Name.Name.L if tableNameL != "" { var matchedTable ast.ResultSetNode for _, ts := range tableSources { if tableNameL == ts.AsName.L { // different table name. matchedTable = ts break } else if ts.AsName.L != "" { // Table as name shadows table real name. continue } if tn, ok := ts.Source.(*ast.TableName); ok { if cn.Name.Schema.L != "" && cn.Name.Schema.L != tn.Schema.L { continue } if tableNameL == tn.Name.L { matchedTable = ts } } } if matchedTable != nil { resultFields := matchedTable.GetResultFields() for _, rf := range resultFields { if rf.ColumnAsName.L == columnNameL || rf.Column.Name.L == columnNameL { // resolve column. matchedResultField = rf break } } } } else { for _, ts := range tableSources { rfs := ts.GetResultFields() for _, rf := range rfs { matchAsName := rf.ColumnAsName.L != "" && rf.ColumnAsName.L == columnNameL matchColumnName := rf.ColumnAsName.L == "" && rf.Column.Name.L == columnNameL if matchAsName || matchColumnName { if matchedResultField != nil { nr.Err = errors.Errorf("column %s is ambiguous.", cn.Name.Name.O) return true } matchedResultField = rf } } } } if matchedResultField != nil { // Bind column. cn.Refer = matchedResultField matchedResultField.Referenced = true return true } return false }
func (nr *nameResolver) resolveColumnInResultFields(ctx *resolverContext, cn *ast.ColumnNameExpr, rfs []*ast.ResultField) bool { var matched *ast.ResultField for _, rf := range rfs { if cn.Name.Table.L != "" { // Check table name if rf.TableAsName.L != "" { if cn.Name.Table.L != rf.TableAsName.L { continue } } else if cn.Name.Table.L != rf.Table.Name.L { continue } } matchAsName := cn.Name.Name.L == rf.ColumnAsName.L var matchColumnName bool if ctx.inHaving { matchColumnName = cn.Name.Name.L == rf.Column.Name.L } else { matchColumnName = rf.ColumnAsName.L == "" && cn.Name.Name.L == rf.Column.Name.L } if matchAsName || matchColumnName { if rf.Column.Name.L == "" { // This is not a real table column, resolve it directly. cn.Refer = rf return true } if matched == nil { matched = rf } else { sameColumn := matched.TableName == rf.TableName && matched.Column.Name.L == rf.Column.Name.L if !sameColumn { nr.Err = errors.Errorf("column %s is ambiguous.", cn.Name.Name.O) return true } } } } if matched != nil { // Bind column. cn.Refer = matched return true } return false }
func (e *Evaluator) columnName(v *ast.ColumnNameExpr) bool { v.SetDatum(*v.Refer.Expr.GetDatum()) return true }
// resolveColumnNameInContext looks up and sets ResultField for a column with the ctx. func (nr *nameResolver) resolveColumnNameInContext(ctx *resolverContext, cn *ast.ColumnNameExpr) bool { if ctx.inTableRefs { // In TableRefsClause, column reference only in join on condition which is handled before. return false } if ctx.inFieldList { // only resolve column using tables. return nr.resolveColumnInTableSources(cn, ctx.tables) } if ctx.inGroupBy { // From tables first, then field list. // If ctx.InByItemExpression is true, the item is not an identifier. // Otherwise it is an identifier. if ctx.inByItemExpression { // From table first, then field list. if nr.resolveColumnInTableSources(cn, ctx.tables) { return true } found := nr.resolveColumnInResultFields(ctx, cn, ctx.fieldList) if nr.Err == nil && found { // Check if resolved refer is an aggregate function expr. if _, ok := cn.Refer.Expr.(*ast.AggregateFuncExpr); ok { nr.Err = ErrIllegalReference.Gen("Reference '%s' not supported (reference to group function)", cn.Name.Name.O) } } return found } // Resolve from table first, then from select list. found := nr.resolveColumnInTableSources(cn, ctx.tables) if nr.Err != nil { return found } // We should copy the refer here. // Because if the ByItem is an identifier, we should check if it // is ambiguous even it is already resolved from table source. // If the ByItem is not an identifier, we do not need the second check. r := cn.Refer if nr.resolveColumnInResultFields(ctx, cn, ctx.fieldList) { if nr.Err != nil { return true } if r != nil { // It is not ambiguous and already resolved from table source. // We should restore its Refer. cn.Refer = r } if _, ok := cn.Refer.Expr.(*ast.AggregateFuncExpr); ok { nr.Err = ErrIllegalReference.Gen("Reference '%s' not supported (reference to group function)", cn.Name.Name.O) } return true } return found } if ctx.inHaving { // First group by, then field list. if nr.resolveColumnInResultFields(ctx, cn, ctx.groupBy) { return true } if ctx.inHavingAgg { // If cn is in an aggregate function in having clause, check tablesource first. if nr.resolveColumnInTableSources(cn, ctx.tables) { return true } } return nr.resolveColumnInResultFields(ctx, cn, ctx.fieldList) } if ctx.inOrderBy { if nr.resolveColumnInResultFields(ctx, cn, ctx.groupBy) { return true } if ctx.inByItemExpression { // From table first, then field list. if nr.resolveColumnInTableSources(cn, ctx.tables) { return true } return nr.resolveColumnInResultFields(ctx, cn, ctx.fieldList) } // Field list first, then from table. if nr.resolveColumnInResultFields(ctx, cn, ctx.fieldList) { return true } return nr.resolveColumnInTableSources(cn, ctx.tables) } // In where clause. return nr.resolveColumnInTableSources(cn, ctx.tables) }
// resolveColumnNameInContext looks up and sets ResultField for a column with the ctx. func (nr *nameResolver) resolveColumnNameInContext(ctx *resolverContext, cn *ast.ColumnNameExpr) bool { if ctx.inTableRefs { // In TableRefsClause, column reference only in join on condition which is handled before. return false } if ctx.inFieldList { // only resolve column using tables. return nr.resolveColumnInTableSources(cn, ctx.tables) } if ctx.inGroupBy { // From tables first, then field list. // If ctx.InByItemExpression is true, the item is not an identifier. // Otherwise it is an identifier. if ctx.inByItemExpression { // From table first, then field list. if nr.resolveColumnInTableSources(cn, ctx.tables) { return true } return nr.resolveColumnInResultFields(cn, ctx.fieldList) } // Resolve from table first, then from select list. found := nr.resolveColumnInTableSources(cn, ctx.tables) if nr.Err != nil { return found } // We should copy the refer here. // Because if the ByItem is an identifier, we should check if it // is ambiguous even it is already resolved from table source. // If the ByItem is not an identifier, we do not need the second check. r := cn.Refer if nr.resolveColumnInResultFields(cn, ctx.fieldList) { if nr.Err != nil { return true } if r != nil { // It is not ambiguous and already resolved from table source. // We should restore its Refer. cn.Refer = r } return true } return found } if ctx.inHaving { // First group by, then field list. if nr.resolveColumnInResultFields(cn, ctx.groupBy) { return true } return nr.resolveColumnInResultFields(cn, ctx.fieldList) } if ctx.inOrderBy { if nr.resolveColumnInResultFields(cn, ctx.groupBy) { return true } if ctx.inByItemExpression { // From table first, then field list. if nr.resolveColumnInTableSources(cn, ctx.tables) { return true } return nr.resolveColumnInResultFields(cn, ctx.fieldList) } // Field list first, then from table. if nr.resolveColumnInResultFields(cn, ctx.fieldList) { return true } return nr.resolveColumnInTableSources(cn, ctx.tables) } // In where clause. return nr.resolveColumnInTableSources(cn, ctx.tables) }