Ejemplo n.º 1
0
// isSameRoute returns true if the join constraint makes the routes
// mergeable by unique vindex. The constraint has to be an equality
// like a.id = b.id where both columns have the same unique vindex.
func (rb *route) isSameRoute(rhs *route, filter sqlparser.BoolExpr) bool {
	comparison, ok := filter.(*sqlparser.ComparisonExpr)
	if !ok {
		return false
	}
	if comparison.Operator != sqlparser.EqualStr {
		return false
	}
	left := comparison.Left
	right := comparison.Right
	lVindex := rb.Symtab().Vindex(left, rb, false)
	if lVindex == nil {
		left, right = right, left
		lVindex = rb.Symtab().Vindex(left, rb, false)
	}
	if lVindex == nil || !vindexes.IsUnique(lVindex) {
		return false
	}
	rVindex := rhs.Symtab().Vindex(right, rhs, false)
	if rVindex == nil {
		return false
	}
	if rVindex != lVindex {
		return false
	}
	return true
}
Ejemplo n.º 2
0
Archivo: dml.go Proyecto: CowLeo/vitess
// getDMLRouting updates the route with the necessary routing
// info. If it cannot find a unique route, then it returns an error.
func getDMLRouting(where *sqlparser.Where, route *engine.Route) error {
	if where == nil {
		return errors.New("unsupported: multi-shard where clause in DML")
	}
	for _, index := range route.Table.Ordered {
		if !vindexes.IsUnique(index.Vindex) {
			continue
		}
		if values := getMatch(where.Expr, index.Column); values != nil {
			route.Vindex = index.Vindex
			route.Values = values
			return nil
		}
	}
	return errors.New("unsupported: multi-shard where clause in DML")
}
Ejemplo n.º 3
0
// computeEqualPlan computes the plan for an equality constraint.
func (rb *route) computeEqualPlan(comparison *sqlparser.ComparisonExpr) (opcode engine.RouteOpcode, vindex vindexes.Vindex, values interface{}) {
	left := comparison.Left
	right := comparison.Right
	vindex = rb.Symtab().Vindex(left, rb, true)
	if vindex == nil {
		left, right = right, left
		vindex = rb.Symtab().Vindex(left, rb, true)
		if vindex == nil {
			return engine.SelectScatter, nil, nil
		}
	}
	if !exprIsValue(right, rb) {
		return engine.SelectScatter, nil, nil
	}
	if vindexes.IsUnique(vindex) {
		return engine.SelectEqualUnique, vindex, right
	}
	return engine.SelectEqual, vindex, right
}
Ejemplo n.º 4
0
// pushGroupBy processes the group by clause. It resolves all symbols,
// and ensures that there are no subqueries. It also verifies that the
// references don't addres an outer query. We only support group by
// for unsharded or single shard routes.
func pushGroupBy(groupBy sqlparser.GroupBy, bldr builder) error {
	if groupBy == nil {
		return nil
	}
	rb, ok := bldr.(*route)
	if !ok {
		return errors.New("unsupported: complex join and group by")
	}
	err := sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
		switch node := node.(type) {
		case *sqlparser.ColName:
			_, isLocal, err := bldr.Symtab().Find(node, true)
			if err != nil {
				return false, err
			}
			if !isLocal {
				return false, errors.New("unsupported: subquery references outer query in group by")
			}
		case *sqlparser.Subquery:
			// TODO(sougou): better error.
			return false, errors.New("unsupported: subqueries in group by expression")
		}
		return true, nil
	}, groupBy)
	if err != nil {
		return err
	}
	if rb.IsSingle() {
		rb.SetGroupBy(groupBy)
		return nil
	}
	// It's a scatter route. We can allow group by if it references a
	// column with a unique vindex.
	for _, expr := range groupBy {
		vindex := bldr.Symtab().Vindex(expr, rb, true)
		if vindex != nil && vindexes.IsUnique(vindex) {
			rb.SetGroupBy(groupBy)
			return nil
		}
	}
	return errors.New("unsupported: scatter and group by")
}
Ejemplo n.º 5
0
// checkAggregates returns an error if the select statement
// has aggregates that cannot be pushed down due to a complex
// plan.
func checkAggregates(sel *sqlparser.Select, bldr builder) error {
	hasAggregates := false
	if sel.Distinct != "" {
		hasAggregates = true
	} else {
		_ = sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
			switch node := node.(type) {
			case *sqlparser.FuncExpr:
				if node.IsAggregate() {
					hasAggregates = true
					return false, errors.New("dummy")
				}
			}
			return true, nil
		}, sel.SelectExprs)
	}
	if !hasAggregates {
		return nil
	}

	// Check if we can allow aggregates.
	rb, ok := bldr.(*route)
	if !ok {
		return errors.New("unsupported: complex join with aggregates")
	}
	if rb.IsSingle() {
		return nil
	}
	// It's a scatter rb. We can allow aggregates if there is a unique
	// vindex in the select list.
	for _, selectExpr := range sel.SelectExprs {
		switch selectExpr := selectExpr.(type) {
		case *sqlparser.NonStarExpr:
			vindex := bldr.Symtab().Vindex(selectExpr.Expr, rb, true)
			if vindex != nil && vindexes.IsUnique(vindex) {
				return nil
			}
		}
	}
	return errors.New("unsupported: scatter with aggregates")
}