merge mssql support
This commit is contained in:
commit
b778bfce82
19
base_test.go
19
base_test.go
|
@ -189,6 +189,13 @@ func insertAutoIncr(engine *Engine, t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BigInsert struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func insertDefault(engine *Engine, t *testing.T) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func insertMulti(engine *Engine, t *testing.T) {
|
func insertMulti(engine *Engine, t *testing.T) {
|
||||||
//engine.InsertMany = true
|
//engine.InsertMany = true
|
||||||
users := []Userinfo{
|
users := []Userinfo{
|
||||||
|
@ -1550,26 +1557,26 @@ func testStrangeName(engine *Engine, t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Version struct {
|
type VersionS struct {
|
||||||
Id int64
|
Id int64
|
||||||
Name string
|
Name string
|
||||||
Ver int `xorm:"version"`
|
Ver int `xorm:"version"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func testVersion(engine *Engine, t *testing.T) {
|
func testVersion(engine *Engine, t *testing.T) {
|
||||||
err := engine.DropTables(new(Version))
|
err := engine.DropTables(new(VersionS))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = engine.CreateTables(new(Version))
|
err = engine.CreateTables(new(VersionS))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ver := &Version{Name: "sfsfdsfds"}
|
ver := &VersionS{Name: "sfsfdsfds"}
|
||||||
_, err = engine.Insert(ver)
|
_, err = engine.Insert(ver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
@ -1582,7 +1589,7 @@ func testVersion(engine *Engine, t *testing.T) {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
newVer := new(Version)
|
newVer := new(VersionS)
|
||||||
has, err := engine.Id(ver.Id).Get(newVer)
|
has, err := engine.Id(ver.Id).Get(newVer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
@ -1607,7 +1614,7 @@ func testVersion(engine *Engine, t *testing.T) {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
newVer = new(Version)
|
newVer = new(VersionS)
|
||||||
has, err = engine.Id(ver.Id).Get(newVer)
|
has, err = engine.Id(ver.Id).Get(newVer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
|
|
@ -21,6 +21,8 @@ const (
|
||||||
MYMYSQL = "mymysql"
|
MYMYSQL = "mymysql"
|
||||||
|
|
||||||
MSSQL = "mssql"
|
MSSQL = "mssql"
|
||||||
|
|
||||||
|
ORACLE_OCI = "oci8"
|
||||||
)
|
)
|
||||||
|
|
||||||
// a dialect is a driver's wrapper
|
// a dialect is a driver's wrapper
|
||||||
|
@ -143,6 +145,12 @@ func (engine *Engine) NoCache() *Session {
|
||||||
return session.NoCache()
|
return session.NoCache()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (engine *Engine) NoCascade() *Session {
|
||||||
|
session := engine.NewSession()
|
||||||
|
session.IsAutoClose = true
|
||||||
|
return session.NoCascade()
|
||||||
|
}
|
||||||
|
|
||||||
// Set a table use a special cacher
|
// Set a table use a special cacher
|
||||||
func (engine *Engine) MapCacher(bean interface{}, cacher Cacher) {
|
func (engine *Engine) MapCacher(bean interface{}, cacher Cacher) {
|
||||||
t := rType(bean)
|
t := rType(bean)
|
||||||
|
@ -749,7 +757,6 @@ func (engine *Engine) Sync(beans ...interface{}) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println("-----", isExist)
|
|
||||||
if !isExist {
|
if !isExist {
|
||||||
session := engine.NewSession()
|
session := engine.NewSession()
|
||||||
session.Statement.RefTable = table
|
session.Statement.RefTable = table
|
||||||
|
|
|
@ -12,8 +12,6 @@ utf8 COLLATE utf8_general_ci;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func newMssqlEngine() (*Engine, error) {
|
func newMssqlEngine() (*Engine, error) {
|
||||||
//return NewEngine("adodb", "Provider=SQLOLEDB; Server=127.0.0.1;Database=xorm_test; uid=sa; pwd=1234;")
|
|
||||||
|
|
||||||
return NewEngine("odbc", "driver={SQL Server};Server=127.0.0.1;Database=xorm_test; uid=sa; pwd=1234;")
|
return NewEngine("odbc", "driver={SQL Server};Server=127.0.0.1;Database=xorm_test; uid=sa; pwd=1234;")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +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
|
||||||
|
}
|
161
session.go
161
session.go
|
@ -129,6 +129,16 @@ func (session *Session) Cols(columns ...string) *Session {
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (session *Session) NoCascade() *Session {
|
||||||
|
session.Statement.UseCascade = false
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func (session *Session) MustCols(columns ...string) *Session {
|
||||||
|
session.Statement.Must()
|
||||||
|
}*/
|
||||||
|
|
||||||
// Xorm automatically retrieve condition according struct, but
|
// Xorm automatically retrieve condition according struct, but
|
||||||
// if struct has bool field, it will ignore them. So use UseBool
|
// if struct has bool field, it will ignore them. So use UseBool
|
||||||
// to tell system to do not ignore them.
|
// to tell system to do not ignore them.
|
||||||
|
@ -635,11 +645,14 @@ func (session *Session) cacheGet(bean interface{}, sql string, args ...interface
|
||||||
newSession := session.Engine.NewSession()
|
newSession := session.Engine.NewSession()
|
||||||
defer newSession.Close()
|
defer newSession.Close()
|
||||||
cacheBean = reflect.New(structValue.Type()).Interface()
|
cacheBean = reflect.New(structValue.Type()).Interface()
|
||||||
|
newSession.Id(id).NoCache()
|
||||||
if session.Statement.AltTableName != "" {
|
if session.Statement.AltTableName != "" {
|
||||||
has, err = newSession.Id(id).NoCache().Table(session.Statement.AltTableName).Get(cacheBean)
|
newSession.Table(session.Statement.AltTableName)
|
||||||
} else {
|
|
||||||
has, err = newSession.Id(id).NoCache().Get(cacheBean)
|
|
||||||
}
|
}
|
||||||
|
if !session.Statement.UseCascade {
|
||||||
|
newSession.NoCascade()
|
||||||
|
}
|
||||||
|
has, err = newSession.Get(cacheBean)
|
||||||
if err != nil || !has {
|
if err != nil || !has {
|
||||||
return has, err
|
return has, err
|
||||||
}
|
}
|
||||||
|
@ -1147,8 +1160,7 @@ func (session *Session) isIndexExist2(tableName string, cols []string, unique bo
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, index := range indexes {
|
for _, index := range indexes {
|
||||||
fmt.Println(i, "new:", cols, "-old:", index.Cols, sliceEq(index.Cols, cols), unique, index.Type)
|
|
||||||
if sliceEq(index.Cols, cols) {
|
if sliceEq(index.Cols, cols) {
|
||||||
if unique {
|
if unique {
|
||||||
return index.Type == UniqueType, nil
|
return index.Type == UniqueType, nil
|
||||||
|
@ -1241,6 +1253,9 @@ func row2map(rows *sql.Rows, fields []string) (resultsMap map[string][]byte, err
|
||||||
if err := rows.Scan(scanResultContainers...); err != nil {
|
if err := rows.Scan(scanResultContainers...); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// !nashtsai! TODO optimization for query performance, where current process has gone from
|
||||||
|
// sql driver converted type back to []bytes then to ORM's fields
|
||||||
for ii, key := range fields {
|
for ii, key := range fields {
|
||||||
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
|
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
|
||||||
|
|
||||||
|
@ -1275,7 +1290,7 @@ func row2map(rows *sql.Rows, fields []string) (resultsMap map[string][]byte, err
|
||||||
}
|
}
|
||||||
//时间类型
|
//时间类型
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
if aa.String() == "time.Time" {
|
if aa == reflect.TypeOf(c_TIME_DEFAULT) {
|
||||||
str = rawValue.Interface().(time.Time).Format(time.RFC3339Nano)
|
str = rawValue.Interface().(time.Time).Format(time.RFC3339Nano)
|
||||||
result[key] = []byte(str)
|
result[key] = []byte(str)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1352,7 +1367,7 @@ func query(db *sql.DB, sql string, params ...interface{}) (resultsSlice []map[st
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
fmt.Println(rows)
|
//fmt.Println(rows)
|
||||||
|
|
||||||
return rows2maps(rows)
|
return rows2maps(rows)
|
||||||
}
|
}
|
||||||
|
@ -1573,6 +1588,53 @@ func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) {
|
||||||
return session.innerInsertMulti(rowsSlicePtr)
|
return session.innerInsertMulti(rowsSlicePtr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (session *Session) byte2Time(col *Column, data []byte) (outTime time.Time, outErr error) {
|
||||||
|
sdata := strings.TrimSpace(string(data))
|
||||||
|
var x time.Time
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if sdata == "0000-00-00 00:00:00" ||
|
||||||
|
sdata == "0001-01-01 00:00:00" {
|
||||||
|
} else if !strings.ContainsAny(sdata, "- :") {
|
||||||
|
// time stamp
|
||||||
|
sd, err := strconv.ParseInt(sdata, 10, 64)
|
||||||
|
if err == nil {
|
||||||
|
x = time.Unix(0, sd)
|
||||||
|
}
|
||||||
|
} else if len(sdata) > 19 {
|
||||||
|
x, err = time.Parse(time.RFC3339Nano, sdata)
|
||||||
|
if err != nil {
|
||||||
|
x, err = time.Parse("2006-01-02 15:04:05.999999999", sdata)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
x, err = time.Parse("2006-01-02 15:04:05.9999999 Z07:00", sdata)
|
||||||
|
}
|
||||||
|
} else if len(sdata) == 19 {
|
||||||
|
x, err = time.Parse("2006-01-02 15:04:05", sdata)
|
||||||
|
} else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' {
|
||||||
|
x, err = time.Parse("2006-01-02", sdata)
|
||||||
|
} else if col.SQLType.Name == Time {
|
||||||
|
if strings.Contains(sdata, " ") {
|
||||||
|
ssd := strings.Split(sdata, " ")
|
||||||
|
sdata = ssd[1]
|
||||||
|
}
|
||||||
|
/*if len(sdata) > 8 {
|
||||||
|
sdata = sdata[len(sdata)-8:]
|
||||||
|
}*/
|
||||||
|
st := fmt.Sprintf("2006-01-02 %v", sdata)
|
||||||
|
x, err = time.Parse("2006-01-02 15:04:05", st)
|
||||||
|
} else {
|
||||||
|
outErr = errors.New(fmt.Sprintf("unsupported time format %v", sdata))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
outErr = errors.New(fmt.Sprintf("unsupported time format %v: %v", sdata, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
outTime = x
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// convert a db data([]byte) to a field value
|
// convert a db data([]byte) to a field value
|
||||||
func (session *Session) bytes2Value(col *Column, fieldValue *reflect.Value, data []byte) error {
|
func (session *Session) bytes2Value(col *Column, fieldValue *reflect.Value, data []byte) error {
|
||||||
if structConvert, ok := fieldValue.Addr().Interface().(Conversion); ok {
|
if structConvert, ok := fieldValue.Addr().Interface().(Conversion); ok {
|
||||||
|
@ -1670,50 +1732,13 @@ func (session *Session) bytes2Value(col *Column, fieldValue *reflect.Value, data
|
||||||
return errors.New("arg " + key + " as int: " + err.Error())
|
return errors.New("arg " + key + " as int: " + err.Error())
|
||||||
}
|
}
|
||||||
fieldValue.SetUint(x)
|
fieldValue.SetUint(x)
|
||||||
//Now only support Time type
|
//Currently only support Time type
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
if fieldType.String() == "time.Time" {
|
if fieldType == reflect.TypeOf(c_TIME_DEFAULT) {
|
||||||
sdata := strings.TrimSpace(string(data))
|
x, err := session.byte2Time(col, data)
|
||||||
var x time.Time
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if sdata == "0000-00-00 00:00:00" ||
|
|
||||||
sdata == "0001-01-01 00:00:00" {
|
|
||||||
} else if !strings.ContainsAny(sdata, "- :") {
|
|
||||||
// time stamp
|
|
||||||
sd, err := strconv.ParseInt(sdata, 10, 64)
|
|
||||||
if err == nil {
|
|
||||||
x = time.Unix(0, sd)
|
|
||||||
}
|
|
||||||
} else if len(sdata) > 19 {
|
|
||||||
x, err = time.Parse(time.RFC3339Nano, sdata)
|
|
||||||
if err != nil {
|
|
||||||
x, err = time.Parse("2006-01-02 15:04:05.999999999", sdata)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
x, err = time.Parse("2006-01-02 15:04:05.9999999 Z07:00", sdata)
|
|
||||||
}
|
|
||||||
} else if len(sdata) == 19 {
|
|
||||||
x, err = time.Parse("2006-01-02 15:04:05", sdata)
|
|
||||||
} else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' {
|
|
||||||
x, err = time.Parse("2006-01-02", sdata)
|
|
||||||
} else if col.SQLType.Name == Time {
|
|
||||||
if strings.Contains(sdata, " ") {
|
|
||||||
ssd := strings.Split(sdata, " ")
|
|
||||||
sdata = ssd[1]
|
|
||||||
}
|
|
||||||
/*if len(sdata) > 8 {
|
|
||||||
sdata = sdata[len(sdata)-8:]
|
|
||||||
}*/
|
|
||||||
st := fmt.Sprintf("2006-01-02 %v", sdata)
|
|
||||||
x, err = time.Parse("2006-01-02 15:04:05", st)
|
|
||||||
} else {
|
|
||||||
return errors.New(fmt.Sprintf("unsupported time format %v", string(data)))
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(fmt.Sprintf("unsupported time format %v: %v", string(data), err))
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
v = x
|
v = x
|
||||||
fieldValue.Set(reflect.ValueOf(v))
|
fieldValue.Set(reflect.ValueOf(v))
|
||||||
} else if session.Statement.UseCascade {
|
} else if session.Statement.UseCascade {
|
||||||
|
@ -1794,40 +1819,10 @@ func (session *Session) bytes2Value(col *Column, fieldValue *reflect.Value, data
|
||||||
fieldValue.Set(reflect.ValueOf(&x))
|
fieldValue.Set(reflect.ValueOf(&x))
|
||||||
// case "*time.Time":
|
// case "*time.Time":
|
||||||
case reflect.TypeOf(&c_TIME_DEFAULT):
|
case reflect.TypeOf(&c_TIME_DEFAULT):
|
||||||
sdata := strings.TrimSpace(string(data))
|
x, err := session.byte2Time(col, data)
|
||||||
var x time.Time
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if sdata == "0000-00-00 00:00:00" ||
|
|
||||||
sdata == "0001-01-01 00:00:00" {
|
|
||||||
} else if !strings.ContainsAny(sdata, "- :") {
|
|
||||||
// time stamp
|
|
||||||
sd, err := strconv.ParseInt(sdata, 10, 64)
|
|
||||||
if err == nil {
|
|
||||||
x = time.Unix(0, sd)
|
|
||||||
}
|
|
||||||
} else if len(sdata) > 19 {
|
|
||||||
x, err = time.Parse(time.RFC3339Nano, sdata)
|
|
||||||
if err != nil {
|
|
||||||
x, err = time.Parse("2006-01-02 15:04:05.999999999", sdata)
|
|
||||||
}
|
|
||||||
} else if len(sdata) == 19 {
|
|
||||||
x, err = time.Parse("2006-01-02 15:04:05", sdata)
|
|
||||||
} else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' {
|
|
||||||
x, err = time.Parse("2006-01-02", sdata)
|
|
||||||
} else if col.SQLType.Name == Time {
|
|
||||||
if len(sdata) > 8 {
|
|
||||||
sdata = sdata[len(sdata)-8:]
|
|
||||||
}
|
|
||||||
st := fmt.Sprintf("2006-01-02 %v", sdata)
|
|
||||||
x, err = time.Parse("2006-01-02 15:04:05", st)
|
|
||||||
} else {
|
|
||||||
return errors.New(fmt.Sprintf("unsupported time format %v", string(data)))
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(fmt.Sprintf("unsupported time format %v: %v", string(data), err))
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
v = x
|
v = x
|
||||||
fieldValue.Set(reflect.ValueOf(&x))
|
fieldValue.Set(reflect.ValueOf(&x))
|
||||||
// case "*uint64":
|
// case "*uint64":
|
||||||
|
@ -2063,9 +2058,8 @@ func (session *Session) value2Interface(col *Column, fieldValue reflect.Value) (
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
return fieldValue.String(), nil
|
return fieldValue.String(), nil
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
if fieldType.String() == "time.Time" {
|
if fieldType == reflect.TypeOf(c_TIME_DEFAULT) {
|
||||||
t := fieldValue.Interface().(time.Time)
|
t := fieldValue.Interface().(time.Time)
|
||||||
|
|
||||||
if session.Engine.dialect.DBType() == MSSQL {
|
if session.Engine.dialect.DBType() == MSSQL {
|
||||||
if t.IsZero() {
|
if t.IsZero() {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -2080,7 +2074,6 @@ func (session *Session) value2Interface(col *Column, fieldValue reflect.Value) (
|
||||||
} else if col.SQLType.Name == TimeStampz {
|
} else if col.SQLType.Name == TimeStampz {
|
||||||
if session.Engine.dialect.DBType() == MSSQL {
|
if session.Engine.dialect.DBType() == MSSQL {
|
||||||
tf := t.Format("2006-01-02T15:04:05.9999999Z07:00")
|
tf := t.Format("2006-01-02T15:04:05.9999999Z07:00")
|
||||||
fmt.Println("====", tf)
|
|
||||||
return tf, nil
|
return tf, nil
|
||||||
}
|
}
|
||||||
return fieldValue.Interface().(time.Time).Format(time.RFC3339Nano), nil
|
return fieldValue.Interface().(time.Time).Format(time.RFC3339Nano), nil
|
||||||
|
@ -2441,10 +2434,8 @@ func (session *Session) cacheUpdate(sql string, args ...interface{}) error {
|
||||||
session.Engine.LogDebug("[xorm:cacheUpdate] set bean field", bean, colName, fieldValue.Interface())
|
session.Engine.LogDebug("[xorm:cacheUpdate] set bean field", bean, colName, fieldValue.Interface())
|
||||||
if col.IsVersion && session.Statement.checkVersion {
|
if col.IsVersion && session.Statement.checkVersion {
|
||||||
fieldValue.SetInt(fieldValue.Int() + 1)
|
fieldValue.SetInt(fieldValue.Int() + 1)
|
||||||
fmt.Println("-----", fieldValue)
|
|
||||||
} else {
|
} else {
|
||||||
fieldValue.Set(reflect.ValueOf(args[idx]))
|
fieldValue.Set(reflect.ValueOf(args[idx]))
|
||||||
fmt.Println("xxxxxx", fieldValue)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
session.Engine.LogError("[xorm:cacheUpdate] ERROR: column %v is not table %v's",
|
session.Engine.LogError("[xorm:cacheUpdate] ERROR: column %v is not table %v's",
|
||||||
|
|
25
statement.go
25
statement.go
|
@ -1,6 +1,7 @@
|
||||||
package xorm
|
package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
//"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
//"strconv"
|
//"strconv"
|
||||||
|
@ -9,27 +10,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// !nashtsai! treat following var as interal const values
|
|
||||||
var (
|
|
||||||
c_EMPTY_STRING = ""
|
|
||||||
c_BOOL_DEFAULT = false
|
|
||||||
c_COMPLEX64_DEFAULT = complex64(0)
|
|
||||||
c_COMPLEX128_DEFAULT = complex128(0)
|
|
||||||
c_FLOAT32_DEFAULT = float32(0)
|
|
||||||
c_FLOAT64_DEFAULT = float64(0)
|
|
||||||
c_INT64_DEFAULT = int64(0)
|
|
||||||
c_UINT64_DEFAULT = uint64(0)
|
|
||||||
c_INT32_DEFAULT = int32(0)
|
|
||||||
c_UINT32_DEFAULT = uint32(0)
|
|
||||||
c_INT16_DEFAULT = int16(0)
|
|
||||||
c_UINT16_DEFAULT = uint16(0)
|
|
||||||
c_INT8_DEFAULT = int8(0)
|
|
||||||
c_UINT8_DEFAULT = uint8(0)
|
|
||||||
c_INT_DEFAULT = int(0)
|
|
||||||
c_UINT_DEFAULT = uint(0)
|
|
||||||
c_TIME_DEFAULT time.Time = time.Unix(0, 0)
|
|
||||||
)
|
|
||||||
|
|
||||||
// statement save all the sql info for executing SQL
|
// statement save all the sql info for executing SQL
|
||||||
type Statement struct {
|
type Statement struct {
|
||||||
RefTable *Table
|
RefTable *Table
|
||||||
|
@ -274,7 +254,7 @@ func buildConditions(engine *Engine, table *Table, bean interface{},
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
fmt.Println(engine.dialect.DBType(), Text)
|
//fmt.Println(engine.dialect.DBType(), Text)
|
||||||
if engine.dialect.DBType() == MSSQL && col.SQLType.Name == Text {
|
if engine.dialect.DBType() == MSSQL && col.SQLType.Name == Text {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -725,7 +705,6 @@ func (s *Statement) genDropSQL() string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// !nashtsai! REVIEW, Statement is a huge struct why is this method not passing *Statement?
|
|
||||||
func (statement *Statement) genGetSql(bean interface{}) (string, []interface{}) {
|
func (statement *Statement) genGetSql(bean interface{}) (string, []interface{}) {
|
||||||
table := statement.Engine.autoMap(bean)
|
table := statement.Engine.autoMap(bean)
|
||||||
statement.RefTable = table
|
statement.RefTable = table
|
||||||
|
|
29
table.go
29
table.go
|
@ -115,8 +115,27 @@ var (
|
||||||
uintTypes = sort.StringSlice{"*uint", "*uint16", "*uint32", "*uint8"}
|
uintTypes = sort.StringSlice{"*uint", "*uint16", "*uint32", "*uint8"}
|
||||||
)
|
)
|
||||||
|
|
||||||
var b byte
|
// !nashtsai! treat following var as interal const values, these are used for reflect.TypeOf comparision
|
||||||
var tm time.Time
|
var (
|
||||||
|
c_EMPTY_STRING string
|
||||||
|
c_BOOL_DEFAULT bool
|
||||||
|
c_BYTE_DEFAULT byte
|
||||||
|
c_COMPLEX64_DEFAULT complex64
|
||||||
|
c_COMPLEX128_DEFAULT complex128
|
||||||
|
c_FLOAT32_DEFAULT float32
|
||||||
|
c_FLOAT64_DEFAULT float64
|
||||||
|
c_INT64_DEFAULT int64
|
||||||
|
c_UINT64_DEFAULT uint64
|
||||||
|
c_INT32_DEFAULT int32
|
||||||
|
c_UINT32_DEFAULT uint32
|
||||||
|
c_INT16_DEFAULT int16
|
||||||
|
c_UINT16_DEFAULT uint16
|
||||||
|
c_INT8_DEFAULT int8
|
||||||
|
c_UINT8_DEFAULT uint8
|
||||||
|
c_INT_DEFAULT int
|
||||||
|
c_UINT_DEFAULT uint
|
||||||
|
c_TIME_DEFAULT time.Time
|
||||||
|
)
|
||||||
|
|
||||||
func Type2SQLType(t reflect.Type) (st SQLType) {
|
func Type2SQLType(t reflect.Type) (st SQLType) {
|
||||||
switch k := t.Kind(); k {
|
switch k := t.Kind(); k {
|
||||||
|
@ -131,7 +150,7 @@ func Type2SQLType(t reflect.Type) (st SQLType) {
|
||||||
case reflect.Complex64, reflect.Complex128:
|
case reflect.Complex64, reflect.Complex128:
|
||||||
st = SQLType{Varchar, 64, 0}
|
st = SQLType{Varchar, 64, 0}
|
||||||
case reflect.Array, reflect.Slice, reflect.Map:
|
case reflect.Array, reflect.Slice, reflect.Map:
|
||||||
if t.Elem() == reflect.TypeOf(b) {
|
if t.Elem() == reflect.TypeOf(c_BYTE_DEFAULT) {
|
||||||
st = SQLType{Blob, 0, 0}
|
st = SQLType{Blob, 0, 0}
|
||||||
} else {
|
} else {
|
||||||
st = SQLType{Text, 0, 0}
|
st = SQLType{Text, 0, 0}
|
||||||
|
@ -141,7 +160,7 @@ func Type2SQLType(t reflect.Type) (st SQLType) {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
st = SQLType{Varchar, 255, 0}
|
st = SQLType{Varchar, 255, 0}
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
if t == reflect.TypeOf(tm) {
|
if t == reflect.TypeOf(c_TIME_DEFAULT) {
|
||||||
st = SQLType{DateTime, 0, 0}
|
st = SQLType{DateTime, 0, 0}
|
||||||
} else {
|
} else {
|
||||||
st = SQLType{Text, 0, 0}
|
st = SQLType{Text, 0, 0}
|
||||||
|
@ -200,7 +219,7 @@ func SQLType2Type(st SQLType) reflect.Type {
|
||||||
case Bool:
|
case Bool:
|
||||||
return reflect.TypeOf(true)
|
return reflect.TypeOf(true)
|
||||||
case DateTime, Date, Time, TimeStamp, TimeStampz:
|
case DateTime, Date, Time, TimeStamp, TimeStampz:
|
||||||
return reflect.TypeOf(tm)
|
return reflect.TypeOf(c_TIME_DEFAULT)
|
||||||
case Decimal, Numeric:
|
case Decimal, Numeric:
|
||||||
return reflect.TypeOf("")
|
return reflect.TypeOf("")
|
||||||
default:
|
default:
|
||||||
|
|
5
xorm.go
5
xorm.go
|
@ -10,7 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
version string = "0.2.3"
|
Version string = "0.2.3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func close(engine *Engine) {
|
func close(engine *Engine) {
|
||||||
|
@ -37,6 +37,9 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
|
||||||
} else if driverName == "odbc" {
|
} else if driverName == "odbc" {
|
||||||
engine.dialect = &mssql{quoteFilter: &QuoteFilter{}}
|
engine.dialect = &mssql{quoteFilter: &QuoteFilter{}}
|
||||||
engine.Filters = append(engine.Filters, &QuoteFilter{})
|
engine.Filters = append(engine.Filters, &QuoteFilter{})
|
||||||
|
} else if driverName == ORACLE_OCI {
|
||||||
|
engine.dialect = &oracle{}
|
||||||
|
engine.Filters = append(engine.Filters, &QuoteFilter{})
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New(fmt.Sprintf("Unsupported driver name: %v", driverName))
|
return nil, errors.New(fmt.Sprintf("Unsupported driver name: %v", driverName))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue