enhance: improve Save feature for drivers oracle and dm (#3426)

This commit is contained in:
oldme
2024-04-01 19:08:26 +08:00
committed by GitHub
parent e0a2645f4a
commit 06826750ed
3 changed files with 67 additions and 62 deletions

View File

@ -17,7 +17,6 @@ import (
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
)
// DoInsert inserts or updates data for given table.
@ -25,15 +24,16 @@ func (d *Driver) DoInsert(
ctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,
) (result sql.Result, err error) {
switch option.InsertOption {
case gdb.InsertOptionSave:
return d.doSave(ctx, link, table, list, option)
case gdb.InsertOptionReplace:
// TODO:: Should be Supported
return nil, gerror.NewCode(
gcode.CodeNotSupported, `Replace operation is not supported by dm driver`,
)
case gdb.InsertOptionSave:
return d.doSave(ctx, link, table, list, option)
}
return d.Core.DoInsert(ctx, link, table, list, option)
}
@ -54,18 +54,23 @@ func (d *Driver) doSave(ctx context.Context,
}
var (
one = list[0]
charL, charR = d.GetChars()
valueCharL, valueCharR = "'", "'"
one = list[0]
oneLen = len(one)
charL, charR = d.GetChars()
conflictKeys = option.OnConflict
conflictKeySet = gset.New(false)
// insertKeys: Handle valid keys that need to be inserted
// insertValues: Handle values that need to be inserted
// updateValues: Handle values that need to be updated
// queryValues: Handle data that need to be upsert
queryValues, insertKeys, insertValues, updateValues []string
// queryHolders: Handle data with Holder that need to be upsert
// queryValues: Handle data that need to be upsert
// insertKeys: Handle valid keys that need to be inserted
// insertValues: Handle values that need to be inserted
// updateValues: Handle values that need to be updated
queryHolders = make([]string, oneLen)
queryValues = make([]interface{}, oneLen)
insertKeys = make([]string, oneLen)
insertValues = make([]string, oneLen)
updateValues []string
)
// conflictKeys slice type conv to set type
@ -73,31 +78,28 @@ func (d *Driver) doSave(ctx context.Context,
conflictKeySet.Add(gstr.ToUpper(conflictKey))
}
index := 0
for key, value := range one {
saveValue := gconv.String(value)
queryValues = append(
queryValues,
fmt.Sprintf(
valueCharL+"%s"+valueCharR+" AS "+charL+"%s"+charR,
saveValue, key,
),
)
keyWithChar := charL + key + charR
queryHolders[index] = fmt.Sprintf("? AS %s", keyWithChar)
queryValues[index] = value
insertKeys[index] = keyWithChar
insertValues[index] = fmt.Sprintf("T2.%s", keyWithChar)
insertKeys = append(insertKeys, charL+key+charR)
insertValues = append(insertValues, "T2."+charL+key+charR)
// filter conflict keys in updateValues
if !conflictKeySet.Contains(key) {
// filter conflict keys in updateValues.
// And the key is not a soft created field.
if !(conflictKeySet.Contains(key) || d.Core.IsSoftCreatedFieldName(key)) {
updateValues = append(
updateValues,
fmt.Sprintf(`T1.%s = T2.%s`, charL+key+charR, charL+key+charR),
fmt.Sprintf(`T1.%s = T2.%s`, keyWithChar, keyWithChar),
)
}
index++
}
batchResult := new(gdb.SqlResult)
sqlStr := parseSqlForUpsert(table, queryValues, insertKeys, insertValues, updateValues, conflictKeys)
r, err := d.DoExec(ctx, link, sqlStr)
sqlStr := parseSqlForUpsert(table, queryHolders, insertKeys, insertValues, updateValues, conflictKeys)
r, err := d.DoExec(ctx, link, sqlStr, queryValues...)
if err != nil {
return r, err
}
@ -112,17 +114,17 @@ func (d *Driver) doSave(ctx context.Context,
// parseSqlForUpsert
// MERGE INTO {{table}} T1
// USING ( SELECT {{queryValues}} FROM DUAL T2
// USING ( SELECT {{queryHolders}} FROM DUAL T2
// ON (T1.{{duplicateKey}} = T2.{{duplicateKey}} AND ...)
// WHEN NOT MATCHED THEN
// INSERT {{insertKeys}} VALUES {{insertValues}}
// WHEN MATCHED THEN
// UPDATE SET {{updateValues}}
func parseSqlForUpsert(table string,
queryValues, insertKeys, insertValues, updateValues, duplicateKey []string,
queryHolders, insertKeys, insertValues, updateValues, duplicateKey []string,
) (sqlStr string) {
var (
queryValueStr = strings.Join(queryValues, ",")
queryHolderStr = strings.Join(queryHolders, ",")
insertKeyStr = strings.Join(insertKeys, ",")
insertValueStr = strings.Join(insertValues, ",")
updateValueStr = strings.Join(updateValues, ",")
@ -140,7 +142,7 @@ func parseSqlForUpsert(table string,
return fmt.Sprintf(pattern,
table,
queryValueStr,
queryHolderStr,
duplicateKeyStr,
insertKeyStr,
insertValueStr,

View File

@ -10,9 +10,10 @@ import (
"context"
"database/sql"
"fmt"
"strings"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/text/gstr"
"strings"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gcode"
@ -110,18 +111,23 @@ func (d *Driver) doSave(ctx context.Context,
}
var (
one = list[0]
charL, charR = d.GetChars()
valueCharL, valueCharR = "'", "'"
one = list[0]
oneLen = len(one)
charL, charR = d.GetChars()
conflictKeys = option.OnConflict
conflictKeySet = gset.New(false)
// insertKeys: Handle valid keys that need to be inserted
// insertValues: Handle values that need to be inserted
// updateValues: Handle values that need to be updated
// queryValues: Handle data that need to be upsert
queryValues, insertKeys, insertValues, updateValues []string
// queryHolders: Handle data with Holder that need to be upsert
// queryValues: Handle data that need to be upsert
// insertKeys: Handle valid keys that need to be inserted
// insertValues: Handle values that need to be inserted
// updateValues: Handle values that need to be updated
queryHolders = make([]string, oneLen)
queryValues = make([]interface{}, oneLen)
insertKeys = make([]string, oneLen)
insertValues = make([]string, oneLen)
updateValues []string
)
// conflictKeys slice type conv to set type
@ -129,31 +135,28 @@ func (d *Driver) doSave(ctx context.Context,
conflictKeySet.Add(gstr.ToUpper(conflictKey))
}
index := 0
for key, value := range one {
saveValue := gconv.String(value)
queryValues = append(
queryValues,
fmt.Sprintf(
valueCharL+"%s"+valueCharR+" AS "+charL+"%s"+charR,
saveValue, key,
),
)
keyWithChar := charL + key + charR
queryHolders[index] = fmt.Sprintf("? AS %s", keyWithChar)
queryValues[index] = value
insertKeys[index] = keyWithChar
insertValues[index] = fmt.Sprintf("T2.%s", keyWithChar)
insertKeys = append(insertKeys, charL+key+charR)
insertValues = append(insertValues, "T2."+charL+key+charR)
// filter conflict keys in updateValues
if !conflictKeySet.Contains(key) {
// filter conflict keys in updateValues.
// And the key is not a soft created field.
if !(conflictKeySet.Contains(key) || d.Core.IsSoftCreatedFieldName(key)) {
updateValues = append(
updateValues,
fmt.Sprintf(`T1.%s = T2.%s`, charL+key+charR, charL+key+charR),
fmt.Sprintf(`T1.%s = T2.%s`, keyWithChar, keyWithChar),
)
}
index++
}
batchResult := new(gdb.SqlResult)
sqlStr := parseSqlForUpsert(table, queryValues, insertKeys, insertValues, updateValues, conflictKeys)
r, err := d.DoExec(ctx, link, sqlStr)
sqlStr := parseSqlForUpsert(table, queryHolders, insertKeys, insertValues, updateValues, conflictKeys)
r, err := d.DoExec(ctx, link, sqlStr, queryValues...)
if err != nil {
return r, err
}
@ -168,17 +171,17 @@ func (d *Driver) doSave(ctx context.Context,
// parseSqlForUpsert
// MERGE INTO {{table}} T1
// USING ( SELECT {{queryValues}} FROM DUAL T2
// USING ( SELECT {{queryHolders}} FROM DUAL T2
// ON (T1.{{duplicateKey}} = T2.{{duplicateKey}} AND ...)
// WHEN NOT MATCHED THEN
// INSERT {{insertKeys}} VALUES {{insertValues}}
// WHEN MATCHED THEN
// UPDATE SET {{updateValues}}
func parseSqlForUpsert(table string,
queryValues, insertKeys, insertValues, updateValues, duplicateKey []string,
queryHolders, insertKeys, insertValues, updateValues, duplicateKey []string,
) (sqlStr string) {
var (
queryValueStr = strings.Join(queryValues, ",")
queryHolderStr = strings.Join(queryHolders, ",")
insertKeyStr = strings.Join(insertKeys, ",")
insertValueStr = strings.Join(insertValues, ",")
updateValueStr = strings.Join(updateValues, ",")
@ -196,7 +199,7 @@ func parseSqlForUpsert(table string,
return fmt.Sprintf(pattern,
table,
queryValueStr,
queryHolderStr,
duplicateKeyStr,
insertKeyStr,
insertValueStr,

View File

@ -126,7 +126,7 @@ func createTable(table ...string) (name string) {
gtest.Fatal(err)
}
//db.Schema("test")
// db.Schema("test")
return
}