Merge pull request #48 from nashtsai/master
code tidy up, minor performance improvement
This commit is contained in:
commit
8648f9458e
88
README.md
88
README.md
|
@ -1,17 +1,17 @@
|
|||
[中文](https://github.com/lunny/xorm/blob/master/README_CN.md)
|
||||
|
||||
Xorm is a simple and powerful ORM for Go.
|
||||
|
||||
[中文](https://github.com/lunny/xorm/blob/master/README_CN.md)
|
||||
|
||||
Xorm is a simple and powerful ORM for Go.
|
||||
|
||||
[](https://drone.io/github.com/lunny/xorm/latest) [](http://gowalker.org/github.com/lunny/xorm) [](https://bitdeli.com/free "Bitdeli Badge")
|
||||
|
||||
# Features
|
||||
|
||||
# Features
|
||||
|
||||
* Struct <-> Table Mapping Support
|
||||
|
||||
* Chainable APIs
|
||||
|
||||
* Transaction Support
|
||||
|
||||
|
||||
* Both ORM and raw SQL operation Support
|
||||
|
||||
* Sync database sechmea Support
|
||||
|
@ -24,26 +24,26 @@ Xorm is a simple and powerful ORM for Go.
|
|||
|
||||
* Optimistic Locking support
|
||||
|
||||
|
||||
# Drivers Support
|
||||
|
||||
Drivers for Go's sql package which currently support database/sql includes:
|
||||
|
||||
|
||||
# Drivers Support
|
||||
|
||||
Drivers for Go's sql package which currently support database/sql includes:
|
||||
|
||||
* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
|
||||
|
||||
* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
|
||||
|
||||
* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
|
||||
|
||||
* Postgres: [github.com/lib/pq](https://github.com/lib/pq)
|
||||
|
||||
* MsSql: [github.com/lunny/godbc](https://github.com/lunny/godbc)
|
||||
|
||||
|
||||
* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
|
||||
|
||||
* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
|
||||
|
||||
* Postgres: [github.com/lib/pq](https://github.com/lib/pq)
|
||||
|
||||
* MsSql: [github.com/lunny/godbc](https://github.com/lunny/godbc)
|
||||
|
||||
# Changelog
|
||||
|
||||
* **v0.3.1**
|
||||
|
||||
Features:
|
||||
* **v0.3.1**
|
||||
|
||||
Features:
|
||||
* Support MSSQL DB via ODBC driver ([github.com/lunny/godbc](https://github.com/lunny/godbc));
|
||||
* Composite Key, using multiple pk xorm tag
|
||||
* Added Row() API as alternative to Iterate() API for traversing result set, provide similar usages to sql.Rows type
|
||||
|
@ -54,22 +54,22 @@ Drivers for Go's sql package which currently support database/sql includes:
|
|||
* Allowed int/int32/int64/uint/uint32/uint64/string as Primary Key type
|
||||
* Performance improvement for Get()/Find()/Iterate()
|
||||
|
||||
[More changelogs ...](https://github.com/lunny/xorm/blob/master/docs/Changelog.md)
|
||||
|
||||
[More changelogs ...](https://github.com/lunny/xorm/blob/master/docs/Changelog.md)
|
||||
|
||||
# Installation
|
||||
|
||||
If you have [gopm](https://github.com/gpmgo/gopm) installed,
|
||||
|
||||
gopm get github.com/lunny/xorm
|
||||
|
||||
Or
|
||||
|
||||
go get github.com/lunny/xorm
|
||||
|
||||
Or
|
||||
|
||||
go get github.com/lunny/xorm
|
||||
|
||||
# Documents
|
||||
|
||||
* [GoDoc](http://godoc.org/github.com/lunny/xorm)
|
||||
|
||||
* [GoDoc](http://godoc.org/github.com/lunny/xorm)
|
||||
|
||||
* [GoWalker](http://gowalker.org/github.com/lunny/xorm)
|
||||
|
||||
* [Quick Start](https://github.com/lunny/xorm/blob/master/docs/QuickStartEn.md)
|
||||
|
@ -82,12 +82,12 @@ Or
|
|||
|
||||
* [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily)
|
||||
|
||||
* [Very Hour](http://veryhour.com/)
|
||||
|
||||
# Todo
|
||||
|
||||
[Todo List](https://trello.com/b/IHsuAnhk/xorm)
|
||||
|
||||
* [Very Hour](http://veryhour.com/)
|
||||
|
||||
# Todo
|
||||
|
||||
[Todo List](https://trello.com/b/IHsuAnhk/xorm)
|
||||
|
||||
# Discuss
|
||||
|
||||
Please visit [Xorm on Google Groups](https://groups.google.com/forum/#!forum/xorm)
|
||||
|
@ -97,9 +97,9 @@ Please visit [Xorm on Google Groups](https://groups.google.com/forum/#!forum/xor
|
|||
If you want to pull request, please see [CONTRIBUTING](https://github.com/lunny/xorm/blob/master/CONTRIBUTING.md)
|
||||
|
||||
* [Lunny](https://github.com/lunny)
|
||||
* [Nashtsai](https://github.com/nashtsai)
|
||||
|
||||
# LICENSE
|
||||
|
||||
BSD License
|
||||
[http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/)
|
||||
* [Nashtsai](https://github.com/nashtsai)
|
||||
|
||||
# LICENSE
|
||||
|
||||
BSD License
|
||||
[http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/)
|
||||
|
|
42
README_CN.md
42
README_CN.md
|
@ -1,7 +1,7 @@
|
|||
# xorm
|
||||
|
||||
[English](https://github.com/lunny/xorm/blob/master/README.md)
|
||||
|
||||
|
||||
[English](https://github.com/lunny/xorm/blob/master/README.md)
|
||||
|
||||
xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。
|
||||
|
||||
[](https://drone.io/github.com/lunny/xorm/latest) [](http://gowalker.org/github.com/lunny/xorm)
|
||||
|
@ -27,11 +27,11 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
|
|||
* 支持记录版本(即乐观锁)
|
||||
|
||||
## 驱动支持
|
||||
|
||||
目前支持的Go数据库驱动和对应的数据库如下:
|
||||
|
||||
* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
|
||||
|
||||
|
||||
目前支持的Go数据库驱动和对应的数据库如下:
|
||||
|
||||
* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
|
||||
|
||||
* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
|
||||
|
||||
* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
|
||||
|
@ -42,7 +42,7 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
|
|||
|
||||
## 更新日志
|
||||
|
||||
* **v0.3.1**
|
||||
* **v0.3.1**
|
||||
|
||||
新特性:
|
||||
* 支持 MSSQL DB 通过 ODBC 驱动 ([github.com/lunny/godbc](https://github.com/lunny/godbc));
|
||||
|
@ -53,11 +53,11 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
|
|||
|
||||
改进:
|
||||
* 允许 int/int32/int64/uint/uint32/uint64/string 作为主键类型
|
||||
* 查询函数 Get()/Find()/Iterate() 在性能上的改进
|
||||
* 查询函数 Get()/Find()/Iterate() 在性能上的改进
|
||||
|
||||
|
||||
[更多更新日志...](https://github.com/lunny/xorm/blob/master/docs/ChangelogCN.md)
|
||||
|
||||
|
||||
## 安装
|
||||
|
||||
推荐使用 [gopm](https://github.com/gpmgo/gopm) 进行安装:
|
||||
|
@ -66,10 +66,10 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
|
|||
|
||||
或者您也可以使用go工具进行安装:
|
||||
|
||||
go get github.com/lunny/xorm
|
||||
|
||||
go get github.com/lunny/xorm
|
||||
|
||||
## 文档
|
||||
|
||||
|
||||
* [快速开始](https://github.com/lunny/xorm/blob/master/docs/QuickStart.md)
|
||||
|
||||
* [GoWalker代码文档](http://gowalker.org/github.com/lunny/xorm)
|
||||
|
@ -85,8 +85,8 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
|
|||
|
||||
* [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily)
|
||||
|
||||
* [Very Hour](http://veryhour.com/)
|
||||
|
||||
* [Very Hour](http://veryhour.com/)
|
||||
|
||||
## Todo
|
||||
|
||||
[开发计划](https://trello.com/b/IHsuAnhk/xorm)
|
||||
|
@ -101,8 +101,8 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
|
|||
|
||||
* [Lunny](https://github.com/lunny)
|
||||
* [Nashtsai](https://github.com/nashtsai)
|
||||
|
||||
## LICENSE
|
||||
|
||||
BSD License
|
||||
[http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/)
|
||||
|
||||
## LICENSE
|
||||
|
||||
BSD License
|
||||
[http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/)
|
||||
|
|
|
@ -590,7 +590,7 @@ func (engine *Engine) mapType(t reflect.Type) *Table {
|
|||
sqlType := Type2SQLType(fieldType)
|
||||
col = &Column{engine.columnMapper.Obj2Table(t.Field(i).Name), t.Field(i).Name, sqlType,
|
||||
sqlType.DefaultLength, sqlType.DefaultLength2, true, "", make(map[string]bool), false, false,
|
||||
TWOSIDES, false, false, false, false}
|
||||
TWOSIDES, false, false, false, false, nil}
|
||||
}
|
||||
if col.IsAutoIncrement {
|
||||
col.Nullable = false
|
||||
|
|
516
oracle.go
516
oracle.go
|
@ -1,258 +1,258 @@
|
|||
package xorm
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type oracle struct {
|
||||
base
|
||||
}
|
||||
|
||||
type oracleParser struct {
|
||||
}
|
||||
|
||||
//dataSourceName=user/password@ipv4:port/dbname
|
||||
//dataSourceName=user/password@[ipv6]:port/dbname
|
||||
func (p *oracleParser) parse(driverName, dataSourceName string) (*uri, error) {
|
||||
db := &uri{dbType: ORACLE_OCI}
|
||||
dsnPattern := regexp.MustCompile(
|
||||
`^(?P<user>.*)\/(?P<password>.*)@` + // user:password@
|
||||
`(?P<net>.*)` + // ip:port
|
||||
`\/(?P<dbname>.*)`) // dbname
|
||||
matches := dsnPattern.FindStringSubmatch(dataSourceName)
|
||||
names := dsnPattern.SubexpNames()
|
||||
for i, match := range matches {
|
||||
switch names[i] {
|
||||
case "dbname":
|
||||
db.dbName = match
|
||||
}
|
||||
}
|
||||
if db.dbName == "" {
|
||||
return nil, errors.New("dbname is empty")
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func (db *oracle) Init(drivername, uri string) error {
|
||||
return db.base.init(&oracleParser{}, drivername, uri)
|
||||
}
|
||||
|
||||
func (db *oracle) SqlType(c *Column) string {
|
||||
var res string
|
||||
switch t := c.SQLType.Name; t {
|
||||
case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, BigInt, Bool, Serial, BigSerial:
|
||||
return "NUMBER"
|
||||
case Binary, VarBinary, Blob, TinyBlob, MediumBlob, LongBlob, Bytea:
|
||||
return Blob
|
||||
case Time, DateTime, TimeStamp:
|
||||
res = TimeStamp
|
||||
case TimeStampz:
|
||||
res = "TIMESTAMP WITH TIME ZONE"
|
||||
case Float, Double, Numeric, Decimal:
|
||||
res = "NUMBER"
|
||||
case Text, MediumText, LongText:
|
||||
res = "CLOB"
|
||||
case Char, Varchar, TinyText:
|
||||
return "VARCHAR2"
|
||||
default:
|
||||
res = t
|
||||
}
|
||||
|
||||
var hasLen1 bool = (c.Length > 0)
|
||||
var hasLen2 bool = (c.Length2 > 0)
|
||||
if hasLen1 {
|
||||
res += "(" + strconv.Itoa(c.Length) + ")"
|
||||
} else if hasLen2 {
|
||||
res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (db *oracle) SupportInsertMany() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (db *oracle) QuoteStr() string {
|
||||
return "\""
|
||||
}
|
||||
|
||||
func (db *oracle) AutoIncrStr() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (db *oracle) SupportEngine() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *oracle) SupportCharset() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *oracle) IndexOnTable() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *oracle) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
|
||||
args := []interface{}{strings.ToUpper(tableName), strings.ToUpper(idxName)}
|
||||
return `SELECT INDEX_NAME FROM USER_INDEXES ` +
|
||||
`WHERE TABLE_NAME = ? AND INDEX_NAME = ?`, args
|
||||
}
|
||||
|
||||
func (db *oracle) TableCheckSql(tableName string) (string, []interface{}) {
|
||||
args := []interface{}{strings.ToUpper(tableName)}
|
||||
return `SELECT table_name FROM user_tables WHERE table_name = ?`, args
|
||||
}
|
||||
|
||||
func (db *oracle) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
|
||||
args := []interface{}{strings.ToUpper(tableName), strings.ToUpper(colName)}
|
||||
return "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = ?" +
|
||||
" AND column_name = ?", args
|
||||
}
|
||||
|
||||
func (db *oracle) GetColumns(tableName string) ([]string, map[string]*Column, error) {
|
||||
args := []interface{}{strings.ToUpper(tableName)}
|
||||
s := "SELECT column_name,data_default,data_type,data_length,data_precision,data_scale," +
|
||||
"nullable FROM USER_TAB_COLUMNS WHERE table_name = :1"
|
||||
|
||||
cnn, err := sql.Open(db.driverName, db.dataSourceName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer cnn.Close()
|
||||
res, err := query(cnn, s, args...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cols := make(map[string]*Column)
|
||||
colSeq := make([]string, 0)
|
||||
for _, record := range res {
|
||||
col := new(Column)
|
||||
col.Indexes = make(map[string]bool)
|
||||
for name, content := range record {
|
||||
switch name {
|
||||
case "column_name":
|
||||
col.Name = strings.Trim(string(content), `" `)
|
||||
case "data_default":
|
||||
col.Default = string(content)
|
||||
case "nullable":
|
||||
if string(content) == "Y" {
|
||||
col.Nullable = true
|
||||
} else {
|
||||
col.Nullable = false
|
||||
}
|
||||
case "data_type":
|
||||
ct := string(content)
|
||||
switch ct {
|
||||
case "VARCHAR2":
|
||||
col.SQLType = SQLType{Varchar, 0, 0}
|
||||
case "TIMESTAMP WITH TIME ZONE":
|
||||
col.SQLType = SQLType{TimeStamp, 0, 0}
|
||||
default:
|
||||
col.SQLType = SQLType{strings.ToUpper(ct), 0, 0}
|
||||
}
|
||||
if _, ok := sqlTypes[col.SQLType.Name]; !ok {
|
||||
return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", ct))
|
||||
}
|
||||
case "data_length":
|
||||
i, err := strconv.Atoi(string(content))
|
||||
if err != nil {
|
||||
return nil, nil, errors.New("retrieve length error")
|
||||
}
|
||||
col.Length = i
|
||||
case "data_precision":
|
||||
case "data_scale":
|
||||
}
|
||||
}
|
||||
if col.SQLType.IsText() {
|
||||
if col.Default != "" {
|
||||
col.Default = "'" + col.Default + "'"
|
||||
}
|
||||
}
|
||||
cols[col.Name] = col
|
||||
colSeq = append(colSeq, col.Name)
|
||||
}
|
||||
|
||||
return colSeq, cols, nil
|
||||
}
|
||||
|
||||
func (db *oracle) GetTables() ([]*Table, error) {
|
||||
args := []interface{}{}
|
||||
s := "SELECT table_name FROM user_tables"
|
||||
cnn, err := sql.Open(db.driverName, db.dataSourceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cnn.Close()
|
||||
res, err := query(cnn, s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tables := make([]*Table, 0)
|
||||
for _, record := range res {
|
||||
table := new(Table)
|
||||
for name, content := range record {
|
||||
switch name {
|
||||
case "table_name":
|
||||
table.Name = string(content)
|
||||
}
|
||||
}
|
||||
tables = append(tables, table)
|
||||
}
|
||||
return tables, nil
|
||||
}
|
||||
|
||||
func (db *oracle) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||
args := []interface{}{tableName}
|
||||
s := "SELECT t.column_name,i.table_name,i.uniqueness,i.index_name FROM user_ind_columns t,user_indexes i " +
|
||||
"WHERE t.index_name = i.index_name and t.table_name = i.table_name and t.table_name =:1"
|
||||
|
||||
cnn, err := sql.Open(db.driverName, db.dataSourceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cnn.Close()
|
||||
res, err := query(cnn, s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
indexes := make(map[string]*Index, 0)
|
||||
for _, record := range res {
|
||||
var indexType int
|
||||
var indexName string
|
||||
var colName string
|
||||
|
||||
for name, content := range record {
|
||||
switch name {
|
||||
case "index_name":
|
||||
indexName = strings.Trim(string(content), `" `)
|
||||
case "uniqueness":
|
||||
c := string(content)
|
||||
if c == "UNIQUE" {
|
||||
indexType = UniqueType
|
||||
} else {
|
||||
indexType = IndexType
|
||||
}
|
||||
case "column_name":
|
||||
colName = string(content)
|
||||
}
|
||||
}
|
||||
|
||||
var index *Index
|
||||
var ok bool
|
||||
if index, ok = indexes[indexName]; !ok {
|
||||
index = new(Index)
|
||||
index.Type = indexType
|
||||
index.Name = indexName
|
||||
indexes[indexName] = index
|
||||
}
|
||||
index.AddColumn(colName)
|
||||
}
|
||||
return indexes, nil
|
||||
}
|
||||
package xorm
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type oracle struct {
|
||||
base
|
||||
}
|
||||
|
||||
type oracleParser struct {
|
||||
}
|
||||
|
||||
//dataSourceName=user/password@ipv4:port/dbname
|
||||
//dataSourceName=user/password@[ipv6]:port/dbname
|
||||
func (p *oracleParser) parse(driverName, dataSourceName string) (*uri, error) {
|
||||
db := &uri{dbType: ORACLE_OCI}
|
||||
dsnPattern := regexp.MustCompile(
|
||||
`^(?P<user>.*)\/(?P<password>.*)@` + // user:password@
|
||||
`(?P<net>.*)` + // ip:port
|
||||
`\/(?P<dbname>.*)`) // dbname
|
||||
matches := dsnPattern.FindStringSubmatch(dataSourceName)
|
||||
names := dsnPattern.SubexpNames()
|
||||
for i, match := range matches {
|
||||
switch names[i] {
|
||||
case "dbname":
|
||||
db.dbName = match
|
||||
}
|
||||
}
|
||||
if db.dbName == "" {
|
||||
return nil, errors.New("dbname is empty")
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func (db *oracle) Init(drivername, uri string) error {
|
||||
return db.base.init(&oracleParser{}, drivername, uri)
|
||||
}
|
||||
|
||||
func (db *oracle) SqlType(c *Column) string {
|
||||
var res string
|
||||
switch t := c.SQLType.Name; t {
|
||||
case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, BigInt, Bool, Serial, BigSerial:
|
||||
return "NUMBER"
|
||||
case Binary, VarBinary, Blob, TinyBlob, MediumBlob, LongBlob, Bytea:
|
||||
return Blob
|
||||
case Time, DateTime, TimeStamp:
|
||||
res = TimeStamp
|
||||
case TimeStampz:
|
||||
res = "TIMESTAMP WITH TIME ZONE"
|
||||
case Float, Double, Numeric, Decimal:
|
||||
res = "NUMBER"
|
||||
case Text, MediumText, LongText:
|
||||
res = "CLOB"
|
||||
case Char, Varchar, TinyText:
|
||||
return "VARCHAR2"
|
||||
default:
|
||||
res = t
|
||||
}
|
||||
|
||||
var hasLen1 bool = (c.Length > 0)
|
||||
var hasLen2 bool = (c.Length2 > 0)
|
||||
if hasLen1 {
|
||||
res += "(" + strconv.Itoa(c.Length) + ")"
|
||||
} else if hasLen2 {
|
||||
res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (db *oracle) SupportInsertMany() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (db *oracle) QuoteStr() string {
|
||||
return "\""
|
||||
}
|
||||
|
||||
func (db *oracle) AutoIncrStr() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (db *oracle) SupportEngine() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *oracle) SupportCharset() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *oracle) IndexOnTable() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *oracle) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
|
||||
args := []interface{}{strings.ToUpper(tableName), strings.ToUpper(idxName)}
|
||||
return `SELECT INDEX_NAME FROM USER_INDEXES ` +
|
||||
`WHERE TABLE_NAME = ? AND INDEX_NAME = ?`, args
|
||||
}
|
||||
|
||||
func (db *oracle) TableCheckSql(tableName string) (string, []interface{}) {
|
||||
args := []interface{}{strings.ToUpper(tableName)}
|
||||
return `SELECT table_name FROM user_tables WHERE table_name = ?`, args
|
||||
}
|
||||
|
||||
func (db *oracle) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
|
||||
args := []interface{}{strings.ToUpper(tableName), strings.ToUpper(colName)}
|
||||
return "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = ?" +
|
||||
" AND column_name = ?", args
|
||||
}
|
||||
|
||||
func (db *oracle) GetColumns(tableName string) ([]string, map[string]*Column, error) {
|
||||
args := []interface{}{strings.ToUpper(tableName)}
|
||||
s := "SELECT column_name,data_default,data_type,data_length,data_precision,data_scale," +
|
||||
"nullable FROM USER_TAB_COLUMNS WHERE table_name = :1"
|
||||
|
||||
cnn, err := sql.Open(db.driverName, db.dataSourceName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer cnn.Close()
|
||||
res, err := query(cnn, s, args...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cols := make(map[string]*Column)
|
||||
colSeq := make([]string, 0)
|
||||
for _, record := range res {
|
||||
col := new(Column)
|
||||
col.Indexes = make(map[string]bool)
|
||||
for name, content := range record {
|
||||
switch name {
|
||||
case "column_name":
|
||||
col.Name = strings.Trim(string(content), `" `)
|
||||
case "data_default":
|
||||
col.Default = string(content)
|
||||
case "nullable":
|
||||
if string(content) == "Y" {
|
||||
col.Nullable = true
|
||||
} else {
|
||||
col.Nullable = false
|
||||
}
|
||||
case "data_type":
|
||||
ct := string(content)
|
||||
switch ct {
|
||||
case "VARCHAR2":
|
||||
col.SQLType = SQLType{Varchar, 0, 0}
|
||||
case "TIMESTAMP WITH TIME ZONE":
|
||||
col.SQLType = SQLType{TimeStamp, 0, 0}
|
||||
default:
|
||||
col.SQLType = SQLType{strings.ToUpper(ct), 0, 0}
|
||||
}
|
||||
if _, ok := sqlTypes[col.SQLType.Name]; !ok {
|
||||
return nil, nil, errors.New(fmt.Sprintf("unkonw colType %v", ct))
|
||||
}
|
||||
case "data_length":
|
||||
i, err := strconv.Atoi(string(content))
|
||||
if err != nil {
|
||||
return nil, nil, errors.New("retrieve length error")
|
||||
}
|
||||
col.Length = i
|
||||
case "data_precision":
|
||||
case "data_scale":
|
||||
}
|
||||
}
|
||||
if col.SQLType.IsText() {
|
||||
if col.Default != "" {
|
||||
col.Default = "'" + col.Default + "'"
|
||||
}
|
||||
}
|
||||
cols[col.Name] = col
|
||||
colSeq = append(colSeq, col.Name)
|
||||
}
|
||||
|
||||
return colSeq, cols, nil
|
||||
}
|
||||
|
||||
func (db *oracle) GetTables() ([]*Table, error) {
|
||||
args := []interface{}{}
|
||||
s := "SELECT table_name FROM user_tables"
|
||||
cnn, err := sql.Open(db.driverName, db.dataSourceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cnn.Close()
|
||||
res, err := query(cnn, s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tables := make([]*Table, 0)
|
||||
for _, record := range res {
|
||||
table := new(Table)
|
||||
for name, content := range record {
|
||||
switch name {
|
||||
case "table_name":
|
||||
table.Name = string(content)
|
||||
}
|
||||
}
|
||||
tables = append(tables, table)
|
||||
}
|
||||
return tables, nil
|
||||
}
|
||||
|
||||
func (db *oracle) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||
args := []interface{}{tableName}
|
||||
s := "SELECT t.column_name,i.table_name,i.uniqueness,i.index_name FROM user_ind_columns t,user_indexes i " +
|
||||
"WHERE t.index_name = i.index_name and t.table_name = i.table_name and t.table_name =:1"
|
||||
|
||||
cnn, err := sql.Open(db.driverName, db.dataSourceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cnn.Close()
|
||||
res, err := query(cnn, s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
indexes := make(map[string]*Index, 0)
|
||||
for _, record := range res {
|
||||
var indexType int
|
||||
var indexName string
|
||||
var colName string
|
||||
|
||||
for name, content := range record {
|
||||
switch name {
|
||||
case "index_name":
|
||||
indexName = strings.Trim(string(content), `" `)
|
||||
case "uniqueness":
|
||||
c := string(content)
|
||||
if c == "UNIQUE" {
|
||||
indexType = UniqueType
|
||||
} else {
|
||||
indexType = IndexType
|
||||
}
|
||||
case "column_name":
|
||||
colName = string(content)
|
||||
}
|
||||
}
|
||||
|
||||
var index *Index
|
||||
var ok bool
|
||||
if index, ok = indexes[indexName]; !ok {
|
||||
index = new(Index)
|
||||
index.Type = indexType
|
||||
index.Name = indexName
|
||||
indexes[indexName] = index
|
||||
}
|
||||
index.AddColumn(colName)
|
||||
}
|
||||
return indexes, nil
|
||||
}
|
||||
|
|
90
session.go
90
session.go
|
@ -1092,25 +1092,41 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
|
|||
|
||||
fieldsCount := len(fields)
|
||||
|
||||
for rawRows.Next() {
|
||||
var newValue reflect.Value
|
||||
var newElemFunc func() reflect.Value
|
||||
if sliceElementType.Kind() == reflect.Ptr {
|
||||
newElemFunc = func() reflect.Value {
|
||||
return reflect.New(sliceElementType.Elem())
|
||||
}
|
||||
} else {
|
||||
newElemFunc = func() reflect.Value {
|
||||
return reflect.New(sliceElementType)
|
||||
}
|
||||
}
|
||||
|
||||
var sliceValueSetFunc func(*reflect.Value)
|
||||
|
||||
if sliceValue.Kind() == reflect.Slice {
|
||||
if sliceElementType.Kind() == reflect.Ptr {
|
||||
newValue = reflect.New(sliceElementType.Elem())
|
||||
} else {
|
||||
newValue = reflect.New(sliceElementType)
|
||||
}
|
||||
err := session.row2Bean(rawRows, fields, fieldsCount, newValue.Interface())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if sliceValue.Kind() == reflect.Slice {
|
||||
if sliceElementType.Kind() == reflect.Ptr {
|
||||
sliceValueSetFunc = func(newValue *reflect.Value) {
|
||||
sliceValue.Set(reflect.Append(sliceValue, reflect.ValueOf(newValue.Interface())))
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
sliceValueSetFunc = func(newValue *reflect.Value) {
|
||||
sliceValue.Set(reflect.Append(sliceValue, reflect.Indirect(reflect.ValueOf(newValue.Interface()))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for rawRows.Next() {
|
||||
var newValue reflect.Value = newElemFunc()
|
||||
if sliceValueSetFunc != nil {
|
||||
err := session.row2Bean(rawRows, fields, fieldsCount, newValue.Interface())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sliceValueSetFunc(&newValue)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
resultsSlice, err := session.query(sqlStr, args...)
|
||||
if err != nil {
|
||||
|
@ -1347,32 +1363,35 @@ func row2map(rows *sql.Rows, fields []string) (resultsMap map[string][]byte, err
|
|||
|
||||
func (session *Session) getField(dataStruct *reflect.Value, key string, table *Table) *reflect.Value {
|
||||
|
||||
key = strings.ToLower(key)
|
||||
if _, ok := table.Columns[key]; !ok {
|
||||
//key = strings.ToLower(key)
|
||||
if col, ok := table.Columns[key]; !ok {
|
||||
session.Engine.LogWarn(fmt.Sprintf("table %v's has not column %v. %v", table.Name, key, table.ColumnsSeq))
|
||||
return nil
|
||||
}
|
||||
col := table.Columns[key]
|
||||
fieldName := col.FieldName
|
||||
fieldPath := strings.Split(fieldName, ".")
|
||||
var fieldValue reflect.Value
|
||||
if len(fieldPath) > 2 {
|
||||
session.Engine.LogError("Unsupported mutliderive", fieldName)
|
||||
return nil
|
||||
} else if len(fieldPath) == 2 {
|
||||
parentField := dataStruct.FieldByName(fieldPath[0])
|
||||
if parentField.IsValid() {
|
||||
fieldValue = parentField.FieldByName(fieldPath[1])
|
||||
}
|
||||
} else {
|
||||
fieldValue = dataStruct.FieldByName(fieldName)
|
||||
fieldName := col.FieldName
|
||||
if col.fieldPath == nil {
|
||||
col.fieldPath = strings.Split(fieldName, ".")
|
||||
}
|
||||
var fieldValue reflect.Value
|
||||
fieldPathLen := len(col.fieldPath)
|
||||
if fieldPathLen > 2 {
|
||||
session.Engine.LogError("Unsupported mutliderive", fieldName)
|
||||
return nil
|
||||
} else if fieldPathLen == 2 {
|
||||
parentField := dataStruct.FieldByName(col.fieldPath[0])
|
||||
if parentField.IsValid() {
|
||||
fieldValue = parentField.FieldByName(col.fieldPath[1])
|
||||
}
|
||||
} else {
|
||||
fieldValue = dataStruct.FieldByName(fieldName)
|
||||
}
|
||||
if !fieldValue.IsValid() || !fieldValue.CanSet() {
|
||||
session.Engine.LogWarn("table %v's column %v is not valid or cannot set",
|
||||
table.Name, key)
|
||||
return nil
|
||||
}
|
||||
return &fieldValue
|
||||
}
|
||||
if !fieldValue.IsValid() || !fieldValue.CanSet() {
|
||||
session.Engine.LogWarn("table %v's column %v is not valid or cannot set",
|
||||
table.Name, key)
|
||||
return nil
|
||||
}
|
||||
return &fieldValue
|
||||
}
|
||||
|
||||
func (session *Session) row2Bean(rows *sql.Rows, fields []string, fieldsCount int, bean interface{}) error {
|
||||
|
@ -1395,7 +1414,6 @@ func (session *Session) row2Bean(rows *sql.Rows, fields []string, fieldsCount in
|
|||
|
||||
for ii, key := range fields {
|
||||
if fieldValue := session.getField(&dataStruct, key, table); fieldValue != nil {
|
||||
|
||||
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
|
||||
|
||||
//if row is null then ignore
|
||||
|
|
1
table.go
1
table.go
|
@ -275,6 +275,7 @@ type Column struct {
|
|||
IsUpdated bool
|
||||
IsCascade bool
|
||||
IsVersion bool
|
||||
fieldPath []string
|
||||
}
|
||||
|
||||
// generate column description string according dialect
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
# xorm tools
|
||||
|
||||
|
||||
xorm tools is a set of tools for database operation.
|
||||
|
||||
## Install
|
||||
|
||||
# xorm tools
|
||||
|
||||
|
||||
xorm tools is a set of tools for database operation.
|
||||
|
||||
## Install
|
||||
|
||||
`go get github.com/lunny/xorm/xorm`
|
||||
|
||||
and you should install the depends below:
|
||||
|
||||
* github.com/lunny/xorm
|
||||
|
||||
* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
|
||||
|
||||
* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
|
||||
|
||||
* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
|
||||
|
||||
* github.com/lunny/xorm
|
||||
|
||||
* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
|
||||
|
||||
* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
|
||||
|
||||
* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
|
||||
|
||||
* Postgres: [github.com/bylevel/pq](https://github.com/bylevel/pq)
|
||||
|
||||
|
||||
## Reverse
|
||||
|
||||
|
||||
## Reverse
|
||||
|
||||
After you installed the tool, you can type
|
||||
|
||||
`xorm help reverse`
|
||||
`xorm help reverse`
|
||||
|
||||
to get help
|
||||
|
||||
|
@ -50,13 +50,13 @@ Now, xorm tool supports go and c++ two languages and have go, goxorm, c++ three
|
|||
|
||||
````
|
||||
lang=go
|
||||
genJson=1
|
||||
genJson=1
|
||||
```
|
||||
|
||||
lang must be go or c++ now.
|
||||
genJson can be 1 or 0, if 1 then the struct will have json tag.
|
||||
|
||||
## LICENSE
|
||||
|
||||
BSD License
|
||||
[http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/)
|
||||
|
||||
## LICENSE
|
||||
|
||||
BSD License
|
||||
[http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/)
|
||||
|
|
Loading…
Reference in New Issue