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 {
return PlanDescription{OperatorType: "fake - not implemented"}
return PlanDescription{OperatorType: "fake"}
}

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

@ -23,6 +23,7 @@ import (
"math"
"reflect"
"sort"
"strings"
"vitess.io/vitess/go/sqltypes"
"vitess.io/vitess/go/vt/key"
@ -201,20 +202,27 @@ func (ms *MemorySort) description() PlanDescription {
}
func orderByParamsToString(i interface{}) string {
ob := i.(OrderbyParams)
return ob.String()
return i.(OrderbyParams).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 {
sl := reflect.ValueOf(input)
str := ""
for i := 0; i < sl.Len(); i++ {
if len(str) != 0 {
str += ","
var keys []string
switch sl.Kind() {
case reflect.Slice:
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.

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

@ -18,6 +18,9 @@ package engine
import (
"fmt"
"strconv"
"vitess.io/vitess/go/vt/key"
"vitess.io/vitess/go/vt/proto/vtrpc"
"vitess.io/vitess/go/vt/vterrors"
@ -67,6 +70,14 @@ func (ap AggregateParams) isDistinct() bool {
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.
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)
}
func aggregateParamsToString(in interface{}) string {
return in.(AggregateParams).String()
}
func intToString(i interface{}) string {
return strconv.Itoa(i.(int))
}
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{
OperatorType: "OrderedAggregation not implemented",
Other: nil,
OperatorType: "Aggregate",
Variant: "Ordered",
TargetDestination: key.DestinationVtGate{},
Other: other,
}
}

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

@ -17,6 +17,8 @@ limitations under the License.
package engine
import (
"encoding/json"
"vitess.io/vitess/go/vt/key"
topodatapb "vitess.io/vitess/go/vt/proto/topodata"
"vitess.io/vitess/go/vt/vtgate/vindexes"
@ -25,16 +27,42 @@ import (
// PlanDescription is used to create a serializable representation of the Primitive tree
type PlanDescription struct {
OperatorType string
Variant string
Variant string `json:",omitempty"`
// 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 key.Destination
TargetDestination key.Destination `json:",omitempty"`
// TargetTabletType specifies an explicit target destination tablet type
// this is only used in conjunction with TargetDestination
TargetTabletType topodatapb.TabletType
Other map[string]string
Inputs []PlanDescription
TargetTabletType topodatapb.TabletType `json:",omitempty"`
Other map[string]string `json:",omitempty"`
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

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

@ -19,6 +19,8 @@ package engine
import (
"fmt"
"vitess.io/vitess/go/vt/key"
"vitess.io/vitess/go/sqltypes"
"vitess.io/vitess/go/vt/vterrors"
@ -31,11 +33,14 @@ var _ Primitive = (*PulloutSubquery)(nil)
// PulloutSubquery executes a "pulled out" subquery and stores
// the results in a bind variable.
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
HasValues string
Subquery Primitive
Underlying Primitive
Subquery Primitive
Underlying Primitive
}
// 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 {
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

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

@ -18,6 +18,7 @@ package engine
import (
"vitess.io/vitess/go/sqltypes"
"vitess.io/vitess/go/vt/key"
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 {
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)
sss, _ := json.MarshalIndent(descr, "", " ")
fmt.Println(string(sss))
bout, _ := json.MarshalIndent(testPlan{
Original: plan.Original,
Instructions: plan.Instructions,
}, "", " ")
bout, _ := json.MarshalIndent(descr, " ", " ")
fmt.Println(string(bout))
return string(bout)
}