Skip to content
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
fa12954
feat:support expaln statement for SCDB(#478)
zhuyanhuazhuyanhua Aug 9, 2025
84ea160
Merge branch 'secretflow:main' into main
zhuyanhuazhuyanhua Aug 9, 2025
14410ef
feat:handle explain in runSQL
zhuyanhuazhuyanhua Aug 11, 2025
71b7164
Feat:imply with runSQL
zhuyanhuazhuyanhua Aug 11, 2025
6e00a83
Merge branch 'main' into main
Candicepan Aug 22, 2025
478cab1
Feat:fix and imply in submitAndGet
zhuyanhuazhuyanhua Aug 26, 2025
6183c85
Merge branch 'main' of https://github.com/zhuyanhuazhuyanhua/scql
zhuyanhuazhuyanhua Aug 26, 2025
b92dbc6
Merge branch 'main' into main
Candicepan Aug 28, 2025
eb23b93
Feat:add isexplain test and fix submitandget
zhuyanhuazhuyanhua Aug 29, 2025
a08f5f6
Merge branch 'main' of https://github.com/zhuyanhuazhuyanhua/scql
zhuyanhuazhuyanhua Aug 29, 2025
19c9397
Feat:support select and union state in buildexplain
zhuyanhuazhuyanhua Sep 1, 2025
2a9615b
Feat:imply explain in 3 steps
zhuyanhuazhuyanhua Sep 6, 2025
8f5ee99
bug:fix bug in scdb_api.swagger.yaml
zhuyanhuazhuyanhua Sep 7, 2025
b742b93
Feat:store expalin in OutColumns instead of Status
zhuyanhuazhuyanhua Sep 9, 2025
034c377
Feat:fix SubmitAndGet in api\scdb_api.proto
zhuyanhuazhuyanhua Sep 9, 2025
c7030f3
Feat:imply explain in runSQL
zhuyanhuazhuyanhua Sep 15, 2025
1b24bbf
Feat:imply in runSQL
zhuyanhuazhuyanhua Sep 19, 2025
258d1f3
undo:imply explain in runDQL
zhuyanhuazhuyanhua Sep 25, 2025
8c6f668
Feat:imply in runSQL
zhuyanhuazhuyanhua Sep 28, 2025
9fde404
feat: add test
zhuyanhuazhuyanhua Sep 28, 2025
757e034
feat:add explain test func
zhuyanhuazhuyanhua Sep 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/scdb_api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ service SCDBService {
// This interface is suitable for executing fast queries,
// such as DDL, DCL, and simple DQL. However,
// if the query takes a long time to run, it may result in a timeout.
// Therefore, it is recommended to use the synchronous query API to run
// Therefore, it is recommended to use the asynchronous query API to run
// complex queries.
rpc SubmitAndGet(SCDBQueryRequest) returns (SCDBQueryResultResponse) {
option (google.api.http) = {
Expand Down
2 changes: 1 addition & 1 deletion cmd/regtest/test_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ func (ds *TestDataSource) getQueryResultFromMySQL(query string, needConvertDateT
case "INT", "BIGINT", "MEDIUMINT":
var a sql.NullInt64
curRowColumns[i] = &a
case "VARCHAR", "TEXT", "NVARCHAR", "LONGTEXT", "DATETIME", "DURATION", "TIMESTAMP", "DATE":
case "VARCHAR", "TEXT", "NVARCHAR", "LONGTEXT", "MEDIUMTEXT", "DATETIME", "DURATION", "TIMESTAMP", "DATE":
var a sql.NullString
curRowColumns[i] = &a
case "BOOL":
Expand Down
2 changes: 1 addition & 1 deletion docs/api/scdb_api.swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ paths:
This interface is suitable for executing fast queries,
such as DDL, DCL, and simple DQL. However,
if the query takes a long time to run, it may result in a timeout.
Therefore, it is recommended to use the synchronous query API to run
Therefore, it is recommended to use the asynchronous query API to run
complex queries.
operationId: SCDBService_SubmitAndGet
responses:
Expand Down
11 changes: 8 additions & 3 deletions pkg/planner/core/planbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -842,11 +842,16 @@ func collectVisitInfoFromGrantStmt(sctx sessionctx.Context, vi []visitInfo, stmt
}

func (b *PlanBuilder) buildExplain(ctx context.Context, explain *ast.ExplainStmt) (Plan, error) {
show, ok := explain.Stmt.(*ast.ShowStmt)
if !ok {
switch stmt := explain.Stmt.(type) {
case *ast.ShowStmt:
return b.buildShow(ctx, stmt)
case *ast.SelectStmt:
return b.buildSelect(ctx, stmt)
case *ast.UnionStmt:
return b.buildUnion(ctx, stmt)
default:
return nil, ErrUnsupportedType.GenWithStack("Unsupported explain stmt %T", explain.Stmt)
}
return b.buildShow(ctx, show)
}

func (b *PlanBuilder) buildInsert(ctx context.Context, insert *ast.InsertStmt) (Plan, error) {
Expand Down
78 changes: 78 additions & 0 deletions pkg/scdb/server/explain_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package server

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestIsExplain(t *testing.T) {
tests := []struct {
name string
query string
expected bool
hasError bool
}{
{
name: "Valid EXPLAIN query",
query: "EXPLAIN SELECT * FROM users",
expected: true,
hasError: false,
},
{
name: "Valid EXPLAIN query in lowercase",
query: "explain select * from users",
expected: true,
hasError: false,
},
{
name: "Valid EXPLAIN query with whitespace",
query: " EXPLAIN SELECT * FROM users ",
expected: true,
hasError: false,
},
{
name: "Non-EXPLAIN query",
query: "SELECT * FROM users",
expected: false,
hasError: false,
},
{
name: "INSERT query",
query: "INSERT INTO users (name) VALUES ('alice')",
expected: false,
hasError: false,
},
{
name: "Empty query",
query: "",
expected: true,
hasError: true,
},
{
name: "EXPLAIN with complex query",
query: "EXPLAIN SELECT u.name, p.title FROM users u JOIN posts p ON u.id = p.user_id WHERE u.age > 18",
expected: true,
hasError: false,
},
{
name: "EXPLAIN ANALYZE query",
query: "EXPLAIN ANALYZE SELECT * FROM users",
expected: true,
hasError: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := isExplainQuery(tt.query)

if tt.hasError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.expected, result)
}
})
}
}
26 changes: 26 additions & 0 deletions pkg/scdb/server/submit_and_get_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,32 @@ func (app *App) runDQL(ctx context.Context, s *session, async bool) (*scql.SCDBQ
}
}

isExplain, err := isExplainQuery(s.request.GetQuery())
if err != nil {
return nil, err
}

if isExplain {
explainTensor := &scql.Tensor{
Name: "explain_result",
ElemType: scql.PrimitiveDataType_STRING,
Option: scql.TensorOptions_VALUE,
}

explainTensor.StringData = []string{compiledPlan.GetExplain().GetExeGraphDot()}

return &scql.SCDBQueryResultResponse{
Status: &scql.Status{
Code: int32(scql.Code_OK),
Message: "ok",
},
OutColumns: []*scql.Tensor{explainTensor},
ScdbSessionId: s.id,
AffectedRows: 0,
Warnings: nil,
}, nil
}

engineClient := executor.NewEngineClient(
app.config.Engine.ClientMode,
app.config.Engine.ClientTimeout,
Expand Down
13 changes: 12 additions & 1 deletion pkg/scdb/server/submit_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,24 @@ func isDQL(sql string) (bool, error) {
}

switch stmt.(type) {
case *ast.SelectStmt, *ast.UnionStmt:
case *ast.SelectStmt, *ast.UnionStmt, *ast.ExplainStmt:
return true, nil
}

return false, nil
}

func isExplainQuery(sql string) (bool, error) {
p := parser.New()
stmt, err := p.ParseOneStmt(sql, "", "")
if err != nil {
return false, err
}

_, ok := stmt.(*ast.ExplainStmt)
return ok, nil
}

// compile and run dql
func (app *App) submitDQL(ctx context.Context, session *session) *scql.SCDBSubmitResponse {
_, err := app.runDQL(ctx, session, true)
Expand Down
Loading