oracle 11g

This commit is contained in:
2024-05-10 11:28:44 +08:00
parent 184a8722d8
commit 2d3723822b
5 changed files with 141 additions and 93 deletions

View File

@ -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
View File

@ -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=

View File

@ -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
})
}

View File

@ -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
View File

@ -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