Added plan descriptions for a few more primitives

Signed-off-by: Andres Taylor <andres@planetscale.com>
This commit is contained in:
Andres Taylor 2020-03-31 17:35:22 +02:00
Родитель 2910261abf
Коммит 3576a2a2f6
7 изменённых файлов: 105 добавлений и 28 удалений

Просмотреть файл

@ -139,5 +139,5 @@ func wrapStreamExecute(prim Primitive, vcursor VCursor, bindVars map[string]*que
} }
func (f *fakePrimitive) description() PlanDescription { func (f *fakePrimitive) description() PlanDescription {
return PlanDescription{OperatorType: "fake - not implemented"} return PlanDescription{OperatorType: "fake"}
} }

Просмотреть файл

@ -23,6 +23,7 @@ import (
"math" "math"
"reflect" "reflect"
"sort" "sort"
"strings"
"vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/sqltypes"
"vitess.io/vitess/go/vt/key" "vitess.io/vitess/go/vt/key"
@ -201,20 +202,27 @@ func (ms *MemorySort) description() PlanDescription {
} }
func orderByParamsToString(i interface{}) string { func orderByParamsToString(i interface{}) string {
ob := i.(OrderbyParams) return i.(OrderbyParams).String()
return ob.String()
} }
//GenericJoin will iterate over arrays, slices or maps, and executes the f function to get a
//string representation of each element, and then uses strings.Join() join all the strings into a single one
func GenericJoin(input interface{}, f func(interface{}) string) string { func GenericJoin(input interface{}, f func(interface{}) string) string {
sl := reflect.ValueOf(input) sl := reflect.ValueOf(input)
str := "" var keys []string
for i := 0; i < sl.Len(); i++ { switch sl.Kind() {
if len(str) != 0 { case reflect.Slice:
str += "," for i := 0; i < sl.Len(); i++ {
keys = append(keys, f(sl.Index(i).Interface()))
} }
str += f(sl.Index(i).Interface()) case reflect.Map:
for _, k := range sl.MapKeys() {
keys = append(keys, f(k.Interface()))
}
default:
panic("GenericJoin doesn't know how to deal with " + sl.Kind().String())
} }
return str return strings.Join(keys, ", ")
} }
// sortHeap is sorted based on the orderBy params. // sortHeap is sorted based on the orderBy params.

Просмотреть файл

@ -18,6 +18,9 @@ package engine
import ( import (
"fmt" "fmt"
"strconv"
"vitess.io/vitess/go/vt/key"
"vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/proto/vtrpc"
"vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vterrors"
@ -67,6 +70,14 @@ func (ap AggregateParams) isDistinct() bool {
return ap.Opcode == AggregateCountDistinct || ap.Opcode == AggregateSumDistinct return ap.Opcode == AggregateCountDistinct || ap.Opcode == AggregateSumDistinct
} }
func (ap AggregateParams) String() string {
if ap.Alias != "" {
return fmt.Sprintf("%s(%d) AS %s", ap.Opcode.String(), ap.Col, ap.Alias)
}
return fmt.Sprintf("%s(%d)", ap.Opcode.String(), ap.Col)
}
// AggregateOpcode is the aggregation Opcode. // AggregateOpcode is the aggregation Opcode.
type AggregateOpcode int type AggregateOpcode int
@ -394,9 +405,26 @@ func createEmptyValueFor(opcode AggregateOpcode) (sqltypes.Value, error) {
return sqltypes.NULL, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "unknown aggregation %v", opcode) return sqltypes.NULL, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "unknown aggregation %v", opcode)
} }
func aggregateParamsToString(in interface{}) string {
return in.(AggregateParams).String()
}
func intToString(i interface{}) string {
return strconv.Itoa(i.(int))
}
func (oa *OrderedAggregate) description() PlanDescription { func (oa *OrderedAggregate) description() PlanDescription {
orderByIndexes := GenericJoin(oa.Aggregates, aggregateParamsToString)
groupBy := GenericJoin(oa.Keys, intToString)
other := map[string]string{
"OrderBy": orderByIndexes,
"GroupBy": groupBy,
"Distinct": strconv.FormatBool(oa.HasDistinct),
}
return PlanDescription{ return PlanDescription{
OperatorType: "OrderedAggregation not implemented", OperatorType: "Aggregate",
Other: nil, Variant: "Ordered",
TargetDestination: key.DestinationVtGate{},
Other: other,
} }
} }

Просмотреть файл

@ -17,6 +17,8 @@ limitations under the License.
package engine package engine
import ( import (
"encoding/json"
"vitess.io/vitess/go/vt/key" "vitess.io/vitess/go/vt/key"
topodatapb "vitess.io/vitess/go/vt/proto/topodata" topodatapb "vitess.io/vitess/go/vt/proto/topodata"
"vitess.io/vitess/go/vt/vtgate/vindexes" "vitess.io/vitess/go/vt/vtgate/vindexes"
@ -25,16 +27,42 @@ import (
// PlanDescription is used to create a serializable representation of the Primitive tree // PlanDescription is used to create a serializable representation of the Primitive tree
type PlanDescription struct { type PlanDescription struct {
OperatorType string OperatorType string
Variant string Variant string `json:",omitempty"`
// Keyspace specifies the keyspace to send the query to. // Keyspace specifies the keyspace to send the query to.
Keyspace *vindexes.Keyspace Keyspace *vindexes.Keyspace `json:",omitempty"`
// TargetDestination specifies an explicit target destination to send the query to. // TargetDestination specifies an explicit target destination to send the query to.
TargetDestination key.Destination TargetDestination key.Destination `json:",omitempty"`
// TargetTabletType specifies an explicit target destination tablet type // TargetTabletType specifies an explicit target destination tablet type
// this is only used in conjunction with TargetDestination // this is only used in conjunction with TargetDestination
TargetTabletType topodatapb.TabletType TargetTabletType topodatapb.TabletType `json:",omitempty"`
Other map[string]string Other map[string]string `json:",omitempty"`
Inputs []PlanDescription Inputs []PlanDescription `json:",omitempty"`
}
// MarshalJSON serializes the PlanDescription into a JSON representation.
func (pd *PlanDescription) MarshalJSON() ([]byte, error) {
var dest string
if pd.TargetDestination != nil {
dest = pd.TargetDestination.String()
}
out := struct {
OperatorType string
Variant string `json:",omitempty"`
Keyspace *vindexes.Keyspace `json:",omitempty"`
TargetDestination string `json:",omitempty"`
TargetTabletType string `json:",omitempty"`
Other map[string]string `json:",omitempty"`
Inputs []PlanDescription `json:",omitempty"`
}{
OperatorType: pd.OperatorType,
Variant: pd.Variant,
Keyspace: pd.Keyspace,
TargetDestination: dest,
TargetTabletType: pd.TargetTabletType.String(),
Other: pd.Other,
Inputs: pd.Inputs,
}
return json.Marshal(out)
} }
//PrimitiveToPlanDescription transforms a primitive tree into a corresponding PlanDescription tree //PrimitiveToPlanDescription transforms a primitive tree into a corresponding PlanDescription tree

Просмотреть файл

@ -19,6 +19,8 @@ package engine
import ( import (
"fmt" "fmt"
"vitess.io/vitess/go/vt/key"
"vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/sqltypes"
"vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vterrors"
@ -31,11 +33,14 @@ var _ Primitive = (*PulloutSubquery)(nil)
// PulloutSubquery executes a "pulled out" subquery and stores // PulloutSubquery executes a "pulled out" subquery and stores
// the results in a bind variable. // the results in a bind variable.
type PulloutSubquery struct { type PulloutSubquery struct {
Opcode PulloutOpcode Opcode PulloutOpcode
// SubqueryResult and HasValues are used to send in the bindvar used in the query to the underlying primitive
SubqueryResult string SubqueryResult string
HasValues string HasValues string
Subquery Primitive
Underlying Primitive Subquery Primitive
Underlying Primitive
} }
// Inputs returns the input primitives for this join // Inputs returns the input primitives for this join
@ -154,7 +159,11 @@ func (ps *PulloutSubquery) execSubquery(vcursor VCursor, bindVars map[string]*qu
} }
func (ps *PulloutSubquery) description() PlanDescription { func (ps *PulloutSubquery) description() PlanDescription {
return PlanDescription{OperatorType: "pullout subquery not implemented"} return PlanDescription{
OperatorType: "Subquery",
Variant: ps.Opcode.String(),
TargetDestination: key.DestinationVtGate{},
}
} }
// PulloutOpcode is a number representing the opcode // PulloutOpcode is a number representing the opcode

Просмотреть файл

@ -18,6 +18,7 @@ package engine
import ( import (
"vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/sqltypes"
"vitess.io/vitess/go/vt/key"
querypb "vitess.io/vitess/go/vt/proto/query" querypb "vitess.io/vitess/go/vt/proto/query"
) )
@ -104,5 +105,12 @@ func (sq *Subquery) buildFields(inner *sqltypes.Result) []*querypb.Field {
} }
func (sq *Subquery) description() PlanDescription { func (sq *Subquery) description() PlanDescription {
return PlanDescription{OperatorType: "subquery - not implemented"} other := map[string]string{
"Columns": GenericJoin(sq.Cols, intToString),
}
return PlanDescription{
OperatorType: "Subquery",
TargetDestination: key.DestinationVtGate{},
Other: other,
}
} }

Просмотреть файл

@ -301,13 +301,9 @@ func getPlanOrErrorOutput(err error, plan *engine.Plan) string {
} }
descr := engine.PrimitiveToPlanDescription(plan.Instructions) descr := engine.PrimitiveToPlanDescription(plan.Instructions)
sss, _ := json.MarshalIndent(descr, "", " ")
fmt.Println(string(sss))
bout, _ := json.MarshalIndent(testPlan{ bout, _ := json.MarshalIndent(descr, " ", " ")
Original: plan.Original, fmt.Println(string(bout))
Instructions: plan.Instructions,
}, "", " ")
return string(bout) return string(bout)
} }