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

fixed:mssqlserver_insert_and_get #4051

Open
wants to merge 52 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
5f6843c
提交go.mod
Jul 31, 2024
999f822
session增加重置方法
Aug 13, 2024
5c0a9ce
session增加重置方法
Aug 14, 2024
8f7f13a
session增加重置方法
Aug 14, 2024
f26b5c7
session增加重置方法
Aug 15, 2024
44da506
Merge branch 'master' into master
lxy1151 Aug 15, 2024
d132f4e
session增加重置方法
Aug 15, 2024
e2f4563
Merge branch 'master' of https://github.com/lxy1151/gf_session
Aug 15, 2024
0435e2a
session增加重置方法
Aug 15, 2024
373b052
session增加重置方法
Aug 16, 2024
8f7c1f4
撤销对多语言翻译的修改
lxy1151 Sep 26, 2024
660e874
提交备注文件
lxy1151 Dec 9, 2024
4168226
撤销对多语言翻译的修改
lxy1151 Dec 9, 2024
29230a3
Merge branch 'master' of https://github.com/lxy1151/gf_session
lxy1151 Dec 16, 2024
988dd05
master保持和gf的master一致
lxy1151 Dec 16, 2024
5339459
master保持和gf的master一致
lxy1151 Dec 16, 2024
cd2c6e4
master保持和gf的master一致
lxy1151 Dec 16, 2024
e978c48
master保持和gf的master一致
lxy1151 Dec 16, 2024
9d0aae6
master保持和gf的master一致
lxy1151 Dec 16, 2024
0a487b9
master保持和gf的master一致
lxy1151 Dec 16, 2024
843876a
master保持和gf的master一致
lxy1151 Dec 16, 2024
6e77f60
修复mssql的InsertAndGetId方法
lxy1151 Dec 17, 2024
701fb15
Merge branch 'master' into fixed_mssqlserver_insert_and_get_id
lxy1151 Dec 17, 2024
f8fe824
修复mssql的InsertAndGetId方法
lxy1151 Dec 17, 2024
a9b92b4
Update mssql_do_insert.go
houseme Dec 17, 2024
cc68d11
Update mssql_z_unit_basic_test.go
houseme Dec 17, 2024
a409642
修复mssql的InsertAndGetId方法
lxy1151 Dec 18, 2024
4916d29
修复mssql的InsertAndGetId方法
lxy1151 Dec 18, 2024
fa39047
Merge remote-tracking branch 'origin/fixed_mssqlserver_insert_and_get…
lxy1151 Dec 18, 2024
017e6c4
修复mssql的InsertAndGetId方法
lxy1151 Dec 18, 2024
7d6b181
修复mssql的InsertAndGetId方法
lxy1151 Dec 18, 2024
13d1670
修复mssql的InsertAndGetId方法
lxy1151 Dec 18, 2024
8bb5c9b
Update mssql_do_insert.go
houseme Dec 18, 2024
ee51d56
修复mssql的InsertAndGetId方法
lxy1151 Dec 18, 2024
7c16184
修复mssql的InsertAndGetId方法
lxy1151 Dec 18, 2024
bcd54f8
修复mssql的InsertAndGetId方法
lxy1151 Dec 18, 2024
3ec1866
修复mssql的InsertAndGetId方法
lxy1151 Dec 18, 2024
b9ef721
Merge branch 'master' into fixed_mssqlserver_insert_and_get_id
lxy1151 Dec 18, 2024
ee463d4
修复mssql的InsertAndGetId方法
lxy1151 Dec 18, 2024
1b623ec
Merge remote-tracking branch 'origin/fixed_mssqlserver_insert_and_get…
lxy1151 Dec 18, 2024
5beb48c
修复mssql的InsertAndGetId方法
lxy1151 Dec 19, 2024
bf43307
修复mssql的InsertAndGetId方法
lxy1151 Dec 19, 2024
405c531
修复mssql的InsertAndGetId方法
lxy1151 Dec 19, 2024
7248bb5
修复mssql的InsertAndGetId方法
lxy1151 Dec 19, 2024
c84d8b4
Merge branch 'master' into fixed_mssqlserver_insert_and_get_id
lxy1151 Dec 19, 2024
8cccf2d
修复mssql的InsertAndGetId方法
lxy1151 Dec 20, 2024
a57d9f6
Merge remote-tracking branch 'origin/fixed_mssqlserver_insert_and_get…
lxy1151 Dec 20, 2024
868b9a7
Merge branch 'master' into fixed_mssqlserver_insert_and_get_id
lxy1151 Dec 20, 2024
282c169
修复mssql的InsertAndGetId方法
lxy1151 Dec 20, 2024
8164522
修复mssql的InsertAndGetId方法
lxy1151 Dec 20, 2024
9def00d
Merge remote-tracking branch 'origin/fixed_mssqlserver_insert_and_get…
lxy1151 Dec 20, 2024
4536b67
修复mssql的InsertAndGetId方法
lxy1151 Dec 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions contrib/drivers/clickhouse/clickhouse_do_insert.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ import (

// DoInsert inserts or updates data for given table.
func (d *Driver) DoInsert(
ctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,
) (result sql.Result, err error) {
ctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption, ext ...interface{}) (result sql.Result, err error) {
var (
keys []string // Field names.
valueHolder = make([]string, 0)
Expand Down
2 changes: 1 addition & 1 deletion contrib/drivers/dm/dm_do_insert.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (

// DoInsert inserts or updates data for given table.
func (d *Driver) DoInsert(
ctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,
ctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption, ext ...interface{},
) (result sql.Result, err error) {
switch option.InsertOption {
case gdb.InsertOptionSave:
Expand Down
89 changes: 85 additions & 4 deletions contrib/drivers/mssql/mssql_do_insert.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,18 @@ import (
"github.com/gogf/gf/v2/text/gstr"
)

// DoInsert inserts or updates data for given table.
func (d *Driver) DoInsert(ctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption) (result sql.Result, err error) {
const (
autoIncrementName = "auto_increment"
mssqlOutPutKey = "OUTPUT"
mssqlInsertedObjName = "INSERTED"
mssqlAffectFd = " 1 as AffectCount"
affectCountFieldName = "AffectCount"
mssqlPrimaryKeyName = "PRI"
fdId = "ID"
)

// DoInsert inserts or updates data for given table. rewrite db.core.DoInsert
func (d *Driver) DoInsert(ctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption, ext ...interface{}) (result sql.Result, err error) {
switch option.InsertOption {
case gdb.InsertOptionSave:
return d.doSave(ctx, link, table, list, option)
Expand All @@ -30,10 +40,81 @@ func (d *Driver) DoInsert(ctx context.Context, link gdb.Link, table string, list
gcode.CodeNotSupported,
`Replace operation is not supported by mssql driver`,
)

default:
return d.Core.DoInsert(ctx, link, table, list, option)
outPutStr := d.GetInsertOutputSql(ctx, table)
var insertHandler gdb.InsertHandler
insertHandler = func(db gdb.DB, ctx context.Context, link gdb.Link, sqlStr string, args ...interface{}) (sql.Result, error) {
var (
stdSqlResult gdb.Result
retResult interface{}
)
stdSqlResult, err = db.DoQuery(ctx, link, sqlStr, args...)
if err != nil {
retResult = &InsertResult{lastInsertId: 0, rowsAffected: 0, err: err}
return retResult.(sql.Result), err
}
var (
aCount int64 // affect count
lId int64 // last insert id
)
if len(stdSqlResult) == 0 {
err = gerror.WrapCode(gcode.CodeDbOperationError, gerror.New("affectcount is zero"), `sql.Result.RowsAffected failed`)
retResult = &InsertResult{lastInsertId: 0, rowsAffected: 0, err: err}
return retResult.(sql.Result), err
}
// get affect count
aCount = stdSqlResult[0].GMap().GetVar(affectCountFieldName).Int64()
// get last_insert_id
lId = stdSqlResult[0].GMap().GetVar(fdId).Int64()

retResult = &InsertResult{lastInsertId: lId, rowsAffected: aCount}
return retResult.(sql.Result), nil
}
return d.Core.DoInsert(ctx, link, table, list, option, insertHandler, outPutStr)
}
lxy1151 marked this conversation as resolved.
Show resolved Hide resolved
}

// InsertResult instance of sql.Result
type InsertResult struct {
lastInsertId int64
rowsAffected int64
err error
}

func (r *InsertResult) LastInsertId() (int64, error) {
return r.lastInsertId, r.err
}

func (r *InsertResult) RowsAffected() (int64, error) {
return r.rowsAffected, r.err
}

// GetInsertOutputSql gen get last_insert_id code
func (m *Driver) GetInsertOutputSql(ctx context.Context, table string) string {
fds, errFd := m.GetDB().TableFields(ctx, table)
if errFd != nil {
return ""
}
extraSqlAry := make([]string, 0)
extraSqlAry = append(extraSqlAry, fmt.Sprintf(" %s %s", mssqlOutPutKey, mssqlAffectFd))
incrNo := 0
if len(fds) > 0 {
for _, fd := range fds {
// has primary key and is auto-incement
if fd.Extra == autoIncrementName && fd.Key == mssqlPrimaryKeyName && !fd.Null {
incrNoStr := ""
if incrNo == 0 { // fixed first field named id, convenient to get
incrNoStr = fmt.Sprintf(" as %s", fdId)
}

extraSqlAry = append(extraSqlAry, fmt.Sprintf("%s.%s%s", mssqlInsertedObjName, fd.Name, incrNoStr))
incrNo++
}
// fmt.Printf("null:%t name:%s key:%s k:%s \n", fd.Null, fd.Name, fd.Key, k)
}
}
return strings.Join(extraSqlAry, ",")
// sql example:INSERT INTO "ip_to_id"("ip") OUTPUT 1 as AffectCount,INSERTED.id as ID VALUES(?)
}

// doSave support upsert for SQL server
Expand Down
16 changes: 16 additions & 0 deletions contrib/drivers/mssql/mssql_z_unit_basic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/encoding/gxml"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/test/gtest"
)
Expand Down Expand Up @@ -148,6 +149,21 @@ func TestDoInsert(t *testing.T) {
})
}

func TestDoInsertGetId(t *testing.T) {
//先创建表
createInsertAndGetIdTableForTest()
gtest.C(t, func(t *gtest.T) {
table := "ip_to_id"
data := map[string]interface{}{
"ip": "192.168.179.1",
}
id, err := db.InsertAndGetId(gctx.New(), table, data)
t.AssertNil(err)
t.AssertGT(id, 0)
//fmt.Println("id:", id)
})
}

func Test_DB_Ping(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
err1 := db.PingMaster()
Expand Down
38 changes: 33 additions & 5 deletions contrib/drivers/mssql/mssql_z_unit_init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,23 @@ var (
)

const (
TableSize = 10
TestDbUser = "sa"
TestDbPass = "LoremIpsum86"
TableSize = 10
TableName = "t_user"
TestSchema1 = "test1"
TestSchema2 = "test2"
TableNamePrefix1 = "gf_"
TestDbUser = "sa"
TestDbPass = "LoremIpsum86" // "theone@123"
CreateTime = "2018-10-24 10:00:00"
)

func init() {
node := gdb.ConfigNode{
Host: "127.0.0.1",
Host: "127.0.0.1", // 192.168.5.72 127.0.0.1
Port: "1433",
User: TestDbUser,
Pass: TestDbPass,
Name: "master",
Name: "test", // "QPLogDB",
Type: "mssql",
Role: "master",
Charset: "utf8",
Expand Down Expand Up @@ -142,3 +147,26 @@ func dropTable(table string) {
gtest.Fatal(err)
}
}

// createInsertAndGetIdTableForTest test for InsertAndGetId
func createInsertAndGetIdTableForTest() (name string) {

if _, err := db.Exec(context.Background(), `
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='ip_to_id' and xtype='U')
begin
CREATE TABLE [ip_to_id](
[id] [int] IDENTITY(1,1) NOT NULL,
[ip] [varchar](128) NULL,
CONSTRAINT [PK_ip_to_id] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
end
`); err != nil {
gtest.Fatal(err)
}

db.Schema(db.GetConfig().Name)
return
}
2 changes: 1 addition & 1 deletion contrib/drivers/mysql/mysql_z_unit_init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const (
TestPartitionDB = "test3"
TableNamePrefix1 = "gf_"
TestDbUser = "root"
TestDbPass = "12345678"
TestDbPass = "12345678" //12345678 123456
CreateTime = "2018-10-24 10:00:00"
)

Expand Down
36 changes: 36 additions & 0 deletions contrib/drivers/mysql/mysql_z_unit_issue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,42 @@ func Test_Issue3086(t *testing.T) {
})
}

func Test_InsertedAndGetId(t *testing.T) {
table := createInitTable()
defer dropTable(table)
// data
gtest.C(t, func(t *gtest.T) {
type User struct {
g.Meta `orm:"do:true"`
Id interface{} `orm:"id,omitempty"`
Passport interface{} `orm:"passport,omitempty"`
Password interface{} `orm:"password,omitempty"`
Nickname interface{} `orm:"nickname,omitempty"`
CreateTime interface{} `orm:"create_time,omitempty"`
}
var (
err error
sqlArray []string
insertId int64
data = User{
Id: 20,
Passport: "passport_20",
Password: "",
}
)
sqlArray, err = gdb.CatchSQL(ctx, func(ctx context.Context) error {
insertId, err = db.Ctx(ctx).Model(table).Data(data).InsertAndGetId()
return err
})
t.AssertNil(err)
t.Assert(insertId, 20)
t.Assert(
gstr.Contains(sqlArray[len(sqlArray)-1], "(`id`,`passport`) VALUES(20,'passport_20')"),
true,
)
})
}

// https://github.com/gogf/gf/issues/3204
func Test_Issue3204(t *testing.T) {
table := createInitTable()
Expand Down
2 changes: 1 addition & 1 deletion contrib/drivers/oracle/oracle_do_insert.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (

// DoInsert inserts or updates data for given table.
func (d *Driver) DoInsert(
ctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,
ctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption, ext ...interface{},
) (result sql.Result, err error) {
switch option.InsertOption {
case gdb.InsertOptionSave:
Expand Down
4 changes: 2 additions & 2 deletions contrib/drivers/pgsql/pgsql_do_insert.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
)

// DoInsert inserts or updates data for given table.
func (d *Driver) DoInsert(ctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption) (result sql.Result, err error) {
func (d *Driver) DoInsert(ctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption, ext ...interface{}) (result sql.Result, err error) {
switch option.InsertOption {
case gdb.InsertOptionReplace:
return nil, gerror.NewCode(
Expand All @@ -36,5 +36,5 @@ func (d *Driver) DoInsert(ctx context.Context, link gdb.Link, table string, list
}
}
}
return d.Core.DoInsert(ctx, link, table, list, option)
return d.Core.DoInsert(ctx, link, table, list, option, ext)
}
2 changes: 1 addition & 1 deletion database/gdb/gdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ type DB interface {

// DoInsert performs the actual INSERT operation with given options.
// This is an internal method that can be overridden by custom implementations.
DoInsert(ctx context.Context, link Link, table string, data List, option DoInsertOption) (result sql.Result, err error)
DoInsert(ctx context.Context, link Link, table string, data List, option DoInsertOption, ext ...interface{}) (result sql.Result, err error)

// DoUpdate performs the actual UPDATE operation.
// This is an internal method that can be overridden by custom implementations.
Expand Down
38 changes: 30 additions & 8 deletions database/gdb/gdb_core.go
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,9 @@ func (c *Core) fieldsToSequence(ctx context.Context, table string, fields []stri
return fieldsResultInSequence, nil
}

// InsertHandler special need for mssql insert and get id
type InsertHandler func(db DB, ctx context.Context, link Link, sql string, args ...interface{}) (sql.Result, error)

// DoInsert inserts or updates data for given table.
// This function is usually used for custom interface definition, you do not need call it manually.
// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.
Expand All @@ -432,13 +435,30 @@ func (c *Core) fieldsToSequence(ctx context.Context, table string, fields []stri
// InsertOptionReplace: if there's unique/primary key in the data, it deletes it from table and inserts a new one;
// InsertOptionSave: if there's unique/primary key in the data, it updates it or else inserts a new one;
// InsertOptionIgnore: if there's unique/primary key in the data, it ignores the inserting;
func (c *Core) DoInsert(ctx context.Context, link Link, table string, list List, option DoInsertOption) (result sql.Result, err error) {
func (c *Core) DoInsert(ctx context.Context, link Link, table string, list List, option DoInsertOption, ext ...interface{}) (result sql.Result, err error) {
var (
keys []string // Field names.
values []string // Value holder string array, like: (?,?,?)
params []interface{} // Values that will be committed to underlying database driver.
onDuplicateStr string // onDuplicateStr is used in "ON DUPLICATE KEY UPDATE" statement.
keys []string // Field names.
values []string // Value holder string array, like: (?,?,?)
params []interface{} // Values that will be committed to underlying database driver.
onDuplicateStr string // onDuplicateStr is used in "ON DUPLICATE KEY UPDATE" statement.
insertDefaultHandler InsertHandler // drive to do insert data
insertOutPutStr string
)
insertOutPutStr = ""
insertDefaultHandler = func(db DB, ctx context.Context, link Link, sql string, args ...interface{}) (sql.Result, error) {
return db.DoExec(ctx, link, sql, args...)
}
// deal special insert. for example: mssql
if len(ext) > 0 {
if fn, ok := ext[0].(InsertHandler); ok {
insertDefaultHandler = fn
}
if len(ext) > 1 {
if outStr, ok := ext[1].(string); ok {
insertOutPutStr = outStr
}
}
}
// ============================================================================================
// Group the list by fields. Different fields to different list.
// It here uses ListMap to keep sequence for data inserting.
Expand Down Expand Up @@ -523,12 +543,14 @@ func (c *Core) DoInsert(ctx context.Context, link Link, table string, list List,
stdSqlResult sql.Result
affectedRows int64
)
stdSqlResult, err = c.db.DoExec(ctx, link, fmt.Sprintf(
"%s INTO %s(%s) VALUES%s %s",
sqlStr := fmt.Sprintf(
"%s INTO %s(%s)%s VALUES%s %s ",
operation, c.QuotePrefixTableName(table), keysStr,
insertOutPutStr,
gstr.Join(valueHolders, ","),
onDuplicateStr,
), params...)
)
stdSqlResult, err = insertDefaultHandler(c.db, ctx, link, sqlStr, params...)
if err != nil {
return stdSqlResult, err
}
Expand Down
4 changes: 2 additions & 2 deletions database/gdb/gdb_driver_wrapper_db.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,13 @@ func (d *DriverWrapperDB) TableFields(
// InsertOptionReplace: if there's unique/primary key in the data, it deletes it from table and inserts a new one;
// InsertOptionSave: if there's unique/primary key in the data, it updates it or else inserts a new one;
// InsertOptionIgnore: if there's unique/primary key in the data, it ignores the inserting;
func (d *DriverWrapperDB) DoInsert(ctx context.Context, link Link, table string, list List, option DoInsertOption) (result sql.Result, err error) {
func (d *DriverWrapperDB) DoInsert(ctx context.Context, link Link, table string, list List, option DoInsertOption, ext ...interface{}) (result sql.Result, err error) {
// Convert data type before commit it to underlying db driver.
for i, item := range list {
list[i], err = d.GetCore().ConvertDataForRecord(ctx, item, table)
if err != nil {
return nil, err
}
}
return d.DB.DoInsert(ctx, link, table, list, option)
return d.DB.DoInsert(ctx, link, table, list, option, ext)
}
Loading