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

drainer:sync lob data to oracle #1158

Merged
merged 7 commits into from
May 5, 2022
Merged

Conversation

cartersz
Copy link
Contributor

What problem does this PR solve?

Issue Number: ref #1157

What is changed and how it works?

Using prepare statement method ,when access to oracle

Check List

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)
  • No code

Code changes

  • Has exported function/method change
  • Has exported variable/fields change
  • Has interface methods change
  • Has persistent data change

Side effects

  • Possible performance regression
  • Increased code complexity
  • Breaking backward compatibility

Related changes

  • Need to cherry-pick to the release branch
  • Need to update the documentation
  • Need to update the tidb-ansible repository
  • Need to be included in the release note

Release note

  • No release note

@ti-chi-bot
Copy link
Member

ti-chi-bot commented Apr 19, 2022

[REVIEW NOTIFICATION]

This pull request has been approved by:

  • glorv
  • lichunzhu

To complete the pull request process, please ask the reviewers in the list to review by filling /cc @reviewer in the comment.
After your PR has acquired the required number of LGTMs, you can assign this pull request to the committer in the list by filling /assign @committer in the comment to help you merge this pull request.

The full list of commands accepted by this bot can be found here.

Reviewer can indicate their review by submitting an approval review.
Reviewer can cancel approval by submitting a request changes review.

@cartersz
Copy link
Contributor Author

@lichunzhu PTAL

@lichunzhu
Copy link
Contributor

/run-all-tests

@@ -31,6 +31,8 @@ import (

const implicitColID = -1

var destDBType = "tidb"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use an iota for this variable? I'm affray that string type is not accurate and may affect the efficiency.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var destDBType = "tidb"
type destDBType int
var (
mysql = iota
oracle
)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK,good idea

data = types.NewDatum(fmt.Sprintf("%v", data.GetValue()))
case mysql.TypeDuration:
//only for oracle db
if destDBType == "oracle" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

case mysql.TypeDuration:
//only for oracle db
if destDBType == "oracle" {
return data, errors.New("unsupport column type[time]")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return data, errors.New("unsupport column type[time]")
return data, errors.New("unsupport column type[time]")

//only for oracle db
if destDBType == "oracle" {
stype := types.TypeToStr(ft.Tp, ft.Charset)
if stype == "blob" || stype == "tinyblob" || stype == "mediumblob" || stype == "longblob" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just use IsTypeBlob in parser here?

Comment on lines 187 to 197
if dml.DestDBType == "oracle" {
colName = escapeName(name)
} else {
colName = quoteName(name)
}
value := dml.Values[name]
if value == nil {
fmt.Fprintf(builder, "%s = NULL", escapeName(name))
if dml.DestDBType == "oracle" {
fmt.Fprintf(builder, "%s = :%d", colName, oracleHolderPos)
oracleHolderPos++
} else {
fmt.Fprintf(builder, "%s = %s", escapeName(name), genOracleValue(dml.UpColumnsInfoMap[name], value))
fmt.Fprintf(builder, "%s = ?", colName)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we directly write here? colName seems useless here but will take another copy time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

@@ -37,6 +35,11 @@ const (
DeleteDMLType DMLType = 3
)

const (
MysqlDB = iota
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

@cartersz
Copy link
Contributor Author

/run-all-tests

Copy link
Contributor

@glorv glorv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rest LGTM

opts = append(opts, loader.DestinationDBType(destDBType), loader.WorkerCount(worker), loader.BatchSize(batchSize),
loader.SaveAppliedTS(destDBType == "tidb" || destDBType == "oracle"), loader.SetloopBackSyncInfo(info))
opts = append(opts, loader.DestinationDBType(destDBTypeInt), loader.WorkerCount(worker), loader.BatchSize(batchSize),
loader.SaveAppliedTS(destDBTypeInt == loader.MysqlDB || destDBTypeInt == loader.OracleDB), loader.SetloopBackSyncInfo(info))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From L60-63, the destDBTypeInt is either MysqlDB or OracleDB, then destDBTypeInt == loader.MysqlDB || destDBTypeInt == loader.OracleDB is always true

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when downstream is mysql or oracle DB, we need to save appliedTS, if it is not , we do not need to save appliedTS.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic has been changed. When destDBType is mysql we shouldn't save applied ts while for tidb we should save.

@@ -31,6 +31,8 @@ import (

const implicitColID = -1

var destDBType = loader.MysqlDB
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why need a global variable here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some method use this variable to check downstream DB, i don't like to pass it from one method to another

drainer/translator/mysql.go Outdated Show resolved Hide resolved
drainer/translator/mysql.go Outdated Show resolved Hide resolved
Comment on lines 39 to 43
const (
DBTypeUnknown = iota
MysqlDB
OracleDB
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const (
DBTypeUnknown = iota
MysqlDB
OracleDB
)
type DBType int
const (
DBTypeUnknown DBType = iota
MysqlDB
OracleDB
)

Always use DBType instead of int

Copy link
Contributor

@glorv glorv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@cartersz
Copy link
Contributor Author

/run-all-tests

opts = append(opts, loader.DestinationDBType(destDBType), loader.WorkerCount(worker), loader.BatchSize(batchSize),
loader.SaveAppliedTS(destDBType == "tidb" || destDBType == "oracle"), loader.SetloopBackSyncInfo(info))
opts = append(opts, loader.DestinationDBType(destDBTypeInt), loader.WorkerCount(worker), loader.BatchSize(batchSize),
loader.SaveAppliedTS(destDBTypeInt == loader.MysqlDB || destDBTypeInt == loader.OracleDB), loader.SetloopBackSyncInfo(info))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic has been changed. When destDBType is mysql we shouldn't save applied ts while for tidb we should save.

case mysql.TypeDuration:
//only for oracle db
if destDBType == loader.OracleDB {
return data, errors.New("unsupported column type[time]")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return data, errors.New("unsupported column type[time]")
return types.Datum{}, errors.New("unsupported column type[time]")


func isBlob(ft types.FieldType) bool {
stype := types.TypeToStr(ft.Tp, ft.Charset)
if stype == "blob" || stype == "tinyblob" || stype == "mediumblob" || stype == "longblob" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if stype == "blob" || stype == "tinyblob" || stype == "mediumblob" || stype == "longblob" {
switch stype:
case "blob", "tinyblob", "mediumblob", "longblob":
return true

@@ -19,6 +19,8 @@ import (
"strings"
"time"

"github.com/pingcap/tidb-binlog/pkg/loader"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this to L34~35

fmt.Fprintf(builder, "%s = ?", quoteName(name))
if dml.DestDBType == OracleDB {
fmt.Fprintf(builder, "%s = :%d", escapeName(name), oracleHolderPos)
oracleHolderPos++
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me oracleHolderPos = i + 1? Can we directly use i + 1 for this?

	for i, name := range dml.columnNames() {

wnames, wargs := dml.whereSlice()
for i := 0; i < len(wnames); i++ {
for i, pOracleHolderPos := 0, oracleHolderPos; i < len(wnames); i++ {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto, is pOracleHolderPos always equal to i+1?

sql = builder.String()
return
}

func (dml *DML) buildWhere(builder *strings.Builder) (args []interface{}) {
func (dml *DML) buildWhere(builder *strings.Builder, oracleHolderPos int) (args []interface{}) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, I'm a bit afraid this combination will make drainer has a lower effiency. We will do a lot of extra if check however half of them are useless because we won't change destDBType when we runs drainer.
refer: https://zhuanlan.zhihu.com/p/143275246 提前进行分支预测

@@ -343,14 +323,16 @@ func (dml *DML) oracleDeleteNewValueSQL() (sql string) {
}
}

for i := 0; i < len(colNames); i++ {
for i, oracleHolderPos := 0, 1; i < len(colNames); i++ {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

@cartersz
Copy link
Contributor Author

cartersz commented May 5, 2022

/run-all-tests

Copy link
Contributor

@lichunzhu lichunzhu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@lichunzhu
Copy link
Contributor

/merge

@ti-chi-bot
Copy link
Member

This pull request has been accepted and is ready to merge.

Commit hash: 4e59a23

@ti-chi-bot ti-chi-bot merged commit 09d4a33 into pingcap:master May 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants