From bf736aee7e01f2320f81588cff4552ec4e28d680 Mon Sep 17 00:00:00 2001 From: huby2358 Date: Thu, 26 Dec 2024 11:33:05 +0800 Subject: [PATCH 1/2] if delete can't rewrite to truncate table, use bind_delete make new plan --- pkg/sql/plan/bind_delete.go | 51 ++++++++++++++++++++++++++++++++----- pkg/sql/plan/build.go | 2 +- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/pkg/sql/plan/bind_delete.go b/pkg/sql/plan/bind_delete.go index 9980ec7e8ce4e..611c267d6acda 100644 --- a/pkg/sql/plan/bind_delete.go +++ b/pkg/sql/plan/bind_delete.go @@ -24,14 +24,40 @@ import ( "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" ) -func (builder *QueryBuilder) bindDelete(stmt *tree.Delete, bindCtx *BindContext) (int32, error) { - if len(stmt.Tables) != 1 { - return 0, moerr.NewUnsupportedDML(builder.GetContext(), "delete from multiple tables") +func canDeleteRewriteToTruncate(ctx CompilerContext, dmlCtx DMLContext) (bool, error) { + accountId, err := ctx.GetAccountId() + if err != nil { + return false, err } - //FIXME: optimize truncate table? - if stmt.Where == nil && stmt.Limit == nil { - return 0, moerr.NewUnsupportedDML(builder.GetContext(), "rewrite to truncate table") + deleteOptToTruncate, err := checkDeleteOptToTruncate(ctx) + if err != nil { + return false, err + } + + if !deleteOptToTruncate { + return false, nil + } + + enabled, err := IsForeignKeyChecksEnabled(ctx) + if err != nil { + return false, err + } + + for i, tableDef := range dmlCtx.tableDefs { + if enabled && len(tableDef.RefChildTbls) > 0 || + tableDef.ViewSql != nil || + (dmlCtx.isClusterTable[i] && accountId != catalog.System_Account) || + dmlCtx.objRefs[i].PubInfo != nil { + return false, nil + } + } + return true, nil +} + +func (builder *QueryBuilder) bindDelete(ctx CompilerContext, stmt *tree.Delete, bindCtx *BindContext) (int32, error) { + if len(stmt.Tables) != 1 { + return 0, moerr.NewUnsupportedDML(builder.GetContext(), "delete from multiple tables") } aliasMap := make(map[string][2]string) @@ -45,6 +71,19 @@ func (builder *QueryBuilder) bindDelete(stmt *tree.Delete, bindCtx *BindContext) return 0, err } + //FIXME: optimize truncate table? + if stmt.Where == nil && stmt.Limit == nil { + var cantrucate bool + cantrucate, err = canDeleteRewriteToTruncate(ctx, *dmlCtx) + if err != nil { + return 0, err + } + + if cantrucate { + return 0, moerr.NewUnsupportedDML(builder.GetContext(), "rewrite to truncate table") + } + } + var selectList []tree.SelectExpr colName2Idx := make([]map[string]int32, len(stmt.Tables)) diff --git a/pkg/sql/plan/build.go b/pkg/sql/plan/build.go index 8361aa32f5c58..0cc77c5188b49 100644 --- a/pkg/sql/plan/build.go +++ b/pkg/sql/plan/build.go @@ -140,7 +140,7 @@ func bindAndOptimizeDeleteQuery(ctx CompilerContext, stmt *tree.Delete, isPrepar bindCtx.snapshot = ctx.GetSnapshot() } - rootId, err := builder.bindDelete(stmt, bindCtx) + rootId, err := builder.bindDelete(ctx, stmt, bindCtx) if err != nil { if err.(*moerr.Error).ErrorCode() == moerr.ErrUnsupportedDML { return buildDelete(stmt, ctx, isPrepareStmt) From acc417b22e5ca084b9205565ef539768993d0ca7 Mon Sep 17 00:00:00 2001 From: huby2358 Date: Sun, 26 Jan 2025 18:11:25 +0800 Subject: [PATCH 2/2] add ut --- pkg/sql/plan/bind_delete.go | 4 ++-- pkg/sql/plan/build_test.go | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/pkg/sql/plan/bind_delete.go b/pkg/sql/plan/bind_delete.go index 611c267d6acda..f492d4ee71bac 100644 --- a/pkg/sql/plan/bind_delete.go +++ b/pkg/sql/plan/bind_delete.go @@ -24,7 +24,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" ) -func canDeleteRewriteToTruncate(ctx CompilerContext, dmlCtx DMLContext) (bool, error) { +func canDeleteRewriteToTruncate(ctx CompilerContext, dmlCtx *DMLContext) (bool, error) { accountId, err := ctx.GetAccountId() if err != nil { return false, err @@ -74,7 +74,7 @@ func (builder *QueryBuilder) bindDelete(ctx CompilerContext, stmt *tree.Delete, //FIXME: optimize truncate table? if stmt.Where == nil && stmt.Limit == nil { var cantrucate bool - cantrucate, err = canDeleteRewriteToTruncate(ctx, *dmlCtx) + cantrucate, err = canDeleteRewriteToTruncate(ctx, dmlCtx) if err != nil { return 0, err } diff --git a/pkg/sql/plan/build_test.go b/pkg/sql/plan/build_test.go index 441bf93b439ce..ee28d83f20514 100644 --- a/pkg/sql/plan/build_test.go +++ b/pkg/sql/plan/build_test.go @@ -22,8 +22,11 @@ import ( "strings" "testing" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + "github.com/matrixorigin/matrixone/pkg/catalog" + "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/pb/plan" "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect/mysql" @@ -1243,3 +1246,15 @@ func Test_limitUint64(t *testing.T) { outPutPlan(logicPlan, true, t) } } + +// test canDeleteRewriteToTruncate +func Test_bind_delete(t *testing.T) { + ctx := context.TODO() + ctrl := gomock.NewController(t) + compileCtx := NewMockCompilerContext2(ctrl) + compileCtx.EXPECT().ResolveVariable(gomock.Any(), gomock.Any(), gomock.Any()).Return("", nil).AnyTimes() + compileCtx.EXPECT().GetAccountId().Return(catalog.System_Account, moerr.NewInternalError(ctx, "no account id in context")).AnyTimes() + dmlCtx := &DMLContext{} + _, err := canDeleteRewriteToTruncate(compileCtx, dmlCtx) + assert.Error(t, err) +}