func (v *subqueryVisitor) Visit(expr parser.Expr, pre bool) (parser.Visitor, parser.Expr) { if v.pErr != nil { return nil, expr } if !pre { v.path = v.path[:len(v.path)-1] return nil, expr } v.path = append(v.path, expr) var exists *parser.ExistsExpr subquery, ok := expr.(*parser.Subquery) if !ok { exists, ok = expr.(*parser.ExistsExpr) if !ok { return v, expr } subquery, ok = exists.Subquery.(*parser.Subquery) if !ok { return v, expr } } // Calling makePlan() might recursively invoke expandSubqueries, so we need a // copy of the planner in order for there to have a separate subqueryVisitor. planMaker := *v.planner var plan planNode if plan, v.pErr = planMaker.makePlan(subquery.Select, false); v.pErr != nil { return nil, expr } if exists != nil { // For EXISTS expressions, all we want to know is if there is at least one // result. if plan.Next() { return v, parser.DBool(true) } v.pErr = plan.PErr() if v.pErr != nil { return nil, expr } return v, parser.DBool(false) } columns, multipleRows := v.getSubqueryContext() if n := len(plan.Columns()); columns != n { switch columns { case 1: v.pErr = roachpb.NewUErrorf("subquery must return only one column, found %d", n) default: v.pErr = roachpb.NewUErrorf("subquery must return %d columns, found %d", columns, n) } return nil, expr } var result parser.Expr if multipleRows { var rows parser.DTuple for plan.Next() { values := plan.Values() switch len(values) { case 1: // This seems hokey, but if we don't do this then the subquery expands // to a tuple of tuples instead of a tuple of values and an expression // like "k IN (SELECT foo FROM bar)" will fail because we're comparing // a single value against a tuple. rows = append(rows, values[0]) default: // The result from plan.Values() is only valid until the next call to // plan.Next(), so make a copy. valuesCopy := make(parser.DTuple, len(values)) copy(valuesCopy, values) rows = append(rows, valuesCopy) } } rows.Normalize() result = rows } else { result = parser.DNull for plan.Next() { values := plan.Values() switch len(values) { case 1: result = values[0] default: valuesCopy := make(parser.DTuple, len(values)) copy(valuesCopy, values) result = valuesCopy } if plan.Next() { v.pErr = roachpb.NewUErrorf("more than one row returned by a subquery used as an expression") return nil, expr } } } v.pErr = plan.PErr() if v.pErr != nil { return nil, expr } return v, result }
func (s *subquery) doEval() (parser.Datum, error) { var result parser.Datum switch s.execMode { case execModeExists: // For EXISTS expressions, all we want to know is if there is at least one // result. next, err := s.plan.Next() if s.err = err; err != nil { return result, err } if next { result = parser.MakeDBool(true) } if result == nil { result = parser.MakeDBool(false) } case execModeAllRows: var rows parser.DTuple next, err := s.plan.Next() for ; next; next, err = s.plan.Next() { values := s.plan.Values() switch len(values) { case 1: // This seems hokey, but if we don't do this then the subquery expands // to a tuple of tuples instead of a tuple of values and an expression // like "k IN (SELECT foo FROM bar)" will fail because we're comparing // a single value against a tuple. rows = append(rows, values[0]) default: // The result from plan.Values() is only valid until the next call to // plan.Next(), so make a copy. valuesCopy := make(parser.DTuple, len(values)) copy(valuesCopy, values) rows = append(rows, &valuesCopy) } } if s.err = err; err != nil { return result, err } if s.wantNormalized { rows.Normalize() } result = &rows case execModeOneRow: result = parser.DNull next, err := s.plan.Next() if s.err = err; err != nil { return result, err } if next { values := s.plan.Values() switch len(values) { case 1: result = values[0] default: valuesCopy := make(parser.DTuple, len(values)) copy(valuesCopy, values) result = &valuesCopy } another, err := s.plan.Next() if s.err = err; err != nil { return result, err } if another { s.err = fmt.Errorf("more than one row returned by a subquery used as an expression") return result, s.err } } } return result, nil }
func (v *subqueryVisitor) VisitPre(expr parser.Expr) (recurse bool, newExpr parser.Expr) { if v.err != nil { return false, expr } v.path = append(v.path, expr) var exists *parser.ExistsExpr subquery, ok := expr.(*parser.Subquery) if !ok { exists, ok = expr.(*parser.ExistsExpr) if !ok { return true, expr } subquery, ok = exists.Subquery.(*parser.Subquery) if !ok { return true, expr } } // Calling makePlan() might recursively invoke expandSubqueries, so we need a // copy of the planner in order for there to have a separate subqueryVisitor. // TODO(nvanbenschoten) We should propagate a desired type here. // TODO(knz) the instantiation of the subquery's select node should be moved // to the TypeCheck() method once the prepare and execute phase are separated // for select nodes. planMaker := *v.planner plan, err := planMaker.makePlan(subquery.Select, nil, false) if err != nil { return false, expr } if v.evalCtx.PrepareOnly { return false, expr } if v.err = plan.Start(); v.err != nil { return false, expr } if exists != nil { // For EXISTS expressions, all we want to know is if there is at least one // result. if plan.Next() { return true, parser.MakeDBool(true) } v.err = plan.Err() if v.err != nil { return false, expr } return true, parser.MakeDBool(false) } columns, multipleRows := v.getSubqueryContext() if n := len(plan.Columns()); columns != n { switch columns { case 1: v.err = fmt.Errorf("subquery must return only one column, found %d", n) default: v.err = fmt.Errorf("subquery must return %d columns, found %d", columns, n) } return true, expr } var result parser.Expr if multipleRows { var rows parser.DTuple for plan.Next() { values := plan.Values() switch len(values) { case 1: // This seems hokey, but if we don't do this then the subquery expands // to a tuple of tuples instead of a tuple of values and an expression // like "k IN (SELECT foo FROM bar)" will fail because we're comparing // a single value against a tuple. rows = append(rows, values[0]) default: // The result from plan.Values() is only valid until the next call to // plan.Next(), so make a copy. valuesCopy := make(parser.DTuple, len(values)) copy(valuesCopy, values) rows = append(rows, &valuesCopy) } } rows.Normalize() result = &rows } else { result = parser.DNull for plan.Next() { values := plan.Values() switch len(values) { case 1: result = values[0] default: valuesCopy := make(parser.DTuple, len(values)) copy(valuesCopy, values) result = &valuesCopy } if plan.Next() { v.err = fmt.Errorf("more than one row returned by a subquery used as an expression") return false, expr } } } v.err = plan.Err() if v.err != nil { return false, expr } return true, result }
func (v *subqueryVisitor) Visit(expr parser.Expr, pre bool) (parser.Visitor, parser.Expr) { if v.err != nil { return nil, expr } if !pre { v.path = v.path[:len(v.path)-1] return nil, expr } v.path = append(v.path, expr) subquery, ok := expr.(*parser.Subquery) if !ok { return v, expr } var plan planNode if plan, v.err = v.makePlan(subquery.Select); v.err != nil { return nil, expr } columns, multipleRows := v.getSubqueryContext() if n := len(plan.Columns()); columns != n { switch columns { case 1: v.err = fmt.Errorf("subquery must return only one column, found %d", n) default: v.err = fmt.Errorf("subquery must return %d columns, found %d", columns, n) } return nil, expr } var result parser.Expr if multipleRows { var rows parser.DTuple for plan.Next() { values := plan.Values() switch len(values) { case 1: // This seems hokey, but if we don't do this then the subquery expands // to a tuple of tuples instead of a tuple of values and an expression // like "k IN (SELECT foo FROM bar)" will fail because we're comparing // a single value against a tuple. rows = append(rows, values[0]) default: // The result from plan.Values() is only valid until the next call to // plan.Next(), so make a copy. valuesCopy := make(parser.DTuple, len(values)) copy(valuesCopy, values) rows = append(rows, valuesCopy) } } rows.Normalize() result = rows } else { result = parser.DNull for plan.Next() { values := plan.Values() switch len(values) { case 1: result = values[0] default: valuesCopy := make(parser.DTuple, len(values)) copy(valuesCopy, values) result = valuesCopy } if plan.Next() { v.err = fmt.Errorf("more than one row returned by a subquery used as an expression") return nil, expr } } } v.err = plan.Err() if v.err != nil { return nil, expr } return v, result }