Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update code of relation exist check #20423

Merged
89 changes: 59 additions & 30 deletions pkg/sql/compile/ddl.go
Original file line number Diff line number Diff line change
Expand Up @@ -929,31 +929,39 @@ func (s *Scope) CreateTable(c *Compile) error {
}
return err
}
if _, err := dbSource.Relation(c.proc.Ctx, tblName, nil); err == nil {
if qry.GetIfNotExists() {
return nil
}

c.proc.Info(c.proc.Ctx, "createTable",
exists, err := dbSource.RelationExists(c.proc.Ctx, tblName, nil)
if err != nil {
c.proc.Error(c.proc.Ctx, "check table relation exists failed",
zap.String("databaseName", c.db),
zap.String("tableName", qry.GetTableDef().GetName()),
zap.String("tableName", tblName),
zap.Error(err),
)
return err
}
if exists {
if qry.GetIfNotExists() {
return nil
}
return moerr.NewTableAlreadyExists(c.proc.Ctx, tblName)
}

// check in EntireEngine.TempEngine, notice that TempEngine may not init
tmpDBSource, err := c.e.Database(c.proc.Ctx, defines.TEMPORARY_DBNAME, c.proc.GetTxnOperator())
if err == nil {
if _, err := tmpDBSource.Relation(c.proc.Ctx, engine.GetTempTableName(dbName, tblName), nil); err == nil {
if qry.GetIfNotExists() {
return nil
}
c.proc.Info(c.proc.Ctx, "createTable",
exists, err := tmpDBSource.RelationExists(c.proc.Ctx, engine.GetTempTableName(dbName, tblName), nil)
if err != nil {
c.proc.Error(c.proc.Ctx, "check temporary table relation exists failed",
zap.String("databaseName", c.db),
zap.String("tableName", qry.GetTableDef().GetName()),
zap.String("tableName", tblName),
zap.Error(err),
)
return err
}
if exists {
if qry.GetIfNotExists() {
return nil
}
return moerr.NewTableAlreadyExists(c.proc.Ctx, fmt.Sprintf("temporary '%s'", tblName))
}
}
Expand Down Expand Up @@ -1273,14 +1281,20 @@ func (s *Scope) CreateTable(c *Compile) error {
)
return err
}
if _, err := dbSource.Relation(c.proc.Ctx, def.Name, nil); err == nil {
c.proc.Info(c.proc.Ctx, "createTable",

exists, err := dbSource.RelationExists(c.proc.Ctx, def.Name, nil)
if err != nil {
c.proc.Error(c.proc.Ctx, "check index relation exists failed",
zap.String("databaseName", c.db),
zap.String("tableName", qry.GetTableDef().GetName()),
zap.String("tableName", def.GetName()),
zap.Error(err),
)
return err
}
if exists {
return moerr.NewTableAlreadyExists(c.proc.Ctx, def.Name)
}

if err := dbSource.Create(c.proc.Ctx, def.Name, append(exeCols, exeDefs...)); err != nil {
c.proc.Info(c.proc.Ctx, "createTable",
zap.String("databaseName", c.db),
Expand Down Expand Up @@ -1480,43 +1494,52 @@ func (s *Scope) CreateView(c *Compile) error {
}

viewName := qry.GetTableDef().GetName()
if _, err = dbSource.Relation(c.proc.Ctx, viewName, nil); err == nil {
exists, err := dbSource.RelationExists(c.proc.Ctx, viewName, nil)
if err != nil {
getLogger(s.Proc.GetService()).Error("check view relation exists failed",
zap.String("databaseName", c.db),
zap.String("viewName", qry.GetTableDef().GetName()),
zap.Error(err),
)
return err
}

if exists {
if qry.GetIfNotExists() {
return nil
}

if qry.GetReplace() {
err = c.runSql(fmt.Sprintf("drop view if exists %s", viewName))
if err != nil {
getLogger(s.Proc.GetService()).Info("createView",
getLogger(s.Proc.GetService()).Error("drop existing view failed",
zap.String("databaseName", c.db),
zap.String("viewName", qry.GetTableDef().GetName()),
zap.Error(err),
)
return err
}
} else {
getLogger(s.Proc.GetService()).Info("createView",
zap.String("databaseName", c.db),
zap.String("viewName", qry.GetTableDef().GetName()),
zap.Error(err),
)
return moerr.NewTableAlreadyExists(c.proc.Ctx, viewName)
}
}

// check in EntireEngine.TempEngine, notice that TempEngine may not init
tmpDBSource, err := c.e.Database(c.proc.Ctx, defines.TEMPORARY_DBNAME, c.proc.GetTxnOperator())
if err == nil {
if _, err = tmpDBSource.Relation(c.proc.Ctx, engine.GetTempTableName(dbName, viewName), nil); err == nil {
if qry.GetIfNotExists() {
return nil
}
getLogger(s.Proc.GetService()).Info("createView",
exists, err = tmpDBSource.RelationExists(c.proc.Ctx, engine.GetTempTableName(dbName, viewName), nil)
if err != nil {
c.proc.Error(c.proc.Ctx, "check temporary table relation exists failed",
zap.String("databaseName", c.db),
zap.String("viewName", qry.GetTableDef().GetName()),
zap.String("tableName", viewName),
zap.Error(err),
)
return err
}
if exists {
if qry.GetIfNotExists() {
return nil
}
return moerr.NewTableAlreadyExists(c.proc.Ctx, fmt.Sprintf("temporary '%s'", viewName))
}
}
Expand Down Expand Up @@ -1781,14 +1804,20 @@ func indexTableBuild(c *Compile, def *plan.TableDef, dbSource engine.Database) e
)
return err
}
if _, err = dbSource.Relation(c.proc.Ctx, def.Name, nil); err == nil {
c.proc.Info(c.proc.Ctx, "createTable",

exists, err := dbSource.RelationExists(c.proc.Ctx, def.Name, nil)
if err != nil {
c.proc.Error(c.proc.Ctx, "check index relation exists failed",
zap.String("databaseName", c.db),
zap.String("tableName", def.GetName()),
zap.Error(err),
)
return err
}
if exists {
return moerr.NewTableAlreadyExists(c.proc.Ctx, def.Name)
}

if err = dbSource.Create(c.proc.Ctx, def.Name, append(exeCols, exeDefs...)); err != nil {
c.proc.Info(c.proc.Ctx, "createTable",
zap.String("databaseName", c.db),
Expand Down
168 changes: 168 additions & 0 deletions pkg/sql/compile/ddl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,18 @@ package compile
import (
"context"
"testing"
"time"

"github.com/golang/mock/gomock"
"github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/assert"

"github.com/matrixorigin/matrixone/pkg/common/buffer"
"github.com/matrixorigin/matrixone/pkg/common/moerr"
"github.com/matrixorigin/matrixone/pkg/defines"
mock_frontend "github.com/matrixorigin/matrixone/pkg/frontend/test"
plan2 "github.com/matrixorigin/matrixone/pkg/pb/plan"
"github.com/matrixorigin/matrixone/pkg/sql/plan"
"github.com/matrixorigin/matrixone/pkg/testutil"
"github.com/matrixorigin/matrixone/pkg/vm/engine"
"github.com/matrixorigin/matrixone/pkg/vm/process"
Expand Down Expand Up @@ -76,3 +83,164 @@ func Test_lockIndexTable(t *testing.T) {
})
}
}

func TestScope_CreateTable(t *testing.T) {
tableDef := &plan.TableDef{
Name: "dept",
Cols: []*plan.ColDef{
{
ColId: 0,
Name: "deptno",
Alg: plan2.CompressType_Lz4,
Typ: plan.Type{
Id: 27,
NotNullable: false,
AutoIncr: true,
Width: 32,
Scale: -1,
},
Default: &plan2.Default{},
NotNull: true,
Primary: true,
Pkidx: 0,
},
{
ColId: 1,
Name: "dname",
Alg: plan2.CompressType_Lz4,
Typ: plan.Type{
Id: 61,
NotNullable: false,
AutoIncr: false,
Width: 15,
Scale: 0,
},
Default: &plan2.Default{},
NotNull: false,
Primary: false,
Pkidx: 0,
},
{
ColId: 2,
Name: "loc",
Alg: plan2.CompressType_Lz4,
Typ: plan.Type{
Id: 61,
NotNullable: false,
AutoIncr: false,
Width: 50,
Scale: 0,
},
Default: &plan2.Default{},
NotNull: false,
Primary: false,
Pkidx: 0,
},
},
Pkey: &plan.PrimaryKeyDef{
Cols: nil,
PkeyColId: 0,
PkeyColName: "deptno",
Names: []string{"deptno"},
},
Defs: []*plan2.TableDef_DefType{
{
Def: &plan.TableDef_DefType_Properties{
Properties: &plan.PropertiesDef{
Properties: []*plan.Property{
{
Key: "relkind",
Value: "r",
},
},
},
},
},
},
}

createTableDef := &plan2.CreateTable{
IfNotExists: false,
Database: "test",
Replace: false,
TableDef: tableDef,
}

cplan := &plan.Plan{
Plan: &plan2.Plan_Ddl{
Ddl: &plan2.DataDefinition{
DdlType: plan2.DataDefinition_CREATE_TABLE,
Definition: &plan2.DataDefinition_CreateTable{
CreateTable: createTableDef,
},
},
},
}

s := &Scope{
Magic: CreateTable,
Plan: cplan,
TxnOffset: 0,
}

sql := `create table dept(
deptno int unsigned auto_increment COMMENT '部门编号',
dname varchar(15) COMMENT '部门名称',
loc varchar(50) COMMENT '部门所在位置',
primary key(deptno)
) COMMENT='部门表'`

convey.Convey("create table FaultTolerance1", t, func() {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

proc := testutil.NewProcess()
proc.Base.SessionInfo.Buf = buffer.New()

ctx := context.Background()
proc.Ctx = context.Background()
proc.ReplaceTopCtx(ctx)

eng := mock_frontend.NewMockEngine(ctrl)
mockDbMeta := mock_frontend.NewMockDatabase(ctrl)
eng.EXPECT().Database(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockDbMeta, nil)

mockDbMeta.EXPECT().RelationExists(gomock.Any(), gomock.Any(), gomock.Any()).Return(false, moerr.NewInternalErrorNoCtx("test"))

c := NewCompile("test", "test", sql, "", "", eng, proc, nil, false, nil, time.Now())
assert.Error(t, s.CreateTable(c))
})

convey.Convey("create table FaultTolerance1", t, func() {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

proc := testutil.NewProcess()
proc.Base.SessionInfo.Buf = buffer.New()

ctx := context.Background()
proc.Ctx = context.Background()
proc.ReplaceTopCtx(ctx)

relation := mock_frontend.NewMockRelation(ctrl)

mockDbMeta := mock_frontend.NewMockDatabase(ctrl)
mockDbMeta.EXPECT().Relation(gomock.Any(), gomock.Any(), gomock.Any()).Return(relation, nil).AnyTimes()
mockDbMeta.EXPECT().RelationExists(gomock.Any(), gomock.Any(), gomock.Any()).Return(false, nil).AnyTimes()

mockDbMeta2 := mock_frontend.NewMockDatabase(ctrl)
mockDbMeta2.EXPECT().RelationExists(gomock.Any(), gomock.Any(), gomock.Any()).Return(false, moerr.NewInternalErrorNoCtx("test"))

eng := mock_frontend.NewMockEngine(ctrl)
eng.EXPECT().Database(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, name string, arg any) (engine.Database, error) {
if name == defines.TEMPORARY_DBNAME {
return mockDbMeta2, nil
}
return mockDbMeta, nil
}).AnyTimes()

c := NewCompile("test", "test", sql, "", "", eng, proc, nil, false, nil, time.Now())
assert.Error(t, s.CreateTable(c))
})

}
Binary file modified test/distributed/cases/table/create_table.result
Binary file not shown.
13 changes: 13 additions & 0 deletions test/distributed/cases/table/create_table.test
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,19 @@ show create table test04.employees;
show create table test04.employee_view;
show create table test05.employee_with_department_view;

CREATE TEMPORARY TABLE temp_employees (
id INT,
name VARCHAR(100),
salary DECIMAL(10, 2)
);

CREATE TABLE IF NOT EXISTS temp_employees (
id INT,
name VARCHAR(100),
salary DECIMAL(10, 2)
);


drop database test04;
drop database test03;
drop database test05;
Loading