121 lines
3.2 KiB
Go
121 lines
3.2 KiB
Go
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
|
//
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
// If a copy of the MIT was not distributed with this file,
|
|
// You can obtain one at https://github.com/gogf/gf.
|
|
|
|
package oracle
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"git.magicany.cc/black1552/gin-base/database"
|
|
"github.com/gogf/gf/v2/errors/gcode"
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
)
|
|
|
|
const (
|
|
returningClause = " RETURNING %s INTO ?"
|
|
)
|
|
|
|
// DoExec commits the sql string and its arguments to underlying driver
|
|
// through given link object and returns the execution result.
|
|
// It handles INSERT statements specially to support LastInsertId.
|
|
func (d *Driver) DoExec(
|
|
ctx context.Context, link database.Link, sql string, args ...interface{},
|
|
) (result sql.Result, err error) {
|
|
var (
|
|
isUseCoreDoExec = true
|
|
primaryKey string
|
|
pkField database.TableField
|
|
)
|
|
|
|
// Transaction checks.
|
|
if link == nil {
|
|
if tx := database.TXFromCtx(ctx, d.GetGroup()); tx != nil {
|
|
link = tx
|
|
} else if link, err = d.MasterLink(); err != nil {
|
|
return nil, err
|
|
}
|
|
} else if !link.IsTransaction() {
|
|
if tx := database.TXFromCtx(ctx, d.GetGroup()); tx != nil {
|
|
link = tx
|
|
}
|
|
}
|
|
|
|
// Check if it is an insert operation with primary key from context.
|
|
if value := ctx.Value(internalPrimaryKeyInCtx); value != nil {
|
|
if field, ok := value.(database.TableField); ok {
|
|
pkField = field
|
|
isUseCoreDoExec = false
|
|
}
|
|
}
|
|
|
|
// Check if it is an INSERT statement with primary key.
|
|
if !isUseCoreDoExec && pkField.Name != "" && strings.Contains(strings.ToUpper(sql), "INSERT INTO") {
|
|
primaryKey = pkField.Name
|
|
// Oracle supports RETURNING clause to get the last inserted id
|
|
sql += fmt.Sprintf(returningClause, d.QuoteWord(primaryKey))
|
|
} else {
|
|
// Use default DoExec for non-INSERT or no primary key scenarios
|
|
return d.Core.DoExec(ctx, link, sql, args...)
|
|
}
|
|
|
|
// Only the insert operation with primary key can execute the following code
|
|
|
|
// SQL filtering.
|
|
sql, args = d.FormatSqlBeforeExecuting(sql, args)
|
|
sql, args, err = d.DoFilter(ctx, link, sql, args)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Prepare output variable for RETURNING clause
|
|
var lastInsertId int64
|
|
// Append the output parameter for the RETURNING clause
|
|
args = append(args, &lastInsertId)
|
|
|
|
// Link execution.
|
|
_, err = d.DoCommit(ctx, database.DoCommitInput{
|
|
Link: link,
|
|
Sql: sql,
|
|
Args: args,
|
|
Stmt: nil,
|
|
Type: database.SqlTypeExecContext,
|
|
IsTransaction: link.IsTransaction(),
|
|
})
|
|
|
|
if err != nil {
|
|
return &Result{
|
|
lastInsertId: 0,
|
|
rowsAffected: 0,
|
|
lastInsertIdError: err,
|
|
}, err
|
|
}
|
|
|
|
// Get rows affected from the result
|
|
// For single insert with RETURNING clause, affected is always 1
|
|
var affected int64 = 1
|
|
|
|
// Check if the primary key field type supports LastInsertId
|
|
if !strings.Contains(strings.ToLower(pkField.Type), "int") {
|
|
return &Result{
|
|
lastInsertId: 0,
|
|
rowsAffected: affected,
|
|
lastInsertIdError: gerror.NewCodef(
|
|
gcode.CodeNotSupported,
|
|
"LastInsertId is not supported by primary key type: %s",
|
|
pkField.Type,
|
|
),
|
|
}, nil
|
|
}
|
|
|
|
return &Result{
|
|
lastInsertId: lastInsertId,
|
|
rowsAffected: affected,
|
|
}, nil
|
|
}
|