oracle 11g
This commit is contained in:
@ -16,13 +16,15 @@ import (
|
||||
|
||||
func Create(db *gorm.DB) {
|
||||
stmt := db.Statement
|
||||
if stmt == nil {
|
||||
return
|
||||
}
|
||||
schema := stmt.Schema
|
||||
boundVars := make(map[string]int)
|
||||
|
||||
if stmt == nil || schema == nil {
|
||||
if schema == nil {
|
||||
return
|
||||
}
|
||||
|
||||
boundVars := make(map[string]int)
|
||||
hasDefaultValues := len(schema.FieldsWithDefaultDBValue) > 0
|
||||
|
||||
if !stmt.Unscoped {
|
||||
|
48
go.sum
48
go.sum
@ -1,48 +0,0 @@
|
||||
github.com/UNO-SOFT/zlog v0.8.1 h1:TEFkGJHtUfTRgMkLZiAjLSHALjwSBdw6/zByMC5GJt4=
|
||||
github.com/UNO-SOFT/zlog v0.8.1/go.mod h1:yqFOjn3OhvJ4j7ArJqQNA+9V+u6t9zSAyIZdWdMweWc=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
|
||||
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/godror/godror v0.43.0 h1:qMbQwG0ejJnKma3bBvrJg1rkiyP5b4v6uxvx9zDrKJw=
|
||||
github.com/godror/godror v0.43.0/go.mod h1:82Uc/HdjsFVnzR5c9Yf6IkTBalK80jzm/U6xojbTo94=
|
||||
github.com/godror/knownpb v0.1.1 h1:A4J7jdx7jWBhJm18NntafzSC//iZDHkDi1+juwQ5pTI=
|
||||
github.com/godror/knownpb v0.1.1/go.mod h1:4nRFbQo1dDuwKnblRXDxrfCFYeT4hjg3GjMqef58eRE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/oklog/ulid/v2 v2.0.2 h1:r4fFzBm+bv0wNKNh5eXTwU7i85y5x+uwkxCUTNVQqLc=
|
||||
github.com/oklog/ulid/v2 v2.0.2/go.mod h1:mtBL0Qe/0HAx6/a4Z30qxVIAL1eQDweXq5lxOEiwQ68=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw=
|
||||
github.com/thoas/go-funk v0.9.3/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
|
||||
golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 h1:6R2FC06FonbXQ8pK11/PDFY6N6LWlf9KlzibaCapmqc=
|
||||
golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4=
|
||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
|
||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
|
||||
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
@ -3,9 +3,10 @@ package oracle
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"gorm.io/gorm/schema"
|
||||
"strings"
|
||||
|
||||
"gorm.io/gorm/schema"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
"gorm.io/gorm/migrator"
|
||||
@ -275,11 +276,10 @@ func (m Migrator) HasIndex(value interface{}, name string) bool {
|
||||
|
||||
// https://docs.oracle.com/database/121/SPATL/alter-index-rename.htm
|
||||
func (m Migrator) RenameIndex(value interface{}, oldName, newName string) error {
|
||||
panic("TODO")
|
||||
return m.RunWithValue(value, func(stmt *gorm.Statement) error {
|
||||
return m.DB.Exec(
|
||||
"ALTER INDEX ?.? RENAME TO ?", // wat
|
||||
clause.Table{Name: stmt.Table}, clause.Column{Name: oldName}, clause.Column{Name: newName},
|
||||
"ALTER INDEX ? RENAME TO ?", // wat
|
||||
clause.Column{Name: oldName}, clause.Column{Name: newName},
|
||||
).Error
|
||||
})
|
||||
}
|
||||
|
22
namer.go
22
namer.go
@ -1,12 +1,15 @@
|
||||
package oracle
|
||||
|
||||
import (
|
||||
"gorm.io/gorm/schema"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"gorm.io/gorm/schema"
|
||||
)
|
||||
|
||||
type Namer struct {
|
||||
schema.NamingStrategy
|
||||
NamingStrategy schema.Namer
|
||||
DBName string
|
||||
}
|
||||
|
||||
func ConvertNameToFormat(x string) string {
|
||||
@ -14,7 +17,12 @@ func ConvertNameToFormat(x string) string {
|
||||
}
|
||||
|
||||
func (n Namer) TableName(table string) (name string) {
|
||||
return ConvertNameToFormat(n.NamingStrategy.TableName(table))
|
||||
tableName := ConvertNameToFormat(n.NamingStrategy.TableName(table))
|
||||
if len(n.DBName) > 0 {
|
||||
return fmt.Sprintf("%s.%s", n.DBName, tableName)
|
||||
}
|
||||
|
||||
return tableName
|
||||
}
|
||||
|
||||
func (n Namer) ColumnName(table, column string) (name string) {
|
||||
@ -36,3 +44,11 @@ func (n Namer) CheckerName(table, column string) (name string) {
|
||||
func (n Namer) IndexName(table, column string) (name string) {
|
||||
return ConvertNameToFormat(n.NamingStrategy.IndexName(table, column))
|
||||
}
|
||||
|
||||
func (n Namer) SchemaName(table string) string {
|
||||
return ConvertNameToFormat(n.NamingStrategy.SchemaName(table))
|
||||
}
|
||||
|
||||
func (n Namer) UniqueName(table, column string) string {
|
||||
return ConvertNameToFormat(n.NamingStrategy.UniqueName(table, column))
|
||||
}
|
||||
|
148
oracle.go
148
oracle.go
@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -21,6 +20,8 @@ import (
|
||||
"gorm.io/gorm/schema"
|
||||
)
|
||||
|
||||
const RowNumberAliasForOracle11 = "ROW_NUM"
|
||||
|
||||
type Config struct {
|
||||
DriverName string
|
||||
DSN string
|
||||
@ -51,7 +52,11 @@ func (d Dialector) Name() string {
|
||||
}
|
||||
|
||||
func (d Dialector) Initialize(db *gorm.DB) (err error) {
|
||||
db.NamingStrategy = Namer{db.NamingStrategy.(schema.NamingStrategy)}
|
||||
|
||||
db.NamingStrategy = Namer{
|
||||
NamingStrategy: db.NamingStrategy,
|
||||
DBName: d.DBName,
|
||||
}
|
||||
d.DefaultStringSize = 1024
|
||||
|
||||
// register callbacks
|
||||
@ -64,10 +69,15 @@ func (d Dialector) Initialize(db *gorm.DB) (err error) {
|
||||
|
||||
d.DriverName = "godror"
|
||||
|
||||
// godror.Batch
|
||||
|
||||
if d.Conn != nil {
|
||||
db.ConnPool = d.Conn
|
||||
} else {
|
||||
db.ConnPool, err = sql.Open(d.DriverName, d.DSN)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = db.ConnPool.QueryRowContext(context.Background(), "select version from product_component_version where rownum = 1").Scan(&d.DBVer)
|
||||
if err != nil {
|
||||
@ -96,7 +106,6 @@ func (d Dialector) ClauseBuilders() map[string]clause.ClauseBuilder {
|
||||
"LIMIT": d.RewriteLimit,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (d Dialector) RewriteLimit(c clause.Clause, builder clause.Builder) {
|
||||
@ -121,9 +130,14 @@ func (d Dialector) RewriteLimit(c clause.Clause, builder clause.Builder) {
|
||||
builder.WriteString(strconv.Itoa(offset))
|
||||
builder.WriteString(" ROWS")
|
||||
}
|
||||
if limit := limit.Limit; *limit > 0 {
|
||||
|
||||
v := 0
|
||||
if limit.Limit != nil {
|
||||
v = *limit.Limit
|
||||
}
|
||||
if v > 0 {
|
||||
builder.WriteString(" FETCH NEXT ")
|
||||
builder.WriteString(strconv.Itoa(*limit))
|
||||
builder.WriteString(strconv.Itoa(v))
|
||||
builder.WriteString(" ROWS ONLY")
|
||||
}
|
||||
}
|
||||
@ -131,34 +145,93 @@ func (d Dialector) RewriteLimit(c clause.Clause, builder clause.Builder) {
|
||||
|
||||
// Oracle11 Limit
|
||||
func (d Dialector) RewriteLimit11(c clause.Clause, builder clause.Builder) {
|
||||
if limit, ok := c.Expression.(clause.Limit); ok {
|
||||
if stmt, ok := builder.(*gorm.Statement); ok {
|
||||
limitsql := strings.Builder{}
|
||||
if limit := limit.Limit; *limit > 0 {
|
||||
if _, ok := stmt.Clauses["WHERE"]; !ok {
|
||||
limitsql.WriteString(" WHERE ")
|
||||
} else {
|
||||
limitsql.WriteString(" AND ")
|
||||
}
|
||||
limitsql.WriteString("ROWNUM <= ")
|
||||
limitsql.WriteString(strconv.Itoa(*limit))
|
||||
}
|
||||
if _, ok := stmt.Clauses["ORDER BY"]; !ok {
|
||||
builder.WriteString(limitsql.String())
|
||||
} else {
|
||||
// "ORDER BY" before insert
|
||||
sqltmp := strings.Builder{}
|
||||
sqlold := stmt.SQL.String()
|
||||
orderindx := strings.Index(sqlold, "ORDER BY") - 1
|
||||
sqltmp.WriteString(sqlold[:orderindx])
|
||||
sqltmp.WriteString(limitsql.String())
|
||||
sqltmp.WriteString(sqlold[orderindx:])
|
||||
log.Println(sqltmp.String())
|
||||
stmt.SQL = sqltmp
|
||||
}
|
||||
}
|
||||
limit, ok := c.Expression.(clause.Limit)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
offsetRows := limit.Offset
|
||||
hasOffset := offsetRows > 0
|
||||
limitRows, hasLimit := d.getLimitRows(limit)
|
||||
if !hasOffset && !hasLimit {
|
||||
return
|
||||
}
|
||||
|
||||
var stmt *gorm.Statement
|
||||
if stmt, ok = builder.(*gorm.Statement); !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if hasLimit && hasOffset {
|
||||
subQuerySQL := fmt.Sprintf(
|
||||
"SELECT * FROM (SELECT T.*, ROW_NUMBER() OVER (ORDER BY %s) AS %s FROM (%s) T) WHERE %s BETWEEN %d AND %d",
|
||||
d.getOrderByColumns(stmt),
|
||||
RowNumberAliasForOracle11,
|
||||
strings.TrimSpace(stmt.SQL.String()),
|
||||
RowNumberAliasForOracle11,
|
||||
offsetRows+1,
|
||||
offsetRows+limitRows,
|
||||
)
|
||||
|
||||
stmt.SQL.Reset()
|
||||
stmt.SQL.WriteString(subQuerySQL)
|
||||
} else if hasLimit {
|
||||
// 只有 Limit 的情况
|
||||
subQuerySQL := fmt.Sprintf(
|
||||
"SELECT * FROM (%s) WHERE ROWNUM <= %d",
|
||||
strings.TrimSpace(stmt.SQL.String()),
|
||||
limitRows,
|
||||
)
|
||||
// d.rewriteRownumStmt(stmt, builder, " <= ", limitRows)
|
||||
|
||||
stmt.SQL.Reset()
|
||||
stmt.SQL.WriteString(subQuerySQL)
|
||||
} else {
|
||||
// 只有 Offset 的情况
|
||||
// 偏移后取剩余所有记录
|
||||
subQuerySQL := fmt.Sprintf(
|
||||
"SELECT * FROM (SELECT T.*, ROW_NUMBER() OVER (ORDER BY %s) AS %s FROM (%s) T) WHERE %s > %d",
|
||||
d.getOrderByColumns(stmt),
|
||||
RowNumberAliasForOracle11,
|
||||
strings.TrimSpace(stmt.SQL.String()),
|
||||
RowNumberAliasForOracle11,
|
||||
offsetRows+1,
|
||||
)
|
||||
|
||||
stmt.SQL.Reset()
|
||||
stmt.SQL.WriteString(subQuerySQL)
|
||||
|
||||
// d.rewriteRownumStmt(stmt, builder, " > ", offsetRows)
|
||||
}
|
||||
}
|
||||
|
||||
func (d Dialector) getOrderByColumns(stmt *gorm.Statement) string {
|
||||
if orderByClause, ok := stmt.Clauses["ORDER BY"]; ok {
|
||||
var orderBy clause.OrderBy
|
||||
if orderBy, ok = orderByClause.Expression.(clause.OrderBy); ok && len(orderBy.Columns) > 0 {
|
||||
orderByBuilder := strings.Builder{}
|
||||
for i, column := range orderBy.Columns {
|
||||
if i > 0 {
|
||||
orderByBuilder.WriteString(", ")
|
||||
}
|
||||
orderByBuilder.WriteString(column.Column.Name)
|
||||
if column.Desc {
|
||||
orderByBuilder.WriteString(" DESC")
|
||||
}
|
||||
}
|
||||
return orderByBuilder.String()
|
||||
}
|
||||
}
|
||||
return "NULL"
|
||||
}
|
||||
|
||||
func (d Dialector) getLimitRows(limit clause.Limit) (limitRows int, hasLimit bool) {
|
||||
if l := limit.Limit; l != nil {
|
||||
limitRows = *l
|
||||
hasLimit = limitRows > 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d Dialector) DefaultValueOf(*schema.Field) clause.Expression {
|
||||
return clause.Expr{SQL: "VALUES (DEFAULT)"}
|
||||
}
|
||||
@ -181,7 +254,14 @@ func (d Dialector) BindVarTo(writer clause.Writer, stmt *gorm.Statement, v inter
|
||||
}
|
||||
|
||||
func (d Dialector) QuoteTo(writer clause.Writer, str string) {
|
||||
writer.WriteString(str)
|
||||
if str != "" && IsReservedWord(str) {
|
||||
writer.WriteByte('"')
|
||||
writer.WriteString(str)
|
||||
writer.WriteByte('"')
|
||||
} else {
|
||||
|
||||
writer.WriteString(str)
|
||||
}
|
||||
}
|
||||
|
||||
var numericPlaceholder = regexp.MustCompile(`:(\d+)`)
|
||||
@ -201,9 +281,7 @@ func (d Dialector) Explain(sql string, vars ...interface{}) string {
|
||||
}
|
||||
|
||||
func (d Dialector) DataTypeOf(field *schema.Field) string {
|
||||
if _, found := field.TagSettings["RESTRICT"]; found {
|
||||
delete(field.TagSettings, "RESTRICT")
|
||||
}
|
||||
delete(field.TagSettings, "RESTRICT")
|
||||
|
||||
var sqlType string
|
||||
|
||||
|
Reference in New Issue
Block a user