Skip to content

Commit

Permalink
sql: add an EXPLAIN (DISTSQL, JSON) variant
Browse files Browse the repository at this point in the history
Add a JSON flag to EXPLAIN (DISTSQL); in this variant we only return
the diagram JSON. This is used for a server API endpoint which used
the json column before. The flag should not be documented for users.

Release note: None
  • Loading branch information
RaduBerinde committed Dec 16, 2020
1 parent 5e143ac commit bb37214
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 12 deletions.
2 changes: 1 addition & 1 deletion pkg/server/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -1593,7 +1593,7 @@ func (s *adminServer) QueryPlan(
}

explain := fmt.Sprintf(
"SELECT json FROM [EXPLAIN (DISTSQL) %s]",
"EXPLAIN (DISTSQL, JSON) %s",
strings.Trim(req.Query, ";"))
rows, err := s.server.sqlServer.internalExecutor.QueryEx(
ctx, "admin-query-plan", nil, /* txn */
Expand Down
4 changes: 2 additions & 2 deletions pkg/sql/distsql_physical_planner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ func TestDistSQLRangeCachesIntegrationTest(t *testing.T) {
// of the splits and still holds the state after the first dummy query at the
// beginning of the test, which had everything on the first node.
query := `SELECT count(1) FROM "left" INNER JOIN "right" USING (num)`
row := db3.QueryRow(fmt.Sprintf(`SELECT json FROM [EXPLAIN (DISTSQL) %v]`, query))
row := db3.QueryRow(fmt.Sprintf(`EXPLAIN (DISTSQL, JSON) %v`, query))
var json string
if err := row.Scan(&json); err != nil {
t.Fatal(err)
Expand All @@ -431,7 +431,7 @@ func TestDistSQLRangeCachesIntegrationTest(t *testing.T) {
// Now assert that new plans correctly contain all the nodes. This is expected
// to be a result of the caches having been updated on the gateway by the
// previous query.
row = db3.QueryRow(fmt.Sprintf(`SELECT json FROM [EXPLAIN (DISTSQL) %v]`, query))
row = db3.QueryRow(fmt.Sprintf(`EXPLAIN (DISTSQL, JSON) %v`, query))
if err := row.Scan(&json); err != nil {
t.Fatal(err)
}
Expand Down
23 changes: 15 additions & 8 deletions pkg/sql/explain_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (e *explainPlanNode) startExec(params runParams) error {
ob := explain.NewOutputBuilder(e.flags)
plan := e.plan.WrappedPlan.(*planComponents)

// Determine the "distributed" and "vectorized" values, which we will emit as
// Determine the "distribution" and "vectorized" values, which we will emit as
// special rows.

distribution := getPlanDistribution(
Expand All @@ -67,6 +67,7 @@ func (e *explainPlanNode) startExec(params runParams) error {
}()
physicalPlan, err := newPhysPlanForExplainPurposes(planCtx, distSQLPlanner, plan.main)
var diagramURL url.URL
var diagramJSON string
if err != nil {
if e.options.Mode == tree.ExplainDistSQL {
if len(plan.subqueryPlans) > 0 {
Expand Down Expand Up @@ -111,21 +112,27 @@ func (e *explainPlanNode) startExec(params runParams) error {
return err
}

_, diagramURL, err = diagram.ToURL()
diagramJSON, diagramURL, err = diagram.ToURL()
if err != nil {
return err
}
}
}

if err := emitExplain(ob, params.EvalContext(), params.p.ExecCfg().Codec, e.plan); err != nil {
return err
var rows []string
if e.options.Flags[tree.ExplainFlagJSON] {
// For the JSON flag, we only want to emit the diagram JSON.
rows = []string{diagramJSON}
} else {
if err := emitExplain(ob, params.EvalContext(), params.p.ExecCfg().Codec, e.plan); err != nil {
return err
}
rows = ob.BuildStringRows()
if e.options.Mode == tree.ExplainDistSQL {
rows = append(rows, "", fmt.Sprintf("Diagram: %s", diagramURL.String()))
}
}
v := params.p.newContainerValuesNode(colinfo.ExplainPlanColumns, 0)
rows := ob.BuildStringRows()
if e.options.Mode == tree.ExplainDistSQL {
rows = append(rows, "", fmt.Sprintf("Diagram: %s", diagramURL.String()))
}
datums := make([]tree.DString, len(rows))
for i, row := range rows {
datums[i] = tree.DString(row)
Expand Down
6 changes: 6 additions & 0 deletions pkg/sql/opt/exec/execbuilder/testdata/distsql_auto_mode
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ SET distsql=auto
statement ok
CREATE TABLE kv (k INT PRIMARY KEY, v INT)

# Verify the JSON variant.
query T
EXPLAIN (DISTSQL, JSON) SELECT 1
----
{"sql":"EXPLAIN (DISTSQL, JSON) SELECT 1","nodeNames":["1"],"processors":[{"nodeIdx":0,"inputs":[],"core":{"title":"local values 0/0","details":[]},"outputs":[],"stage":1},{"nodeIdx":0,"inputs":[],"core":{"title":"Response","details":[]},"outputs":[],"stage":0}],"edges":[{"sourceProc":0,"sourceOutput":0,"destProc":1,"destInput":0}]}

# Full table scan - distribute.
query T
SELECT info FROM [EXPLAIN SELECT * FROM kv] WHERE info LIKE 'distribution%'
Expand Down
2 changes: 1 addition & 1 deletion pkg/sql/opt/exec/execbuilder/testdata/distsql_misc
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ subtest scrub
# ON leftside.v = rightside.v AND leftside.k = rightside.k AND leftside.data = rightside.data
# WHERE (leftside.k IS NULL) OR
# (rightside.k IS NULL)
# ]
# ----
# https://cockroachdb.github.io/distsqlplan/decode.html#eJyckc2K2zAQgO99CjGnLBlIJDs9CAq6dCFLGpdscio-uNY0a3AkM5Khy5J3L45hNw5x2vQ4I33zzc8bOG9pXRwogP4BEnKEhn1JIXjuUv2Hpf0Neo5QuaaNXTpHKD0T6DeIVawJNGyLnzVtqLDEszkgWIpFVZ_KNlwdCn41kUIEhKyNWhiFRqJJID8i-DZ-FA6x2BNoecR_lz97jsQzOfQaOUWjpmiS6ahG3aM5n1ENXYFK7-zdUyb_MWUyPiXCoYjli6jJaaFGremo9UPWOs-WmOzAlnfk375caf0b8Z6efOWIZ-mw_-1rQ1o87lYrke22XzfiKVuuAaGmX3FyNtzDF672L8MUIDxWdSTWYmKUWD6L9W61ehDZRkzM4j1-P4fE7iIJmhTNAs3n0Q0t7rnLhkLjXaDLTV2tPO_WQ3ZP_bqDb7mk7-zLk6YPsxN3SlgKsX-VfbB0_VPX4Dksb8LpAJaXsLoJJ7fNyR1mdQmnN-HFhTk_fvoTAAD__3P7gDg=
#
# # Verify the foreign key check execution plan uses a merge join.
Expand Down
2 changes: 2 additions & 0 deletions pkg/sql/parser/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,8 @@ func TestParse(t *testing.T) {

{`EXPLAIN SELECT 1`},
{`EXPLAIN EXPLAIN SELECT 1`},
{`EXPLAIN (DISTSQL) SELECT 1`},
{`EXPLAIN (DISTSQL, JSON) SELECT 1`},
{`EXPLAIN (OPT, VERBOSE) SELECT 1`},
{`EXPLAIN ANALYZE (DISTSQL) SELECT 1`},
{`EXPLAIN ANALYZE (DEBUG) SELECT 1`},
Expand Down
24 changes: 24 additions & 0 deletions pkg/sql/parser/testdata/errors
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,30 @@ DETAIL: source SQL:
EXPLAIN (PLAN, DEBUG) SELECT 1
^

error
EXPLAIN (JSON) SELECT 1
----
at or near "EOF": syntax error: the JSON flag can only be used with DISTSQL
DETAIL: source SQL:
EXPLAIN (JSON) SELECT 1
^

error
EXPLAIN (PLAN, JSON) SELECT 1
----
at or near "EOF": syntax error: the JSON flag can only be used with DISTSQL
DETAIL: source SQL:
EXPLAIN (PLAN, JSON) SELECT 1
^

error
EXPLAIN ANALYZE (DISTSQL, JSON) SELECT 1
----
at or near "EOF": syntax error: the JSON flag cannot be used with ANALYZE
DETAIL: source SQL:
EXPLAIN ANALYZE (DISTSQL, JSON) SELECT 1
^

error
SELECT $0
----
Expand Down
10 changes: 10 additions & 0 deletions pkg/sql/sem/tree/explain.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ const (
ExplainFlagTypes
ExplainFlagEnv
ExplainFlagCatalog
ExplainFlagJSON
numExplainFlags = iota
)

Expand All @@ -112,6 +113,7 @@ var explainFlagStrings = [...]string{
ExplainFlagTypes: "TYPES",
ExplainFlagEnv: "ENV",
ExplainFlagCatalog: "CATALOG",
ExplainFlagJSON: "JSON",
}

var explainFlagStringMap = func() map[string]ExplainFlag {
Expand Down Expand Up @@ -236,6 +238,14 @@ func MakeExplain(options []string, stmt Statement) (Statement, error) {
// Default mode is ExplainPlan.
opts.Mode = ExplainPlan
}
if opts.Flags[ExplainFlagJSON] {
if opts.Mode != ExplainDistSQL {
return nil, pgerror.Newf(pgcode.Syntax, "the JSON flag can only be used with DISTSQL")
}
if analyze {
return nil, pgerror.Newf(pgcode.Syntax, "the JSON flag cannot be used with ANALYZE")
}
}

if analyze {
if opts.Mode != ExplainDistSQL && opts.Mode != ExplainDebug && opts.Mode != ExplainPlan {
Expand Down

0 comments on commit bb37214

Please sign in to comment.