diff --git a/bql/planner/planner.go b/bql/planner/planner.go index 85d5f16a..cbbab3fb 100644 --- a/bql/planner/planner.go +++ b/bql/planner/planner.go @@ -37,6 +37,9 @@ import ( type Executor interface { // Execute runs the proposed plan for a given statement. Execute(ctx context.Context) (*table.Table, error) + + // String returns a readable description of the execution plan. + String() string } // createPlan encapsulates the sequence of instructions that need to be @@ -64,6 +67,11 @@ func (p *createPlan) Execute(ctx context.Context) (*table.Table, error) { return t, nil } +// String returns a readable description of the execution plan. +func (p *createPlan) String() string { + return "not implemented" +} + // dropPlan encapsulates the sequence of instructions that need to be // executed in order to satisfy the execution of a valid drop BQL statement. type dropPlan struct { @@ -89,6 +97,11 @@ func (p *dropPlan) Execute(ctx context.Context) (*table.Table, error) { return t, nil } +// String returns a readable description of the execution plan. +func (p *dropPlan) String() string { + return "not implemented" +} + // insertPlan encapsulates the sequence of instructions that need to be // executed in order to satisfy the execution of a valid insert BQL statement. type insertPlan struct { @@ -143,6 +156,11 @@ func (p *insertPlan) Execute(ctx context.Context) (*table.Table, error) { }) } +// String returns a readable description of the execution plan. +func (p *insertPlan) String() string { + return "not implemented" +} + // deletePlan encapsulates the sequence of instructions that need to be // executed in order to satisfy the execution of a valid delete BQL statement. type deletePlan struct { @@ -161,6 +179,11 @@ func (p *deletePlan) Execute(ctx context.Context) (*table.Table, error) { }) } +// String returns a readable description of the execution plan. +func (p *deletePlan) String() string { + return "not implemented" +} + // queryPlan encapsulates the sequence of instructions that need to be // executed in order to satisfy the execution of a valid query BQL statement. type queryPlan struct { @@ -615,6 +638,11 @@ func (p *queryPlan) Execute(ctx context.Context) (*table.Table, error) { return p.tbl, nil } +// String returns a readable description of the execution plan. +func (p *queryPlan) String() string { + return "not implemented" +} + // New create a new executable plan given a semantic BQL statement. func New(ctx context.Context, store storage.Store, stm *semantic.Statement, chanSize int) (Executor, error) { switch stm.Type() { diff --git a/bql/semantic/semantic.go b/bql/semantic/semantic.go index 629949c4..8dd3196a 100644 --- a/bql/semantic/semantic.go +++ b/bql/semantic/semantic.go @@ -84,6 +84,11 @@ type Statement struct { lookupOptions storage.LookupOptions } +// String returns a readable representaion of a statement. +func (s *Statement) String() string { + return "" +} + // GraphClause represents a clause of a graph pattern in a where clause. type GraphClause struct { S *node.Node @@ -120,6 +125,11 @@ type GraphClause struct { OTemporal bool } +// String returns a readable representaion of a graph clause. +func (c *GraphClause) String() string { + return "" +} + // Specificity return func (c *GraphClause) Specificity() int { s := 0 diff --git a/tools/vcli/bw/repl/repl.go b/tools/vcli/bw/repl/repl.go index b81fad62..e36f54ec 100644 --- a/tools/vcli/bw/repl/repl.go +++ b/tools/vcli/bw/repl/repl.go @@ -123,6 +123,18 @@ func REPL(driver storage.Store, input *os.File, rl ReadLiner, chanSize, bulkSize l = "" continue } + if strings.HasPrefix(l, "desc") { + pln, err := planBQL(ctx, l[4:], driver, chanSize) + if err != nil { + fmt.Printf("[ERROR] %s\n\n", err) + } else { + fmt.Println(pln.String()) + fmt.Println("[OK]") + } + fmt.Print(prompt) + l = "" + continue + } if strings.HasPrefix(l, "run") { path, cmds, err := runBQLFromFile(ctx, driver, chanSize, strings.TrimSpace(l[:len(l)-1])) if err != nil { @@ -154,6 +166,7 @@ func REPL(driver storage.Store, input *os.File, rl ReadLiner, chanSize, bulkSize func printHelp() { fmt.Println("help - prints help for the bw console.") fmt.Println("export - dumps triples from graphs into a file path.") + fmt.Println("desc - prints the execution plan for a BQL statement.") fmt.Println("load - load triples into the specified graphs.") fmt.Println("run - runs all the BQL statements in the file.") fmt.Println("quit - quits the console.") @@ -184,6 +197,19 @@ func runBQLFromFile(ctx context.Context, driver storage.Store, chanSize int, lin // runBQL attempts to execute the provided query against the given store. func runBQL(ctx context.Context, bql string, s storage.Store, chanSize int) (*table.Table, error) { + pln, err := planBQL(ctx, bql, s, chanSize) + if err != nil { + return nil, err + } + res, err := pln.Execute(ctx) + if err != nil { + return nil, fmt.Errorf("planner.Execute: failed to execute insert plan with error %v", err) + } + return res, nil +} + +// planBQL attempts to create the excecution plan for the provided query against the given store. +func planBQL(ctx context.Context, bql string, s storage.Store, chanSize int) (planner.Executor, error) { p, err := grammar.NewParser(grammar.SemanticBQL()) if err != nil { return nil, fmt.Errorf("failed to initilize a valid BQL parser") @@ -196,9 +222,5 @@ func runBQL(ctx context.Context, bql string, s storage.Store, chanSize int) (*ta if err != nil { return nil, fmt.Errorf("should have not failed to create a plan using memory.DefaultStorage for statement %v with error %v", stm, err) } - res, err := pln.Execute(ctx) - if err != nil { - return nil, fmt.Errorf("planner.Execute: failed to execute insert plan with error %v", err) - } - return res, nil + return pln, nil }