* use created & updated instead BeforeInsert & BeforeUpdate * fix vendor checksum * only show generated SQL when development mode * remove extra update column updated_unix * remove trace configmaster
@@ -86,13 +86,7 @@ type Action struct { | |||||
IsPrivate bool `xorm:"INDEX NOT NULL DEFAULT false"` | IsPrivate bool `xorm:"INDEX NOT NULL DEFAULT false"` | ||||
Content string `xorm:"TEXT"` | Content string `xorm:"TEXT"` | ||||
Created time.Time `xorm:"-"` | Created time.Time `xorm:"-"` | ||||
CreatedUnix int64 `xorm:"INDEX"` | |||||
} | |||||
// BeforeInsert will be invoked by XORM before inserting a record | |||||
// representing this object. | |||||
func (a *Action) BeforeInsert() { | |||||
a.CreatedUnix = time.Now().Unix() | |||||
CreatedUnix int64 `xorm:"INDEX created"` | |||||
} | } | ||||
// AfterSet updates the webhook object upon setting a column. | // AfterSet updates the webhook object upon setting a column. | ||||
@@ -29,12 +29,7 @@ type Notice struct { | |||||
Type NoticeType | Type NoticeType | ||||
Description string `xorm:"TEXT"` | Description string `xorm:"TEXT"` | ||||
Created time.Time `xorm:"-"` | Created time.Time `xorm:"-"` | ||||
CreatedUnix int64 `xorm:"INDEX"` | |||||
} | |||||
// BeforeInsert is invoked from XORM before inserting an object of this type. | |||||
func (n *Notice) BeforeInsert() { | |||||
n.CreatedUnix = time.Now().Unix() | |||||
CreatedUnix int64 `xorm:"INDEX created"` | |||||
} | } | ||||
// AfterSet is invoked from XORM after setting the value of a field of this object. | // AfterSet is invoked from XORM after setting the value of a field of this object. | ||||
@@ -28,12 +28,7 @@ type Attachment struct { | |||||
Name string | Name string | ||||
DownloadCount int64 `xorm:"DEFAULT 0"` | DownloadCount int64 `xorm:"DEFAULT 0"` | ||||
Created time.Time `xorm:"-"` | Created time.Time `xorm:"-"` | ||||
CreatedUnix int64 | |||||
} | |||||
// BeforeInsert is invoked from XORM before inserting an object of this type. | |||||
func (a *Attachment) BeforeInsert() { | |||||
a.CreatedUnix = time.Now().Unix() | |||||
CreatedUnix int64 `xorm:"created"` | |||||
} | } | ||||
// AfterSet is invoked from XORM after setting the value of a field of | // AfterSet is invoked from XORM after setting the value of a field of | ||||
@@ -22,20 +22,9 @@ type ProtectedBranch struct { | |||||
BranchName string `xorm:"UNIQUE(s)"` | BranchName string `xorm:"UNIQUE(s)"` | ||||
CanPush bool | CanPush bool | ||||
Created time.Time `xorm:"-"` | Created time.Time `xorm:"-"` | ||||
CreatedUnix int64 | |||||
CreatedUnix int64 `xorm:"created"` | |||||
Updated time.Time `xorm:"-"` | Updated time.Time `xorm:"-"` | ||||
UpdatedUnix int64 | |||||
} | |||||
// BeforeInsert before protected branch insert create and update time | |||||
func (protectBranch *ProtectedBranch) BeforeInsert() { | |||||
protectBranch.CreatedUnix = time.Now().Unix() | |||||
protectBranch.UpdatedUnix = protectBranch.CreatedUnix | |||||
} | |||||
// BeforeUpdate before protected branch update time | |||||
func (protectBranch *ProtectedBranch) BeforeUpdate() { | |||||
protectBranch.UpdatedUnix = time.Now().Unix() | |||||
UpdatedUnix int64 `xorm:"updated"` | |||||
} | } | ||||
// GetProtectedBranchByRepoID getting protected branch by repo ID | // GetProtectedBranchByRepoID getting protected branch by repo ID | ||||
@@ -54,23 +54,16 @@ type Issue struct { | |||||
Deadline time.Time `xorm:"-"` | Deadline time.Time `xorm:"-"` | ||||
DeadlineUnix int64 `xorm:"INDEX"` | DeadlineUnix int64 `xorm:"INDEX"` | ||||
Created time.Time `xorm:"-"` | Created time.Time `xorm:"-"` | ||||
CreatedUnix int64 `xorm:"INDEX"` | |||||
CreatedUnix int64 `xorm:"INDEX created"` | |||||
Updated time.Time `xorm:"-"` | Updated time.Time `xorm:"-"` | ||||
UpdatedUnix int64 `xorm:"INDEX"` | |||||
UpdatedUnix int64 `xorm:"INDEX updated"` | |||||
Attachments []*Attachment `xorm:"-"` | Attachments []*Attachment `xorm:"-"` | ||||
Comments []*Comment `xorm:"-"` | Comments []*Comment `xorm:"-"` | ||||
} | } | ||||
// BeforeInsert is invoked from XORM before inserting an object of this type. | |||||
func (issue *Issue) BeforeInsert() { | |||||
issue.CreatedUnix = time.Now().Unix() | |||||
issue.UpdatedUnix = issue.CreatedUnix | |||||
} | |||||
// BeforeUpdate is invoked from XORM before updating this object. | // BeforeUpdate is invoked from XORM before updating this object. | ||||
func (issue *Issue) BeforeUpdate() { | func (issue *Issue) BeforeUpdate() { | ||||
issue.UpdatedUnix = time.Now().Unix() | |||||
issue.DeadlineUnix = issue.Deadline.Unix() | issue.DeadlineUnix = issue.Deadline.Unix() | ||||
} | } | ||||
@@ -581,7 +574,6 @@ func (issue *Issue) ReadBy(userID int64) error { | |||||
} | } | ||||
func updateIssueCols(e Engine, issue *Issue, cols ...string) error { | func updateIssueCols(e Engine, issue *Issue, cols ...string) error { | ||||
cols = append(cols, "updated_unix") | |||||
if _, err := e.Id(issue.ID).Cols(cols...).Update(issue); err != nil { | if _, err := e.Id(issue.ID).Cols(cols...).Update(issue); err != nil { | ||||
return err | return err | ||||
} | } | ||||
@@ -99,9 +99,9 @@ type Comment struct { | |||||
RenderedContent string `xorm:"-"` | RenderedContent string `xorm:"-"` | ||||
Created time.Time `xorm:"-"` | Created time.Time `xorm:"-"` | ||||
CreatedUnix int64 `xorm:"INDEX"` | |||||
CreatedUnix int64 `xorm:"INDEX created"` | |||||
Updated time.Time `xorm:"-"` | Updated time.Time `xorm:"-"` | ||||
UpdatedUnix int64 `xorm:"INDEX"` | |||||
UpdatedUnix int64 `xorm:"INDEX updated"` | |||||
// Reference issue in commit message | // Reference issue in commit message | ||||
CommitSHA string `xorm:"VARCHAR(40)"` | CommitSHA string `xorm:"VARCHAR(40)"` | ||||
@@ -112,18 +112,6 @@ type Comment struct { | |||||
ShowTag CommentTag `xorm:"-"` | ShowTag CommentTag `xorm:"-"` | ||||
} | } | ||||
// BeforeInsert will be invoked by XORM before inserting a record | |||||
// representing this object. | |||||
func (c *Comment) BeforeInsert() { | |||||
c.CreatedUnix = time.Now().Unix() | |||||
c.UpdatedUnix = c.CreatedUnix | |||||
} | |||||
// BeforeUpdate is invoked from XORM before updating this object. | |||||
func (c *Comment) BeforeUpdate() { | |||||
c.UpdatedUnix = time.Now().Unix() | |||||
} | |||||
// AfterSet is invoked from XORM after setting the value of a field of this object. | // AfterSet is invoked from XORM after setting the value of a field of this object. | ||||
func (c *Comment) AfterSet(colName string, _ xorm.Cell) { | func (c *Comment) AfterSet(colName string, _ xorm.Cell) { | ||||
var err error | var err error | ||||
@@ -2,8 +2,9 @@ package models | |||||
import ( | import ( | ||||
"errors" | "errors" | ||||
"github.com/go-xorm/xorm" | |||||
"time" | "time" | ||||
"github.com/go-xorm/xorm" | |||||
) | ) | ||||
// LFSMetaObject stores metadata for LFS tracked files. | // LFSMetaObject stores metadata for LFS tracked files. | ||||
@@ -14,7 +15,7 @@ type LFSMetaObject struct { | |||||
RepositoryID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` | RepositoryID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` | ||||
Existing bool `xorm:"-"` | Existing bool `xorm:"-"` | ||||
Created time.Time `xorm:"-"` | Created time.Time `xorm:"-"` | ||||
CreatedUnix int64 | |||||
CreatedUnix int64 `xorm:"created"` | |||||
} | } | ||||
// LFSTokenResponse defines the JSON structure in which the JWT token is stored. | // LFSTokenResponse defines the JSON structure in which the JWT token is stored. | ||||
@@ -108,11 +109,6 @@ func RemoveLFSMetaObjectByOid(oid string) error { | |||||
return sess.Commit() | return sess.Commit() | ||||
} | } | ||||
// BeforeInsert sets the time at which the LFSMetaObject was created. | |||||
func (m *LFSMetaObject) BeforeInsert() { | |||||
m.CreatedUnix = time.Now().Unix() | |||||
} | |||||
// AfterSet stores the LFSMetaObject creation time in the database as local time. | // AfterSet stores the LFSMetaObject creation time in the database as local time. | ||||
func (m *LFSMetaObject) AfterSet(colName string, _ xorm.Cell) { | func (m *LFSMetaObject) AfterSet(colName string, _ xorm.Cell) { | ||||
switch colName { | switch colName { | ||||
@@ -148,20 +148,9 @@ type LoginSource struct { | |||||
Cfg core.Conversion `xorm:"TEXT"` | Cfg core.Conversion `xorm:"TEXT"` | ||||
Created time.Time `xorm:"-"` | Created time.Time `xorm:"-"` | ||||
CreatedUnix int64 `xorm:"INDEX"` | |||||
CreatedUnix int64 `xorm:"INDEX created"` | |||||
Updated time.Time `xorm:"-"` | Updated time.Time `xorm:"-"` | ||||
UpdatedUnix int64 `xorm:"INDEX"` | |||||
} | |||||
// BeforeInsert is invoked from XORM before inserting an object of this type. | |||||
func (source *LoginSource) BeforeInsert() { | |||||
source.CreatedUnix = time.Now().Unix() | |||||
source.UpdatedUnix = source.CreatedUnix | |||||
} | |||||
// BeforeUpdate is invoked from XORM before updating this object. | |||||
func (source *LoginSource) BeforeUpdate() { | |||||
source.UpdatedUnix = time.Now().Unix() | |||||
UpdatedUnix int64 `xorm:"INDEX updated"` | |||||
} | } | ||||
// Cell2Int64 converts a xorm.Cell type to int64, | // Cell2Int64 converts a xorm.Cell type to int64, | ||||
@@ -241,6 +241,7 @@ func NewTestEngine(x *xorm.Engine) (err error) { | |||||
x.SetMapper(core.GonicMapper{}) | x.SetMapper(core.GonicMapper{}) | ||||
x.SetLogger(log.XORMLogger) | x.SetLogger(log.XORMLogger) | ||||
x.ShowSQL(!setting.ProdMode) | |||||
return x.StoreEngine("InnoDB").Sync2(tables...) | return x.StoreEngine("InnoDB").Sync2(tables...) | ||||
} | } | ||||
@@ -211,20 +211,9 @@ type Repository struct { | |||||
Size int64 `xorm:"NOT NULL DEFAULT 0"` | Size int64 `xorm:"NOT NULL DEFAULT 0"` | ||||
Created time.Time `xorm:"-"` | Created time.Time `xorm:"-"` | ||||
CreatedUnix int64 `xorm:"INDEX"` | |||||
CreatedUnix int64 `xorm:"INDEX created"` | |||||
Updated time.Time `xorm:"-"` | Updated time.Time `xorm:"-"` | ||||
UpdatedUnix int64 `xorm:"INDEX"` | |||||
} | |||||
// BeforeInsert is invoked from XORM before inserting an object of this type. | |||||
func (repo *Repository) BeforeInsert() { | |||||
repo.CreatedUnix = time.Now().Unix() | |||||
repo.UpdatedUnix = repo.CreatedUnix | |||||
} | |||||
// BeforeUpdate is invoked from XORM before updating this object. | |||||
func (repo *Repository) BeforeUpdate() { | |||||
repo.UpdatedUnix = time.Now().Unix() | |||||
UpdatedUnix int64 `xorm:"INDEX updated"` | |||||
} | } | ||||
// AfterSet is invoked from XORM after setting the value of a field of this object. | // AfterSet is invoked from XORM after setting the value of a field of this object. | ||||
@@ -40,18 +40,26 @@ type Mirror struct { | |||||
// BeforeInsert will be invoked by XORM before inserting a record | // BeforeInsert will be invoked by XORM before inserting a record | ||||
func (m *Mirror) BeforeInsert() { | func (m *Mirror) BeforeInsert() { | ||||
m.UpdatedUnix = time.Now().Unix() | |||||
m.NextUpdateUnix = m.NextUpdate.Unix() | |||||
if m != nil { | |||||
m.UpdatedUnix = time.Now().Unix() | |||||
m.NextUpdateUnix = m.NextUpdate.Unix() | |||||
} | |||||
} | } | ||||
// BeforeUpdate is invoked from XORM before updating this object. | // BeforeUpdate is invoked from XORM before updating this object. | ||||
func (m *Mirror) BeforeUpdate() { | func (m *Mirror) BeforeUpdate() { | ||||
m.UpdatedUnix = time.Now().Unix() | |||||
m.NextUpdateUnix = m.NextUpdate.Unix() | |||||
if m != nil { | |||||
m.UpdatedUnix = time.Now().Unix() | |||||
m.NextUpdateUnix = m.NextUpdate.Unix() | |||||
} | |||||
} | } | ||||
// AfterSet is invoked from XORM after setting the value of a field of this object. | // AfterSet is invoked from XORM after setting the value of a field of this object. | ||||
func (m *Mirror) AfterSet(colName string, _ xorm.Cell) { | func (m *Mirror) AfterSet(colName string, _ xorm.Cell) { | ||||
if m == nil { | |||||
return | |||||
} | |||||
var err error | var err error | ||||
switch colName { | switch colName { | ||||
case "repo_id": | case "repo_id": | ||||
@@ -55,21 +55,11 @@ type PublicKey struct { | |||||
Type KeyType `xorm:"NOT NULL DEFAULT 1"` | Type KeyType `xorm:"NOT NULL DEFAULT 1"` | ||||
Created time.Time `xorm:"-"` | Created time.Time `xorm:"-"` | ||||
CreatedUnix int64 | |||||
CreatedUnix int64 `xorm:"created"` | |||||
Updated time.Time `xorm:"-"` // Note: Updated must below Created for AfterSet. | Updated time.Time `xorm:"-"` // Note: Updated must below Created for AfterSet. | ||||
UpdatedUnix int64 | |||||
HasRecentActivity bool `xorm:"-"` | |||||
HasUsed bool `xorm:"-"` | |||||
} | |||||
// BeforeInsert will be invoked by XORM before inserting a record | |||||
func (key *PublicKey) BeforeInsert() { | |||||
key.CreatedUnix = time.Now().Unix() | |||||
} | |||||
// BeforeUpdate is invoked from XORM before updating this object. | |||||
func (key *PublicKey) BeforeUpdate() { | |||||
key.UpdatedUnix = time.Now().Unix() | |||||
UpdatedUnix int64 `xorm:"updated"` | |||||
HasRecentActivity bool `xorm:"-"` | |||||
HasUsed bool `xorm:"-"` | |||||
} | } | ||||
// AfterSet is invoked from XORM after setting the value of a field of this object. | // AfterSet is invoked from XORM after setting the value of a field of this object. | ||||
@@ -633,21 +623,11 @@ type DeployKey struct { | |||||
Content string `xorm:"-"` | Content string `xorm:"-"` | ||||
Created time.Time `xorm:"-"` | Created time.Time `xorm:"-"` | ||||
CreatedUnix int64 | |||||
CreatedUnix int64 `xorm:"created"` | |||||
Updated time.Time `xorm:"-"` // Note: Updated must below Created for AfterSet. | Updated time.Time `xorm:"-"` // Note: Updated must below Created for AfterSet. | ||||
UpdatedUnix int64 | |||||
HasRecentActivity bool `xorm:"-"` | |||||
HasUsed bool `xorm:"-"` | |||||
} | |||||
// BeforeInsert will be invoked by XORM before inserting a record | |||||
func (key *DeployKey) BeforeInsert() { | |||||
key.CreatedUnix = time.Now().Unix() | |||||
} | |||||
// BeforeUpdate is invoked from XORM before updating this object. | |||||
func (key *DeployKey) BeforeUpdate() { | |||||
key.UpdatedUnix = time.Now().Unix() | |||||
UpdatedUnix int64 `xorm:"updated"` | |||||
HasRecentActivity bool `xorm:"-"` | |||||
HasUsed bool `xorm:"-"` | |||||
} | } | ||||
// AfterSet is invoked from XORM after setting the value of a field of this object. | // AfterSet is invoked from XORM after setting the value of a field of this object. | ||||
@@ -66,20 +66,9 @@ type CommitStatus struct { | |||||
CreatorID int64 | CreatorID int64 | ||||
Created time.Time `xorm:"-"` | Created time.Time `xorm:"-"` | ||||
CreatedUnix int64 `xorm:"INDEX"` | |||||
CreatedUnix int64 `xorm:"INDEX created"` | |||||
Updated time.Time `xorm:"-"` | Updated time.Time `xorm:"-"` | ||||
UpdatedUnix int64 `xorm:"INDEX"` | |||||
} | |||||
// BeforeInsert is invoked from XORM before inserting an object of this type. | |||||
func (status *CommitStatus) BeforeInsert() { | |||||
status.CreatedUnix = time.Now().Unix() | |||||
status.UpdatedUnix = status.CreatedUnix | |||||
} | |||||
// BeforeUpdate is invoked from XORM before updating this object. | |||||
func (status *CommitStatus) BeforeUpdate() { | |||||
status.UpdatedUnix = time.Now().Unix() | |||||
UpdatedUnix int64 `xorm:"INDEX updated"` | |||||
} | } | ||||
// AfterSet is invoked from XORM after setting the value of a field of | // AfterSet is invoked from XORM after setting the value of a field of | ||||
@@ -21,23 +21,13 @@ type AccessToken struct { | |||||
Sha1 string `xorm:"UNIQUE VARCHAR(40)"` | Sha1 string `xorm:"UNIQUE VARCHAR(40)"` | ||||
Created time.Time `xorm:"-"` | Created time.Time `xorm:"-"` | ||||
CreatedUnix int64 `xorm:"INDEX"` | |||||
CreatedUnix int64 `xorm:"INDEX created"` | |||||
Updated time.Time `xorm:"-"` // Note: Updated must below Created for AfterSet. | Updated time.Time `xorm:"-"` // Note: Updated must below Created for AfterSet. | ||||
UpdatedUnix int64 `xorm:"INDEX"` | |||||
UpdatedUnix int64 `xorm:"INDEX updated"` | |||||
HasRecentActivity bool `xorm:"-"` | HasRecentActivity bool `xorm:"-"` | ||||
HasUsed bool `xorm:"-"` | HasUsed bool `xorm:"-"` | ||||
} | } | ||||
// BeforeInsert will be invoked by XORM before inserting a record representing this object. | |||||
func (t *AccessToken) BeforeInsert() { | |||||
t.CreatedUnix = time.Now().Unix() | |||||
} | |||||
// BeforeUpdate is invoked from XORM before updating this object. | |||||
func (t *AccessToken) BeforeUpdate() { | |||||
t.UpdatedUnix = time.Now().Unix() | |||||
} | |||||
// AfterSet is invoked from XORM after setting the value of a field of this object. | // AfterSet is invoked from XORM after setting the value of a field of this object. | ||||
func (t *AccessToken) AfterSet(colName string, _ xorm.Cell) { | func (t *AccessToken) AfterSet(colName string, _ xorm.Cell) { | ||||
switch colName { | switch colName { | ||||
@@ -26,19 +26,9 @@ type TwoFactor struct { | |||||
ScratchToken string | ScratchToken string | ||||
Created time.Time `xorm:"-"` | Created time.Time `xorm:"-"` | ||||
CreatedUnix int64 `xorm:"INDEX"` | |||||
CreatedUnix int64 `xorm:"INDEX created"` | |||||
Updated time.Time `xorm:"-"` // Note: Updated must below Created for AfterSet. | Updated time.Time `xorm:"-"` // Note: Updated must below Created for AfterSet. | ||||
UpdatedUnix int64 `xorm:"INDEX"` | |||||
} | |||||
// BeforeInsert will be invoked by XORM before inserting a record representing this object. | |||||
func (t *TwoFactor) BeforeInsert() { | |||||
t.CreatedUnix = time.Now().Unix() | |||||
} | |||||
// BeforeUpdate is invoked from XORM before updating this object. | |||||
func (t *TwoFactor) BeforeUpdate() { | |||||
t.UpdatedUnix = time.Now().Unix() | |||||
UpdatedUnix int64 `xorm:"INDEX updated"` | |||||
} | } | ||||
// AfterSet is invoked from XORM after setting the value of a field of this object. | // AfterSet is invoked from XORM after setting the value of a field of this object. | ||||
@@ -28,6 +28,7 @@ func CreateTestEngine(fixturesDir string) error { | |||||
if err = x.StoreEngine("InnoDB").Sync2(tables...); err != nil { | if err = x.StoreEngine("InnoDB").Sync2(tables...); err != nil { | ||||
return err | return err | ||||
} | } | ||||
x.ShowSQL(true) | |||||
return InitFixtures(&testfixtures.SQLite{}, fixturesDir) | return InitFixtures(&testfixtures.SQLite{}, fixturesDir) | ||||
} | } | ||||
@@ -94,9 +94,9 @@ type User struct { | |||||
Salt string `xorm:"VARCHAR(10)"` | Salt string `xorm:"VARCHAR(10)"` | ||||
Created time.Time `xorm:"-"` | Created time.Time `xorm:"-"` | ||||
CreatedUnix int64 `xorm:"INDEX"` | |||||
CreatedUnix int64 `xorm:"INDEX created"` | |||||
Updated time.Time `xorm:"-"` | Updated time.Time `xorm:"-"` | ||||
UpdatedUnix int64 `xorm:"INDEX"` | |||||
UpdatedUnix int64 `xorm:"INDEX updated"` | |||||
LastLogin time.Time `xorm:"-"` | LastLogin time.Time `xorm:"-"` | ||||
LastLoginUnix int64 `xorm:"INDEX"` | LastLoginUnix int64 `xorm:"INDEX"` | ||||
@@ -135,18 +135,11 @@ type User struct { | |||||
DiffViewStyle string `xorm:"NOT NULL DEFAULT ''"` | DiffViewStyle string `xorm:"NOT NULL DEFAULT ''"` | ||||
} | } | ||||
// BeforeInsert is invoked from XORM before inserting an object of this type. | |||||
func (u *User) BeforeInsert() { | |||||
u.CreatedUnix = time.Now().Unix() | |||||
u.UpdatedUnix = u.CreatedUnix | |||||
} | |||||
// BeforeUpdate is invoked from XORM before updating this object. | // BeforeUpdate is invoked from XORM before updating this object. | ||||
func (u *User) BeforeUpdate() { | func (u *User) BeforeUpdate() { | ||||
if u.MaxRepoCreation < -1 { | if u.MaxRepoCreation < -1 { | ||||
u.MaxRepoCreation = -1 | u.MaxRepoCreation = -1 | ||||
} | } | ||||
u.UpdatedUnix = time.Now().Unix() | |||||
} | } | ||||
// SetLastLogin set time to last login | // SetLastLogin set time to last login | ||||
@@ -897,7 +890,6 @@ func UpdateUserCols(u *User, cols ...string) error { | |||||
u.Website = base.TruncateString(u.Website, 255) | u.Website = base.TruncateString(u.Website, 255) | ||||
u.Description = base.TruncateString(u.Description, 255) | u.Description = base.TruncateString(u.Description, 255) | ||||
cols = append(cols, "updated_unix") | |||||
_, err := x.Id(u.ID).Cols(cols...).Update(u) | _, err := x.Id(u.ID).Cols(cols...).Update(u) | ||||
return err | return err | ||||
} | } | ||||
@@ -107,22 +107,9 @@ type Webhook struct { | |||||
LastStatus HookStatus // Last delivery status | LastStatus HookStatus // Last delivery status | ||||
Created time.Time `xorm:"-"` | Created time.Time `xorm:"-"` | ||||
CreatedUnix int64 `xorm:"INDEX"` | |||||
CreatedUnix int64 `xorm:"INDEX created"` | |||||
Updated time.Time `xorm:"-"` | Updated time.Time `xorm:"-"` | ||||
UpdatedUnix int64 `xorm:"INDEX"` | |||||
} | |||||
// BeforeInsert will be invoked by XORM before inserting a record | |||||
// representing this object | |||||
func (w *Webhook) BeforeInsert() { | |||||
w.CreatedUnix = time.Now().Unix() | |||||
w.UpdatedUnix = w.CreatedUnix | |||||
} | |||||
// BeforeUpdate will be invoked by XORM before updating a record | |||||
// representing this object | |||||
func (w *Webhook) BeforeUpdate() { | |||||
w.UpdatedUnix = time.Now().Unix() | |||||
UpdatedUnix int64 `xorm:"INDEX updated"` | |||||
} | } | ||||
// AfterSet updates the webhook object upon setting a column | // AfterSet updates the webhook object upon setting a column | ||||
@@ -100,7 +100,8 @@ var ( | |||||
LongBlob = "LONGBLOB" | LongBlob = "LONGBLOB" | ||||
Bytea = "BYTEA" | Bytea = "BYTEA" | ||||
Bool = "BOOL" | |||||
Bool = "BOOL" | |||||
Boolean = "BOOLEAN" | |||||
Serial = "SERIAL" | Serial = "SERIAL" | ||||
BigSerial = "BIGSERIAL" | BigSerial = "BIGSERIAL" | ||||
@@ -163,7 +164,7 @@ var ( | |||||
uintTypes = sort.StringSlice{"*uint", "*uint16", "*uint32", "*uint8"} | uintTypes = sort.StringSlice{"*uint", "*uint16", "*uint32", "*uint8"} | ||||
) | ) | ||||
// !nashtsai! treat following var as interal const values, these are used for reflect.TypeOf comparision | |||||
// !nashtsai! treat following var as interal const values, these are used for reflect.TypeOf comparison | |||||
var ( | var ( | ||||
c_EMPTY_STRING string | c_EMPTY_STRING string | ||||
c_BOOL_DEFAULT bool | c_BOOL_DEFAULT bool | ||||
@@ -34,7 +34,7 @@ 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) | * 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) | |||||
* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/tree/master/godrv) | |||||
* Postgres: [github.com/lib/pq](https://github.com/lib/pq) | * Postgres: [github.com/lib/pq](https://github.com/lib/pq) | ||||
@@ -15,13 +15,12 @@ import ( | |||||
// LRUCacher implments cache object facilities | // LRUCacher implments cache object facilities | ||||
type LRUCacher struct { | type LRUCacher struct { | ||||
idList *list.List | |||||
sqlList *list.List | |||||
idIndex map[string]map[string]*list.Element | |||||
sqlIndex map[string]map[string]*list.Element | |||||
store core.CacheStore | |||||
mutex sync.Mutex | |||||
// maxSize int | |||||
idList *list.List | |||||
sqlList *list.List | |||||
idIndex map[string]map[string]*list.Element | |||||
sqlIndex map[string]map[string]*list.Element | |||||
store core.CacheStore | |||||
mutex sync.Mutex | |||||
MaxElementSize int | MaxElementSize int | ||||
Expired time.Duration | Expired time.Duration | ||||
GcInterval time.Duration | GcInterval time.Duration | ||||
@@ -54,8 +53,6 @@ func (m *LRUCacher) RunGC() { | |||||
// GC check ids lit and sql list to remove all element expired | // GC check ids lit and sql list to remove all element expired | ||||
func (m *LRUCacher) GC() { | func (m *LRUCacher) GC() { | ||||
//fmt.Println("begin gc ...") | |||||
//defer fmt.Println("end gc ...") | |||||
m.mutex.Lock() | m.mutex.Lock() | ||||
defer m.mutex.Unlock() | defer m.mutex.Unlock() | ||||
var removedNum int | var removedNum int | ||||
@@ -64,12 +61,10 @@ func (m *LRUCacher) GC() { | |||||
time.Now().Sub(e.Value.(*idNode).lastVisit) > m.Expired { | time.Now().Sub(e.Value.(*idNode).lastVisit) > m.Expired { | ||||
removedNum++ | removedNum++ | ||||
next := e.Next() | next := e.Next() | ||||
//fmt.Println("removing ...", e.Value) | |||||
node := e.Value.(*idNode) | node := e.Value.(*idNode) | ||||
m.delBean(node.tbName, node.id) | m.delBean(node.tbName, node.id) | ||||
e = next | e = next | ||||
} else { | } else { | ||||
//fmt.Printf("removing %d cache nodes ..., left %d\n", removedNum, m.idList.Len()) | |||||
break | break | ||||
} | } | ||||
} | } | ||||
@@ -80,12 +75,10 @@ func (m *LRUCacher) GC() { | |||||
time.Now().Sub(e.Value.(*sqlNode).lastVisit) > m.Expired { | time.Now().Sub(e.Value.(*sqlNode).lastVisit) > m.Expired { | ||||
removedNum++ | removedNum++ | ||||
next := e.Next() | next := e.Next() | ||||
//fmt.Println("removing ...", e.Value) | |||||
node := e.Value.(*sqlNode) | node := e.Value.(*sqlNode) | ||||
m.delIds(node.tbName, node.sql) | m.delIds(node.tbName, node.sql) | ||||
e = next | e = next | ||||
} else { | } else { | ||||
//fmt.Printf("removing %d cache nodes ..., left %d\n", removedNum, m.sqlList.Len()) | |||||
break | break | ||||
} | } | ||||
} | } | ||||
@@ -116,7 +109,6 @@ func (m *LRUCacher) GetIds(tableName, sql string) interface{} { | |||||
} | } | ||||
m.delIds(tableName, sql) | m.delIds(tableName, sql) | ||||
return nil | return nil | ||||
} | } | ||||
@@ -134,7 +126,6 @@ func (m *LRUCacher) GetBean(tableName string, id string) interface{} { | |||||
// if expired, remove the node and return nil | // if expired, remove the node and return nil | ||||
if time.Now().Sub(lastTime) > m.Expired { | if time.Now().Sub(lastTime) > m.Expired { | ||||
m.delBean(tableName, id) | m.delBean(tableName, id) | ||||
//m.clearIds(tableName) | |||||
return nil | return nil | ||||
} | } | ||||
m.idList.MoveToBack(el) | m.idList.MoveToBack(el) | ||||
@@ -148,7 +139,6 @@ func (m *LRUCacher) GetBean(tableName string, id string) interface{} { | |||||
// store bean is not exist, then remove memory's index | // store bean is not exist, then remove memory's index | ||||
m.delBean(tableName, id) | m.delBean(tableName, id) | ||||
//m.clearIds(tableName) | |||||
return nil | return nil | ||||
} | } | ||||
@@ -166,8 +156,8 @@ func (m *LRUCacher) clearIds(tableName string) { | |||||
// ClearIds clears all sql-ids mapping on table tableName from cache | // ClearIds clears all sql-ids mapping on table tableName from cache | ||||
func (m *LRUCacher) ClearIds(tableName string) { | func (m *LRUCacher) ClearIds(tableName string) { | ||||
m.mutex.Lock() | m.mutex.Lock() | ||||
defer m.mutex.Unlock() | |||||
m.clearIds(tableName) | m.clearIds(tableName) | ||||
m.mutex.Unlock() | |||||
} | } | ||||
func (m *LRUCacher) clearBeans(tableName string) { | func (m *LRUCacher) clearBeans(tableName string) { | ||||
@@ -184,14 +174,13 @@ func (m *LRUCacher) clearBeans(tableName string) { | |||||
// ClearBeans clears all beans in some table | // ClearBeans clears all beans in some table | ||||
func (m *LRUCacher) ClearBeans(tableName string) { | func (m *LRUCacher) ClearBeans(tableName string) { | ||||
m.mutex.Lock() | m.mutex.Lock() | ||||
defer m.mutex.Unlock() | |||||
m.clearBeans(tableName) | m.clearBeans(tableName) | ||||
m.mutex.Unlock() | |||||
} | } | ||||
// PutIds pus ids into table | // PutIds pus ids into table | ||||
func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) { | func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) { | ||||
m.mutex.Lock() | m.mutex.Lock() | ||||
defer m.mutex.Unlock() | |||||
if _, ok := m.sqlIndex[tableName]; !ok { | if _, ok := m.sqlIndex[tableName]; !ok { | ||||
m.sqlIndex[tableName] = make(map[string]*list.Element) | m.sqlIndex[tableName] = make(map[string]*list.Element) | ||||
} | } | ||||
@@ -207,12 +196,12 @@ func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) { | |||||
node := e.Value.(*sqlNode) | node := e.Value.(*sqlNode) | ||||
m.delIds(node.tbName, node.sql) | m.delIds(node.tbName, node.sql) | ||||
} | } | ||||
m.mutex.Unlock() | |||||
} | } | ||||
// PutBean puts beans into table | // PutBean puts beans into table | ||||
func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) { | func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) { | ||||
m.mutex.Lock() | m.mutex.Lock() | ||||
defer m.mutex.Unlock() | |||||
var el *list.Element | var el *list.Element | ||||
var ok bool | var ok bool | ||||
@@ -229,6 +218,7 @@ func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) { | |||||
node := e.Value.(*idNode) | node := e.Value.(*idNode) | ||||
m.delBean(node.tbName, node.id) | m.delBean(node.tbName, node.id) | ||||
} | } | ||||
m.mutex.Unlock() | |||||
} | } | ||||
func (m *LRUCacher) delIds(tableName, sql string) { | func (m *LRUCacher) delIds(tableName, sql string) { | ||||
@@ -244,8 +234,8 @@ func (m *LRUCacher) delIds(tableName, sql string) { | |||||
// DelIds deletes ids | // DelIds deletes ids | ||||
func (m *LRUCacher) DelIds(tableName, sql string) { | func (m *LRUCacher) DelIds(tableName, sql string) { | ||||
m.mutex.Lock() | m.mutex.Lock() | ||||
defer m.mutex.Unlock() | |||||
m.delIds(tableName, sql) | m.delIds(tableName, sql) | ||||
m.mutex.Unlock() | |||||
} | } | ||||
func (m *LRUCacher) delBean(tableName string, id string) { | func (m *LRUCacher) delBean(tableName string, id string) { | ||||
@@ -261,8 +251,8 @@ func (m *LRUCacher) delBean(tableName string, id string) { | |||||
// DelBean deletes beans in some table | // DelBean deletes beans in some table | ||||
func (m *LRUCacher) DelBean(tableName string, id string) { | func (m *LRUCacher) DelBean(tableName string, id string) { | ||||
m.mutex.Lock() | m.mutex.Lock() | ||||
defer m.mutex.Unlock() | |||||
m.delBean(tableName, id) | m.delBean(tableName, id) | ||||
m.mutex.Unlock() | |||||
} | } | ||||
type idNode struct { | type idNode struct { | ||||
@@ -21,7 +21,16 @@ database: | |||||
test: | test: | ||||
override: | override: | ||||
# './...' is a relative pattern which means all subdirectories | # './...' is a relative pattern which means all subdirectories | ||||
- go test -v -race -db="sqlite3::mysql::mymysql::postgres" -conn_str="./test.db::root:@/xorm_test::xorm_test/root/::dbname=xorm_test sslmode=disable" -coverprofile=coverage.txt -covermode=atomic | |||||
- go get -u github.com/wadey/gocovmerge; | |||||
- go test -v -race -db="sqlite3" -conn_str="./test.db" -coverprofile=coverage1-1.txt -covermode=atomic | |||||
- go test -v -race -db="sqlite3" -conn_str="./test.db" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic | |||||
- go test -v -race -db="mysql" -conn_str="root:@/xorm_test" -coverprofile=coverage2-1.txt -covermode=atomic | |||||
- go test -v -race -db="mysql" -conn_str="root:@/xorm_test" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic | |||||
- go test -v -race -db="mymysql" -conn_str="xorm_test/root/" -coverprofile=coverage3-1.txt -covermode=atomic | |||||
- go test -v -race -db="mymysql" -conn_str="xorm_test/root/" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic | |||||
- go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -coverprofile=coverage4-1.txt -covermode=atomic | |||||
- go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic | |||||
- gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt > coverage.txt | |||||
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./sqlite3.sh | - cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./sqlite3.sh | ||||
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./mysql.sh | - cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./mysql.sh | ||||
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./postgres.sh | - cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./postgres.sh | ||||
@@ -334,3 +334,15 @@ func convertInt(v interface{}) (int64, error) { | |||||
} | } | ||||
return 0, fmt.Errorf("unsupported type: %v", v) | return 0, fmt.Errorf("unsupported type: %v", v) | ||||
} | } | ||||
func asBool(bs []byte) (bool, error) { | |||||
if len(bs) == 0 { | |||||
return false, nil | |||||
} | |||||
if bs[0] == 0x00 { | |||||
return false, nil | |||||
} else if bs[0] == 0x01 { | |||||
return true, nil | |||||
} | |||||
return strconv.ParseBool(string(bs)) | |||||
} |
@@ -781,6 +781,9 @@ func (db *postgres) SqlType(c *core.Column) string { | |||||
case core.TinyInt: | case core.TinyInt: | ||||
res = core.SmallInt | res = core.SmallInt | ||||
return res | return res | ||||
case core.Bit: | |||||
res = core.Boolean | |||||
return res | |||||
case core.MediumInt, core.Int, core.Integer: | case core.MediumInt, core.Int, core.Integer: | ||||
if c.IsAutoIncrement { | if c.IsAutoIncrement { | ||||
return core.Serial | return core.Serial | ||||
@@ -90,7 +90,7 @@ another is Rows | |||||
5. Update one or more records | 5. Update one or more records | ||||
affected, err := engine.Id(...).Update(&user) | |||||
affected, err := engine.ID(...).Update(&user) | |||||
// UPDATE user SET ... | // UPDATE user SET ... | ||||
6. Delete one or more records, Delete MUST has condition | 6. Delete one or more records, Delete MUST has condition | ||||
@@ -273,36 +273,6 @@ func (engine *Engine) logSQL(sqlStr string, sqlArgs ...interface{}) { | |||||
} | } | ||||
} | } | ||||
func (engine *Engine) logSQLQueryTime(sqlStr string, args []interface{}, executionBlock func() (*core.Stmt, *core.Rows, error)) (*core.Stmt, *core.Rows, error) { | |||||
if engine.showSQL && engine.showExecTime { | |||||
b4ExecTime := time.Now() | |||||
stmt, res, err := executionBlock() | |||||
execDuration := time.Since(b4ExecTime) | |||||
if len(args) > 0 { | |||||
engine.logger.Infof("[SQL] %s %v - took: %v", sqlStr, args, execDuration) | |||||
} else { | |||||
engine.logger.Infof("[SQL] %s - took: %v", sqlStr, execDuration) | |||||
} | |||||
return stmt, res, err | |||||
} | |||||
return executionBlock() | |||||
} | |||||
func (engine *Engine) logSQLExecutionTime(sqlStr string, args []interface{}, executionBlock func() (sql.Result, error)) (sql.Result, error) { | |||||
if engine.showSQL && engine.showExecTime { | |||||
b4ExecTime := time.Now() | |||||
res, err := executionBlock() | |||||
execDuration := time.Since(b4ExecTime) | |||||
if len(args) > 0 { | |||||
engine.logger.Infof("[sql] %s [args] %v - took: %v", sqlStr, args, execDuration) | |||||
} else { | |||||
engine.logger.Infof("[sql] %s - took: %v", sqlStr, execDuration) | |||||
} | |||||
return res, err | |||||
} | |||||
return executionBlock() | |||||
} | |||||
// Sql provides raw sql input parameter. When you have a complex SQL statement | // Sql provides raw sql input parameter. When you have a complex SQL statement | ||||
// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL. | // and cannot use Where, Id, In and etc. Methods to describe, you can use SQL. | ||||
// | // | ||||
@@ -1384,6 +1354,13 @@ func (engine *Engine) QueryString(sqlStr string, args ...interface{}) ([]map[str | |||||
return session.QueryString(sqlStr, args...) | return session.QueryString(sqlStr, args...) | ||||
} | } | ||||
// QueryInterface runs a raw sql and return records as []map[string]interface{} | |||||
func (engine *Engine) QueryInterface(sqlStr string, args ...interface{}) ([]map[string]interface{}, error) { | |||||
session := engine.NewSession() | |||||
defer session.Close() | |||||
return session.QueryInterface(sqlStr, args...) | |||||
} | |||||
// Insert one or more records | // Insert one or more records | ||||
func (engine *Engine) Insert(beans ...interface{}) (int64, error) { | func (engine *Engine) Insert(beans ...interface{}) (int64, error) { | ||||
session := engine.NewSession() | session := engine.NewSession() | ||||
@@ -17,7 +17,6 @@ type Rows struct { | |||||
NoTypeCheck bool | NoTypeCheck bool | ||||
session *Session | session *Session | ||||
stmt *core.Stmt | |||||
rows *core.Rows | rows *core.Rows | ||||
fields []string | fields []string | ||||
beanType reflect.Type | beanType reflect.Type | ||||
@@ -29,8 +28,6 @@ func newRows(session *Session, bean interface{}) (*Rows, error) { | |||||
rows.session = session | rows.session = session | ||||
rows.beanType = reflect.Indirect(reflect.ValueOf(bean)).Type() | rows.beanType = reflect.Indirect(reflect.ValueOf(bean)).Type() | ||||
defer rows.session.resetStatement() | |||||
var sqlStr string | var sqlStr string | ||||
var args []interface{} | var args []interface{} | ||||
var err error | var err error | ||||
@@ -53,32 +50,11 @@ func newRows(session *Session, bean interface{}) (*Rows, error) { | |||||
args = rows.session.statement.RawParams | args = rows.session.statement.RawParams | ||||
} | } | ||||
for _, filter := range rows.session.engine.dialect.Filters() { | |||||
sqlStr = filter.Do(sqlStr, session.engine.dialect, rows.session.statement.RefTable) | |||||
} | |||||
rows.session.saveLastSQL(sqlStr, args...) | |||||
if rows.session.prepareStmt { | |||||
rows.stmt, err = rows.session.DB().Prepare(sqlStr) | |||||
if err != nil { | |||||
rows.lastError = err | |||||
rows.Close() | |||||
return nil, err | |||||
} | |||||
rows.rows, err = rows.stmt.Query(args...) | |||||
if err != nil { | |||||
rows.lastError = err | |||||
rows.Close() | |||||
return nil, err | |||||
} | |||||
} else { | |||||
rows.rows, err = rows.session.DB().Query(sqlStr, args...) | |||||
if err != nil { | |||||
rows.lastError = err | |||||
rows.Close() | |||||
return nil, err | |||||
} | |||||
rows.rows, err = rows.session.queryRows(sqlStr, args...) | |||||
if err != nil { | |||||
rows.lastError = err | |||||
rows.Close() | |||||
return nil, err | |||||
} | } | ||||
rows.fields, err = rows.rows.Columns() | rows.fields, err = rows.rows.Columns() | ||||
@@ -142,17 +118,10 @@ func (rows *Rows) Close() error { | |||||
if rows.rows != nil { | if rows.rows != nil { | ||||
rows.lastError = rows.rows.Close() | rows.lastError = rows.rows.Close() | ||||
if rows.lastError != nil { | if rows.lastError != nil { | ||||
defer rows.stmt.Close() | |||||
return rows.lastError | return rows.lastError | ||||
} | } | ||||
} | } | ||||
if rows.stmt != nil { | |||||
rows.lastError = rows.stmt.Close() | |||||
} | |||||
} else { | } else { | ||||
if rows.stmt != nil { | |||||
defer rows.stmt.Close() | |||||
} | |||||
if rows.rows != nil { | if rows.rows != nil { | ||||
defer rows.rows.Close() | defer rows.rows.Close() | ||||
} | } | ||||
@@ -303,6 +303,7 @@ func (session *Session) rows2Beans(rows *core.Rows, fields []string, fieldsCount | |||||
var newValue = newElemFunc(fields) | var newValue = newElemFunc(fields) | ||||
bean := newValue.Interface() | bean := newValue.Interface() | ||||
dataStruct := rValue(bean) | dataStruct := rValue(bean) | ||||
// handle beforeClosures | // handle beforeClosures | ||||
scanResults, err := session.row2Slice(rows, fields, fieldsCount, bean) | scanResults, err := session.row2Slice(rows, fields, fieldsCount, bean) | ||||
if err != nil { | if err != nil { | ||||
@@ -312,7 +313,6 @@ func (session *Session) rows2Beans(rows *core.Rows, fields []string, fieldsCount | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
err = sliceValueSetFunc(&newValue, pk) | err = sliceValueSetFunc(&newValue, pk) | ||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
@@ -631,9 +631,7 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, f | |||||
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne | // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne | ||||
// property to be fetched lazily | // property to be fetched lazily | ||||
structInter := reflect.New(fieldValue.Type()) | structInter := reflect.New(fieldValue.Type()) | ||||
newsession := session.engine.NewSession() | |||||
defer newsession.Close() | |||||
has, err := newsession.ID(pk).NoCascade().Get(structInter.Interface()) | |||||
has, err := session.ID(pk).NoCascade().get(structInter.Interface()) | |||||
if err != nil { | if err != nil { | ||||
return nil, err | return nil, err | ||||
} | } | ||||
@@ -777,14 +775,6 @@ func (session *Session) slice2Bean(scanResults []interface{}, fields []string, f | |||||
return pk, nil | return pk, nil | ||||
} | } | ||||
func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) { | |||||
for _, filter := range session.engine.dialect.Filters() { | |||||
*sqlStr = filter.Do(*sqlStr, session.engine.dialect, session.statement.RefTable) | |||||
} | |||||
session.saveLastSQL(*sqlStr, paramStr...) | |||||
} | |||||
// saveLastSQL stores executed query information | // saveLastSQL stores executed query information | ||||
func (session *Session) saveLastSQL(sql string, args ...interface{}) { | func (session *Session) saveLastSQL(sql string, args ...interface{}) { | ||||
session.lastSQL = sql | session.lastSQL = sql | ||||
@@ -144,8 +144,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, | |||||
case reflect.String: | case reflect.String: | ||||
fieldValue.SetString(string(data)) | fieldValue.SetString(string(data)) | ||||
case reflect.Bool: | case reflect.Bool: | ||||
d := string(data) | |||||
v, err := strconv.ParseBool(d) | |||||
v, err := asBool(data) | |||||
if err != nil { | if err != nil { | ||||
return fmt.Errorf("arg %v as bool: %s", key, err.Error()) | return fmt.Errorf("arg %v as bool: %s", key, err.Error()) | ||||
} | } | ||||
@@ -227,9 +226,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, | |||||
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne | // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne | ||||
// property to be fetched lazily | // property to be fetched lazily | ||||
structInter := reflect.New(fieldValue.Type()) | structInter := reflect.New(fieldValue.Type()) | ||||
newsession := session.engine.NewSession() | |||||
defer newsession.Close() | |||||
has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface()) | |||||
has, err := session.ID(pk).NoCascade().get(structInter.Interface()) | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
@@ -510,9 +507,7 @@ func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, | |||||
// !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch | // !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch | ||||
// however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne | // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne | ||||
// property to be fetched lazily | // property to be fetched lazily | ||||
newsession := session.engine.NewSession() | |||||
defer newsession.Close() | |||||
has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface()) | |||||
has, err := session.ID(pk).NoCascade().get(structInter.Interface()) | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
@@ -12,14 +12,14 @@ import ( | |||||
"github.com/go-xorm/core" | "github.com/go-xorm/core" | ||||
) | ) | ||||
func (session *Session) cacheDelete(sqlStr string, args ...interface{}) error { | |||||
if session.statement.RefTable == nil || | |||||
func (session *Session) cacheDelete(table *core.Table, tableName, sqlStr string, args ...interface{}) error { | |||||
if table == nil || | |||||
session.tx != nil { | session.tx != nil { | ||||
return ErrCacheFailed | return ErrCacheFailed | ||||
} | } | ||||
for _, filter := range session.engine.dialect.Filters() { | for _, filter := range session.engine.dialect.Filters() { | ||||
sqlStr = filter.Do(sqlStr, session.engine.dialect, session.statement.RefTable) | |||||
sqlStr = filter.Do(sqlStr, session.engine.dialect, table) | |||||
} | } | ||||
newsql := session.statement.convertIDSQL(sqlStr) | newsql := session.statement.convertIDSQL(sqlStr) | ||||
@@ -27,11 +27,11 @@ func (session *Session) cacheDelete(sqlStr string, args ...interface{}) error { | |||||
return ErrCacheFailed | return ErrCacheFailed | ||||
} | } | ||||
cacher := session.engine.getCacher2(session.statement.RefTable) | |||||
tableName := session.statement.TableName() | |||||
cacher := session.engine.getCacher2(table) | |||||
pkColumns := table.PKColumns() | |||||
ids, err := core.GetCacheSql(cacher, tableName, newsql, args) | ids, err := core.GetCacheSql(cacher, tableName, newsql, args) | ||||
if err != nil { | if err != nil { | ||||
resultsSlice, err := session.query(newsql, args...) | |||||
resultsSlice, err := session.queryBytes(newsql, args...) | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
@@ -40,7 +40,7 @@ func (session *Session) cacheDelete(sqlStr string, args ...interface{}) error { | |||||
for _, data := range resultsSlice { | for _, data := range resultsSlice { | ||||
var id int64 | var id int64 | ||||
var pk core.PK = make([]interface{}, 0) | var pk core.PK = make([]interface{}, 0) | ||||
for _, col := range session.statement.RefTable.PKColumns() { | |||||
for _, col := range pkColumns { | |||||
if v, ok := data[col.Name]; !ok { | if v, ok := data[col.Name]; !ok { | ||||
return errors.New("no id") | return errors.New("no id") | ||||
} else if col.SQLType.IsText() { | } else if col.SQLType.IsText() { | ||||
@@ -58,27 +58,23 @@ func (session *Session) cacheDelete(sqlStr string, args ...interface{}) error { | |||||
ids = append(ids, pk) | ids = append(ids, pk) | ||||
} | } | ||||
} | } | ||||
} /*else { | |||||
session.engine.LogDebug("delete cache sql %v", newsql) | |||||
cacher.DelIds(tableName, genSqlKey(newsql, args)) | |||||
}*/ | |||||
} | |||||
for _, id := range ids { | for _, id := range ids { | ||||
session.engine.logger.Debug("[cacheDelete] delete cache obj", tableName, id) | |||||
session.engine.logger.Debug("[cacheDelete] delete cache obj:", tableName, id) | |||||
sid, err := id.ToString() | sid, err := id.ToString() | ||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
cacher.DelBean(tableName, sid) | cacher.DelBean(tableName, sid) | ||||
} | } | ||||
session.engine.logger.Debug("[cacheDelete] clear cache sql", tableName) | |||||
session.engine.logger.Debug("[cacheDelete] clear cache table:", tableName) | |||||
cacher.ClearIds(tableName) | cacher.ClearIds(tableName) | ||||
return nil | return nil | ||||
} | } | ||||
// Delete records, bean's non-empty fields are conditions | // Delete records, bean's non-empty fields are conditions | ||||
func (session *Session) Delete(bean interface{}) (int64, error) { | func (session *Session) Delete(bean interface{}) (int64, error) { | ||||
defer session.resetStatement() | |||||
if session.isAutoClose { | if session.isAutoClose { | ||||
defer session.Close() | defer session.Close() | ||||
} | } | ||||
@@ -86,7 +82,6 @@ func (session *Session) Delete(bean interface{}) (int64, error) { | |||||
if err := session.statement.setRefValue(rValue(bean)); err != nil { | if err := session.statement.setRefValue(rValue(bean)); err != nil { | ||||
return 0, err | return 0, err | ||||
} | } | ||||
var table = session.statement.RefTable | |||||
// handle before delete processors | // handle before delete processors | ||||
for _, closure := range session.beforeClosures { | for _, closure := range session.beforeClosures { | ||||
@@ -106,7 +101,9 @@ func (session *Session) Delete(bean interface{}) (int64, error) { | |||||
return 0, ErrNeedDeletedCond | return 0, ErrNeedDeletedCond | ||||
} | } | ||||
var tableName = session.engine.Quote(session.statement.TableName()) | |||||
var tableNameNoQuote = session.statement.TableName() | |||||
var tableName = session.engine.Quote(tableNameNoQuote) | |||||
var table = session.statement.RefTable | |||||
var deleteSQL string | var deleteSQL string | ||||
if len(condSQL) > 0 { | if len(condSQL) > 0 { | ||||
deleteSQL = fmt.Sprintf("DELETE FROM %v WHERE %v", tableName, condSQL) | deleteSQL = fmt.Sprintf("DELETE FROM %v WHERE %v", tableName, condSQL) | ||||
@@ -202,10 +199,11 @@ func (session *Session) Delete(bean interface{}) (int64, error) { | |||||
}) | }) | ||||
} | } | ||||
if cacher := session.engine.getCacher2(session.statement.RefTable); cacher != nil && session.statement.UseCache { | |||||
session.cacheDelete(deleteSQL, argsForCache...) | |||||
if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache { | |||||
session.cacheDelete(table, tableNameNoQuote, deleteSQL, argsForCache...) | |||||
} | } | ||||
session.statement.RefTable = table | |||||
res, err := session.exec(realSQL, condArgs...) | res, err := session.exec(realSQL, condArgs...) | ||||
if err != nil { | if err != nil { | ||||
return 0, err | return 0, err | ||||
@@ -10,12 +10,10 @@ import ( | |||||
"reflect" | "reflect" | ||||
"github.com/go-xorm/builder" | "github.com/go-xorm/builder" | ||||
"github.com/go-xorm/core" | |||||
) | ) | ||||
// Exist returns true if the record exist otherwise return false | // Exist returns true if the record exist otherwise return false | ||||
func (session *Session) Exist(bean ...interface{}) (bool, error) { | func (session *Session) Exist(bean ...interface{}) (bool, error) { | ||||
defer session.resetStatement() | |||||
if session.isAutoClose { | if session.isAutoClose { | ||||
defer session.Close() | defer session.Close() | ||||
} | } | ||||
@@ -69,19 +67,11 @@ func (session *Session) Exist(bean ...interface{}) (bool, error) { | |||||
args = session.statement.RawParams | args = session.statement.RawParams | ||||
} | } | ||||
session.queryPreprocess(&sqlStr, args...) | |||||
var rawRows *core.Rows | |||||
if session.isAutoCommit { | |||||
_, rawRows, err = session.innerQuery(sqlStr, args...) | |||||
} else { | |||||
rawRows, err = session.tx.Query(sqlStr, args...) | |||||
} | |||||
rows, err := session.queryRows(sqlStr, args...) | |||||
if err != nil { | if err != nil { | ||||
return false, err | return false, err | ||||
} | } | ||||
defer rows.Close() | |||||
defer rawRows.Close() | |||||
return rawRows.Next(), nil | |||||
return rows.Next(), nil | |||||
} | } |
@@ -23,11 +23,13 @@ const ( | |||||
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct | // are conditions. beans could be []Struct, []*Struct, map[int64]Struct | ||||
// map[int64]*Struct | // map[int64]*Struct | ||||
func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error { | func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error { | ||||
defer session.resetStatement() | |||||
if session.isAutoClose { | if session.isAutoClose { | ||||
defer session.Close() | defer session.Close() | ||||
} | } | ||||
return session.find(rowsSlicePtr, condiBean...) | |||||
} | |||||
func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error { | |||||
sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) | sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) | ||||
if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map { | if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map { | ||||
return errors.New("needs a pointer to a slice or a map") | return errors.New("needs a pointer to a slice or a map") | ||||
@@ -157,21 +159,13 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) | |||||
} | } | ||||
func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Value, sqlStr string, args ...interface{}) error { | func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Value, sqlStr string, args ...interface{}) error { | ||||
var rawRows *core.Rows | |||||
var err error | |||||
session.queryPreprocess(&sqlStr, args...) | |||||
if session.isAutoCommit { | |||||
_, rawRows, err = session.innerQuery(sqlStr, args...) | |||||
} else { | |||||
rawRows, err = session.tx.Query(sqlStr, args...) | |||||
} | |||||
rows, err := session.queryRows(sqlStr, args...) | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
defer rawRows.Close() | |||||
defer rows.Close() | |||||
fields, err := rawRows.Columns() | |||||
fields, err := rows.Columns() | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
@@ -245,20 +239,20 @@ func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Va | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
return session.rows2Beans(rawRows, fields, len(fields), tb, newElemFunc, containerValueSetFunc) | |||||
return session.rows2Beans(rows, fields, len(fields), tb, newElemFunc, containerValueSetFunc) | |||||
} | } | ||||
for rawRows.Next() { | |||||
for rows.Next() { | |||||
var newValue = newElemFunc(fields) | var newValue = newElemFunc(fields) | ||||
bean := newValue.Interface() | bean := newValue.Interface() | ||||
switch elemType.Kind() { | switch elemType.Kind() { | ||||
case reflect.Slice: | case reflect.Slice: | ||||
err = rawRows.ScanSlice(bean) | |||||
err = rows.ScanSlice(bean) | |||||
case reflect.Map: | case reflect.Map: | ||||
err = rawRows.ScanMap(bean) | |||||
err = rows.ScanMap(bean) | |||||
default: | default: | ||||
err = rawRows.Scan(bean) | |||||
err = rows.Scan(bean) | |||||
} | } | ||||
if err != nil { | if err != nil { | ||||
@@ -299,12 +293,11 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in | |||||
} | } | ||||
tableName := session.statement.TableName() | tableName := session.statement.TableName() | ||||
table := session.statement.RefTable | table := session.statement.RefTable | ||||
cacher := session.engine.getCacher2(table) | cacher := session.engine.getCacher2(table) | ||||
ids, err := core.GetCacheSql(cacher, tableName, newsql, args) | ids, err := core.GetCacheSql(cacher, tableName, newsql, args) | ||||
if err != nil { | if err != nil { | ||||
rows, err := session.DB().Query(newsql, args...) | |||||
rows, err := session.queryRows(newsql, args...) | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
@@ -334,13 +327,13 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in | |||||
ids = append(ids, pk) | ids = append(ids, pk) | ||||
} | } | ||||
session.engine.logger.Debug("[cacheFind] cache sql:", ids, tableName, newsql, args) | |||||
session.engine.logger.Debug("[cacheFind] cache sql:", ids, tableName, sqlStr, newsql, args) | |||||
err = core.PutCacheSql(cacher, ids, tableName, newsql, args) | err = core.PutCacheSql(cacher, ids, tableName, newsql, args) | ||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
} else { | } else { | ||||
session.engine.logger.Debug("[cacheFind] cache hit sql:", newsql, args) | |||||
session.engine.logger.Debug("[cacheFind] cache hit sql:", tableName, sqlStr, newsql, args) | |||||
} | } | ||||
sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) | sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) | ||||
@@ -355,7 +348,7 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in | |||||
return err | return err | ||||
} | } | ||||
bean := cacher.GetBean(tableName, sid) | bean := cacher.GetBean(tableName, sid) | ||||
if bean == nil { | |||||
if bean == nil || reflect.ValueOf(bean).Elem().Type() != t { | |||||
ides = append(ides, id) | ides = append(ides, id) | ||||
ididxes[sid] = idx | ididxes[sid] = idx | ||||
} else { | } else { | ||||
@@ -376,9 +369,6 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in | |||||
} | } | ||||
if len(ides) > 0 { | if len(ides) > 0 { | ||||
newSession := session.engine.NewSession() | |||||
defer newSession.Close() | |||||
slices := reflect.New(reflect.SliceOf(t)) | slices := reflect.New(reflect.SliceOf(t)) | ||||
beans := slices.Interface() | beans := slices.Interface() | ||||
@@ -388,18 +378,18 @@ func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr in | |||||
ff = append(ff, ie[0]) | ff = append(ff, ie[0]) | ||||
} | } | ||||
newSession.In("`"+table.PrimaryKeys[0]+"`", ff...) | |||||
session.In("`"+table.PrimaryKeys[0]+"`", ff...) | |||||
} else { | } else { | ||||
for _, ie := range ides { | for _, ie := range ides { | ||||
cond := builder.NewCond() | cond := builder.NewCond() | ||||
for i, name := range table.PrimaryKeys { | for i, name := range table.PrimaryKeys { | ||||
cond = cond.And(builder.Eq{"`" + name + "`": ie[i]}) | cond = cond.And(builder.Eq{"`" + name + "`": ie[i]}) | ||||
} | } | ||||
newSession.Or(cond) | |||||
session.Or(cond) | |||||
} | } | ||||
} | } | ||||
err = newSession.NoCache().Find(beans) | |||||
err = session.NoCache().Table(tableName).find(beans) | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
@@ -15,11 +15,13 @@ import ( | |||||
// Get retrieve one record from database, bean's non-empty fields | // Get retrieve one record from database, bean's non-empty fields | ||||
// will be as conditions | // will be as conditions | ||||
func (session *Session) Get(bean interface{}) (bool, error) { | func (session *Session) Get(bean interface{}) (bool, error) { | ||||
defer session.resetStatement() | |||||
if session.isAutoClose { | if session.isAutoClose { | ||||
defer session.Close() | defer session.Close() | ||||
} | } | ||||
return session.get(bean) | |||||
} | |||||
func (session *Session) get(bean interface{}) (bool, error) { | |||||
beanValue := reflect.ValueOf(bean) | beanValue := reflect.ValueOf(bean) | ||||
if beanValue.Kind() != reflect.Ptr { | if beanValue.Kind() != reflect.Ptr { | ||||
return false, errors.New("needs a pointer to a value") | return false, errors.New("needs a pointer to a value") | ||||
@@ -51,8 +53,10 @@ func (session *Session) Get(bean interface{}) (bool, error) { | |||||
args = session.statement.RawParams | args = session.statement.RawParams | ||||
} | } | ||||
table := session.statement.RefTable | |||||
if session.canCache() && beanValue.Elem().Kind() == reflect.Struct { | if session.canCache() && beanValue.Elem().Kind() == reflect.Struct { | ||||
if cacher := session.engine.getCacher2(session.statement.RefTable); cacher != nil && | |||||
if cacher := session.engine.getCacher2(table); cacher != nil && | |||||
!session.statement.unscoped { | !session.statement.unscoped { | ||||
has, err := session.cacheGet(bean, sqlStr, args...) | has, err := session.cacheGet(bean, sqlStr, args...) | ||||
if err != ErrCacheFailed { | if err != ErrCacheFailed { | ||||
@@ -61,54 +65,43 @@ func (session *Session) Get(bean interface{}) (bool, error) { | |||||
} | } | ||||
} | } | ||||
return session.nocacheGet(beanValue.Elem().Kind(), bean, sqlStr, args...) | |||||
return session.nocacheGet(beanValue.Elem().Kind(), table, bean, sqlStr, args...) | |||||
} | } | ||||
func (session *Session) nocacheGet(beanKind reflect.Kind, bean interface{}, sqlStr string, args ...interface{}) (bool, error) { | |||||
session.queryPreprocess(&sqlStr, args...) | |||||
var rawRows *core.Rows | |||||
var err error | |||||
if session.isAutoCommit { | |||||
_, rawRows, err = session.innerQuery(sqlStr, args...) | |||||
} else { | |||||
rawRows, err = session.tx.Query(sqlStr, args...) | |||||
} | |||||
func (session *Session) nocacheGet(beanKind reflect.Kind, table *core.Table, bean interface{}, sqlStr string, args ...interface{}) (bool, error) { | |||||
rows, err := session.queryRows(sqlStr, args...) | |||||
if err != nil { | if err != nil { | ||||
return false, err | return false, err | ||||
} | } | ||||
defer rows.Close() | |||||
defer rawRows.Close() | |||||
if !rawRows.Next() { | |||||
if !rows.Next() { | |||||
return false, nil | return false, nil | ||||
} | } | ||||
switch beanKind { | switch beanKind { | ||||
case reflect.Struct: | case reflect.Struct: | ||||
fields, err := rawRows.Columns() | |||||
fields, err := rows.Columns() | |||||
if err != nil { | if err != nil { | ||||
// WARN: Alougth rawRows return true, but get fields failed | |||||
// WARN: Alougth rows return true, but get fields failed | |||||
return true, err | return true, err | ||||
} | } | ||||
dataStruct := rValue(bean) | |||||
if err := session.statement.setRefValue(dataStruct); err != nil { | |||||
return false, err | |||||
} | |||||
scanResults, err := session.row2Slice(rawRows, fields, len(fields), bean) | |||||
scanResults, err := session.row2Slice(rows, fields, len(fields), bean) | |||||
if err != nil { | if err != nil { | ||||
return false, err | return false, err | ||||
} | } | ||||
rawRows.Close() | |||||
// close it before covert data | |||||
rows.Close() | |||||
_, err = session.slice2Bean(scanResults, fields, len(fields), bean, &dataStruct, session.statement.RefTable) | |||||
dataStruct := rValue(bean) | |||||
_, err = session.slice2Bean(scanResults, fields, len(fields), bean, &dataStruct, table) | |||||
case reflect.Slice: | case reflect.Slice: | ||||
err = rawRows.ScanSlice(bean) | |||||
err = rows.ScanSlice(bean) | |||||
case reflect.Map: | case reflect.Map: | ||||
err = rawRows.ScanMap(bean) | |||||
err = rows.ScanMap(bean) | |||||
default: | default: | ||||
err = rawRows.Scan(bean) | |||||
err = rows.Scan(bean) | |||||
} | } | ||||
return true, err | return true, err | ||||
@@ -131,11 +124,11 @@ func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interf | |||||
cacher := session.engine.getCacher2(session.statement.RefTable) | cacher := session.engine.getCacher2(session.statement.RefTable) | ||||
tableName := session.statement.TableName() | tableName := session.statement.TableName() | ||||
session.engine.logger.Debug("[cacheGet] find sql:", newsql, args) | session.engine.logger.Debug("[cacheGet] find sql:", newsql, args) | ||||
ids, err := core.GetCacheSql(cacher, tableName, newsql, args) | |||||
table := session.statement.RefTable | table := session.statement.RefTable | ||||
ids, err := core.GetCacheSql(cacher, tableName, newsql, args) | |||||
if err != nil { | if err != nil { | ||||
var res = make([]string, len(table.PrimaryKeys)) | var res = make([]string, len(table.PrimaryKeys)) | ||||
rows, err := session.DB().Query(newsql, args...) | |||||
rows, err := session.NoCache().queryRows(newsql, args...) | |||||
if err != nil { | if err != nil { | ||||
return false, err | return false, err | ||||
} | } | ||||
@@ -172,7 +165,7 @@ func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interf | |||||
return false, err | return false, err | ||||
} | } | ||||
} else { | } else { | ||||
session.engine.logger.Debug("[cacheGet] cache hit sql:", newsql) | |||||
session.engine.logger.Debug("[cacheGet] cache hit sql:", newsql, ids) | |||||
} | } | ||||
if len(ids) > 0 { | if len(ids) > 0 { | ||||
@@ -186,7 +179,7 @@ func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interf | |||||
cacheBean := cacher.GetBean(tableName, sid) | cacheBean := cacher.GetBean(tableName, sid) | ||||
if cacheBean == nil { | if cacheBean == nil { | ||||
cacheBean = bean | cacheBean = bean | ||||
has, err = session.nocacheGet(reflect.Struct, cacheBean, sqlStr, args...) | |||||
has, err = session.nocacheGet(reflect.Struct, table, cacheBean, sqlStr, args...) | |||||
if err != nil || !has { | if err != nil || !has { | ||||
return has, err | return has, err | ||||
} | } | ||||
@@ -22,7 +22,6 @@ func (session *Session) Insert(beans ...interface{}) (int64, error) { | |||||
if session.isAutoClose { | if session.isAutoClose { | ||||
defer session.Close() | defer session.Close() | ||||
} | } | ||||
defer session.resetStatement() | |||||
for _, bean := range beans { | for _, bean := range beans { | ||||
sliceValue := reflect.Indirect(reflect.ValueOf(bean)) | sliceValue := reflect.Indirect(reflect.ValueOf(bean)) | ||||
@@ -214,22 +213,23 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error | |||||
var sql = "INSERT INTO %s (%v%v%v) VALUES (%v)" | var sql = "INSERT INTO %s (%v%v%v) VALUES (%v)" | ||||
var statement string | var statement string | ||||
var tableName = session.statement.TableName() | |||||
if session.engine.dialect.DBType() == core.ORACLE { | if session.engine.dialect.DBType() == core.ORACLE { | ||||
sql = "INSERT ALL INTO %s (%v%v%v) VALUES (%v) SELECT 1 FROM DUAL" | sql = "INSERT ALL INTO %s (%v%v%v) VALUES (%v) SELECT 1 FROM DUAL" | ||||
temp := fmt.Sprintf(") INTO %s (%v%v%v) VALUES (", | temp := fmt.Sprintf(") INTO %s (%v%v%v) VALUES (", | ||||
session.engine.Quote(session.statement.TableName()), | |||||
session.engine.Quote(tableName), | |||||
session.engine.QuoteStr(), | session.engine.QuoteStr(), | ||||
strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()), | strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()), | ||||
session.engine.QuoteStr()) | session.engine.QuoteStr()) | ||||
statement = fmt.Sprintf(sql, | statement = fmt.Sprintf(sql, | ||||
session.engine.Quote(session.statement.TableName()), | |||||
session.engine.Quote(tableName), | |||||
session.engine.QuoteStr(), | session.engine.QuoteStr(), | ||||
strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()), | strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()), | ||||
session.engine.QuoteStr(), | session.engine.QuoteStr(), | ||||
strings.Join(colMultiPlaces, temp)) | strings.Join(colMultiPlaces, temp)) | ||||
} else { | } else { | ||||
statement = fmt.Sprintf(sql, | statement = fmt.Sprintf(sql, | ||||
session.engine.Quote(session.statement.TableName()), | |||||
session.engine.Quote(tableName), | |||||
session.engine.QuoteStr(), | session.engine.QuoteStr(), | ||||
strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()), | strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()), | ||||
session.engine.QuoteStr(), | session.engine.QuoteStr(), | ||||
@@ -241,7 +241,7 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error | |||||
} | } | ||||
if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache { | if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache { | ||||
session.cacheInsert(session.statement.TableName()) | |||||
session.cacheInsert(table, tableName) | |||||
} | } | ||||
lenAfterClosures := len(session.afterClosures) | lenAfterClosures := len(session.afterClosures) | ||||
@@ -280,7 +280,6 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error | |||||
// InsertMulti insert multiple records | // InsertMulti insert multiple records | ||||
func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) { | func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) { | ||||
defer session.resetStatement() | |||||
if session.isAutoClose { | if session.isAutoClose { | ||||
defer session.Close() | defer session.Close() | ||||
} | } | ||||
@@ -349,18 +348,19 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { | |||||
} | } | ||||
var sqlStr string | var sqlStr string | ||||
var tableName = session.statement.TableName() | |||||
if len(colPlaces) > 0 { | if len(colPlaces) > 0 { | ||||
sqlStr = fmt.Sprintf("INSERT INTO %s (%v%v%v) VALUES (%v)", | sqlStr = fmt.Sprintf("INSERT INTO %s (%v%v%v) VALUES (%v)", | ||||
session.engine.Quote(session.statement.TableName()), | |||||
session.engine.Quote(tableName), | |||||
session.engine.QuoteStr(), | session.engine.QuoteStr(), | ||||
strings.Join(colNames, session.engine.Quote(", ")), | strings.Join(colNames, session.engine.Quote(", ")), | ||||
session.engine.QuoteStr(), | session.engine.QuoteStr(), | ||||
colPlaces) | colPlaces) | ||||
} else { | } else { | ||||
if session.engine.dialect.DBType() == core.MYSQL { | if session.engine.dialect.DBType() == core.MYSQL { | ||||
sqlStr = fmt.Sprintf("INSERT INTO %s VALUES ()", session.engine.Quote(session.statement.TableName())) | |||||
sqlStr = fmt.Sprintf("INSERT INTO %s VALUES ()", session.engine.Quote(tableName)) | |||||
} else { | } else { | ||||
sqlStr = fmt.Sprintf("INSERT INTO %s DEFAULT VALUES", session.engine.Quote(session.statement.TableName())) | |||||
sqlStr = fmt.Sprintf("INSERT INTO %s DEFAULT VALUES", session.engine.Quote(tableName)) | |||||
} | } | ||||
} | } | ||||
@@ -395,7 +395,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { | |||||
// for postgres, many of them didn't implement lastInsertId, so we should | // for postgres, many of them didn't implement lastInsertId, so we should | ||||
// implemented it ourself. | // implemented it ourself. | ||||
if session.engine.dialect.DBType() == core.ORACLE && len(table.AutoIncrement) > 0 { | if session.engine.dialect.DBType() == core.ORACLE && len(table.AutoIncrement) > 0 { | ||||
res, err := session.query("select seq_atable.currval from dual", args...) | |||||
res, err := session.queryBytes("select seq_atable.currval from dual", args...) | |||||
if err != nil { | if err != nil { | ||||
return 0, err | return 0, err | ||||
} | } | ||||
@@ -403,7 +403,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { | |||||
handleAfterInsertProcessorFunc(bean) | handleAfterInsertProcessorFunc(bean) | ||||
if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache { | if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache { | ||||
session.cacheInsert(session.statement.TableName()) | |||||
session.cacheInsert(table, tableName) | |||||
} | } | ||||
if table.Version != "" && session.statement.checkVersion { | if table.Version != "" && session.statement.checkVersion { | ||||
@@ -440,7 +440,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { | |||||
} else if session.engine.dialect.DBType() == core.POSTGRES && len(table.AutoIncrement) > 0 { | } else if session.engine.dialect.DBType() == core.POSTGRES && len(table.AutoIncrement) > 0 { | ||||
//assert table.AutoIncrement != "" | //assert table.AutoIncrement != "" | ||||
sqlStr = sqlStr + " RETURNING " + session.engine.Quote(table.AutoIncrement) | sqlStr = sqlStr + " RETURNING " + session.engine.Quote(table.AutoIncrement) | ||||
res, err := session.query(sqlStr, args...) | |||||
res, err := session.queryBytes(sqlStr, args...) | |||||
if err != nil { | if err != nil { | ||||
return 0, err | return 0, err | ||||
@@ -448,7 +448,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { | |||||
handleAfterInsertProcessorFunc(bean) | handleAfterInsertProcessorFunc(bean) | ||||
if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache { | if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache { | ||||
session.cacheInsert(session.statement.TableName()) | |||||
session.cacheInsert(table, tableName) | |||||
} | } | ||||
if table.Version != "" && session.statement.checkVersion { | if table.Version != "" && session.statement.checkVersion { | ||||
@@ -491,7 +491,7 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { | |||||
defer handleAfterInsertProcessorFunc(bean) | defer handleAfterInsertProcessorFunc(bean) | ||||
if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache { | if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache { | ||||
session.cacheInsert(session.statement.TableName()) | |||||
session.cacheInsert(table, tableName) | |||||
} | } | ||||
if table.Version != "" && session.statement.checkVersion { | if table.Version != "" && session.statement.checkVersion { | ||||
@@ -532,7 +532,6 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) { | |||||
// The in parameter bean must a struct or a point to struct. The return | // The in parameter bean must a struct or a point to struct. The return | ||||
// parameter is inserted and error | // parameter is inserted and error | ||||
func (session *Session) InsertOne(bean interface{}) (int64, error) { | func (session *Session) InsertOne(bean interface{}) (int64, error) { | ||||
defer session.resetStatement() | |||||
if session.isAutoClose { | if session.isAutoClose { | ||||
defer session.Close() | defer session.Close() | ||||
} | } | ||||
@@ -540,14 +539,12 @@ func (session *Session) InsertOne(bean interface{}) (int64, error) { | |||||
return session.innerInsert(bean) | return session.innerInsert(bean) | ||||
} | } | ||||
func (session *Session) cacheInsert(tables ...string) error { | |||||
if session.statement.RefTable == nil { | |||||
func (session *Session) cacheInsert(table *core.Table, tables ...string) error { | |||||
if table == nil { | |||||
return ErrCacheFailed | return ErrCacheFailed | ||||
} | } | ||||
table := session.statement.RefTable | |||||
cacher := session.engine.getCacher2(table) | cacher := session.engine.getCacher2(table) | ||||
for _, t := range tables { | for _, t := range tables { | ||||
session.engine.logger.Debug("[cache] clear sql:", t) | session.engine.logger.Debug("[cache] clear sql:", t) | ||||
cacher.ClearIds(t) | cacher.ClearIds(t) | ||||
@@ -19,6 +19,10 @@ func (session *Session) Rows(bean interface{}) (*Rows, error) { | |||||
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct | // are conditions. beans could be []Struct, []*Struct, map[int64]Struct | ||||
// map[int64]*Struct | // map[int64]*Struct | ||||
func (session *Session) Iterate(bean interface{}, fun IterFunc) error { | func (session *Session) Iterate(bean interface{}, fun IterFunc) error { | ||||
if session.isAutoClose { | |||||
defer session.Close() | |||||
} | |||||
rows, err := session.Rows(bean) | rows, err := session.Rows(bean) | ||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
@@ -0,0 +1,177 @@ | |||||
// Copyright 2017 The Xorm Authors. All rights reserved. | |||||
// Use of this source code is governed by a BSD-style | |||||
// license that can be found in the LICENSE file. | |||||
package xorm | |||||
import ( | |||||
"fmt" | |||||
"reflect" | |||||
"strconv" | |||||
"time" | |||||
"github.com/go-xorm/core" | |||||
) | |||||
// Query runs a raw sql and return records as []map[string][]byte | |||||
func (session *Session) Query(sqlStr string, args ...interface{}) ([]map[string][]byte, error) { | |||||
if session.isAutoClose { | |||||
defer session.Close() | |||||
} | |||||
return session.queryBytes(sqlStr, args...) | |||||
} | |||||
func value2String(rawValue *reflect.Value) (str string, err error) { | |||||
aa := reflect.TypeOf((*rawValue).Interface()) | |||||
vv := reflect.ValueOf((*rawValue).Interface()) | |||||
switch aa.Kind() { | |||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | |||||
str = strconv.FormatInt(vv.Int(), 10) | |||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | |||||
str = strconv.FormatUint(vv.Uint(), 10) | |||||
case reflect.Float32, reflect.Float64: | |||||
str = strconv.FormatFloat(vv.Float(), 'f', -1, 64) | |||||
case reflect.String: | |||||
str = vv.String() | |||||
case reflect.Array, reflect.Slice: | |||||
switch aa.Elem().Kind() { | |||||
case reflect.Uint8: | |||||
data := rawValue.Interface().([]byte) | |||||
str = string(data) | |||||
if str == "\x00" { | |||||
str = "0" | |||||
} | |||||
default: | |||||
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name()) | |||||
} | |||||
// time type | |||||
case reflect.Struct: | |||||
if aa.ConvertibleTo(core.TimeType) { | |||||
str = vv.Convert(core.TimeType).Interface().(time.Time).Format(time.RFC3339Nano) | |||||
} else { | |||||
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name()) | |||||
} | |||||
case reflect.Bool: | |||||
str = strconv.FormatBool(vv.Bool()) | |||||
case reflect.Complex128, reflect.Complex64: | |||||
str = fmt.Sprintf("%v", vv.Complex()) | |||||
/* TODO: unsupported types below | |||||
case reflect.Map: | |||||
case reflect.Ptr: | |||||
case reflect.Uintptr: | |||||
case reflect.UnsafePointer: | |||||
case reflect.Chan, reflect.Func, reflect.Interface: | |||||
*/ | |||||
default: | |||||
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name()) | |||||
} | |||||
return | |||||
} | |||||
func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string, err error) { | |||||
result := make(map[string]string) | |||||
scanResultContainers := make([]interface{}, len(fields)) | |||||
for i := 0; i < len(fields); i++ { | |||||
var scanResultContainer interface{} | |||||
scanResultContainers[i] = &scanResultContainer | |||||
} | |||||
if err := rows.Scan(scanResultContainers...); err != nil { | |||||
return nil, err | |||||
} | |||||
for ii, key := range fields { | |||||
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii])) | |||||
// if row is null then as empty string | |||||
if rawValue.Interface() == nil { | |||||
result[key] = "" | |||||
continue | |||||
} | |||||
if data, err := value2String(&rawValue); err == nil { | |||||
result[key] = data | |||||
} else { | |||||
return nil, err | |||||
} | |||||
} | |||||
return result, nil | |||||
} | |||||
func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) { | |||||
fields, err := rows.Columns() | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
for rows.Next() { | |||||
result, err := row2mapStr(rows, fields) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
resultsSlice = append(resultsSlice, result) | |||||
} | |||||
return resultsSlice, nil | |||||
} | |||||
// QueryString runs a raw sql and return records as []map[string]string | |||||
func (session *Session) QueryString(sqlStr string, args ...interface{}) ([]map[string]string, error) { | |||||
if session.isAutoClose { | |||||
defer session.Close() | |||||
} | |||||
rows, err := session.queryRows(sqlStr, args...) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
defer rows.Close() | |||||
return rows2Strings(rows) | |||||
} | |||||
func row2mapInterface(rows *core.Rows, fields []string) (resultsMap map[string]interface{}, err error) { | |||||
resultsMap = make(map[string]interface{}, len(fields)) | |||||
scanResultContainers := make([]interface{}, len(fields)) | |||||
for i := 0; i < len(fields); i++ { | |||||
var scanResultContainer interface{} | |||||
scanResultContainers[i] = &scanResultContainer | |||||
} | |||||
if err := rows.Scan(scanResultContainers...); err != nil { | |||||
return nil, err | |||||
} | |||||
for ii, key := range fields { | |||||
resultsMap[key] = reflect.Indirect(reflect.ValueOf(scanResultContainers[ii])).Interface() | |||||
} | |||||
return | |||||
} | |||||
func rows2Interfaces(rows *core.Rows) (resultsSlice []map[string]interface{}, err error) { | |||||
fields, err := rows.Columns() | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
for rows.Next() { | |||||
result, err := row2mapInterface(rows, fields) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
resultsSlice = append(resultsSlice, result) | |||||
} | |||||
return resultsSlice, nil | |||||
} | |||||
// QueryInterface runs a raw sql and return records as []map[string]interface{} | |||||
func (session *Session) QueryInterface(sqlStr string, args ...interface{}) ([]map[string]interface{}, error) { | |||||
if session.isAutoClose { | |||||
defer session.Close() | |||||
} | |||||
rows, err := session.queryRows(sqlStr, args...) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
defer rows.Close() | |||||
return rows2Interfaces(rows) | |||||
} |
@@ -6,87 +6,85 @@ package xorm | |||||
import ( | import ( | ||||
"database/sql" | "database/sql" | ||||
"fmt" | |||||
"reflect" | "reflect" | ||||
"strconv" | |||||
"time" | "time" | ||||
"github.com/go-xorm/core" | "github.com/go-xorm/core" | ||||
) | ) | ||||
func (session *Session) query(sqlStr string, paramStr ...interface{}) ([]map[string][]byte, error) { | |||||
session.queryPreprocess(&sqlStr, paramStr...) | |||||
if session.isAutoCommit { | |||||
return session.innerQuery2(sqlStr, paramStr...) | |||||
func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) { | |||||
for _, filter := range session.engine.dialect.Filters() { | |||||
*sqlStr = filter.Do(*sqlStr, session.engine.dialect, session.statement.RefTable) | |||||
} | } | ||||
return session.txQuery(session.tx, sqlStr, paramStr...) | |||||
session.lastSQL = *sqlStr | |||||
session.lastSQLArgs = paramStr | |||||
} | } | ||||
func (session *Session) txQuery(tx *core.Tx, sqlStr string, params ...interface{}) ([]map[string][]byte, error) { | |||||
rows, err := tx.Query(sqlStr, params...) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
defer rows.Close() | |||||
func (session *Session) queryRows(sqlStr string, args ...interface{}) (*core.Rows, error) { | |||||
defer session.resetStatement() | |||||
return rows2maps(rows) | |||||
} | |||||
session.queryPreprocess(&sqlStr, args...) | |||||
func (session *Session) innerQuery(sqlStr string, params ...interface{}) (*core.Stmt, *core.Rows, error) { | |||||
var callback func() (*core.Stmt, *core.Rows, error) | |||||
if session.prepareStmt { | |||||
callback = func() (*core.Stmt, *core.Rows, error) { | |||||
if session.engine.showSQL { | |||||
if session.engine.showExecTime { | |||||
b4ExecTime := time.Now() | |||||
defer func() { | |||||
execDuration := time.Since(b4ExecTime) | |||||
if len(args) > 0 { | |||||
session.engine.logger.Infof("[SQL] %s %#v - took: %v", sqlStr, args, execDuration) | |||||
} else { | |||||
session.engine.logger.Infof("[SQL] %s - took: %v", sqlStr, execDuration) | |||||
} | |||||
}() | |||||
} else { | |||||
if len(args) > 0 { | |||||
session.engine.logger.Infof("[SQL] %v %#v", sqlStr, args) | |||||
} else { | |||||
session.engine.logger.Infof("[SQL] %v", sqlStr) | |||||
} | |||||
} | |||||
} | |||||
if session.isAutoCommit { | |||||
if session.prepareStmt { | |||||
// don't clear stmt since session will cache them | |||||
stmt, err := session.doPrepare(sqlStr) | stmt, err := session.doPrepare(sqlStr) | ||||
if err != nil { | if err != nil { | ||||
return nil, nil, err | |||||
return nil, err | |||||
} | } | ||||
rows, err := stmt.Query(params...) | |||||
rows, err := stmt.Query(args...) | |||||
if err != nil { | if err != nil { | ||||
return nil, nil, err | |||||
return nil, err | |||||
} | } | ||||
return stmt, rows, nil | |||||
return rows, nil | |||||
} | } | ||||
} else { | |||||
callback = func() (*core.Stmt, *core.Rows, error) { | |||||
rows, err := session.DB().Query(sqlStr, params...) | |||||
if err != nil { | |||||
return nil, nil, err | |||||
} | |||||
return nil, rows, err | |||||
rows, err := session.DB().Query(sqlStr, args...) | |||||
if err != nil { | |||||
return nil, err | |||||
} | } | ||||
return rows, nil | |||||
} | } | ||||
stmt, rows, err := session.engine.logSQLQueryTime(sqlStr, params, callback) | |||||
if err != nil { | |||||
return nil, nil, err | |||||
} | |||||
return stmt, rows, nil | |||||
} | |||||
func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) { | |||||
fields, err := rows.Columns() | |||||
rows, err := session.tx.Query(sqlStr, args...) | |||||
if err != nil { | if err != nil { | ||||
return nil, err | return nil, err | ||||
} | } | ||||
for rows.Next() { | |||||
result, err := row2map(rows, fields) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
resultsSlice = append(resultsSlice, result) | |||||
} | |||||
return rows, nil | |||||
} | |||||
return resultsSlice, nil | |||||
func (session *Session) queryRow(sqlStr string, args ...interface{}) *core.Row { | |||||
return core.NewRow(session.queryRows(sqlStr, args...)) | |||||
} | } | ||||
func value2Bytes(rawValue *reflect.Value) (data []byte, err error) { | |||||
var str string | |||||
str, err = reflect2value(rawValue) | |||||
func value2Bytes(rawValue *reflect.Value) ([]byte, error) { | |||||
str, err := value2String(rawValue) | |||||
if err != nil { | if err != nil { | ||||
return | |||||
return nil, err | |||||
} | } | ||||
data = []byte(str) | |||||
return | |||||
return []byte(str), nil | |||||
} | } | ||||
func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, err error) { | func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, err error) { | ||||
@@ -104,7 +102,7 @@ func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, er | |||||
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii])) | rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii])) | ||||
//if row is null then ignore | //if row is null then ignore | ||||
if rawValue.Interface() == nil { | if rawValue.Interface() == nil { | ||||
//fmt.Println("ignore ...", key, rawValue) | |||||
result[key] = []byte{} | |||||
continue | continue | ||||
} | } | ||||
@@ -117,34 +115,13 @@ func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, er | |||||
return result, nil | return result, nil | ||||
} | } | ||||
func (session *Session) innerQuery2(sqlStr string, params ...interface{}) ([]map[string][]byte, error) { | |||||
_, rows, err := session.innerQuery(sqlStr, params...) | |||||
if rows != nil { | |||||
defer rows.Close() | |||||
} | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
return rows2maps(rows) | |||||
} | |||||
// Query runs a raw sql and return records as []map[string][]byte | |||||
func (session *Session) Query(sqlStr string, paramStr ...interface{}) ([]map[string][]byte, error) { | |||||
defer session.resetStatement() | |||||
if session.isAutoClose { | |||||
defer session.Close() | |||||
} | |||||
return session.query(sqlStr, paramStr...) | |||||
} | |||||
func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) { | |||||
func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) { | |||||
fields, err := rows.Columns() | fields, err := rows.Columns() | ||||
if err != nil { | if err != nil { | ||||
return nil, err | return nil, err | ||||
} | } | ||||
for rows.Next() { | for rows.Next() { | ||||
result, err := row2mapStr(rows, fields) | |||||
result, err := row2map(rows, fields) | |||||
if err != nil { | if err != nil { | ||||
return nil, err | return nil, err | ||||
} | } | ||||
@@ -154,122 +131,45 @@ func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) | |||||
return resultsSlice, nil | return resultsSlice, nil | ||||
} | } | ||||
func reflect2value(rawValue *reflect.Value) (str string, err error) { | |||||
aa := reflect.TypeOf((*rawValue).Interface()) | |||||
vv := reflect.ValueOf((*rawValue).Interface()) | |||||
switch aa.Kind() { | |||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | |||||
str = strconv.FormatInt(vv.Int(), 10) | |||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | |||||
str = strconv.FormatUint(vv.Uint(), 10) | |||||
case reflect.Float32, reflect.Float64: | |||||
str = strconv.FormatFloat(vv.Float(), 'f', -1, 64) | |||||
case reflect.String: | |||||
str = vv.String() | |||||
case reflect.Array, reflect.Slice: | |||||
switch aa.Elem().Kind() { | |||||
case reflect.Uint8: | |||||
data := rawValue.Interface().([]byte) | |||||
str = string(data) | |||||
default: | |||||
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name()) | |||||
} | |||||
// time type | |||||
case reflect.Struct: | |||||
if aa.ConvertibleTo(core.TimeType) { | |||||
str = vv.Convert(core.TimeType).Interface().(time.Time).Format(time.RFC3339Nano) | |||||
} else { | |||||
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name()) | |||||
} | |||||
case reflect.Bool: | |||||
str = strconv.FormatBool(vv.Bool()) | |||||
case reflect.Complex128, reflect.Complex64: | |||||
str = fmt.Sprintf("%v", vv.Complex()) | |||||
/* TODO: unsupported types below | |||||
case reflect.Map: | |||||
case reflect.Ptr: | |||||
case reflect.Uintptr: | |||||
case reflect.UnsafePointer: | |||||
case reflect.Chan, reflect.Func, reflect.Interface: | |||||
*/ | |||||
default: | |||||
err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name()) | |||||
} | |||||
return | |||||
} | |||||
func value2String(rawValue *reflect.Value) (data string, err error) { | |||||
data, err = reflect2value(rawValue) | |||||
if err != nil { | |||||
return | |||||
} | |||||
return | |||||
} | |||||
func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string, err error) { | |||||
result := make(map[string]string) | |||||
scanResultContainers := make([]interface{}, len(fields)) | |||||
for i := 0; i < len(fields); i++ { | |||||
var scanResultContainer interface{} | |||||
scanResultContainers[i] = &scanResultContainer | |||||
} | |||||
if err := rows.Scan(scanResultContainers...); err != nil { | |||||
return nil, err | |||||
} | |||||
for ii, key := range fields { | |||||
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii])) | |||||
//if row is null then ignore | |||||
if rawValue.Interface() == nil { | |||||
//fmt.Println("ignore ...", key, rawValue) | |||||
continue | |||||
} | |||||
if data, err := value2String(&rawValue); err == nil { | |||||
result[key] = data | |||||
} else { | |||||
return nil, err // !nashtsai! REVIEW, should return err or just error log? | |||||
} | |||||
} | |||||
return result, nil | |||||
} | |||||
func txQuery2(tx *core.Tx, sqlStr string, params ...interface{}) ([]map[string]string, error) { | |||||
rows, err := tx.Query(sqlStr, params...) | |||||
func (session *Session) queryBytes(sqlStr string, args ...interface{}) ([]map[string][]byte, error) { | |||||
rows, err := session.queryRows(sqlStr, args...) | |||||
if err != nil { | if err != nil { | ||||
return nil, err | return nil, err | ||||
} | } | ||||
defer rows.Close() | defer rows.Close() | ||||
return rows2Strings(rows) | |||||
} | |||||
func query2(db *core.DB, sqlStr string, params ...interface{}) ([]map[string]string, error) { | |||||
rows, err := db.Query(sqlStr, params...) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
defer rows.Close() | |||||
return rows2Strings(rows) | |||||
return rows2maps(rows) | |||||
} | } | ||||
// QueryString runs a raw sql and return records as []map[string]string | |||||
func (session *Session) QueryString(sqlStr string, args ...interface{}) ([]map[string]string, error) { | |||||
func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) { | |||||
defer session.resetStatement() | defer session.resetStatement() | ||||
if session.isAutoClose { | |||||
defer session.Close() | |||||
} | |||||
session.queryPreprocess(&sqlStr, args...) | session.queryPreprocess(&sqlStr, args...) | ||||
if session.isAutoCommit { | |||||
return query2(session.DB(), sqlStr, args...) | |||||
if session.engine.showSQL { | |||||
if session.engine.showExecTime { | |||||
b4ExecTime := time.Now() | |||||
defer func() { | |||||
execDuration := time.Since(b4ExecTime) | |||||
if len(args) > 0 { | |||||
session.engine.logger.Infof("[SQL] %s %#v - took: %v", sqlStr, args, execDuration) | |||||
} else { | |||||
session.engine.logger.Infof("[SQL] %s - took: %v", sqlStr, execDuration) | |||||
} | |||||
}() | |||||
} else { | |||||
if len(args) > 0 { | |||||
session.engine.logger.Infof("[SQL] %v %#v", sqlStr, args) | |||||
} else { | |||||
session.engine.logger.Infof("[SQL] %v", sqlStr) | |||||
} | |||||
} | |||||
} | |||||
if !session.isAutoCommit { | |||||
return session.tx.Exec(sqlStr, args...) | |||||
} | } | ||||
return txQuery2(session.tx, sqlStr, args...) | |||||
} | |||||
// Execute sql | |||||
func (session *Session) innerExec(sqlStr string, args ...interface{}) (sql.Result, error) { | |||||
if session.prepareStmt { | if session.prepareStmt { | ||||
stmt, err := session.doPrepare(sqlStr) | stmt, err := session.doPrepare(sqlStr) | ||||
if err != nil { | if err != nil { | ||||
@@ -286,32 +186,8 @@ func (session *Session) innerExec(sqlStr string, args ...interface{}) (sql.Resul | |||||
return session.DB().Exec(sqlStr, args...) | return session.DB().Exec(sqlStr, args...) | ||||
} | } | ||||
func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) { | |||||
for _, filter := range session.engine.dialect.Filters() { | |||||
// TODO: for table name, it's no need to RefTable | |||||
sqlStr = filter.Do(sqlStr, session.engine.dialect, session.statement.RefTable) | |||||
} | |||||
session.saveLastSQL(sqlStr, args...) | |||||
return session.engine.logSQLExecutionTime(sqlStr, args, func() (sql.Result, error) { | |||||
if session.isAutoCommit { | |||||
// FIXME: oci8 can not auto commit (github.com/mattn/go-oci8) | |||||
if session.engine.dialect.DBType() == core.ORACLE { | |||||
session.Begin() | |||||
r, err := session.tx.Exec(sqlStr, args...) | |||||
session.Commit() | |||||
return r, err | |||||
} | |||||
return session.innerExec(sqlStr, args...) | |||||
} | |||||
return session.tx.Exec(sqlStr, args...) | |||||
}) | |||||
} | |||||
// Exec raw sql | // Exec raw sql | ||||
func (session *Session) Exec(sqlStr string, args ...interface{}) (sql.Result, error) { | func (session *Session) Exec(sqlStr string, args ...interface{}) (sql.Result, error) { | ||||
defer session.resetStatement() | |||||
if session.isAutoClose { | if session.isAutoClose { | ||||
defer session.Close() | defer session.Close() | ||||
} | } | ||||
@@ -16,7 +16,6 @@ import ( | |||||
// Ping test if database is ok | // Ping test if database is ok | ||||
func (session *Session) Ping() error { | func (session *Session) Ping() error { | ||||
defer session.resetStatement() | |||||
if session.isAutoClose { | if session.isAutoClose { | ||||
defer session.Close() | defer session.Close() | ||||
} | } | ||||
@@ -35,7 +34,6 @@ func (session *Session) CreateTable(bean interface{}) error { | |||||
} | } | ||||
func (session *Session) createTable(bean interface{}) error { | func (session *Session) createTable(bean interface{}) error { | ||||
defer session.resetStatement() | |||||
v := rValue(bean) | v := rValue(bean) | ||||
if err := session.statement.setRefValue(v); err != nil { | if err := session.statement.setRefValue(v); err != nil { | ||||
return err | return err | ||||
@@ -56,7 +54,6 @@ func (session *Session) CreateIndexes(bean interface{}) error { | |||||
} | } | ||||
func (session *Session) createIndexes(bean interface{}) error { | func (session *Session) createIndexes(bean interface{}) error { | ||||
defer session.resetStatement() | |||||
v := rValue(bean) | v := rValue(bean) | ||||
if err := session.statement.setRefValue(v); err != nil { | if err := session.statement.setRefValue(v); err != nil { | ||||
return err | return err | ||||
@@ -81,7 +78,6 @@ func (session *Session) CreateUniques(bean interface{}) error { | |||||
} | } | ||||
func (session *Session) createUniques(bean interface{}) error { | func (session *Session) createUniques(bean interface{}) error { | ||||
defer session.resetStatement() | |||||
v := rValue(bean) | v := rValue(bean) | ||||
if err := session.statement.setRefValue(v); err != nil { | if err := session.statement.setRefValue(v); err != nil { | ||||
return err | return err | ||||
@@ -107,7 +103,6 @@ func (session *Session) DropIndexes(bean interface{}) error { | |||||
} | } | ||||
func (session *Session) dropIndexes(bean interface{}) error { | func (session *Session) dropIndexes(bean interface{}) error { | ||||
defer session.resetStatement() | |||||
v := rValue(bean) | v := rValue(bean) | ||||
if err := session.statement.setRefValue(v); err != nil { | if err := session.statement.setRefValue(v); err != nil { | ||||
return err | return err | ||||
@@ -133,7 +128,6 @@ func (session *Session) DropTable(beanOrTableName interface{}) error { | |||||
} | } | ||||
func (session *Session) dropTable(beanOrTableName interface{}) error { | func (session *Session) dropTable(beanOrTableName interface{}) error { | ||||
defer session.resetStatement() | |||||
tableName, err := session.engine.tableName(beanOrTableName) | tableName, err := session.engine.tableName(beanOrTableName) | ||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
@@ -142,7 +136,7 @@ func (session *Session) dropTable(beanOrTableName interface{}) error { | |||||
var needDrop = true | var needDrop = true | ||||
if !session.engine.dialect.SupportDropIfExists() { | if !session.engine.dialect.SupportDropIfExists() { | ||||
sqlStr, args := session.engine.dialect.TableCheckSql(tableName) | sqlStr, args := session.engine.dialect.TableCheckSql(tableName) | ||||
results, err := session.query(sqlStr, args...) | |||||
results, err := session.queryBytes(sqlStr, args...) | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
@@ -172,9 +166,8 @@ func (session *Session) IsTableExist(beanOrTableName interface{}) (bool, error) | |||||
} | } | ||||
func (session *Session) isTableExist(tableName string) (bool, error) { | func (session *Session) isTableExist(tableName string) (bool, error) { | ||||
defer session.resetStatement() | |||||
sqlStr, args := session.engine.dialect.TableCheckSql(tableName) | sqlStr, args := session.engine.dialect.TableCheckSql(tableName) | ||||
results, err := session.query(sqlStr, args...) | |||||
results, err := session.queryBytes(sqlStr, args...) | |||||
return len(results) > 0, err | return len(results) > 0, err | ||||
} | } | ||||
@@ -196,12 +189,9 @@ func (session *Session) IsTableEmpty(bean interface{}) (bool, error) { | |||||
} | } | ||||
func (session *Session) isTableEmpty(tableName string) (bool, error) { | func (session *Session) isTableEmpty(tableName string) (bool, error) { | ||||
defer session.resetStatement() | |||||
var total int64 | var total int64 | ||||
sqlStr := fmt.Sprintf("select count(*) from %s", session.engine.Quote(tableName)) | sqlStr := fmt.Sprintf("select count(*) from %s", session.engine.Quote(tableName)) | ||||
err := session.DB().QueryRow(sqlStr).Scan(&total) | |||||
session.saveLastSQL(sqlStr) | |||||
err := session.queryRow(sqlStr).Scan(&total) | |||||
if err != nil { | if err != nil { | ||||
if err == sql.ErrNoRows { | if err == sql.ErrNoRows { | ||||
err = nil | err = nil | ||||
@@ -214,8 +204,6 @@ func (session *Session) isTableEmpty(tableName string) (bool, error) { | |||||
// find if index is exist according cols | // find if index is exist according cols | ||||
func (session *Session) isIndexExist2(tableName string, cols []string, unique bool) (bool, error) { | func (session *Session) isIndexExist2(tableName string, cols []string, unique bool) (bool, error) { | ||||
defer session.resetStatement() | |||||
indexes, err := session.engine.dialect.GetIndexes(tableName) | indexes, err := session.engine.dialect.GetIndexes(tableName) | ||||
if err != nil { | if err != nil { | ||||
return false, err | return false, err | ||||
@@ -233,8 +221,6 @@ func (session *Session) isIndexExist2(tableName string, cols []string, unique bo | |||||
} | } | ||||
func (session *Session) addColumn(colName string) error { | func (session *Session) addColumn(colName string) error { | ||||
defer session.resetStatement() | |||||
col := session.statement.RefTable.GetColumn(colName) | col := session.statement.RefTable.GetColumn(colName) | ||||
sql, args := session.statement.genAddColumnStr(col) | sql, args := session.statement.genAddColumnStr(col) | ||||
_, err := session.exec(sql, args...) | _, err := session.exec(sql, args...) | ||||
@@ -242,18 +228,13 @@ func (session *Session) addColumn(colName string) error { | |||||
} | } | ||||
func (session *Session) addIndex(tableName, idxName string) error { | func (session *Session) addIndex(tableName, idxName string) error { | ||||
defer session.resetStatement() | |||||
index := session.statement.RefTable.Indexes[idxName] | index := session.statement.RefTable.Indexes[idxName] | ||||
sqlStr := session.engine.dialect.CreateIndexSql(tableName, index) | sqlStr := session.engine.dialect.CreateIndexSql(tableName, index) | ||||
_, err := session.exec(sqlStr) | _, err := session.exec(sqlStr) | ||||
return err | return err | ||||
} | } | ||||
func (session *Session) addUnique(tableName, uqeName string) error { | func (session *Session) addUnique(tableName, uqeName string) error { | ||||
defer session.resetStatement() | |||||
index := session.statement.RefTable.Indexes[uqeName] | index := session.statement.RefTable.Indexes[uqeName] | ||||
sqlStr := session.engine.dialect.CreateIndexSql(tableName, index) | sqlStr := session.engine.dialect.CreateIndexSql(tableName, index) | ||||
_, err := session.exec(sqlStr) | _, err := session.exec(sqlStr) | ||||
@@ -13,7 +13,6 @@ import ( | |||||
// Count counts the records. bean's non-empty fields | // Count counts the records. bean's non-empty fields | ||||
// are conditions. | // are conditions. | ||||
func (session *Session) Count(bean ...interface{}) (int64, error) { | func (session *Session) Count(bean ...interface{}) (int64, error) { | ||||
defer session.resetStatement() | |||||
if session.isAutoClose { | if session.isAutoClose { | ||||
defer session.Close() | defer session.Close() | ||||
} | } | ||||
@@ -31,15 +30,8 @@ func (session *Session) Count(bean ...interface{}) (int64, error) { | |||||
args = session.statement.RawParams | args = session.statement.RawParams | ||||
} | } | ||||
session.queryPreprocess(&sqlStr, args...) | |||||
var total int64 | var total int64 | ||||
if session.isAutoCommit { | |||||
err = session.DB().QueryRow(sqlStr, args...).Scan(&total) | |||||
} else { | |||||
err = session.tx.QueryRow(sqlStr, args...).Scan(&total) | |||||
} | |||||
err = session.queryRow(sqlStr, args...).Scan(&total) | |||||
if err == sql.ErrNoRows || err == nil { | if err == sql.ErrNoRows || err == nil { | ||||
return total, nil | return total, nil | ||||
} | } | ||||
@@ -49,7 +41,6 @@ func (session *Session) Count(bean ...interface{}) (int64, error) { | |||||
// sum call sum some column. bean's non-empty fields are conditions. | // sum call sum some column. bean's non-empty fields are conditions. | ||||
func (session *Session) sum(res interface{}, bean interface{}, columnNames ...string) error { | func (session *Session) sum(res interface{}, bean interface{}, columnNames ...string) error { | ||||
defer session.resetStatement() | |||||
if session.isAutoClose { | if session.isAutoClose { | ||||
defer session.Close() | defer session.Close() | ||||
} | } | ||||
@@ -73,22 +64,11 @@ func (session *Session) sum(res interface{}, bean interface{}, columnNames ...st | |||||
args = session.statement.RawParams | args = session.statement.RawParams | ||||
} | } | ||||
session.queryPreprocess(&sqlStr, args...) | |||||
if isSlice { | if isSlice { | ||||
if session.isAutoCommit { | |||||
err = session.DB().QueryRow(sqlStr, args...).ScanSlice(res) | |||||
} else { | |||||
err = session.tx.QueryRow(sqlStr, args...).ScanSlice(res) | |||||
} | |||||
err = session.queryRow(sqlStr, args...).ScanSlice(res) | |||||
} else { | } else { | ||||
if session.isAutoCommit { | |||||
err = session.DB().QueryRow(sqlStr, args...).Scan(res) | |||||
} else { | |||||
err = session.tx.QueryRow(sqlStr, args...).Scan(res) | |||||
} | |||||
err = session.queryRow(sqlStr, args...).Scan(res) | |||||
} | } | ||||
if err == sql.ErrNoRows || err == nil { | if err == sql.ErrNoRows || err == nil { | ||||
return nil | return nil | ||||
} | } | ||||
@@ -15,8 +15,8 @@ import ( | |||||
"github.com/go-xorm/core" | "github.com/go-xorm/core" | ||||
) | ) | ||||
func (session *Session) cacheUpdate(sqlStr string, args ...interface{}) error { | |||||
if session.statement.RefTable == nil || | |||||
func (session *Session) cacheUpdate(table *core.Table, tableName, sqlStr string, args ...interface{}) error { | |||||
if table == nil || | |||||
session.tx != nil { | session.tx != nil { | ||||
return ErrCacheFailed | return ErrCacheFailed | ||||
} | } | ||||
@@ -26,7 +26,7 @@ func (session *Session) cacheUpdate(sqlStr string, args ...interface{}) error { | |||||
return ErrCacheFailed | return ErrCacheFailed | ||||
} | } | ||||
for _, filter := range session.engine.dialect.Filters() { | for _, filter := range session.engine.dialect.Filters() { | ||||
newsql = filter.Do(newsql, session.engine.dialect, session.statement.RefTable) | |||||
newsql = filter.Do(newsql, session.engine.dialect, table) | |||||
} | } | ||||
session.engine.logger.Debug("[cacheUpdate] new sql", oldhead, newsql) | session.engine.logger.Debug("[cacheUpdate] new sql", oldhead, newsql) | ||||
@@ -39,13 +39,12 @@ func (session *Session) cacheUpdate(sqlStr string, args ...interface{}) error { | |||||
nStart = strings.Count(oldhead, "$") | nStart = strings.Count(oldhead, "$") | ||||
} | } | ||||
} | } | ||||
table := session.statement.RefTable | |||||
cacher := session.engine.getCacher2(table) | cacher := session.engine.getCacher2(table) | ||||
tableName := session.statement.TableName() | |||||
session.engine.logger.Debug("[cacheUpdate] get cache sql", newsql, args[nStart:]) | session.engine.logger.Debug("[cacheUpdate] get cache sql", newsql, args[nStart:]) | ||||
ids, err := core.GetCacheSql(cacher, tableName, newsql, args[nStart:]) | ids, err := core.GetCacheSql(cacher, tableName, newsql, args[nStart:]) | ||||
if err != nil { | if err != nil { | ||||
rows, err := session.DB().Query(newsql, args[nStart:]...) | |||||
rows, err := session.NoCache().queryRows(newsql, args[nStart:]...) | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
@@ -144,7 +143,6 @@ func (session *Session) cacheUpdate(sqlStr string, args ...interface{}) error { | |||||
// You should call UseBool if you have bool to use. | // You should call UseBool if you have bool to use. | ||||
// 2.float32 & float64 may be not inexact as conditions | // 2.float32 & float64 may be not inexact as conditions | ||||
func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int64, error) { | func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int64, error) { | ||||
defer session.resetStatement() | |||||
if session.isAutoClose { | if session.isAutoClose { | ||||
defer session.Close() | defer session.Close() | ||||
} | } | ||||
@@ -249,8 +247,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 | |||||
} | } | ||||
} | } | ||||
st := session.statement | |||||
defer session.resetStatement() | |||||
st := &session.statement | |||||
var sqlStr string | var sqlStr string | ||||
var condArgs []interface{} | var condArgs []interface{} | ||||
@@ -282,6 +279,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 | |||||
condSQL = condSQL + fmt.Sprintf(" ORDER BY %v", st.OrderStr) | condSQL = condSQL + fmt.Sprintf(" ORDER BY %v", st.OrderStr) | ||||
} | } | ||||
var tableName = session.statement.TableName() | |||||
// TODO: Oracle support needed | // TODO: Oracle support needed | ||||
var top string | var top string | ||||
if st.LimitN > 0 { | if st.LimitN > 0 { | ||||
@@ -290,7 +288,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 | |||||
} else if st.Engine.dialect.DBType() == core.SQLITE { | } else if st.Engine.dialect.DBType() == core.SQLITE { | ||||
tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN) | tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN) | ||||
cond = cond.And(builder.Expr(fmt.Sprintf("rowid IN (SELECT rowid FROM %v %v)", | cond = cond.And(builder.Expr(fmt.Sprintf("rowid IN (SELECT rowid FROM %v %v)", | ||||
session.engine.Quote(session.statement.TableName()), tempCondSQL), condArgs...)) | |||||
session.engine.Quote(tableName), tempCondSQL), condArgs...)) | |||||
condSQL, condArgs, err = builder.ToSQL(cond) | condSQL, condArgs, err = builder.ToSQL(cond) | ||||
if err != nil { | if err != nil { | ||||
return 0, err | return 0, err | ||||
@@ -301,7 +299,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 | |||||
} else if st.Engine.dialect.DBType() == core.POSTGRES { | } else if st.Engine.dialect.DBType() == core.POSTGRES { | ||||
tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN) | tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN) | ||||
cond = cond.And(builder.Expr(fmt.Sprintf("CTID IN (SELECT CTID FROM %v %v)", | cond = cond.And(builder.Expr(fmt.Sprintf("CTID IN (SELECT CTID FROM %v %v)", | ||||
session.engine.Quote(session.statement.TableName()), tempCondSQL), condArgs...)) | |||||
session.engine.Quote(tableName), tempCondSQL), condArgs...)) | |||||
condSQL, condArgs, err = builder.ToSQL(cond) | condSQL, condArgs, err = builder.ToSQL(cond) | ||||
if err != nil { | if err != nil { | ||||
return 0, err | return 0, err | ||||
@@ -315,7 +313,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 | |||||
table != nil && len(table.PrimaryKeys) == 1 { | table != nil && len(table.PrimaryKeys) == 1 { | ||||
cond = builder.Expr(fmt.Sprintf("%s IN (SELECT TOP (%d) %s FROM %v%v)", | cond = builder.Expr(fmt.Sprintf("%s IN (SELECT TOP (%d) %s FROM %v%v)", | ||||
table.PrimaryKeys[0], st.LimitN, table.PrimaryKeys[0], | table.PrimaryKeys[0], st.LimitN, table.PrimaryKeys[0], | ||||
session.engine.Quote(session.statement.TableName()), condSQL), condArgs...) | |||||
session.engine.Quote(tableName), condSQL), condArgs...) | |||||
condSQL, condArgs, err = builder.ToSQL(cond) | condSQL, condArgs, err = builder.ToSQL(cond) | ||||
if err != nil { | if err != nil { | ||||
@@ -336,7 +334,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 | |||||
sqlStr = fmt.Sprintf("UPDATE %v%v SET %v %v", | sqlStr = fmt.Sprintf("UPDATE %v%v SET %v %v", | ||||
top, | top, | ||||
session.engine.Quote(session.statement.TableName()), | |||||
session.engine.Quote(tableName), | |||||
strings.Join(colNames, ", "), | strings.Join(colNames, ", "), | ||||
condSQL) | condSQL) | ||||
@@ -351,8 +349,9 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 | |||||
if table != nil { | if table != nil { | ||||
if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache { | if cacher := session.engine.getCacher2(table); cacher != nil && session.statement.UseCache { | ||||
cacher.ClearIds(session.statement.TableName()) | |||||
cacher.ClearBeans(session.statement.TableName()) | |||||
//session.cacheUpdate(table, tableName, sqlStr, args...) | |||||
cacher.ClearIds(tableName) | |||||
cacher.ClearBeans(tableName) | |||||
} | } | ||||
} | } | ||||
@@ -362,7 +361,7 @@ func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int6 | |||||
closure(bean) | closure(bean) | ||||
} | } | ||||
if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok { | if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok { | ||||
session.engine.logger.Debug("[event]", session.statement.TableName(), " has after update processor") | |||||
session.engine.logger.Debug("[event]", tableName, " has after update processor") | |||||
processor.AfterUpdate() | processor.AfterUpdate() | ||||
} | } | ||||
} else { | } else { | ||||
@@ -1205,7 +1205,8 @@ func (statement *Statement) convertIDSQL(sqlStr string) string { | |||||
top = fmt.Sprintf("TOP %d ", statement.LimitN) | top = fmt.Sprintf("TOP %d ", statement.LimitN) | ||||
} | } | ||||
return fmt.Sprintf("SELECT %s%s FROM %v", top, colstrs, sqls[1]) | |||||
newsql := fmt.Sprintf("SELECT %s%s FROM %v", top, colstrs, sqls[1]) | |||||
return newsql | |||||
} | } | ||||
return "" | return "" | ||||
} | } | ||||
@@ -0,0 +1 @@ | |||||
go test -db=mssql -conn_str="server=192.168.1.58;user id=sa;password=123456;database=xorm_test" -cache=true |
@@ -0,0 +1 @@ | |||||
go test -db=mymysql -conn_str="xorm_test/root/" -cache=true |
@@ -0,0 +1 @@ | |||||
go test -db=mysql -conn_str="root:@/xorm_test" -cache=true |
@@ -0,0 +1 @@ | |||||
go test -db=postgres -conn_str="dbname=xorm_test sslmode=disable" -cache=true |
@@ -0,0 +1 @@ | |||||
go test -db=sqlite3 -conn_str="./test.db?cache=shared&mode=rwc" -cache=true |
@@ -17,7 +17,7 @@ import ( | |||||
const ( | const ( | ||||
// Version show the xorm's version | // Version show the xorm's version | ||||
Version string = "0.6.3.0713" | |||||
Version string = "0.6.4.0910" | |||||
) | ) | ||||
func regDrvsNDialects() bool { | func regDrvsNDialects() bool { | ||||
@@ -456,10 +456,10 @@ | |||||
"revisionTime": "2017-05-19T03:21:30Z" | "revisionTime": "2017-05-19T03:21:30Z" | ||||
}, | }, | ||||
{ | { | ||||
"checksumSHA1": "KOHXTLwpgTMxBB9aGF2aIxkWdm8=", | |||||
"checksumSHA1": "HMavuxvDhKOwmbbFnYt9hfT6jE0=", | |||||
"path": "github.com/go-xorm/core", | "path": "github.com/go-xorm/core", | ||||
"revision": "71c1070a861118827352b1394eb86cbfeef5c513", | |||||
"revisionTime": "2017-08-22T05:50:40Z" | |||||
"revision": "da1adaf7a28ca792961721a34e6e04945200c890", | |||||
"revisionTime": "2017-09-09T08:56:53Z" | |||||
}, | }, | ||||
{ | { | ||||
"checksumSHA1": "k52lEKLp8j5M+jFpe+3u+bIFpxQ=", | "checksumSHA1": "k52lEKLp8j5M+jFpe+3u+bIFpxQ=", | ||||
@@ -468,10 +468,10 @@ | |||||
"revisionTime": "2016-08-11T02:11:45Z" | "revisionTime": "2016-08-11T02:11:45Z" | ||||
}, | }, | ||||
{ | { | ||||
"checksumSHA1": "0F65zfDi1ys3KD/wMKtxC2k13DA=", | |||||
"checksumSHA1": "SoZDnkd5NdwE0g4MY1nTAl8ZtPo=", | |||||
"path": "github.com/go-xorm/xorm", | "path": "github.com/go-xorm/xorm", | ||||
"revision": "a10b5aba4bb97b30daa74e7c0363d3084ede0514", | |||||
"revisionTime": "2017-08-20T09:05:42Z" | |||||
"revision": "c29485f954ed6495861c0098f9a1642a467299c8", | |||||
"revisionTime": "2017-09-10T12:58:18Z" | |||||
}, | }, | ||||
{ | { | ||||
"checksumSHA1": "1ft/4j5MFa7C9dPI9whL03HSUzk=", | "checksumSHA1": "1ft/4j5MFa7C9dPI9whL03HSUzk=", | ||||