Skip to content

Commit

Permalink
feat: support comQuery request globallock hint (#137)
Browse files Browse the repository at this point in the history
  • Loading branch information
dk-lockdown authored Jun 8, 2022
1 parent 43cf2a7 commit 437667e
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 8 deletions.
2 changes: 1 addition & 1 deletion pkg/filter/dt/exec/prepare_global_lock.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ func (executor *prepareGlobalLockExecutor) buildBeforeImageSql(tableMeta schema.
b.WriteByte(' ')
}
}
b.WriteString(fmt.Sprintf(" FROM %s WHERE ", executor.GetTableName()))
b.WriteString(fmt.Sprintf("FROM %s WHERE ", executor.GetTableName()))
b.WriteString(executor.GetWhereCondition())
return b.String()
}
Expand Down
16 changes: 11 additions & 5 deletions pkg/filter/dt/exec/prepare_global_lock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ var (
}
)

func TestGlobalLock(t *testing.T) {
func TestPrepareGlobalLock(t *testing.T) {
testCases := []*struct {
sql string
isUpdate bool
Expand All @@ -160,7 +160,7 @@ func TestGlobalLock(t *testing.T) {
lockTimes: 3,
expectedTableName: "`T`",
expectedWhereCondition: "`id`=?",
expectedBeforeImageSql: "SELECT id,name,age FROM `T` WHERE `id`=?",
expectedBeforeImageSql: "SELECT id,name,age FROM `T` WHERE `id`=?",
expectedErr: err,
},
{
Expand All @@ -170,7 +170,7 @@ func TestGlobalLock(t *testing.T) {
lockTimes: 10,
expectedTableName: "`T`",
expectedWhereCondition: "`id`=?",
expectedBeforeImageSql: "SELECT id,name,age FROM `T` WHERE `id`=?",
expectedBeforeImageSql: "SELECT id,name,age FROM `T` WHERE `id`=?",
expectedErr: nil,
},
{
Expand All @@ -180,7 +180,7 @@ func TestGlobalLock(t *testing.T) {
lockTimes: 3,
expectedTableName: "`T`",
expectedWhereCondition: "`id`=?",
expectedBeforeImageSql: "SELECT id,name,age FROM `T` WHERE `id`=?",
expectedBeforeImageSql: "SELECT id,name,age FROM `T` WHERE `id`=?",
expectedErr: err,
},
{
Expand All @@ -190,7 +190,7 @@ func TestGlobalLock(t *testing.T) {
lockTimes: 10,
expectedTableName: "`T`",
expectedWhereCondition: "`id`=?",
expectedBeforeImageSql: "SELECT id,name,age FROM `T` WHERE `id`=?",
expectedBeforeImageSql: "SELECT id,name,age FROM `T` WHERE `id`=?",
expectedErr: nil,
},
}
Expand Down Expand Up @@ -273,6 +273,12 @@ func beforeImagePatch() *gomonkey.Patches {
Type: 0,
Value: "10",
},
{
Name: "name",
KeyType: schema.Null,
Type: 0,
Value: "scott",
},
{
Name: "age",
KeyType: schema.Null,
Expand Down
46 changes: 44 additions & 2 deletions pkg/filter/dt/exec/query_global_lock.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package exec

import (
"context"
"fmt"
"strings"
"time"

Expand All @@ -26,6 +27,7 @@ import (
"github.com/cectc/dbpack/pkg/dt/schema"
"github.com/cectc/dbpack/pkg/log"
"github.com/cectc/dbpack/pkg/meta"
"github.com/cectc/dbpack/pkg/misc"
"github.com/cectc/dbpack/pkg/resource"
"github.com/cectc/dbpack/third_party/parser/ast"
"github.com/cectc/dbpack/third_party/parser/format"
Expand Down Expand Up @@ -100,6 +102,46 @@ func (executor *queryGlobalLockExecutor) GetTableName() string {
}

func (executor *queryGlobalLockExecutor) BeforeImage(ctx context.Context) (*schema.TableRecords, error) {
// todo
return nil, nil
tableMeta, err := executor.GetTableMeta(ctx)
if err != nil {
return nil, err
}

sql := executor.buildBeforeImageSql(tableMeta)
result, _, err := executor.conn.ExecuteWithWarningCount(sql, true)
if err != nil {
return nil, err
}
return schema.BuildTextRecords(tableMeta, result), nil
}

func (executor *queryGlobalLockExecutor) buildBeforeImageSql(tableMeta schema.TableMeta) string {
var b strings.Builder
b.WriteString("SELECT ")
columnCount := len(tableMeta.Columns)
for i, column := range tableMeta.Columns {
b.WriteString(misc.CheckAndReplace(column))
if i < columnCount-1 {
b.WriteByte(',')
} else {
b.WriteByte(' ')
}
}
b.WriteString(fmt.Sprintf("FROM %s WHERE ", executor.GetTableName()))
b.WriteString(executor.GetWhereCondition())
return b.String()
}

func (executor *queryGlobalLockExecutor) GetWhereCondition() string {
var sb strings.Builder
if executor.isUpdate {
if err := executor.updateStmt.Where.Restore(format.NewRestoreCtx(format.DefaultRestoreFlags, &sb)); err != nil {
log.Panic(err)
}
} else {
if err := executor.deleteStmt.Where.Restore(format.NewRestoreCtx(format.DefaultRestoreFlags, &sb)); err != nil {
log.Panic(err)
}
}
return sb.String()
}
173 changes: 173 additions & 0 deletions pkg/filter/dt/exec/query_global_lock_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/*
* Copyright 2022 CECTC, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package exec

import (
"context"
"testing"
"time"

"github.com/agiledragon/gomonkey/v2"
"github.com/stretchr/testify/assert"

"github.com/cectc/dbpack/pkg/constant"
"github.com/cectc/dbpack/pkg/driver"
"github.com/cectc/dbpack/pkg/dt/schema"
"github.com/cectc/dbpack/pkg/proto"
"github.com/cectc/dbpack/pkg/visitor"
"github.com/cectc/dbpack/third_party/parser"
"github.com/cectc/dbpack/third_party/parser/ast"
)

func TestQueryGlobalLock(t *testing.T) {
testCases := []*struct {
sql string
isUpdate bool
lockInterval time.Duration
lockTimes int
expectedTableName string
expectedWhereCondition string
expectedBeforeImageSql string
expectedErr error
}{
{
sql: "delete /*+ GlobalLock() */ from T where id = 10",
isUpdate: false,
lockInterval: 5 * time.Millisecond,
lockTimes: 3,
expectedTableName: "`T`",
expectedWhereCondition: "`id`=10",
expectedBeforeImageSql: "SELECT id,name,age FROM `T` WHERE `id`=10",
expectedErr: err,
},
{
sql: "delete /*+ GlobalLock() */ from T where id = 10",
isUpdate: false,
lockInterval: 5 * time.Millisecond,
lockTimes: 10,
expectedTableName: "`T`",
expectedWhereCondition: "`id`=10",
expectedBeforeImageSql: "SELECT id,name,age FROM `T` WHERE `id`=10",
expectedErr: nil,
},
{
sql: "update /*+ GlobalLock() */ T set age = 18 where id = 10",
isUpdate: true,
lockInterval: 5 * time.Millisecond,
lockTimes: 3,
expectedTableName: "`T`",
expectedWhereCondition: "`id`=10",
expectedBeforeImageSql: "SELECT id,name,age FROM `T` WHERE `id`=10",
expectedErr: err,
},
{
sql: "update /*+ GlobalLock() */ T set age = 18 where id = 10",
isUpdate: true,
lockInterval: 5 * time.Millisecond,
lockTimes: 10,
expectedTableName: "`T`",
expectedWhereCondition: "`id`=10",
expectedBeforeImageSql: "SELECT id,name,age FROM `T` WHERE `id`=10",
expectedErr: nil,
},
}

patches1 := isLockablePatch()
defer patches1.Reset()

patches2 := beforeImagePatch2()
defer patches2.Reset()

for _, c := range testCases {
t.Run(c.sql, func(t *testing.T) {
count = 0
p := parser.New()
stmt, err := p.ParseOneStmt(c.sql, "", "")
if err != nil {
t.Error(err)
return
}
stmt.Accept(&visitor.ParamVisitor{})

ctx := proto.WithCommandType(context.Background(), constant.ComStmtExecute)
protoStmt := &proto.Stmt{
StatementID: 1,
PrepareStmt: c.sql,
ParamsCount: 1,
ParamData: nil,
ParamsType: nil,
ColumnNames: nil,
BindVars: map[string]interface{}{
"v1": 10,
},
StmtNode: stmt,
}
ctx = proto.WithPrepareStmt(ctx, protoStmt)

var executor Executable
if c.isUpdate {
updateStmt := stmt.(*ast.UpdateStmt)
executor = NewQueryGlobalLockExecutor(&driver.BackendConnection{}, c.isUpdate, nil, updateStmt)
} else {
deleteStmt := stmt.(*ast.DeleteStmt)
executor = NewQueryGlobalLockExecutor(&driver.BackendConnection{}, c.isUpdate, deleteStmt, nil)
}
tableName := executor.GetTableName()
assert.Equal(t, c.expectedTableName, tableName)
whereCondition := executor.(*queryGlobalLockExecutor).GetWhereCondition()
assert.Equal(t, c.expectedWhereCondition, whereCondition)
beforeImageSql := executor.(*queryGlobalLockExecutor).buildBeforeImageSql(tableMeta)
assert.Equal(t, c.expectedBeforeImageSql, beforeImageSql)
_, executeErr := executor.Executable(ctx, c.lockInterval, c.lockTimes)
assert.Equal(t, c.expectedErr, executeErr)
})
}
}

func beforeImagePatch2() *gomonkey.Patches {
var executor *queryGlobalLockExecutor
return gomonkey.ApplyMethodFunc(executor, "BeforeImage", func(ctx context.Context) (*schema.TableRecords, error) {
return &schema.TableRecords{
TableMeta: tableMeta,
TableName: "t",
Rows: []*schema.Row{
{
Fields: []*schema.Field{
{
Name: "id",
KeyType: schema.PrimaryKey,
Type: 0,
Value: "10",
},
{
Name: "name",
KeyType: schema.Null,
Type: 0,
Value: "scott",
},
{
Name: "age",
KeyType: schema.Null,
Type: 0,
Value: "20",
},
},
},
},
}, nil
})
}

0 comments on commit 437667e

Please sign in to comment.