remove no use package

This commit is contained in:
Jay 2018-04-20 14:37:39 +08:00
parent a3dae8424b
commit 1429c7fd85
109 changed files with 154 additions and 20887 deletions

View File

@ -0,0 +1,148 @@
package dbtool
import (
"database/sql"
"errors"
"reflect"
"strconv"
"strings"
"time"
)
// ScanToStruct - scan query rows to struct
func ScanToStruct(rows *sql.Rows, ss interface{}) (ok bool, err error) {
data, err := ResultToMap(rows)
if err != nil {
return false, err
}
if len(data) == 0 {
return false, nil
}
err = MapToStruct(data[0], ss)
if err != nil {
return false, err
}
return true, nil
}
func ScanToStructAll(rows *sql.Rows, ss interface{}) error {
sliceVal := reflect.Indirect(reflect.ValueOf(ss))
if sliceVal.Kind() != reflect.Slice {
return errors.New("need a pointer to a slice ")
}
vt := sliceVal.Type().Elem()
if vt.Kind() != reflect.Struct {
return errors.New("need struct slice")
}
data, err := ResultToMap(rows)
if err != nil {
return err
}
for i := range data {
tmp := reflect.New(vt)
iface := tmp.Interface()
err = MapToStruct(data[i], iface)
if err != nil {
return err
}
sliceVal.Set(reflect.Append(sliceVal, reflect.ValueOf(iface).Elem()))
}
return nil
}
func ResultToMap(r *sql.Rows) ([]map[string]interface{}, error) {
result := make([]map[string]interface{}, 0)
cols, err := r.Columns()
if err != nil {
return nil, err
}
vals := make([]sql.RawBytes, len(cols))
scans := make([]interface{}, len(vals))
for i := range vals {
scans[i] = &vals[i]
}
for r.Next() {
tmp := make(map[string]interface{})
err := r.Scan(scans...)
if err != nil {
return nil, err
}
for i, v := range vals {
tmp[cols[i]] = v
}
result = append(result, tmp)
}
return result, nil
}
func MapToStruct(data map[string]interface{}, out interface{}) error {
ss := reflect.ValueOf(out).Elem()
for i := 0; i < ss.NumField(); i++ {
tag := ss.Type().Field(i).Tag.Get("sql")
name := ss.Type().Field(i).Name
fname := strings.ToLower(name)
if len(tag) > 0 {
fname = tag
}
if fname == "-" {
continue
}
d, ok := data[fname]
if !ok {
continue
}
switch ss.Field(i).Interface().(type) {
case string:
ss.Field(i).SetString(string(d.(sql.RawBytes)))
case int, int8, int16, int32, int64:
str := string(d.(sql.RawBytes))
tmpi, err := strconv.ParseInt(str, 10, 64)
if err != nil {
return err
}
ss.Field(i).SetInt(tmpi)
case uint, uint8, uint16, uint32, uint64:
str := string(d.(sql.RawBytes))
tmpi, err := strconv.ParseUint(str, 10, 64)
if err != nil {
return err
}
ss.Field(i).SetUint(tmpi)
case bool:
str := string(d.(sql.RawBytes))
tmpb, err := strconv.ParseBool(str)
if err != nil {
return err
}
ss.Field(i).SetBool(tmpb)
case float32, float64:
str := string(d.(sql.RawBytes))
tmpf, err := strconv.ParseFloat(str, 64)
if err != nil {
return err
}
ss.Field(i).SetFloat(tmpf)
case time.Time:
str := string(d.(sql.RawBytes))
t, err := time.Parse(time.RFC3339, str)
if err != nil {
return err
}
ss.Field(i).Set(reflect.ValueOf(t))
default:
str := string(d.(sql.RawBytes))
ss.Field(i).Set(reflect.ValueOf(str))
}
}
return nil
}

View File

@ -1,27 +0,0 @@
Copyright (c) 2016 The Xorm Authors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the {organization} nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,175 +0,0 @@
# SQL builder
[![CircleCI](https://circleci.com/gh/go-xorm/builder/tree/master.svg?style=svg)](https://circleci.com/gh/go-xorm/builder/tree/master)
Package builder is a lightweight and fast SQL builder for Go and XORM.
Make sure you have installed Go 1.1+ and then:
go get github.com/go-xorm/builder
# Insert
```Go
sql, args, err := Insert(Eq{"c": 1, "d": 2}).Into("table1").ToSQL()
```
# Select
```Go
sql, args, err := Select("c, d").From("table1").Where(Eq{"a": 1}).ToSQL()
sql, args, err = Select("c, d").From("table1").LeftJoin("table2", Eq{"table1.id": 1}.And(Lt{"table2.id": 3})).
RightJoin("table3", "table2.id = table3.tid").Where(Eq{"a": 1}).ToSQL()
```
# Update
```Go
sql, args, err := Update(Eq{"a": 2}).From("table1").Where(Eq{"a": 1}).ToSQL()
```
# Delete
```Go
sql, args, err := Delete(Eq{"a": 1}).From("table1").ToSQL()
```
# Conditions
* `Eq` is a redefine of a map, you can give one or more conditions to `Eq`
```Go
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(Eq{"a":1})
// a=? [1]
sql, args, _ := ToSQL(Eq{"b":"c"}.And(Eq{"c": 0}))
// b=? AND c=? ["c", 0]
sql, args, _ := ToSQL(Eq{"b":"c", "c":0})
// b=? AND c=? ["c", 0]
sql, args, _ := ToSQL(Eq{"b":"c"}.Or(Eq{"b":"d"}))
// b=? OR b=? ["c", "d"]
sql, args, _ := ToSQL(Eq{"b": []string{"c", "d"}})
// b IN (?,?) ["c", "d"]
sql, args, _ := ToSQL(Eq{"b": 1, "c":[]int{2, 3}})
// b=? AND c IN (?,?) [1, 2, 3]
```
* `Neq` is the same to `Eq`
```Go
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(Neq{"a":1})
// a<>? [1]
sql, args, _ := ToSQL(Neq{"b":"c"}.And(Neq{"c": 0}))
// b<>? AND c<>? ["c", 0]
sql, args, _ := ToSQL(Neq{"b":"c", "c":0})
// b<>? AND c<>? ["c", 0]
sql, args, _ := ToSQL(Neq{"b":"c"}.Or(Neq{"b":"d"}))
// b<>? OR b<>? ["c", "d"]
sql, args, _ := ToSQL(Neq{"b": []string{"c", "d"}})
// b NOT IN (?,?) ["c", "d"]
sql, args, _ := ToSQL(Neq{"b": 1, "c":[]int{2, 3}})
// b<>? AND c NOT IN (?,?) [1, 2, 3]
```
* `Gt`, `Gte`, `Lt`, `Lte`
```Go
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(Gt{"a", 1}.And(Gte{"b", 2}))
// a>? AND b>=? [1, 2]
sql, args, _ := ToSQL(Lt{"a", 1}.Or(Lte{"b", 2}))
// a<? OR b<=? [1, 2]
```
* `Like`
```Go
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(Like{"a", "c"})
// a LIKE ? [%c%]
```
* `Expr` you can customerize your sql with `Expr`
```Go
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(Expr("a = ? ", 1))
// a = ? [1]
sql, args, _ := ToSQL(Eq{"a": Expr("select id from table where c = ?", 1)})
// a=(select id from table where c = ?) [1]
```
* `In` and `NotIn`
```Go
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(In("a", 1, 2, 3))
// a IN (?,?,?) [1,2,3]
sql, args, _ := ToSQL(In("a", []int{1, 2, 3}))
// a IN (?,?,?) [1,2,3]
sql, args, _ := ToSQL(In("a", Expr("select id from b where c = ?", 1))))
// a IN (select id from b where c = ?) [1]
```
* `IsNull` and `NotNull`
```Go
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(IsNull{"a"})
// a IS NULL []
sql, args, _ := ToSQL(NotNull{"b"})
// b IS NOT NULL []
```
* `And(conds ...Cond)`, And can connect one or more condtions via And
```Go
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(And(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
// a=? AND b LIKE ? AND d<>? [1, %c%, 2]
```
* `Or(conds ...Cond)`, Or can connect one or more conditions via Or
```Go
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(Or(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
// a=? OR b LIKE ? OR d<>? [1, %c%, 2]
sql, args, _ := ToSQL(Or(Eq{"a":1}, And(Like{"b", "c"}, Neq{"d", 2})))
// a=? OR (b LIKE ? AND d<>?) [1, %c%, 2]
```
* `Between`
```Go
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(Between{"a", 1, 2})
// a BETWEEN 1 AND 2
```
* Define yourself conditions
Since `Cond` is an interface.
```Go
type Cond interface {
WriteTo(Writer) error
And(...Cond) Cond
Or(...Cond) Cond
IsValid() bool
}
```
You can define yourself conditions and compose with other `Cond`.

View File

@ -1,190 +0,0 @@
// Copyright 2016 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 builder
type optype byte
const (
condType optype = iota // only conditions
selectType // select
insertType // insert
updateType // update
deleteType // delete
)
type join struct {
joinType string
joinTable string
joinCond Cond
}
// Builder describes a SQL statement
type Builder struct {
optype
tableName string
cond Cond
selects []string
joins []join
inserts Eq
updates []Eq
}
// Select creates a select Builder
func Select(cols ...string) *Builder {
builder := &Builder{cond: NewCond()}
return builder.Select(cols...)
}
// Insert creates an insert Builder
func Insert(eq Eq) *Builder {
builder := &Builder{cond: NewCond()}
return builder.Insert(eq)
}
// Update creates an update Builder
func Update(updates ...Eq) *Builder {
builder := &Builder{cond: NewCond()}
return builder.Update(updates...)
}
// Delete creates a delete Builder
func Delete(conds ...Cond) *Builder {
builder := &Builder{cond: NewCond()}
return builder.Delete(conds...)
}
// Where sets where SQL
func (b *Builder) Where(cond Cond) *Builder {
b.cond = b.cond.And(cond)
return b
}
// From sets the table name
func (b *Builder) From(tableName string) *Builder {
b.tableName = tableName
return b
}
// Into sets insert table name
func (b *Builder) Into(tableName string) *Builder {
b.tableName = tableName
return b
}
// Join sets join table and contions
func (b *Builder) Join(joinType, joinTable string, joinCond interface{}) *Builder {
switch joinCond.(type) {
case Cond:
b.joins = append(b.joins, join{joinType, joinTable, joinCond.(Cond)})
case string:
b.joins = append(b.joins, join{joinType, joinTable, Expr(joinCond.(string))})
}
return b
}
// InnerJoin sets inner join
func (b *Builder) InnerJoin(joinTable string, joinCond interface{}) *Builder {
return b.Join("INNER", joinTable, joinCond)
}
// LeftJoin sets left join SQL
func (b *Builder) LeftJoin(joinTable string, joinCond interface{}) *Builder {
return b.Join("LEFT", joinTable, joinCond)
}
// RightJoin sets right join SQL
func (b *Builder) RightJoin(joinTable string, joinCond interface{}) *Builder {
return b.Join("RIGHT", joinTable, joinCond)
}
// CrossJoin sets cross join SQL
func (b *Builder) CrossJoin(joinTable string, joinCond interface{}) *Builder {
return b.Join("CROSS", joinTable, joinCond)
}
// FullJoin sets full join SQL
func (b *Builder) FullJoin(joinTable string, joinCond interface{}) *Builder {
return b.Join("FULL", joinTable, joinCond)
}
// Select sets select SQL
func (b *Builder) Select(cols ...string) *Builder {
b.selects = cols
b.optype = selectType
return b
}
// And sets AND condition
func (b *Builder) And(cond Cond) *Builder {
b.cond = And(b.cond, cond)
return b
}
// Or sets OR condition
func (b *Builder) Or(cond Cond) *Builder {
b.cond = Or(b.cond, cond)
return b
}
// Insert sets insert SQL
func (b *Builder) Insert(eq Eq) *Builder {
b.inserts = eq
b.optype = insertType
return b
}
// Update sets update SQL
func (b *Builder) Update(updates ...Eq) *Builder {
b.updates = updates
b.optype = updateType
return b
}
// Delete sets delete SQL
func (b *Builder) Delete(conds ...Cond) *Builder {
b.cond = b.cond.And(conds...)
b.optype = deleteType
return b
}
// WriteTo implements Writer interface
func (b *Builder) WriteTo(w Writer) error {
switch b.optype {
case condType:
return b.cond.WriteTo(w)
case selectType:
return b.selectWriteTo(w)
case insertType:
return b.insertWriteTo(w)
case updateType:
return b.updateWriteTo(w)
case deleteType:
return b.deleteWriteTo(w)
}
return ErrNotSupportType
}
// ToSQL convert a builder to SQL and args
func (b *Builder) ToSQL() (string, []interface{}, error) {
w := NewWriter()
if err := b.WriteTo(w); err != nil {
return "", nil, err
}
return w.writer.String(), w.args, nil
}
// ToSQL convert a builder or condtions to SQL and args
func ToSQL(cond interface{}) (string, []interface{}, error) {
switch cond.(type) {
case Cond:
return condToSQL(cond.(Cond))
case *Builder:
return cond.(*Builder).ToSQL()
}
return "", nil, ErrNotSupportType
}

View File

@ -1,22 +0,0 @@
// Copyright 2016 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 builder
import (
"errors"
"fmt"
)
func (b *Builder) deleteWriteTo(w Writer) error {
if len(b.tableName) <= 0 {
return errors.New("no table indicated")
}
if _, err := fmt.Fprintf(w, "DELETE FROM %s WHERE ", b.tableName); err != nil {
return err
}
return b.cond.WriteTo(w)
}

View File

@ -1,64 +0,0 @@
// Copyright 2016 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 builder
import (
"bytes"
"errors"
"fmt"
)
func (b *Builder) insertWriteTo(w Writer) error {
if len(b.tableName) <= 0 {
return errors.New("no table indicated")
}
if len(b.inserts) <= 0 {
return errors.New("no column to be update")
}
if _, err := fmt.Fprintf(w, "INSERT INTO %s (", b.tableName); err != nil {
return err
}
var args = make([]interface{}, 0)
var bs []byte
var valBuffer = bytes.NewBuffer(bs)
var i = 0
for col, value := range b.inserts {
fmt.Fprint(w, col)
if e, ok := value.(expr); ok {
fmt.Fprint(valBuffer, e.sql)
args = append(args, e.args...)
} else {
fmt.Fprint(valBuffer, "?")
args = append(args, value)
}
if i != len(b.inserts)-1 {
if _, err := fmt.Fprint(w, ","); err != nil {
return err
}
if _, err := fmt.Fprint(valBuffer, ","); err != nil {
return err
}
}
i = i + 1
}
if _, err := fmt.Fprint(w, ") Values ("); err != nil {
return err
}
if _, err := w.Write(valBuffer.Bytes()); err != nil {
return err
}
if _, err := fmt.Fprint(w, ")"); err != nil {
return err
}
w.Append(args...)
return nil
}

View File

@ -1,57 +0,0 @@
// Copyright 2016 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 builder
import (
"errors"
"fmt"
)
func (b *Builder) selectWriteTo(w Writer) error {
if len(b.tableName) <= 0 {
return errors.New("no table indicated")
}
if _, err := fmt.Fprint(w, "SELECT "); err != nil {
return err
}
if len(b.selects) > 0 {
for i, s := range b.selects {
if _, err := fmt.Fprint(w, s); err != nil {
return err
}
if i != len(b.selects)-1 {
if _, err := fmt.Fprint(w, ","); err != nil {
return err
}
}
}
} else {
if _, err := fmt.Fprint(w, "*"); err != nil {
return err
}
}
if _, err := fmt.Fprintf(w, " FROM %s", b.tableName); err != nil {
return err
}
for _, v := range b.joins {
fmt.Fprintf(w, " %s JOIN %s ON ", v.joinType, v.joinTable)
if err := v.joinCond.WriteTo(w); err != nil {
return err
}
}
if !b.cond.IsValid() {
return nil
}
if _, err := fmt.Fprint(w, " WHERE "); err != nil {
return err
}
return b.cond.WriteTo(w)
}

View File

@ -1,41 +0,0 @@
// Copyright 2016 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 builder
import (
"errors"
"fmt"
)
func (b *Builder) updateWriteTo(w Writer) error {
if len(b.tableName) <= 0 {
return errors.New("no table indicated")
}
if len(b.updates) <= 0 {
return errors.New("no column to be update")
}
if _, err := fmt.Fprintf(w, "UPDATE %s SET ", b.tableName); err != nil {
return err
}
for i, s := range b.updates {
if err := s.opWriteTo(",", w); err != nil {
return err
}
if i != len(b.updates)-1 {
if _, err := fmt.Fprint(w, ","); err != nil {
return err
}
}
}
if _, err := fmt.Fprint(w, " WHERE "); err != nil {
return err
}
return b.cond.WriteTo(w)
}

View File

@ -1,12 +0,0 @@
dependencies:
override:
# './...' is a relative pattern which means all subdirectories
- go get -t -d -v ./...
- go build -v
- go get -u github.com/golang/lint/golint
test:
override:
# './...' is a relative pattern which means all subdirectories
- golint ./...
- go test -v -race

View File

@ -1,87 +0,0 @@
// Copyright 2016 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 builder
import (
"bytes"
"io"
)
// Writer defines the interface
type Writer interface {
io.Writer
Append(...interface{})
}
var _ Writer = NewWriter()
// BytesWriter implments Writer and save SQL in bytes.Buffer
type BytesWriter struct {
writer *bytes.Buffer
buffer []byte
args []interface{}
}
// NewWriter creates a new string writer
func NewWriter() *BytesWriter {
w := &BytesWriter{}
w.writer = bytes.NewBuffer(w.buffer)
return w
}
// Write writes data to Writer
func (s *BytesWriter) Write(buf []byte) (int, error) {
return s.writer.Write(buf)
}
// Append appends args to Writer
func (s *BytesWriter) Append(args ...interface{}) {
s.args = append(s.args, args...)
}
// Cond defines an interface
type Cond interface {
WriteTo(Writer) error
And(...Cond) Cond
Or(...Cond) Cond
IsValid() bool
}
type condEmpty struct{}
var _ Cond = condEmpty{}
// NewCond creates an empty condition
func NewCond() Cond {
return condEmpty{}
}
func (condEmpty) WriteTo(w Writer) error {
return nil
}
func (condEmpty) And(conds ...Cond) Cond {
return And(conds...)
}
func (condEmpty) Or(conds ...Cond) Cond {
return Or(conds...)
}
func (condEmpty) IsValid() bool {
return false
}
func condToSQL(cond Cond) (string, []interface{}, error) {
if cond == nil || !cond.IsValid() {
return "", nil, nil
}
w := NewWriter()
if err := cond.WriteTo(w); err != nil {
return "", nil, err
}
return w.writer.String(), w.args, nil
}

View File

@ -1,61 +0,0 @@
// Copyright 2016 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 builder
import "fmt"
type condAnd []Cond
var _ Cond = condAnd{}
// And generates AND conditions
func And(conds ...Cond) Cond {
var result = make(condAnd, 0, len(conds))
for _, cond := range conds {
if cond == nil || !cond.IsValid() {
continue
}
result = append(result, cond)
}
return result
}
func (and condAnd) WriteTo(w Writer) error {
for i, cond := range and {
_, isOr := cond.(condOr)
_, isExpr := cond.(expr)
wrap := isOr || isExpr
if wrap {
fmt.Fprint(w, "(")
}
err := cond.WriteTo(w)
if err != nil {
return err
}
if wrap {
fmt.Fprint(w, ")")
}
if i != len(and)-1 {
fmt.Fprint(w, " AND ")
}
}
return nil
}
func (and condAnd) And(conds ...Cond) Cond {
return And(and, And(conds...))
}
func (and condAnd) Or(conds ...Cond) Cond {
return Or(and, Or(conds...))
}
func (and condAnd) IsValid() bool {
return len(and) > 0
}

View File

@ -1,40 +0,0 @@
// Copyright 2016 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 builder
import "fmt"
// Between implmentes between condition
type Between struct {
Col string
LessVal interface{}
MoreVal interface{}
}
var _ Cond = Between{}
// WriteTo write data to Writer
func (between Between) WriteTo(w Writer) error {
if _, err := fmt.Fprintf(w, "%s BETWEEN ? AND ?", between.Col); err != nil {
return err
}
w.Append(between.LessVal, between.MoreVal)
return nil
}
// And implments And with other conditions
func (between Between) And(conds ...Cond) Cond {
return And(between, And(conds...))
}
// Or implments Or with other conditions
func (between Between) Or(conds ...Cond) Cond {
return Or(between, Or(conds...))
}
// IsValid tests if the condition is valid
func (between Between) IsValid() bool {
return len(between.Col) > 0
}

View File

@ -1,154 +0,0 @@
// Copyright 2016 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 builder
import "fmt"
// WriteMap writes conditions' SQL to Writer, op could be =, <>, >, <, <=, >= and etc.
func WriteMap(w Writer, data map[string]interface{}, op string) error {
var args = make([]interface{}, 0, len(data))
var i = 0
for k, v := range data {
switch v.(type) {
case expr:
if _, err := fmt.Fprintf(w, "%s%s(", k, op); err != nil {
return err
}
if err := v.(expr).WriteTo(w); err != nil {
return err
}
if _, err := fmt.Fprintf(w, ")"); err != nil {
return err
}
case *Builder:
if _, err := fmt.Fprintf(w, "%s%s(", k, op); err != nil {
return err
}
if err := v.(*Builder).WriteTo(w); err != nil {
return err
}
if _, err := fmt.Fprintf(w, ")"); err != nil {
return err
}
default:
if _, err := fmt.Fprintf(w, "%s%s?", k, op); err != nil {
return err
}
args = append(args, v)
}
if i != len(data)-1 {
if _, err := fmt.Fprint(w, " AND "); err != nil {
return err
}
}
i = i + 1
}
w.Append(args...)
return nil
}
// Lt defines < condition
type Lt map[string]interface{}
var _ Cond = Lt{}
// WriteTo write SQL to Writer
func (lt Lt) WriteTo(w Writer) error {
return WriteMap(w, lt, "<")
}
// And implements And with other conditions
func (lt Lt) And(conds ...Cond) Cond {
return condAnd{lt, And(conds...)}
}
// Or implements Or with other conditions
func (lt Lt) Or(conds ...Cond) Cond {
return condOr{lt, Or(conds...)}
}
// IsValid tests if this Eq is valid
func (lt Lt) IsValid() bool {
return len(lt) > 0
}
// Lte defines <= condition
type Lte map[string]interface{}
var _ Cond = Lte{}
// WriteTo write SQL to Writer
func (lte Lte) WriteTo(w Writer) error {
return WriteMap(w, lte, "<=")
}
// And implements And with other conditions
func (lte Lte) And(conds ...Cond) Cond {
return And(lte, And(conds...))
}
// Or implements Or with other conditions
func (lte Lte) Or(conds ...Cond) Cond {
return Or(lte, Or(conds...))
}
// IsValid tests if this Eq is valid
func (lte Lte) IsValid() bool {
return len(lte) > 0
}
// Gt defines > condition
type Gt map[string]interface{}
var _ Cond = Gt{}
// WriteTo write SQL to Writer
func (gt Gt) WriteTo(w Writer) error {
return WriteMap(w, gt, ">")
}
// And implements And with other conditions
func (gt Gt) And(conds ...Cond) Cond {
return And(gt, And(conds...))
}
// Or implements Or with other conditions
func (gt Gt) Or(conds ...Cond) Cond {
return Or(gt, Or(conds...))
}
// IsValid tests if this Eq is valid
func (gt Gt) IsValid() bool {
return len(gt) > 0
}
// Gte defines >= condition
type Gte map[string]interface{}
var _ Cond = Gte{}
// WriteTo write SQL to Writer
func (gte Gte) WriteTo(w Writer) error {
return WriteMap(w, gte, ">=")
}
// And implements And with other conditions
func (gte Gte) And(conds ...Cond) Cond {
return And(gte, And(conds...))
}
// Or implements Or with other conditions
func (gte Gte) Or(conds ...Cond) Cond {
return Or(gte, Or(conds...))
}
// IsValid tests if this Eq is valid
func (gte Gte) IsValid() bool {
return len(gte) > 0
}

View File

@ -1,96 +0,0 @@
// Copyright 2016 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 builder
import "fmt"
// Incr implements a type used by Eq
type Incr int
// Decr implements a type used by Eq
type Decr int
// Eq defines equals conditions
type Eq map[string]interface{}
var _ Cond = Eq{}
func (eq Eq) opWriteTo(op string, w Writer) error {
var i = 0
for k, v := range eq {
switch v.(type) {
case []int, []int64, []string, []int32, []int16, []int8, []uint, []uint64, []uint32, []uint16, []interface{}:
if err := In(k, v).WriteTo(w); err != nil {
return err
}
case expr:
if _, err := fmt.Fprintf(w, "%s=(", k); err != nil {
return err
}
if err := v.(expr).WriteTo(w); err != nil {
return err
}
if _, err := fmt.Fprintf(w, ")"); err != nil {
return err
}
case *Builder:
if _, err := fmt.Fprintf(w, "%s=(", k); err != nil {
return err
}
if err := v.(*Builder).WriteTo(w); err != nil {
return err
}
if _, err := fmt.Fprintf(w, ")"); err != nil {
return err
}
case Incr:
if _, err := fmt.Fprintf(w, "%s=%s+?", k, k); err != nil {
return err
}
w.Append(int(v.(Incr)))
case Decr:
if _, err := fmt.Fprintf(w, "%s=%s-?", k, k); err != nil {
return err
}
w.Append(int(v.(Decr)))
default:
if _, err := fmt.Fprintf(w, "%s=?", k); err != nil {
return err
}
w.Append(v)
}
if i != len(eq)-1 {
if _, err := fmt.Fprint(w, op); err != nil {
return err
}
}
i = i + 1
}
return nil
}
// WriteTo writes SQL to Writer
func (eq Eq) WriteTo(w Writer) error {
return eq.opWriteTo(" AND ", w)
}
// And implements And with other conditions
func (eq Eq) And(conds ...Cond) Cond {
return And(eq, And(conds...))
}
// Or implements Or with other conditions
func (eq Eq) Or(conds ...Cond) Cond {
return Or(eq, Or(conds...))
}
// IsValid tests if this Eq is valid
func (eq Eq) IsValid() bool {
return len(eq) > 0
}

View File

@ -1,39 +0,0 @@
// Copyright 2016 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 builder
import "fmt"
type expr struct {
sql string
args []interface{}
}
var _ Cond = expr{}
// Expr generate customerize SQL
func Expr(sql string, args ...interface{}) Cond {
return expr{sql, args}
}
func (expr expr) WriteTo(w Writer) error {
if _, err := fmt.Fprint(w, expr.sql); err != nil {
return err
}
w.Append(expr.args...)
return nil
}
func (expr expr) And(conds ...Cond) Cond {
return And(expr, And(conds...))
}
func (expr expr) Or(conds ...Cond) Cond {
return Or(expr, Or(conds...))
}
func (expr expr) IsValid() bool {
return len(expr.sql) > 0
}

View File

@ -1,237 +0,0 @@
// Copyright 2016 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 builder
import (
"fmt"
"reflect"
"strings"
)
type condIn struct {
col string
vals []interface{}
}
var _ Cond = condIn{}
// In generates IN condition
func In(col string, values ...interface{}) Cond {
return condIn{col, values}
}
func (condIn condIn) handleBlank(w Writer) error {
_, err := fmt.Fprint(w, "0=1")
return err
}
func (condIn condIn) WriteTo(w Writer) error {
if len(condIn.vals) <= 0 {
return condIn.handleBlank(w)
}
switch condIn.vals[0].(type) {
case []int8:
vals := condIn.vals[0].([]int8)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []int16:
vals := condIn.vals[0].([]int16)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []int:
vals := condIn.vals[0].([]int)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []int32:
vals := condIn.vals[0].([]int32)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []int64:
vals := condIn.vals[0].([]int64)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []uint8:
vals := condIn.vals[0].([]uint8)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []uint16:
vals := condIn.vals[0].([]uint16)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []uint:
vals := condIn.vals[0].([]uint)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []uint32:
vals := condIn.vals[0].([]uint32)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []uint64:
vals := condIn.vals[0].([]uint64)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []string:
vals := condIn.vals[0].([]string)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []interface{}:
vals := condIn.vals[0].([]interface{})
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
w.Append(vals...)
case expr:
val := condIn.vals[0].(expr)
if _, err := fmt.Fprintf(w, "%s IN (", condIn.col); err != nil {
return err
}
if err := val.WriteTo(w); err != nil {
return err
}
if _, err := fmt.Fprintf(w, ")"); err != nil {
return err
}
case *Builder:
bd := condIn.vals[0].(*Builder)
if _, err := fmt.Fprintf(w, "%s IN (", condIn.col); err != nil {
return err
}
if err := bd.WriteTo(w); err != nil {
return err
}
if _, err := fmt.Fprintf(w, ")"); err != nil {
return err
}
default:
v := reflect.ValueOf(condIn.vals[0])
if v.Kind() == reflect.Slice {
l := v.Len()
if l == 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", l)
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for i := 0; i < l; i++ {
w.Append(v.Index(i).Interface())
}
} else {
questionMark := strings.Repeat("?,", len(condIn.vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
w.Append(condIn.vals...)
}
}
return nil
}
func (condIn condIn) And(conds ...Cond) Cond {
return And(condIn, And(conds...))
}
func (condIn condIn) Or(conds ...Cond) Cond {
return Or(condIn, Or(conds...))
}
func (condIn condIn) IsValid() bool {
return len(condIn.col) > 0 && len(condIn.vals) > 0
}

View File

@ -1,41 +0,0 @@
// Copyright 2016 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 builder
import "fmt"
// Like defines like condition
type Like [2]string
var _ Cond = Like{"", ""}
// WriteTo write SQL to Writer
func (like Like) WriteTo(w Writer) error {
if _, err := fmt.Fprintf(w, "%s LIKE ?", like[0]); err != nil {
return err
}
// FIXME: if use other regular express, this will be failed. but for compitable, keep this
if like[1][0] == '%' || like[1][len(like[1])-1] == '%' {
w.Append(like[1])
} else {
w.Append("%" + like[1] + "%")
}
return nil
}
// And implements And with other conditions
func (like Like) And(conds ...Cond) Cond {
return And(like, And(conds...))
}
// Or implements Or with other conditions
func (like Like) Or(conds ...Cond) Cond {
return Or(like, Or(conds...))
}
// IsValid tests if this condition is valid
func (like Like) IsValid() bool {
return len(like[0]) > 0 && len(like[1]) > 0
}

View File

@ -1,78 +0,0 @@
// Copyright 2016 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 builder
import "fmt"
// Neq defines not equal conditions
type Neq map[string]interface{}
var _ Cond = Neq{}
// WriteTo writes SQL to Writer
func (neq Neq) WriteTo(w Writer) error {
var args = make([]interface{}, 0, len(neq))
var i = 0
for k, v := range neq {
switch v.(type) {
case []int, []int64, []string, []int32, []int16, []int8:
if err := NotIn(k, v).WriteTo(w); err != nil {
return err
}
case expr:
if _, err := fmt.Fprintf(w, "%s<>(", k); err != nil {
return err
}
if err := v.(expr).WriteTo(w); err != nil {
return err
}
if _, err := fmt.Fprintf(w, ")"); err != nil {
return err
}
case *Builder:
if _, err := fmt.Fprintf(w, "%s<>(", k); err != nil {
return err
}
if err := v.(*Builder).WriteTo(w); err != nil {
return err
}
if _, err := fmt.Fprintf(w, ")"); err != nil {
return err
}
default:
if _, err := fmt.Fprintf(w, "%s<>?", k); err != nil {
return err
}
args = append(args, v)
}
if i != len(neq)-1 {
if _, err := fmt.Fprint(w, " AND "); err != nil {
return err
}
}
i = i + 1
}
w.Append(args...)
return nil
}
// And implements And with other conditions
func (neq Neq) And(conds ...Cond) Cond {
return And(neq, And(conds...))
}
// Or implements Or with other conditions
func (neq Neq) Or(conds ...Cond) Cond {
return Or(neq, Or(conds...))
}
// IsValid tests if this condition is valid
func (neq Neq) IsValid() bool {
return len(neq) > 0
}

View File

@ -1,53 +0,0 @@
// Copyright 2016 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 builder
import "fmt"
// Not defines NOT condition
type Not [1]Cond
var _ Cond = Not{}
// WriteTo writes SQL to Writer
func (not Not) WriteTo(w Writer) error {
if _, err := fmt.Fprint(w, "NOT "); err != nil {
return err
}
switch not[0].(type) {
case condAnd, condOr:
if _, err := fmt.Fprint(w, "("); err != nil {
return err
}
}
if err := not[0].WriteTo(w); err != nil {
return err
}
switch not[0].(type) {
case condAnd, condOr:
if _, err := fmt.Fprint(w, ")"); err != nil {
return err
}
}
return nil
}
// And implements And with other conditions
func (not Not) And(conds ...Cond) Cond {
return And(not, And(conds...))
}
// Or implements Or with other conditions
func (not Not) Or(conds ...Cond) Cond {
return Or(not, Or(conds...))
}
// IsValid tests if this condition is valid
func (not Not) IsValid() bool {
return not[0] != nil && not[0].IsValid()
}

View File

@ -1,234 +0,0 @@
// Copyright 2016 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 builder
import (
"fmt"
"reflect"
"strings"
)
type condNotIn condIn
var _ Cond = condNotIn{}
// NotIn generate NOT IN condition
func NotIn(col string, values ...interface{}) Cond {
return condNotIn{col, values}
}
func (condNotIn condNotIn) handleBlank(w Writer) error {
_, err := fmt.Fprint(w, "0=0")
return err
}
func (condNotIn condNotIn) WriteTo(w Writer) error {
if len(condNotIn.vals) <= 0 {
return condNotIn.handleBlank(w)
}
switch condNotIn.vals[0].(type) {
case []int8:
vals := condNotIn.vals[0].([]int8)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []int16:
vals := condNotIn.vals[0].([]int16)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []int:
vals := condNotIn.vals[0].([]int)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []int32:
vals := condNotIn.vals[0].([]int32)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []int64:
vals := condNotIn.vals[0].([]int64)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []uint8:
vals := condNotIn.vals[0].([]uint8)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []uint16:
vals := condNotIn.vals[0].([]uint16)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []uint:
vals := condNotIn.vals[0].([]uint)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []uint32:
vals := condNotIn.vals[0].([]uint32)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []uint64:
vals := condNotIn.vals[0].([]uint64)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []string:
vals := condNotIn.vals[0].([]string)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for _, val := range vals {
w.Append(val)
}
case []interface{}:
vals := condNotIn.vals[0].([]interface{})
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
w.Append(vals...)
case expr:
val := condNotIn.vals[0].(expr)
if _, err := fmt.Fprintf(w, "%s NOT IN (", condNotIn.col); err != nil {
return err
}
if err := val.WriteTo(w); err != nil {
return err
}
if _, err := fmt.Fprintf(w, ")"); err != nil {
return err
}
case *Builder:
val := condNotIn.vals[0].(*Builder)
if _, err := fmt.Fprintf(w, "%s NOT IN (", condNotIn.col); err != nil {
return err
}
if err := val.WriteTo(w); err != nil {
return err
}
if _, err := fmt.Fprintf(w, ")"); err != nil {
return err
}
default:
v := reflect.ValueOf(condNotIn.vals[0])
if v.Kind() == reflect.Slice {
l := v.Len()
if l == 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", l)
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
for i := 0; i < l; i++ {
w.Append(v.Index(i).Interface())
}
} else {
questionMark := strings.Repeat("?,", len(condNotIn.vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
w.Append(condNotIn.vals...)
}
}
return nil
}
func (condNotIn condNotIn) And(conds ...Cond) Cond {
return And(condNotIn, And(conds...))
}
func (condNotIn condNotIn) Or(conds ...Cond) Cond {
return Or(condNotIn, Or(conds...))
}
func (condNotIn condNotIn) IsValid() bool {
return len(condNotIn.col) > 0 && len(condNotIn.vals) > 0
}

View File

@ -1,59 +0,0 @@
// Copyright 2016 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 builder
import "fmt"
// IsNull defines IS NULL condition
type IsNull [1]string
var _ Cond = IsNull{""}
// WriteTo write SQL to Writer
func (isNull IsNull) WriteTo(w Writer) error {
_, err := fmt.Fprintf(w, "%s IS NULL", isNull[0])
return err
}
// And implements And with other conditions
func (isNull IsNull) And(conds ...Cond) Cond {
return And(isNull, And(conds...))
}
// Or implements Or with other conditions
func (isNull IsNull) Or(conds ...Cond) Cond {
return Or(isNull, Or(conds...))
}
// IsValid tests if this condition is valid
func (isNull IsNull) IsValid() bool {
return len(isNull[0]) > 0
}
// NotNull defines NOT NULL condition
type NotNull [1]string
var _ Cond = NotNull{""}
// WriteTo write SQL to Writer
func (notNull NotNull) WriteTo(w Writer) error {
_, err := fmt.Fprintf(w, "%s IS NOT NULL", notNull[0])
return err
}
// And implements And with other conditions
func (notNull NotNull) And(conds ...Cond) Cond {
return And(notNull, And(conds...))
}
// Or implements Or with other conditions
func (notNull NotNull) Or(conds ...Cond) Cond {
return Or(notNull, Or(conds...))
}
// IsValid tests if this condition is valid
func (notNull NotNull) IsValid() bool {
return len(notNull[0]) > 0
}

View File

@ -1,67 +0,0 @@
// Copyright 2016 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 builder
import "fmt"
type condOr []Cond
var _ Cond = condOr{}
// Or sets OR conditions
func Or(conds ...Cond) Cond {
var result = make(condOr, 0, len(conds))
for _, cond := range conds {
if cond == nil || !cond.IsValid() {
continue
}
result = append(result, cond)
}
return result
}
// WriteTo implments Cond
func (o condOr) WriteTo(w Writer) error {
for i, cond := range o {
var needQuote bool
switch cond.(type) {
case condAnd:
needQuote = true
case Eq:
needQuote = (len(cond.(Eq)) > 1)
}
if needQuote {
fmt.Fprint(w, "(")
}
err := cond.WriteTo(w)
if err != nil {
return err
}
if needQuote {
fmt.Fprint(w, ")")
}
if i != len(o)-1 {
fmt.Fprint(w, " OR ")
}
}
return nil
}
func (o condOr) And(conds ...Cond) Cond {
return And(o, And(conds...))
}
func (o condOr) Or(conds ...Cond) Cond {
return Or(o, Or(conds...))
}
func (o condOr) IsValid() bool {
return len(o) > 0
}

View File

@ -1,120 +0,0 @@
// Copyright 2016 The XORM Authors. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.
/*
Package builder is a simple and powerful sql builder for Go.
Make sure you have installed Go 1.1+ and then:
go get github.com/go-xorm/builder
WARNNING: Currently, only query conditions are supported. Below is the supported conditions.
1. Eq is a redefine of a map, you can give one or more conditions to Eq
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(Eq{"a":1})
// a=? [1]
sql, args, _ := ToSQL(Eq{"b":"c"}.And(Eq{"c": 0}))
// b=? AND c=? ["c", 0]
sql, args, _ := ToSQL(Eq{"b":"c", "c":0})
// b=? AND c=? ["c", 0]
sql, args, _ := ToSQL(Eq{"b":"c"}.Or(Eq{"b":"d"}))
// b=? OR b=? ["c", "d"]
sql, args, _ := ToSQL(Eq{"b": []string{"c", "d"}})
// b IN (?,?) ["c", "d"]
sql, args, _ := ToSQL(Eq{"b": 1, "c":[]int{2, 3}})
// b=? AND c IN (?,?) [1, 2, 3]
2. Neq is the same to Eq
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(Neq{"a":1})
// a<>? [1]
sql, args, _ := ToSQL(Neq{"b":"c"}.And(Neq{"c": 0}))
// b<>? AND c<>? ["c", 0]
sql, args, _ := ToSQL(Neq{"b":"c", "c":0})
// b<>? AND c<>? ["c", 0]
sql, args, _ := ToSQL(Neq{"b":"c"}.Or(Neq{"b":"d"}))
// b<>? OR b<>? ["c", "d"]
sql, args, _ := ToSQL(Neq{"b": []string{"c", "d"}})
// b NOT IN (?,?) ["c", "d"]
sql, args, _ := ToSQL(Neq{"b": 1, "c":[]int{2, 3}})
// b<>? AND c NOT IN (?,?) [1, 2, 3]
3. Gt, Gte, Lt, Lte
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(Gt{"a", 1}.And(Gte{"b", 2}))
// a>? AND b>=? [1, 2]
sql, args, _ := ToSQL(Lt{"a", 1}.Or(Lte{"b", 2}))
// a<? OR b<=? [1, 2]
4. Like
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(Like{"a", "c"})
// a LIKE ? [%c%]
5. Expr you can customerize your sql with Expr
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(Expr("a = ? ", 1))
// a = ? [1]
sql, args, _ := ToSQL(Eq{"a": Expr("select id from table where c = ?", 1)})
// a=(select id from table where c = ?) [1]
6. In and NotIn
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(In("a", 1, 2, 3))
// a IN (?,?,?) [1,2,3]
sql, args, _ := ToSQL(In("a", []int{1, 2, 3}))
// a IN (?,?,?) [1,2,3]
sql, args, _ := ToSQL(In("a", Expr("select id from b where c = ?", 1))))
// a IN (select id from b where c = ?) [1]
7. IsNull and NotNull
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(IsNull{"a"})
// a IS NULL []
sql, args, _ := ToSQL(NotNull{"b"})
// b IS NOT NULL []
8. And(conds ...Cond), And can connect one or more condtions via AND
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(And(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
// a=? AND b LIKE ? AND d<>? [1, %c%, 2]
9. Or(conds ...Cond), Or can connect one or more conditions via Or
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(Or(Eq{"a":1}, Like{"b", "c"}, Neq{"d", 2}))
// a=? OR b LIKE ? OR d<>? [1, %c%, 2]
sql, args, _ := ToSQL(Or(Eq{"a":1}, And(Like{"b", "c"}, Neq{"d", 2})))
// a=? OR (b LIKE ? AND d<>?) [1, %c%, 2]
10. Between
import . "github.com/go-xorm/builder"
sql, args, _ := ToSQL(Between("a", 1, 2))
// a BETWEEN 1 AND 2
11. define yourself conditions
Since Cond is a interface, you can define yourself conditions and compare with them
*/
package builder

View File

@ -1,16 +0,0 @@
// Copyright 2016 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 builder
import "errors"
var (
// ErrNotSupportType not supported SQL type error
ErrNotSupportType = errors.New("not supported SQL type")
// ErrNoNotInConditions no NOT IN params error
ErrNoNotInConditions = errors.New("No NOT IN conditions")
// ErrNoInConditions no IN params error
ErrNoInConditions = errors.New("No IN conditions")
)

View File

@ -1 +0,0 @@
module "github.com/go-xorm/builder"

View File

@ -1,27 +0,0 @@
Copyright (c) 2013 - 2015 Lunny Xiao <xiaolunwen@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the {organization} nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,116 +0,0 @@
Core is a lightweight wrapper of sql.DB.
[![CircleCI](https://circleci.com/gh/go-xorm/core/tree/master.svg?style=svg)](https://circleci.com/gh/go-xorm/core/tree/master)
# Open
```Go
db, _ := core.Open(db, connstr)
```
# SetMapper
```Go
db.SetMapper(SameMapper())
```
## Scan usage
### Scan
```Go
rows, _ := db.Query()
for rows.Next() {
rows.Scan()
}
```
### ScanMap
```Go
rows, _ := db.Query()
for rows.Next() {
rows.ScanMap()
```
### ScanSlice
You can use `[]string`, `[][]byte`, `[]interface{}`, `[]*string`, `[]sql.NullString` to ScanSclice. Notice, slice's length should be equal or less than select columns.
```Go
rows, _ := db.Query()
cols, _ := rows.Columns()
for rows.Next() {
var s = make([]string, len(cols))
rows.ScanSlice(&s)
}
```
```Go
rows, _ := db.Query()
cols, _ := rows.Columns()
for rows.Next() {
var s = make([]*string, len(cols))
rows.ScanSlice(&s)
}
```
### ScanStruct
```Go
rows, _ := db.Query()
for rows.Next() {
rows.ScanStructByName()
rows.ScanStructByIndex()
}
```
## Query usage
```Go
rows, err := db.Query("select * from table where name = ?", name)
user = User{
Name:"lunny",
}
rows, err := db.QueryStruct("select * from table where name = ?Name",
&user)
var user = map[string]interface{}{
"name": "lunny",
}
rows, err = db.QueryMap("select * from table where name = ?name",
&user)
```
## QueryRow usage
```Go
row := db.QueryRow("select * from table where name = ?", name)
user = User{
Name:"lunny",
}
row := db.QueryRowStruct("select * from table where name = ?Name",
&user)
var user = map[string]interface{}{
"name": "lunny",
}
row = db.QueryRowMap("select * from table where name = ?name",
&user)
```
## Exec usage
```Go
db.Exec("insert into user (`name`, title, age, alias, nick_name,created) values (?,?,?,?,?,?)", name, title, age, alias...)
user = User{
Name:"lunny",
Title:"test",
Age: 18,
}
result, err = db.ExecStruct("insert into user (`name`, title, age, alias, nick_name,created) values (?Name,?Title,?Age,?Alias,?NickName,?Created)",
&user)
var user = map[string]interface{}{
"Name": "lunny",
"Title": "test",
"Age": 18,
}
result, err = db.ExecMap("insert into user (`name`, title, age, alias, nick_name,created) values (?Name,?Title,?Age,?Alias,?NickName,?Created)",
&user)
```

View File

@ -1 +0,0 @@
go test -v -bench=. -run=XXX

View File

@ -1,87 +0,0 @@
package core
import (
"bytes"
"encoding/gob"
"errors"
"fmt"
"strings"
"time"
)
const (
// default cache expired time
CacheExpired = 60 * time.Minute
// not use now
CacheMaxMemory = 256
// evey ten minutes to clear all expired nodes
CacheGcInterval = 10 * time.Minute
// each time when gc to removed max nodes
CacheGcMaxRemoved = 20
)
var (
ErrCacheMiss = errors.New("xorm/cache: key not found.")
ErrNotStored = errors.New("xorm/cache: not stored.")
)
// CacheStore is a interface to store cache
type CacheStore interface {
// key is primary key or composite primary key
// value is struct's pointer
// key format : <tablename>-p-<pk1>-<pk2>...
Put(key string, value interface{}) error
Get(key string) (interface{}, error)
Del(key string) error
}
// Cacher is an interface to provide cache
// id format : u-<pk1>-<pk2>...
type Cacher interface {
GetIds(tableName, sql string) interface{}
GetBean(tableName string, id string) interface{}
PutIds(tableName, sql string, ids interface{})
PutBean(tableName string, id string, obj interface{})
DelIds(tableName, sql string)
DelBean(tableName string, id string)
ClearIds(tableName string)
ClearBeans(tableName string)
}
func encodeIds(ids []PK) (string, error) {
buf := new(bytes.Buffer)
enc := gob.NewEncoder(buf)
err := enc.Encode(ids)
return buf.String(), err
}
func decodeIds(s string) ([]PK, error) {
pks := make([]PK, 0)
dec := gob.NewDecoder(strings.NewReader(s))
err := dec.Decode(&pks)
return pks, err
}
func GetCacheSql(m Cacher, tableName, sql string, args interface{}) ([]PK, error) {
bytes := m.GetIds(tableName, GenSqlKey(sql, args))
if bytes == nil {
return nil, errors.New("Not Exist")
}
return decodeIds(bytes.(string))
}
func PutCacheSql(m Cacher, ids []PK, tableName, sql string, args interface{}) error {
bytes, err := encodeIds(ids)
if err != nil {
return err
}
m.PutIds(tableName, GenSqlKey(sql, args), bytes)
return nil
}
func GenSqlKey(sql string, args interface{}) string {
return fmt.Sprintf("%v-%v", sql, args)
}

View File

@ -1,15 +0,0 @@
dependencies:
override:
# './...' is a relative pattern which means all subdirectories
- go get -t -d -v ./...
- go build -v
database:
override:
- mysql -u root -e "CREATE DATABASE core_test DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci"
test:
override:
# './...' is a relative pattern which means all subdirectories
- go test -v -race
- go test -v -race --dbtype=sqlite3

View File

@ -1,159 +0,0 @@
package core
import (
"fmt"
"reflect"
"strings"
"time"
)
const (
TWOSIDES = iota + 1
ONLYTODB
ONLYFROMDB
)
// Column defines database column
type Column struct {
Name string
TableName string
FieldName string
SQLType SQLType
IsJSON bool
Length int
Length2 int
Nullable bool
Default string
Indexes map[string]int
IsPrimaryKey bool
IsAutoIncrement bool
MapType int
IsCreated bool
IsUpdated bool
IsDeleted bool
IsCascade bool
IsVersion bool
DefaultIsEmpty bool
EnumOptions map[string]int
SetOptions map[string]int
DisableTimeZone bool
TimeZone *time.Location // column specified time zone
Comment string
}
func NewColumn(name, fieldName string, sqlType SQLType, len1, len2 int, nullable bool) *Column {
return &Column{
Name: name,
TableName: "",
FieldName: fieldName,
SQLType: sqlType,
Length: len1,
Length2: len2,
Nullable: nullable,
Default: "",
Indexes: make(map[string]int),
IsPrimaryKey: false,
IsAutoIncrement: false,
MapType: TWOSIDES,
IsCreated: false,
IsUpdated: false,
IsDeleted: false,
IsCascade: false,
IsVersion: false,
DefaultIsEmpty: false,
EnumOptions: make(map[string]int),
Comment: "",
}
}
// generate column description string according dialect
func (col *Column) String(d Dialect) string {
sql := d.QuoteStr() + col.Name + d.QuoteStr() + " "
sql += d.SqlType(col) + " "
if col.IsPrimaryKey {
sql += "PRIMARY KEY "
if col.IsAutoIncrement {
sql += d.AutoIncrStr() + " "
}
}
if col.Default != "" {
sql += "DEFAULT " + col.Default + " "
}
if d.ShowCreateNull() {
if col.Nullable {
sql += "NULL "
} else {
sql += "NOT NULL "
}
}
return sql
}
func (col *Column) StringNoPk(d Dialect) string {
sql := d.QuoteStr() + col.Name + d.QuoteStr() + " "
sql += d.SqlType(col) + " "
if col.Default != "" {
sql += "DEFAULT " + col.Default + " "
}
if d.ShowCreateNull() {
if col.Nullable {
sql += "NULL "
} else {
sql += "NOT NULL "
}
}
return sql
}
// return col's filed of struct's value
func (col *Column) ValueOf(bean interface{}) (*reflect.Value, error) {
dataStruct := reflect.Indirect(reflect.ValueOf(bean))
return col.ValueOfV(&dataStruct)
}
func (col *Column) ValueOfV(dataStruct *reflect.Value) (*reflect.Value, error) {
var fieldValue reflect.Value
fieldPath := strings.Split(col.FieldName, ".")
if dataStruct.Type().Kind() == reflect.Map {
keyValue := reflect.ValueOf(fieldPath[len(fieldPath)-1])
fieldValue = dataStruct.MapIndex(keyValue)
return &fieldValue, nil
} else if dataStruct.Type().Kind() == reflect.Interface {
structValue := reflect.ValueOf(dataStruct.Interface())
dataStruct = &structValue
}
level := len(fieldPath)
fieldValue = dataStruct.FieldByName(fieldPath[0])
for i := 0; i < level-1; i++ {
if !fieldValue.IsValid() {
break
}
if fieldValue.Kind() == reflect.Struct {
fieldValue = fieldValue.FieldByName(fieldPath[i+1])
} else if fieldValue.Kind() == reflect.Ptr {
if fieldValue.IsNil() {
fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
}
fieldValue = fieldValue.Elem().FieldByName(fieldPath[i+1])
} else {
return nil, fmt.Errorf("field %v is not valid", col.FieldName)
}
}
if !fieldValue.IsValid() {
return nil, fmt.Errorf("field %v is not valid", col.FieldName)
}
return &fieldValue, nil
}

View File

@ -1,8 +0,0 @@
package core
// Conversion is an interface. A type implements Conversion will according
// the custom method to fill into database and retrieve from database.
type Conversion interface {
FromDB([]byte) error
ToDB() ([]byte, error)
}

401
vendor/github.com/go-xorm/core/db.go generated vendored
View File

@ -1,401 +0,0 @@
package core
import (
"database/sql"
"database/sql/driver"
"errors"
"fmt"
"reflect"
"regexp"
"sync"
)
var (
DefaultCacheSize = 200
)
func MapToSlice(query string, mp interface{}) (string, []interface{}, error) {
vv := reflect.ValueOf(mp)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
return "", []interface{}{}, ErrNoMapPointer
}
args := make([]interface{}, 0, len(vv.Elem().MapKeys()))
var err error
query = re.ReplaceAllStringFunc(query, func(src string) string {
v := vv.Elem().MapIndex(reflect.ValueOf(src[1:]))
if !v.IsValid() {
err = fmt.Errorf("map key %s is missing", src[1:])
} else {
args = append(args, v.Interface())
}
return "?"
})
return query, args, err
}
func StructToSlice(query string, st interface{}) (string, []interface{}, error) {
vv := reflect.ValueOf(st)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
return "", []interface{}{}, ErrNoStructPointer
}
args := make([]interface{}, 0)
var err error
query = re.ReplaceAllStringFunc(query, func(src string) string {
fv := vv.Elem().FieldByName(src[1:]).Interface()
if v, ok := fv.(driver.Valuer); ok {
var value driver.Value
value, err = v.Value()
if err != nil {
return "?"
}
args = append(args, value)
} else {
args = append(args, fv)
}
return "?"
})
if err != nil {
return "", []interface{}{}, err
}
return query, args, nil
}
type cacheStruct struct {
value reflect.Value
idx int
}
type DB struct {
*sql.DB
Mapper IMapper
reflectCache map[reflect.Type]*cacheStruct
reflectCacheMutex sync.RWMutex
}
func Open(driverName, dataSourceName string) (*DB, error) {
db, err := sql.Open(driverName, dataSourceName)
if err != nil {
return nil, err
}
return &DB{
DB: db,
Mapper: NewCacheMapper(&SnakeMapper{}),
reflectCache: make(map[reflect.Type]*cacheStruct),
}, nil
}
func FromDB(db *sql.DB) *DB {
return &DB{
DB: db,
Mapper: NewCacheMapper(&SnakeMapper{}),
reflectCache: make(map[reflect.Type]*cacheStruct),
}
}
func (db *DB) reflectNew(typ reflect.Type) reflect.Value {
db.reflectCacheMutex.Lock()
defer db.reflectCacheMutex.Unlock()
cs, ok := db.reflectCache[typ]
if !ok || cs.idx+1 > DefaultCacheSize-1 {
cs = &cacheStruct{reflect.MakeSlice(reflect.SliceOf(typ), DefaultCacheSize, DefaultCacheSize), 0}
db.reflectCache[typ] = cs
} else {
cs.idx = cs.idx + 1
}
return cs.value.Index(cs.idx).Addr()
}
func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
rows, err := db.DB.Query(query, args...)
if err != nil {
if rows != nil {
rows.Close()
}
return nil, err
}
return &Rows{rows, db}, nil
}
func (db *DB) QueryMap(query string, mp interface{}) (*Rows, error) {
query, args, err := MapToSlice(query, mp)
if err != nil {
return nil, err
}
return db.Query(query, args...)
}
func (db *DB) QueryStruct(query string, st interface{}) (*Rows, error) {
query, args, err := StructToSlice(query, st)
if err != nil {
return nil, err
}
return db.Query(query, args...)
}
func (db *DB) QueryRow(query string, args ...interface{}) *Row {
rows, err := db.Query(query, args...)
if err != nil {
return &Row{nil, err}
}
return &Row{rows, nil}
}
func (db *DB) QueryRowMap(query string, mp interface{}) *Row {
query, args, err := MapToSlice(query, mp)
if err != nil {
return &Row{nil, err}
}
return db.QueryRow(query, args...)
}
func (db *DB) QueryRowStruct(query string, st interface{}) *Row {
query, args, err := StructToSlice(query, st)
if err != nil {
return &Row{nil, err}
}
return db.QueryRow(query, args...)
}
type Stmt struct {
*sql.Stmt
db *DB
names map[string]int
}
func (db *DB) Prepare(query string) (*Stmt, error) {
names := make(map[string]int)
var i int
query = re.ReplaceAllStringFunc(query, func(src string) string {
names[src[1:]] = i
i += 1
return "?"
})
stmt, err := db.DB.Prepare(query)
if err != nil {
return nil, err
}
return &Stmt{stmt, db, names}, nil
}
func (s *Stmt) ExecMap(mp interface{}) (sql.Result, error) {
vv := reflect.ValueOf(mp)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
return nil, errors.New("mp should be a map's pointer")
}
args := make([]interface{}, len(s.names))
for k, i := range s.names {
args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface()
}
return s.Stmt.Exec(args...)
}
func (s *Stmt) ExecStruct(st interface{}) (sql.Result, error) {
vv := reflect.ValueOf(st)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
return nil, errors.New("mp should be a map's pointer")
}
args := make([]interface{}, len(s.names))
for k, i := range s.names {
args[i] = vv.Elem().FieldByName(k).Interface()
}
return s.Stmt.Exec(args...)
}
func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
rows, err := s.Stmt.Query(args...)
if err != nil {
return nil, err
}
return &Rows{rows, s.db}, nil
}
func (s *Stmt) QueryMap(mp interface{}) (*Rows, error) {
vv := reflect.ValueOf(mp)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
return nil, errors.New("mp should be a map's pointer")
}
args := make([]interface{}, len(s.names))
for k, i := range s.names {
args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface()
}
return s.Query(args...)
}
func (s *Stmt) QueryStruct(st interface{}) (*Rows, error) {
vv := reflect.ValueOf(st)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
return nil, errors.New("mp should be a map's pointer")
}
args := make([]interface{}, len(s.names))
for k, i := range s.names {
args[i] = vv.Elem().FieldByName(k).Interface()
}
return s.Query(args...)
}
func (s *Stmt) QueryRow(args ...interface{}) *Row {
rows, err := s.Query(args...)
return &Row{rows, err}
}
func (s *Stmt) QueryRowMap(mp interface{}) *Row {
vv := reflect.ValueOf(mp)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
return &Row{nil, errors.New("mp should be a map's pointer")}
}
args := make([]interface{}, len(s.names))
for k, i := range s.names {
args[i] = vv.Elem().MapIndex(reflect.ValueOf(k)).Interface()
}
return s.QueryRow(args...)
}
func (s *Stmt) QueryRowStruct(st interface{}) *Row {
vv := reflect.ValueOf(st)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
return &Row{nil, errors.New("st should be a struct's pointer")}
}
args := make([]interface{}, len(s.names))
for k, i := range s.names {
args[i] = vv.Elem().FieldByName(k).Interface()
}
return s.QueryRow(args...)
}
var (
re = regexp.MustCompile(`[?](\w+)`)
)
// insert into (name) values (?)
// insert into (name) values (?name)
func (db *DB) ExecMap(query string, mp interface{}) (sql.Result, error) {
query, args, err := MapToSlice(query, mp)
if err != nil {
return nil, err
}
return db.DB.Exec(query, args...)
}
func (db *DB) ExecStruct(query string, st interface{}) (sql.Result, error) {
query, args, err := StructToSlice(query, st)
if err != nil {
return nil, err
}
return db.DB.Exec(query, args...)
}
type EmptyScanner struct {
}
func (EmptyScanner) Scan(src interface{}) error {
return nil
}
type Tx struct {
*sql.Tx
db *DB
}
func (db *DB) Begin() (*Tx, error) {
tx, err := db.DB.Begin()
if err != nil {
return nil, err
}
return &Tx{tx, db}, nil
}
func (tx *Tx) Prepare(query string) (*Stmt, error) {
names := make(map[string]int)
var i int
query = re.ReplaceAllStringFunc(query, func(src string) string {
names[src[1:]] = i
i += 1
return "?"
})
stmt, err := tx.Tx.Prepare(query)
if err != nil {
return nil, err
}
return &Stmt{stmt, tx.db, names}, nil
}
func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
// TODO:
return stmt
}
func (tx *Tx) ExecMap(query string, mp interface{}) (sql.Result, error) {
query, args, err := MapToSlice(query, mp)
if err != nil {
return nil, err
}
return tx.Tx.Exec(query, args...)
}
func (tx *Tx) ExecStruct(query string, st interface{}) (sql.Result, error) {
query, args, err := StructToSlice(query, st)
if err != nil {
return nil, err
}
return tx.Tx.Exec(query, args...)
}
func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
rows, err := tx.Tx.Query(query, args...)
if err != nil {
return nil, err
}
return &Rows{rows, tx.db}, nil
}
func (tx *Tx) QueryMap(query string, mp interface{}) (*Rows, error) {
query, args, err := MapToSlice(query, mp)
if err != nil {
return nil, err
}
return tx.Query(query, args...)
}
func (tx *Tx) QueryStruct(query string, st interface{}) (*Rows, error) {
query, args, err := StructToSlice(query, st)
if err != nil {
return nil, err
}
return tx.Query(query, args...)
}
func (tx *Tx) QueryRow(query string, args ...interface{}) *Row {
rows, err := tx.Query(query, args...)
return &Row{rows, err}
}
func (tx *Tx) QueryRowMap(query string, mp interface{}) *Row {
query, args, err := MapToSlice(query, mp)
if err != nil {
return &Row{nil, err}
}
return tx.QueryRow(query, args...)
}
func (tx *Tx) QueryRowStruct(query string, st interface{}) *Row {
query, args, err := StructToSlice(query, st)
if err != nil {
return &Row{nil, err}
}
return tx.QueryRow(query, args...)
}

View File

@ -1,315 +0,0 @@
package core
import (
"fmt"
"strings"
"time"
)
type DbType string
type Uri struct {
DbType DbType
Proto string
Host string
Port string
DbName string
User string
Passwd string
Charset string
Laddr string
Raddr string
Timeout time.Duration
Schema string
}
// a dialect is a driver's wrapper
type Dialect interface {
SetLogger(logger ILogger)
Init(*DB, *Uri, string, string) error
URI() *Uri
DB() *DB
DBType() DbType
SqlType(*Column) string
FormatBytes(b []byte) string
DriverName() string
DataSourceName() string
QuoteStr() string
IsReserved(string) bool
Quote(string) string
AndStr() string
OrStr() string
EqStr() string
RollBackStr() string
AutoIncrStr() string
SupportInsertMany() bool
SupportEngine() bool
SupportCharset() bool
SupportDropIfExists() bool
IndexOnTable() bool
ShowCreateNull() bool
IndexCheckSql(tableName, idxName string) (string, []interface{})
TableCheckSql(tableName string) (string, []interface{})
IsColumnExist(tableName string, colName string) (bool, error)
CreateTableSql(table *Table, tableName, storeEngine, charset string) string
DropTableSql(tableName string) string
CreateIndexSql(tableName string, index *Index) string
DropIndexSql(tableName string, index *Index) string
ModifyColumnSql(tableName string, col *Column) string
ForUpdateSql(query string) string
//CreateTableIfNotExists(table *Table, tableName, storeEngine, charset string) error
//MustDropTable(tableName string) error
GetColumns(tableName string) ([]string, map[string]*Column, error)
GetTables() ([]*Table, error)
GetIndexes(tableName string) (map[string]*Index, error)
Filters() []Filter
SetParams(params map[string]string)
}
func OpenDialect(dialect Dialect) (*DB, error) {
return Open(dialect.DriverName(), dialect.DataSourceName())
}
type Base struct {
db *DB
dialect Dialect
driverName string
dataSourceName string
logger ILogger
*Uri
}
func (b *Base) DB() *DB {
return b.db
}
func (b *Base) SetLogger(logger ILogger) {
b.logger = logger
}
func (b *Base) Init(db *DB, dialect Dialect, uri *Uri, drivername, dataSourceName string) error {
b.db, b.dialect, b.Uri = db, dialect, uri
b.driverName, b.dataSourceName = drivername, dataSourceName
return nil
}
func (b *Base) URI() *Uri {
return b.Uri
}
func (b *Base) DBType() DbType {
return b.Uri.DbType
}
func (b *Base) FormatBytes(bs []byte) string {
return fmt.Sprintf("0x%x", bs)
}
func (b *Base) DriverName() string {
return b.driverName
}
func (b *Base) ShowCreateNull() bool {
return true
}
func (b *Base) DataSourceName() string {
return b.dataSourceName
}
func (b *Base) AndStr() string {
return "AND"
}
func (b *Base) OrStr() string {
return "OR"
}
func (b *Base) EqStr() string {
return "="
}
func (db *Base) RollBackStr() string {
return "ROLL BACK"
}
func (db *Base) SupportDropIfExists() bool {
return true
}
func (db *Base) DropTableSql(tableName string) string {
quote := db.dialect.Quote
return fmt.Sprintf("DROP TABLE IF EXISTS %s", quote(tableName))
}
func (db *Base) HasRecords(query string, args ...interface{}) (bool, error) {
db.LogSQL(query, args)
rows, err := db.DB().Query(query, args...)
if err != nil {
return false, err
}
defer rows.Close()
if rows.Next() {
return true, nil
}
return false, nil
}
func (db *Base) IsColumnExist(tableName, colName string) (bool, error) {
query := "SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `COLUMN_NAME` = ?"
query = strings.Replace(query, "`", db.dialect.QuoteStr(), -1)
return db.HasRecords(query, db.DbName, tableName, colName)
}
/*
func (db *Base) CreateTableIfNotExists(table *Table, tableName, storeEngine, charset string) error {
sql, args := db.dialect.TableCheckSql(tableName)
rows, err := db.DB().Query(sql, args...)
if db.Logger != nil {
db.Logger.Info("[sql]", sql, args)
}
if err != nil {
return err
}
defer rows.Close()
if rows.Next() {
return nil
}
sql = db.dialect.CreateTableSql(table, tableName, storeEngine, charset)
_, err = db.DB().Exec(sql)
if db.Logger != nil {
db.Logger.Info("[sql]", sql)
}
return err
}*/
func (db *Base) CreateIndexSql(tableName string, index *Index) string {
quote := db.dialect.Quote
var unique string
var idxName string
if index.Type == UniqueType {
unique = " UNIQUE"
}
idxName = index.XName(tableName)
return fmt.Sprintf("CREATE%s INDEX %v ON %v (%v)", unique,
quote(idxName), quote(tableName),
quote(strings.Join(index.Cols, quote(","))))
}
func (db *Base) DropIndexSql(tableName string, index *Index) string {
quote := db.dialect.Quote
var name string
if index.IsRegular {
name = index.XName(tableName)
} else {
name = index.Name
}
return fmt.Sprintf("DROP INDEX %v ON %s", quote(name), quote(tableName))
}
func (db *Base) ModifyColumnSql(tableName string, col *Column) string {
return fmt.Sprintf("alter table %s MODIFY COLUMN %s", tableName, col.StringNoPk(db.dialect))
}
func (b *Base) CreateTableSql(table *Table, tableName, storeEngine, charset string) string {
var sql string
sql = "CREATE TABLE IF NOT EXISTS "
if tableName == "" {
tableName = table.Name
}
sql += b.dialect.Quote(tableName)
sql += " ("
if len(table.ColumnsSeq()) > 0 {
pkList := table.PrimaryKeys
for _, colName := range table.ColumnsSeq() {
col := table.GetColumn(colName)
if col.IsPrimaryKey && len(pkList) == 1 {
sql += col.String(b.dialect)
} else {
sql += col.StringNoPk(b.dialect)
}
sql = strings.TrimSpace(sql)
if b.DriverName() == MYSQL && len(col.Comment) > 0 {
sql += " COMMENT '" + col.Comment + "'"
}
sql += ", "
}
if len(pkList) > 1 {
sql += "PRIMARY KEY ( "
sql += b.dialect.Quote(strings.Join(pkList, b.dialect.Quote(",")))
sql += " ), "
}
sql = sql[:len(sql)-2]
}
sql += ")"
if b.dialect.SupportEngine() && storeEngine != "" {
sql += " ENGINE=" + storeEngine
}
if b.dialect.SupportCharset() {
if len(charset) == 0 {
charset = b.dialect.URI().Charset
}
if len(charset) > 0 {
sql += " DEFAULT CHARSET " + charset
}
}
return sql
}
func (b *Base) ForUpdateSql(query string) string {
return query + " FOR UPDATE"
}
func (b *Base) LogSQL(sql string, args []interface{}) {
if b.logger != nil && b.logger.IsShowSQL() {
if len(args) > 0 {
b.logger.Infof("[SQL] %v %v", sql, args)
} else {
b.logger.Infof("[SQL] %v", sql)
}
}
}
func (b *Base) SetParams(params map[string]string) {
}
var (
dialects = map[string]func() Dialect{}
)
// RegisterDialect register database dialect
func RegisterDialect(dbName DbType, dialectFunc func() Dialect) {
if dialectFunc == nil {
panic("core: Register dialect is nil")
}
dialects[strings.ToLower(string(dbName))] = dialectFunc // !nashtsai! allow override dialect
}
// QueryDialect query if registed database dialect
func QueryDialect(dbName DbType) Dialect {
if d, ok := dialects[strings.ToLower(string(dbName))]; ok {
return d()
}
return nil
}

View File

@ -1,27 +0,0 @@
package core
type Driver interface {
Parse(string, string) (*Uri, error)
}
var (
drivers = map[string]Driver{}
)
func RegisterDriver(driverName string, driver Driver) {
if driver == nil {
panic("core: Register driver is nil")
}
if _, dup := drivers[driverName]; dup {
panic("core: Register called twice for driver " + driverName)
}
drivers[driverName] = driver
}
func QueryDriver(driverName string) Driver {
return drivers[driverName]
}
func RegisteredDriverSize() int {
return len(drivers)
}

View File

@ -1,8 +0,0 @@
package core
import "errors"
var (
ErrNoMapPointer = errors.New("mp should be a map's pointer")
ErrNoStructPointer = errors.New("mp should be a struct's pointer")
)

View File

@ -1,64 +0,0 @@
package core
import (
"fmt"
"strings"
)
// Filter is an interface to filter SQL
type Filter interface {
Do(sql string, dialect Dialect, table *Table) string
}
// QuoteFilter filter SQL replace ` to database's own quote character
type QuoteFilter struct {
}
func (s *QuoteFilter) Do(sql string, dialect Dialect, table *Table) string {
return strings.Replace(sql, "`", dialect.QuoteStr(), -1)
}
// IdFilter filter SQL replace (id) to primary key column name
type IdFilter struct {
}
type Quoter struct {
dialect Dialect
}
func NewQuoter(dialect Dialect) *Quoter {
return &Quoter{dialect}
}
func (q *Quoter) Quote(content string) string {
return q.dialect.QuoteStr() + content + q.dialect.QuoteStr()
}
func (i *IdFilter) Do(sql string, dialect Dialect, table *Table) string {
quoter := NewQuoter(dialect)
if table != nil && len(table.PrimaryKeys) == 1 {
sql = strings.Replace(sql, " `(id)` ", " "+quoter.Quote(table.PrimaryKeys[0])+" ", -1)
sql = strings.Replace(sql, " "+quoter.Quote("(id)")+" ", " "+quoter.Quote(table.PrimaryKeys[0])+" ", -1)
return strings.Replace(sql, " (id) ", " "+quoter.Quote(table.PrimaryKeys[0])+" ", -1)
}
return sql
}
// SeqFilter filter SQL replace ?, ? ... to $1, $2 ...
type SeqFilter struct {
Prefix string
Start int
}
func (s *SeqFilter) Do(sql string, dialect Dialect, table *Table) string {
segs := strings.Split(sql, "?")
size := len(segs)
res := ""
for i, c := range segs {
if i < size-1 {
res += c + fmt.Sprintf("%s%v", s.Prefix, i+s.Start)
}
}
res += segs[size-1]
return res
}

View File

@ -1 +0,0 @@
module "github.com/go-xorm/core"

View File

@ -1,31 +0,0 @@
package core
type LogLevel int
const (
// !nashtsai! following level also match syslog.Priority value
LOG_DEBUG LogLevel = iota
LOG_INFO
LOG_WARNING
LOG_ERR
LOG_OFF
LOG_UNKNOWN
)
// logger interface
type ILogger interface {
Debug(v ...interface{})
Debugf(format string, v ...interface{})
Error(v ...interface{})
Errorf(format string, v ...interface{})
Info(v ...interface{})
Infof(format string, v ...interface{})
Warn(v ...interface{})
Warnf(format string, v ...interface{})
Level() LogLevel
SetLevel(l LogLevel)
ShowSQL(show ...bool)
IsShowSQL() bool
}

View File

@ -1,63 +0,0 @@
package core
import (
"fmt"
"sort"
"strings"
)
const (
IndexType = iota + 1
UniqueType
)
// database index
type Index struct {
IsRegular bool
Name string
Type int
Cols []string
}
func (index *Index) XName(tableName string) string {
if !strings.HasPrefix(index.Name, "UQE_") &&
!strings.HasPrefix(index.Name, "IDX_") {
tableName = strings.Replace(tableName, `"`, "", -1)
tableName = strings.Replace(tableName, `.`, "_", -1)
if index.Type == UniqueType {
return fmt.Sprintf("UQE_%v_%v", tableName, index.Name)
}
return fmt.Sprintf("IDX_%v_%v", tableName, index.Name)
}
return index.Name
}
// add columns which will be composite index
func (index *Index) AddColumn(cols ...string) {
for _, col := range cols {
index.Cols = append(index.Cols, col)
}
}
func (index *Index) Equal(dst *Index) bool {
if index.Type != dst.Type {
return false
}
if len(index.Cols) != len(dst.Cols) {
return false
}
sort.StringSlice(index.Cols).Sort()
sort.StringSlice(dst.Cols).Sort()
for i := 0; i < len(index.Cols); i++ {
if index.Cols[i] != dst.Cols[i] {
return false
}
}
return true
}
// new an index
func NewIndex(name string, indexType int) *Index {
return &Index{true, name, indexType, make([]string, 0)}
}

View File

@ -1,254 +0,0 @@
package core
import (
"strings"
"sync"
)
// name translation between struct, fields names and table, column names
type IMapper interface {
Obj2Table(string) string
Table2Obj(string) string
}
type CacheMapper struct {
oriMapper IMapper
obj2tableCache map[string]string
obj2tableMutex sync.RWMutex
table2objCache map[string]string
table2objMutex sync.RWMutex
}
func NewCacheMapper(mapper IMapper) *CacheMapper {
return &CacheMapper{oriMapper: mapper, obj2tableCache: make(map[string]string),
table2objCache: make(map[string]string),
}
}
func (m *CacheMapper) Obj2Table(o string) string {
m.obj2tableMutex.RLock()
t, ok := m.obj2tableCache[o]
m.obj2tableMutex.RUnlock()
if ok {
return t
}
t = m.oriMapper.Obj2Table(o)
m.obj2tableMutex.Lock()
m.obj2tableCache[o] = t
m.obj2tableMutex.Unlock()
return t
}
func (m *CacheMapper) Table2Obj(t string) string {
m.table2objMutex.RLock()
o, ok := m.table2objCache[t]
m.table2objMutex.RUnlock()
if ok {
return o
}
o = m.oriMapper.Table2Obj(t)
m.table2objMutex.Lock()
m.table2objCache[t] = o
m.table2objMutex.Unlock()
return o
}
// SameMapper implements IMapper and provides same name between struct and
// database table
type SameMapper struct {
}
func (m SameMapper) Obj2Table(o string) string {
return o
}
func (m SameMapper) Table2Obj(t string) string {
return t
}
// SnakeMapper implements IMapper and provides name transaltion between
// struct and database table
type SnakeMapper struct {
}
func snakeCasedName(name string) string {
newstr := make([]rune, 0)
for idx, chr := range name {
if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
if idx > 0 {
newstr = append(newstr, '_')
}
chr -= ('A' - 'a')
}
newstr = append(newstr, chr)
}
return string(newstr)
}
func (mapper SnakeMapper) Obj2Table(name string) string {
return snakeCasedName(name)
}
func titleCasedName(name string) string {
newstr := make([]rune, 0)
upNextChar := true
name = strings.ToLower(name)
for _, chr := range name {
switch {
case upNextChar:
upNextChar = false
if 'a' <= chr && chr <= 'z' {
chr -= ('a' - 'A')
}
case chr == '_':
upNextChar = true
continue
}
newstr = append(newstr, chr)
}
return string(newstr)
}
func (mapper SnakeMapper) Table2Obj(name string) string {
return titleCasedName(name)
}
// GonicMapper implements IMapper. It will consider initialisms when mapping names.
// E.g. id -> ID, user -> User and to table names: UserID -> user_id, MyUID -> my_uid
type GonicMapper map[string]bool
func isASCIIUpper(r rune) bool {
return 'A' <= r && r <= 'Z'
}
func toASCIIUpper(r rune) rune {
if 'a' <= r && r <= 'z' {
r -= ('a' - 'A')
}
return r
}
func gonicCasedName(name string) string {
newstr := make([]rune, 0, len(name)+3)
for idx, chr := range name {
if isASCIIUpper(chr) && idx > 0 {
if !isASCIIUpper(newstr[len(newstr)-1]) {
newstr = append(newstr, '_')
}
}
if !isASCIIUpper(chr) && idx > 1 {
l := len(newstr)
if isASCIIUpper(newstr[l-1]) && isASCIIUpper(newstr[l-2]) {
newstr = append(newstr, newstr[l-1])
newstr[l-1] = '_'
}
}
newstr = append(newstr, chr)
}
return strings.ToLower(string(newstr))
}
func (mapper GonicMapper) Obj2Table(name string) string {
return gonicCasedName(name)
}
func (mapper GonicMapper) Table2Obj(name string) string {
newstr := make([]rune, 0)
name = strings.ToLower(name)
parts := strings.Split(name, "_")
for _, p := range parts {
_, isInitialism := mapper[strings.ToUpper(p)]
for i, r := range p {
if i == 0 || isInitialism {
r = toASCIIUpper(r)
}
newstr = append(newstr, r)
}
}
return string(newstr)
}
// A GonicMapper that contains a list of common initialisms taken from golang/lint
var LintGonicMapper = GonicMapper{
"API": true,
"ASCII": true,
"CPU": true,
"CSS": true,
"DNS": true,
"EOF": true,
"GUID": true,
"HTML": true,
"HTTP": true,
"HTTPS": true,
"ID": true,
"IP": true,
"JSON": true,
"LHS": true,
"QPS": true,
"RAM": true,
"RHS": true,
"RPC": true,
"SLA": true,
"SMTP": true,
"SSH": true,
"TLS": true,
"TTL": true,
"UI": true,
"UID": true,
"UUID": true,
"URI": true,
"URL": true,
"UTF8": true,
"VM": true,
"XML": true,
"XSRF": true,
"XSS": true,
}
// provide prefix table name support
type PrefixMapper struct {
Mapper IMapper
Prefix string
}
func (mapper PrefixMapper) Obj2Table(name string) string {
return mapper.Prefix + mapper.Mapper.Obj2Table(name)
}
func (mapper PrefixMapper) Table2Obj(name string) string {
return mapper.Mapper.Table2Obj(name[len(mapper.Prefix):])
}
func NewPrefixMapper(mapper IMapper, prefix string) PrefixMapper {
return PrefixMapper{mapper, prefix}
}
// provide suffix table name support
type SuffixMapper struct {
Mapper IMapper
Suffix string
}
func (mapper SuffixMapper) Obj2Table(name string) string {
return mapper.Mapper.Obj2Table(name) + mapper.Suffix
}
func (mapper SuffixMapper) Table2Obj(name string) string {
return mapper.Mapper.Table2Obj(name[:len(name)-len(mapper.Suffix)])
}
func NewSuffixMapper(mapper IMapper, suffix string) SuffixMapper {
return SuffixMapper{mapper, suffix}
}

26
vendor/github.com/go-xorm/core/pk.go generated vendored
View File

@ -1,26 +0,0 @@
package core
import (
"bytes"
"encoding/gob"
)
type PK []interface{}
func NewPK(pks ...interface{}) *PK {
p := PK(pks)
return &p
}
func (p *PK) ToString() (string, error) {
buf := new(bytes.Buffer)
enc := gob.NewEncoder(buf)
err := enc.Encode(*p)
return buf.String(), err
}
func (p *PK) FromString(content string) error {
dec := gob.NewDecoder(bytes.NewBufferString(content))
err := dec.Decode(p)
return err
}

View File

@ -1,334 +0,0 @@
package core
import (
"database/sql"
"errors"
"reflect"
"sync"
)
type Rows struct {
*sql.Rows
db *DB
}
func (rs *Rows) ToMapString() ([]map[string]string, error) {
cols, err := rs.Columns()
if err != nil {
return nil, err
}
var results = make([]map[string]string, 0, 10)
for rs.Next() {
var record = make(map[string]string, len(cols))
err = rs.ScanMap(&record)
if err != nil {
return nil, err
}
results = append(results, record)
}
return results, nil
}
// scan data to a struct's pointer according field index
func (rs *Rows) ScanStructByIndex(dest ...interface{}) error {
if len(dest) == 0 {
return errors.New("at least one struct")
}
vvvs := make([]reflect.Value, len(dest))
for i, s := range dest {
vv := reflect.ValueOf(s)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
return errors.New("dest should be a struct's pointer")
}
vvvs[i] = vv.Elem()
}
cols, err := rs.Columns()
if err != nil {
return err
}
newDest := make([]interface{}, len(cols))
var i = 0
for _, vvv := range vvvs {
for j := 0; j < vvv.NumField(); j++ {
newDest[i] = vvv.Field(j).Addr().Interface()
i = i + 1
}
}
return rs.Rows.Scan(newDest...)
}
var (
fieldCache = make(map[reflect.Type]map[string]int)
fieldCacheMutex sync.RWMutex
)
func fieldByName(v reflect.Value, name string) reflect.Value {
t := v.Type()
fieldCacheMutex.RLock()
cache, ok := fieldCache[t]
fieldCacheMutex.RUnlock()
if !ok {
cache = make(map[string]int)
for i := 0; i < v.NumField(); i++ {
cache[t.Field(i).Name] = i
}
fieldCacheMutex.Lock()
fieldCache[t] = cache
fieldCacheMutex.Unlock()
}
if i, ok := cache[name]; ok {
return v.Field(i)
}
return reflect.Zero(t)
}
// scan data to a struct's pointer according field name
func (rs *Rows) ScanStructByName(dest interface{}) error {
vv := reflect.ValueOf(dest)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Struct {
return errors.New("dest should be a struct's pointer")
}
cols, err := rs.Columns()
if err != nil {
return err
}
newDest := make([]interface{}, len(cols))
var v EmptyScanner
for j, name := range cols {
f := fieldByName(vv.Elem(), rs.db.Mapper.Table2Obj(name))
if f.IsValid() {
newDest[j] = f.Addr().Interface()
} else {
newDest[j] = &v
}
}
return rs.Rows.Scan(newDest...)
}
// scan data to a slice's pointer, slice's length should equal to columns' number
func (rs *Rows) ScanSlice(dest interface{}) error {
vv := reflect.ValueOf(dest)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Slice {
return errors.New("dest should be a slice's pointer")
}
vvv := vv.Elem()
cols, err := rs.Columns()
if err != nil {
return err
}
newDest := make([]interface{}, len(cols))
for j := 0; j < len(cols); j++ {
if j >= vvv.Len() {
newDest[j] = reflect.New(vvv.Type().Elem()).Interface()
} else {
newDest[j] = vvv.Index(j).Addr().Interface()
}
}
err = rs.Rows.Scan(newDest...)
if err != nil {
return err
}
srcLen := vvv.Len()
for i := srcLen; i < len(cols); i++ {
vvv = reflect.Append(vvv, reflect.ValueOf(newDest[i]).Elem())
}
return nil
}
// scan data to a map's pointer
func (rs *Rows) ScanMap(dest interface{}) error {
vv := reflect.ValueOf(dest)
if vv.Kind() != reflect.Ptr || vv.Elem().Kind() != reflect.Map {
return errors.New("dest should be a map's pointer")
}
cols, err := rs.Columns()
if err != nil {
return err
}
newDest := make([]interface{}, len(cols))
vvv := vv.Elem()
for i, _ := range cols {
newDest[i] = rs.db.reflectNew(vvv.Type().Elem()).Interface()
}
err = rs.Rows.Scan(newDest...)
if err != nil {
return err
}
for i, name := range cols {
vname := reflect.ValueOf(name)
vvv.SetMapIndex(vname, reflect.ValueOf(newDest[i]).Elem())
}
return nil
}
type Row struct {
rows *Rows
// One of these two will be non-nil:
err error // deferred error for easy chaining
}
// ErrorRow return an error row
func ErrorRow(err error) *Row {
return &Row{
err: err,
}
}
// NewRow from rows
func NewRow(rows *Rows, err error) *Row {
return &Row{rows, err}
}
func (row *Row) Columns() ([]string, error) {
if row.err != nil {
return nil, row.err
}
return row.rows.Columns()
}
func (row *Row) Scan(dest ...interface{}) error {
if row.err != nil {
return row.err
}
defer row.rows.Close()
for _, dp := range dest {
if _, ok := dp.(*sql.RawBytes); ok {
return errors.New("sql: RawBytes isn't allowed on Row.Scan")
}
}
if !row.rows.Next() {
if err := row.rows.Err(); err != nil {
return err
}
return sql.ErrNoRows
}
err := row.rows.Scan(dest...)
if err != nil {
return err
}
// Make sure the query can be processed to completion with no errors.
return row.rows.Close()
}
func (row *Row) ScanStructByName(dest interface{}) error {
if row.err != nil {
return row.err
}
defer row.rows.Close()
if !row.rows.Next() {
if err := row.rows.Err(); err != nil {
return err
}
return sql.ErrNoRows
}
err := row.rows.ScanStructByName(dest)
if err != nil {
return err
}
// Make sure the query can be processed to completion with no errors.
return row.rows.Close()
}
func (row *Row) ScanStructByIndex(dest interface{}) error {
if row.err != nil {
return row.err
}
defer row.rows.Close()
if !row.rows.Next() {
if err := row.rows.Err(); err != nil {
return err
}
return sql.ErrNoRows
}
err := row.rows.ScanStructByIndex(dest)
if err != nil {
return err
}
// Make sure the query can be processed to completion with no errors.
return row.rows.Close()
}
// scan data to a slice's pointer, slice's length should equal to columns' number
func (row *Row) ScanSlice(dest interface{}) error {
if row.err != nil {
return row.err
}
defer row.rows.Close()
if !row.rows.Next() {
if err := row.rows.Err(); err != nil {
return err
}
return sql.ErrNoRows
}
err := row.rows.ScanSlice(dest)
if err != nil {
return err
}
// Make sure the query can be processed to completion with no errors.
return row.rows.Close()
}
// scan data to a map's pointer
func (row *Row) ScanMap(dest interface{}) error {
if row.err != nil {
return row.err
}
defer row.rows.Close()
if !row.rows.Next() {
if err := row.rows.Err(); err != nil {
return err
}
return sql.ErrNoRows
}
err := row.rows.ScanMap(dest)
if err != nil {
return err
}
// Make sure the query can be processed to completion with no errors.
return row.rows.Close()
}
func (row *Row) ToMapString() (map[string]string, error) {
cols, err := row.Columns()
if err != nil {
return nil, err
}
var record = make(map[string]string, len(cols))
err = row.ScanMap(&record)
if err != nil {
return nil, err
}
return record, nil
}

View File

@ -1,55 +0,0 @@
package core
import (
"database/sql/driver"
"fmt"
"time"
)
type NullTime time.Time
var (
_ driver.Valuer = NullTime{}
)
func (ns *NullTime) Scan(value interface{}) error {
if value == nil {
return nil
}
return convertTime(ns, value)
}
// Value implements the driver Valuer interface.
func (ns NullTime) Value() (driver.Value, error) {
if (time.Time)(ns).IsZero() {
return nil, nil
}
return (time.Time)(ns).Format("2006-01-02 15:04:05"), nil
}
func convertTime(dest *NullTime, src interface{}) error {
// Common cases, without reflect.
switch s := src.(type) {
case string:
t, err := time.Parse("2006-01-02 15:04:05", s)
if err != nil {
return err
}
*dest = NullTime(t)
return nil
case []uint8:
t, err := time.Parse("2006-01-02 15:04:05", string(s))
if err != nil {
return err
}
*dest = NullTime(t)
return nil
case time.Time:
*dest = NullTime(s)
return nil
case nil:
default:
return fmt.Errorf("unsupported driver -> Scan pair: %T -> %T", src, dest)
}
return nil
}

View File

@ -1,152 +0,0 @@
package core
import (
"reflect"
"strings"
)
// database table
type Table struct {
Name string
Type reflect.Type
columnsSeq []string
columnsMap map[string][]*Column
columns []*Column
Indexes map[string]*Index
PrimaryKeys []string
AutoIncrement string
Created map[string]bool
Updated string
Deleted string
Version string
Cacher Cacher
StoreEngine string
Charset string
Comment string
}
func (table *Table) Columns() []*Column {
return table.columns
}
func (table *Table) ColumnsSeq() []string {
return table.columnsSeq
}
func NewEmptyTable() *Table {
return NewTable("", nil)
}
func NewTable(name string, t reflect.Type) *Table {
return &Table{Name: name, Type: t,
columnsSeq: make([]string, 0),
columns: make([]*Column, 0),
columnsMap: make(map[string][]*Column),
Indexes: make(map[string]*Index),
Created: make(map[string]bool),
PrimaryKeys: make([]string, 0),
}
}
func (table *Table) columnsByName(name string) []*Column {
n := len(name)
for k := range table.columnsMap {
if len(k) != n {
continue
}
if strings.EqualFold(k, name) {
return table.columnsMap[k]
}
}
return nil
}
func (table *Table) GetColumn(name string) *Column {
cols := table.columnsByName(name)
if cols != nil {
return cols[0]
}
return nil
}
func (table *Table) GetColumnIdx(name string, idx int) *Column {
cols := table.columnsByName(name)
if cols != nil && idx < len(cols) {
return cols[idx]
}
return nil
}
// if has primary key, return column
func (table *Table) PKColumns() []*Column {
columns := make([]*Column, len(table.PrimaryKeys))
for i, name := range table.PrimaryKeys {
columns[i] = table.GetColumn(name)
}
return columns
}
func (table *Table) ColumnType(name string) reflect.Type {
t, _ := table.Type.FieldByName(name)
return t.Type
}
func (table *Table) AutoIncrColumn() *Column {
return table.GetColumn(table.AutoIncrement)
}
func (table *Table) VersionColumn() *Column {
return table.GetColumn(table.Version)
}
func (table *Table) UpdatedColumn() *Column {
return table.GetColumn(table.Updated)
}
func (table *Table) DeletedColumn() *Column {
return table.GetColumn(table.Deleted)
}
// add a column to table
func (table *Table) AddColumn(col *Column) {
table.columnsSeq = append(table.columnsSeq, col.Name)
table.columns = append(table.columns, col)
colName := strings.ToLower(col.Name)
if c, ok := table.columnsMap[colName]; ok {
table.columnsMap[colName] = append(c, col)
} else {
table.columnsMap[colName] = []*Column{col}
}
if col.IsPrimaryKey {
table.PrimaryKeys = append(table.PrimaryKeys, col.Name)
}
if col.IsAutoIncrement {
table.AutoIncrement = col.Name
}
if col.IsCreated {
table.Created[col.Name] = true
}
if col.IsUpdated {
table.Updated = col.Name
}
if col.IsDeleted {
table.Deleted = col.Name
}
if col.IsVersion {
table.Version = col.Name
}
}
// add an index or an unique to table
func (table *Table) AddIndex(index *Index) {
table.Indexes[index.Name] = index
}

View File

@ -1,309 +0,0 @@
package core
import (
"reflect"
"sort"
"strings"
"time"
)
const (
POSTGRES = "postgres"
SQLITE = "sqlite3"
MYSQL = "mysql"
MSSQL = "mssql"
ORACLE = "oracle"
)
// xorm SQL types
type SQLType struct {
Name string
DefaultLength int
DefaultLength2 int
}
const (
UNKNOW_TYPE = iota
TEXT_TYPE
BLOB_TYPE
TIME_TYPE
NUMERIC_TYPE
)
func (s *SQLType) IsType(st int) bool {
if t, ok := SqlTypes[s.Name]; ok && t == st {
return true
}
return false
}
func (s *SQLType) IsText() bool {
return s.IsType(TEXT_TYPE)
}
func (s *SQLType) IsBlob() bool {
return s.IsType(BLOB_TYPE)
}
func (s *SQLType) IsTime() bool {
return s.IsType(TIME_TYPE)
}
func (s *SQLType) IsNumeric() bool {
return s.IsType(NUMERIC_TYPE)
}
func (s *SQLType) IsJson() bool {
return s.Name == Json || s.Name == Jsonb
}
var (
Bit = "BIT"
TinyInt = "TINYINT"
SmallInt = "SMALLINT"
MediumInt = "MEDIUMINT"
Int = "INT"
Integer = "INTEGER"
BigInt = "BIGINT"
Enum = "ENUM"
Set = "SET"
Char = "CHAR"
Varchar = "VARCHAR"
NVarchar = "NVARCHAR"
TinyText = "TINYTEXT"
Text = "TEXT"
Clob = "CLOB"
MediumText = "MEDIUMTEXT"
LongText = "LONGTEXT"
Uuid = "UUID"
UniqueIdentifier = "UNIQUEIDENTIFIER"
SysName = "SYSNAME"
Date = "DATE"
DateTime = "DATETIME"
Time = "TIME"
TimeStamp = "TIMESTAMP"
TimeStampz = "TIMESTAMPZ"
Decimal = "DECIMAL"
Numeric = "NUMERIC"
Real = "REAL"
Float = "FLOAT"
Double = "DOUBLE"
Binary = "BINARY"
VarBinary = "VARBINARY"
TinyBlob = "TINYBLOB"
Blob = "BLOB"
MediumBlob = "MEDIUMBLOB"
LongBlob = "LONGBLOB"
Bytea = "BYTEA"
Bool = "BOOL"
Boolean = "BOOLEAN"
Serial = "SERIAL"
BigSerial = "BIGSERIAL"
Json = "JSON"
Jsonb = "JSONB"
SqlTypes = map[string]int{
Bit: NUMERIC_TYPE,
TinyInt: NUMERIC_TYPE,
SmallInt: NUMERIC_TYPE,
MediumInt: NUMERIC_TYPE,
Int: NUMERIC_TYPE,
Integer: NUMERIC_TYPE,
BigInt: NUMERIC_TYPE,
Enum: TEXT_TYPE,
Set: TEXT_TYPE,
Json: TEXT_TYPE,
Jsonb: TEXT_TYPE,
Char: TEXT_TYPE,
Varchar: TEXT_TYPE,
NVarchar: TEXT_TYPE,
TinyText: TEXT_TYPE,
Text: TEXT_TYPE,
MediumText: TEXT_TYPE,
LongText: TEXT_TYPE,
Uuid: TEXT_TYPE,
Clob: TEXT_TYPE,
SysName: TEXT_TYPE,
Date: TIME_TYPE,
DateTime: TIME_TYPE,
Time: TIME_TYPE,
TimeStamp: TIME_TYPE,
TimeStampz: TIME_TYPE,
Decimal: NUMERIC_TYPE,
Numeric: NUMERIC_TYPE,
Real: NUMERIC_TYPE,
Float: NUMERIC_TYPE,
Double: NUMERIC_TYPE,
Binary: BLOB_TYPE,
VarBinary: BLOB_TYPE,
TinyBlob: BLOB_TYPE,
Blob: BLOB_TYPE,
MediumBlob: BLOB_TYPE,
LongBlob: BLOB_TYPE,
Bytea: BLOB_TYPE,
UniqueIdentifier: BLOB_TYPE,
Bool: NUMERIC_TYPE,
Serial: NUMERIC_TYPE,
BigSerial: NUMERIC_TYPE,
}
intTypes = sort.StringSlice{"*int", "*int16", "*int32", "*int8"}
uintTypes = sort.StringSlice{"*uint", "*uint16", "*uint32", "*uint8"}
)
// !nashtsai! treat following var as interal const values, these are used for reflect.TypeOf comparison
var (
c_EMPTY_STRING string
c_BOOL_DEFAULT bool
c_BYTE_DEFAULT byte
c_COMPLEX64_DEFAULT complex64
c_COMPLEX128_DEFAULT complex128
c_FLOAT32_DEFAULT float32
c_FLOAT64_DEFAULT float64
c_INT64_DEFAULT int64
c_UINT64_DEFAULT uint64
c_INT32_DEFAULT int32
c_UINT32_DEFAULT uint32
c_INT16_DEFAULT int16
c_UINT16_DEFAULT uint16
c_INT8_DEFAULT int8
c_UINT8_DEFAULT uint8
c_INT_DEFAULT int
c_UINT_DEFAULT uint
c_TIME_DEFAULT time.Time
)
var (
IntType = reflect.TypeOf(c_INT_DEFAULT)
Int8Type = reflect.TypeOf(c_INT8_DEFAULT)
Int16Type = reflect.TypeOf(c_INT16_DEFAULT)
Int32Type = reflect.TypeOf(c_INT32_DEFAULT)
Int64Type = reflect.TypeOf(c_INT64_DEFAULT)
UintType = reflect.TypeOf(c_UINT_DEFAULT)
Uint8Type = reflect.TypeOf(c_UINT8_DEFAULT)
Uint16Type = reflect.TypeOf(c_UINT16_DEFAULT)
Uint32Type = reflect.TypeOf(c_UINT32_DEFAULT)
Uint64Type = reflect.TypeOf(c_UINT64_DEFAULT)
Float32Type = reflect.TypeOf(c_FLOAT32_DEFAULT)
Float64Type = reflect.TypeOf(c_FLOAT64_DEFAULT)
Complex64Type = reflect.TypeOf(c_COMPLEX64_DEFAULT)
Complex128Type = reflect.TypeOf(c_COMPLEX128_DEFAULT)
StringType = reflect.TypeOf(c_EMPTY_STRING)
BoolType = reflect.TypeOf(c_BOOL_DEFAULT)
ByteType = reflect.TypeOf(c_BYTE_DEFAULT)
BytesType = reflect.SliceOf(ByteType)
TimeType = reflect.TypeOf(c_TIME_DEFAULT)
)
var (
PtrIntType = reflect.PtrTo(IntType)
PtrInt8Type = reflect.PtrTo(Int8Type)
PtrInt16Type = reflect.PtrTo(Int16Type)
PtrInt32Type = reflect.PtrTo(Int32Type)
PtrInt64Type = reflect.PtrTo(Int64Type)
PtrUintType = reflect.PtrTo(UintType)
PtrUint8Type = reflect.PtrTo(Uint8Type)
PtrUint16Type = reflect.PtrTo(Uint16Type)
PtrUint32Type = reflect.PtrTo(Uint32Type)
PtrUint64Type = reflect.PtrTo(Uint64Type)
PtrFloat32Type = reflect.PtrTo(Float32Type)
PtrFloat64Type = reflect.PtrTo(Float64Type)
PtrComplex64Type = reflect.PtrTo(Complex64Type)
PtrComplex128Type = reflect.PtrTo(Complex128Type)
PtrStringType = reflect.PtrTo(StringType)
PtrBoolType = reflect.PtrTo(BoolType)
PtrByteType = reflect.PtrTo(ByteType)
PtrTimeType = reflect.PtrTo(TimeType)
)
// Type2SQLType generate SQLType acorrding Go's type
func Type2SQLType(t reflect.Type) (st SQLType) {
switch k := t.Kind(); k {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
st = SQLType{Int, 0, 0}
case reflect.Int64, reflect.Uint64:
st = SQLType{BigInt, 0, 0}
case reflect.Float32:
st = SQLType{Float, 0, 0}
case reflect.Float64:
st = SQLType{Double, 0, 0}
case reflect.Complex64, reflect.Complex128:
st = SQLType{Varchar, 64, 0}
case reflect.Array, reflect.Slice, reflect.Map:
if t.Elem() == reflect.TypeOf(c_BYTE_DEFAULT) {
st = SQLType{Blob, 0, 0}
} else {
st = SQLType{Text, 0, 0}
}
case reflect.Bool:
st = SQLType{Bool, 0, 0}
case reflect.String:
st = SQLType{Varchar, 255, 0}
case reflect.Struct:
if t.ConvertibleTo(TimeType) {
st = SQLType{DateTime, 0, 0}
} else {
// TODO need to handle association struct
st = SQLType{Text, 0, 0}
}
case reflect.Ptr:
st = Type2SQLType(t.Elem())
default:
st = SQLType{Text, 0, 0}
}
return
}
// default sql type change to go types
func SQLType2Type(st SQLType) reflect.Type {
name := strings.ToUpper(st.Name)
switch name {
case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, Serial:
return reflect.TypeOf(1)
case BigInt, BigSerial:
return reflect.TypeOf(int64(1))
case Float, Real:
return reflect.TypeOf(float32(1))
case Double:
return reflect.TypeOf(float64(1))
case Char, Varchar, NVarchar, TinyText, Text, MediumText, LongText, Enum, Set, Uuid, Clob, SysName:
return reflect.TypeOf("")
case TinyBlob, Blob, LongBlob, Bytea, Binary, MediumBlob, VarBinary, UniqueIdentifier:
return reflect.TypeOf([]byte{})
case Bool:
return reflect.TypeOf(true)
case DateTime, Date, Time, TimeStamp, TimeStampz:
return reflect.TypeOf(c_TIME_DEFAULT)
case Decimal, Numeric:
return reflect.TypeOf("")
default:
return reflect.TypeOf("")
}
}

View File

@ -1,46 +0,0 @@
## Contributing to xorm
`xorm` has a backlog of [pull requests](https://help.github.com/articles/using-pull-requests), but contributions are still very
much welcome. You can help with patch review, submitting bug reports,
or adding new functionality. There is no formal style guide, but
please conform to the style of existing code and general Go formatting
conventions when submitting patches.
* [fork a repo](https://help.github.com/articles/fork-a-repo)
* [creating a pull request ](https://help.github.com/articles/creating-a-pull-request)
### Language
Since `xorm` is a world-wide open source project, please describe your issues or code changes in English as soon as possible.
### Sign your codes with comments
```
// !<you github id>! your comments
e.g.,
// !lunny! this is comments made by lunny
```
### Patch review
Help review existing open [pull requests](https://help.github.com/articles/using-pull-requests) by commenting on the code or
proposed functionality.
### Bug reports
We appreciate any bug reports, but especially ones with self-contained
(doesn't depend on code outside of xorm), minimal (can't be simplified
further) test cases. It's especially helpful if you can submit a pull
request with just the failing test case(you can find some example test file like [session_get_test.go](https://github.com/go-xorm/xorm/blob/master/session_get_test.go)).
If you implements a new database interface, you maybe need to add a test_<databasename>.sh file.
For example, [mysql_test.go](https://github.com/go-xorm/xorm/blob/master/test_mysql.sh)
### New functionality
There are a number of pending patches for new functionality, so
additional feature patches will take a while to merge. Still, patches
are generally reviewed based on usefulness and complexity in addition
to time-in-queue, so if you have a knockout idea, take a shot. Feel
free to open an issue discussion your proposed patch beforehand.

View File

@ -1,27 +0,0 @@
Copyright (c) 2013 - 2015 The Xorm Authors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the {organization} nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,437 +0,0 @@
[中文](https://github.com/go-xorm/xorm/blob/master/README_CN.md)
Xorm is a simple and powerful ORM for Go.
[![CircleCI](https://circleci.com/gh/go-xorm/xorm.svg?style=shield)](https://circleci.com/gh/go-xorm/xorm) [![codecov](https://codecov.io/gh/go-xorm/xorm/branch/master/graph/badge.svg)](https://codecov.io/gh/go-xorm/xorm)
[![](https://goreportcard.com/badge/github.com/go-xorm/xorm)](https://goreportcard.com/report/github.com/go-xorm/xorm)
[![Join the chat at https://img.shields.io/discord/323460943201959939.svg](https://img.shields.io/discord/323460943201959939.svg)](https://discord.gg/HuR2CF3)
# Features
* Struct <-> Table Mapping Support
* Chainable APIs
* Transaction Support
* Both ORM and raw SQL operation Support
* Sync database schema Support
* Query Cache speed up
* Database Reverse support, See [Xorm Tool README](https://github.com/go-xorm/cmd/blob/master/README.md)
* Simple cascade loading support
* Optimistic Locking support
* SQL Builder support via [github.com/go-xorm/builder](https://github.com/go-xorm/builder)
* Automatical Read/Write seperatelly
* Postgres schema support
# Drivers Support
Drivers for Go's sql package which currently support database/sql includes:
* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/tree/master/godrv)
* Postgres: [github.com/lib/pq](https://github.com/lib/pq)
* Tidb: [github.com/pingcap/tidb](https://github.com/pingcap/tidb)
* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
* MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
* Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (experiment)
# Changelog
* **v0.6.6**
* Some bugs fixed
* **v0.6.5**
* Postgres schema support
* vgo support
* Add FindAndCount
* Database special params support via NewEngineWithParams
* Some bugs fixed
* **v0.6.4**
* Automatical Read/Write seperatelly
* Query/QueryString/QueryInterface and action with Where/And
* Get support non-struct variables
* BufferSize on Iterate
* fix some other bugs.
* **v0.6.3**
* merge tests to main project
* add `Exist` function
* add `SumInt` function
* Mysql now support read and create column comment.
* fix time related bugs.
* fix some other bugs.
[More changes ...](https://github.com/go-xorm/manual-en-US/tree/master/chapter-16)
# Installation
go get github.com/go-xorm/xorm
# Documents
* [Manual](http://xorm.io/docs)
* [GoDoc](http://godoc.org/github.com/go-xorm/xorm)
* [GoWalker](http://gowalker.org/github.com/go-xorm/xorm)
# Quick Start
* Create Engine
```Go
engine, err := xorm.NewEngine(driverName, dataSourceName)
```
* Define a struct and Sync2 table struct to database
```Go
type User struct {
Id int64
Name string
Salt string
Age int
Passwd string `xorm:"varchar(200)"`
Created time.Time `xorm:"created"`
Updated time.Time `xorm:"updated"`
}
err := engine.Sync2(new(User))
```
* Create Engine Group
```Go
dataSourceNameSlice := []string{masterDataSourceName, slave1DataSourceName, slave2DataSourceName}
engineGroup, err := xorm.NewEngineGroup(driverName, dataSourceNameSlice)
```
```Go
masterEngine, err := xorm.NewEngine(driverName, masterDataSourceName)
slave1Engine, err := xorm.NewEngine(driverName, slave1DataSourceName)
slave2Engine, err := xorm.NewEngine(driverName, slave2DataSourceName)
engineGroup, err := xorm.NewEngineGroup(masterEngine, []*Engine{slave1Engine, slave2Engine})
```
Then all place where `engine` you can just use `engineGroup`.
* `Query` runs a SQL string, the returned results is `[]map[string][]byte`, `QueryString` returns `[]map[string]string`, `QueryInterface` returns `[]map[string]interface{}`.
```Go
results, err := engine.Query("select * from user")
results, err := engine.Where("a = 1").Query()
results, err := engine.QueryString("select * from user")
results, err := engine.Where("a = 1").QueryString()
results, err := engine.QueryInterface("select * from user")
results, err := engine.Where("a = 1").QueryInterface()
```
* `Exec` runs a SQL string, it returns `affected` and `error`
```Go
affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
```
* `Insert` one or multiple records to database
```Go
affected, err := engine.Insert(&user)
// INSERT INTO struct () values ()
affected, err := engine.Insert(&user1, &user2)
// INSERT INTO struct1 () values ()
// INSERT INTO struct2 () values ()
affected, err := engine.Insert(&users)
// INSERT INTO struct () values (),(),()
affected, err := engine.Insert(&user1, &users)
// INSERT INTO struct1 () values ()
// INSERT INTO struct2 () values (),(),()
```
* `Get` query one record from database
```Go
has, err := engine.Get(&user)
// SELECT * FROM user LIMIT 1
has, err := engine.Where("name = ?", name).Desc("id").Get(&user)
// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1
var name string
has, err := engine.Where("id = ?", id).Cols("name").Get(&name)
// SELECT name FROM user WHERE id = ?
var id int64
has, err := engine.Where("name = ?", name).Cols("id").Get(&id)
has, err := engine.SQL("select id from user").Get(&id)
// SELECT id FROM user WHERE name = ?
var valuesMap = make(map[string]string)
has, err := engine.Where("id = ?", id).Get(&valuesMap)
// SELECT * FROM user WHERE id = ?
var valuesSlice = make([]interface{}, len(cols))
has, err := engine.Where("id = ?", id).Cols(cols...).Get(&valuesSlice)
// SELECT col1, col2, col3 FROM user WHERE id = ?
```
* `Exist` check if one record exist on table
```Go
has, err := testEngine.Exist(new(RecordExist))
// SELECT * FROM record_exist LIMIT 1
has, err = testEngine.Exist(&RecordExist{
Name: "test1",
})
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
has, err = testEngine.Where("name = ?", "test1").Exist(&RecordExist{})
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
has, err = testEngine.SQL("select * from record_exist where name = ?", "test1").Exist()
// select * from record_exist where name = ?
has, err = testEngine.Table("record_exist").Exist()
// SELECT * FROM record_exist LIMIT 1
has, err = testEngine.Table("record_exist").Where("name = ?", "test1").Exist()
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
```
* `Find` query multiple records from database, also you can use join and extends
```Go
var users []User
err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users)
// SELECT * FROM user WHERE name = ? AND age > 10 limit 10 offset 0
type Detail struct {
Id int64
UserId int64 `xorm:"index"`
}
type UserDetail struct {
User `xorm:"extends"`
Detail `xorm:"extends"`
}
var users []UserDetail
err := engine.Table("user").Select("user.*, detail.*").
Join("INNER", "detail", "detail.user_id = user.id").
Where("user.name = ?", name).Limit(10, 0).
Find(&users)
// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 10 offset 0
```
* `Iterate` and `Rows` query multiple records and record by record handle, there are two methods Iterate and Rows
```Go
err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
user := bean.(*User)
return nil
})
// SELECT * FROM user
err := engine.BufferSize(100).Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
user := bean.(*User)
return nil
})
// SELECT * FROM user Limit 0, 100
// SELECT * FROM user Limit 101, 100
rows, err := engine.Rows(&User{Name:name})
// SELECT * FROM user
defer rows.Close()
bean := new(Struct)
for rows.Next() {
err = rows.Scan(bean)
}
```
* `Update` update one or more records, default will update non-empty and non-zero fields except when you use Cols, AllCols and so on.
```Go
affected, err := engine.ID(1).Update(&user)
// UPDATE user SET ... Where id = ?
affected, err := engine.Update(&user, &User{Name:name})
// UPDATE user SET ... Where name = ?
var ids = []int64{1, 2, 3}
affected, err := engine.In("id", ids).Update(&user)
// UPDATE user SET ... Where id IN (?, ?, ?)
// force update indicated columns by Cols
affected, err := engine.ID(1).Cols("age").Update(&User{Name:name, Age: 12})
// UPDATE user SET age = ?, updated=? Where id = ?
// force NOT update indicated columns by Omit
affected, err := engine.ID(1).Omit("name").Update(&User{Name:name, Age: 12})
// UPDATE user SET age = ?, updated=? Where id = ?
affected, err := engine.ID(1).AllCols().Update(&user)
// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ?
```
* `Delete` delete one or more records, Delete MUST have condition
```Go
affected, err := engine.Where(...).Delete(&user)
// DELETE FROM user Where ...
affected, err := engine.ID(2).Delete(&user)
// DELETE FROM user Where id = ?
```
* `Count` count records
```Go
counts, err := engine.Count(&user)
// SELECT count(*) AS total FROM user
```
* `Sum` sum functions
```Go
agesFloat64, err := engine.Sum(&user, "age")
// SELECT sum(age) AS total FROM user
agesInt64, err := engine.SumInt(&user, "age")
// SELECT sum(age) AS total FROM user
sumFloat64Slice, err := engine.Sums(&user, "age", "score")
// SELECT sum(age), sum(score) FROM user
sumInt64Slice, err := engine.SumsInt(&user, "age", "score")
// SELECT sum(age), sum(score) FROM user
```
* Query conditions builder
```Go
err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))).Find(&users)
// SELECT id, name ... FROM user WHERE a NOT IN (?, ?) AND b IN (?, ?, ?)
```
* Multiple operations in one go routine, no transation here but resue session memory
```Go
session := engine.NewSession()
defer session.Close()
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
if _, err := session.Insert(&user1); err != nil {
return err
}
user2 := Userinfo{Username: "yyy"}
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
return err
}
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
return err
}
return nil
```
* Transation should on one go routine. There is transaction and resue session memory
```Go
session := engine.NewSession()
defer session.Close()
// add Begin() before any action
if err := session.Begin(); err != nil {
// if returned then will rollback automatically
return err
}
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
if _, err := session.Insert(&user1); err != nil {
return err
}
user2 := Userinfo{Username: "yyy"}
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
return err
}
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
return err
}
// add Commit() after all actions
return session.Commit()
```
# Cases
* [studygolang](http://studygolang.com/) - [github.com/studygolang/studygolang](https://github.com/studygolang/studygolang)
* [Gitea](http://gitea.io) - [github.com/go-gitea/gitea](http://github.com/go-gitea/gitea)
* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs)
* [grafana](https://grafana.com/) - [github.com/grafana/grafana](http://github.com/grafana/grafana)
* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)
* [Wego](http://github.com/go-tango/wego)
* [Docker.cn](https://docker.cn/)
* [Xorm Adapter](https://github.com/casbin/xorm-adapter) for [Casbin](https://github.com/casbin/casbin) - [github.com/casbin/xorm-adapter](https://github.com/casbin/xorm-adapter)
* [Gorevel](http://gorevel.cn/) - [github.com/goofcc/gorevel](http://github.com/goofcc/gorevel)
* [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker)
* [Gobuild.io](http://gobuild.io) - [github.com/shxsun/gobuild](http://github.com/shxsun/gobuild)
* [Sudo China](http://sudochina.com) - [github.com/insionng/toropress](http://github.com/insionng/toropress)
* [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily)
* [YouGam](http://www.yougam.com/)
* [GoCMS - github.com/zzboy/GoCMS](https://github.com/zzdboy/GoCMS)
* [GoBBS - gobbs.domolo.com](http://gobbs.domolo.com/)
* [go-blog](http://wangcheng.me) - [github.com/easykoo/go-blog](https://github.com/easykoo/go-blog)
# Discuss
Please visit [Xorm on Google Groups](https://groups.google.com/forum/#!forum/xorm)
# Contributing
If you want to pull request, please see [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md)
# LICENSE
BSD License
[http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/)

View File

@ -1,438 +0,0 @@
# xorm
[English](https://github.com/go-xorm/xorm/blob/master/README.md)
xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。
[![CircleCI](https://circleci.com/gh/go-xorm/xorm.svg?style=shield)](https://circleci.com/gh/go-xorm/xorm) [![codecov](https://codecov.io/gh/go-xorm/xorm/branch/master/graph/badge.svg)](https://codecov.io/gh/go-xorm/xorm)
[![](https://goreportcard.com/badge/github.com/go-xorm/xorm)](https://goreportcard.com/report/github.com/go-xorm/xorm)
[![Join the chat at https://img.shields.io/discord/323460943201959939.svg](https://img.shields.io/discord/323460943201959939.svg)](https://discord.gg/HuR2CF3)
## 特性
* 支持Struct和数据库表之间的灵活映射并支持自动同步
* 事务支持
* 同时支持原始SQL语句和ORM操作的混合执行
* 使用连写来简化调用
* 支持使用Id, In, Where, Limit, Join, Having, Table, Sql, Cols等函数和结构体等方式作为条件
* 支持级联加载Struct
* Schema支持仅Postgres
* 支持缓存
* 支持根据数据库自动生成xorm的结构体
* 支持记录版本(即乐观锁)
* 内置SQL Builder支持
## 驱动支持
目前支持的Go数据库驱动和对应的数据库如下
* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql)
* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv)
* Postgres: [github.com/lib/pq](https://github.com/lib/pq)
* Tidb: [github.com/pingcap/tidb](https://github.com/pingcap/tidb)
* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3)
* MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb)
* MsSql: [github.com/lunny/godbc](https://github.com/lunny/godbc)
* Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (试验性支持)
## 更新日志
* **v0.6.6**
* 修正部分Bug
* **v0.6.5**
* 通过 engine.SetSchema 来支持 schema当前仅支持Postgres
* vgo 支持
* 新增 `FindAndCount` 函数
* 通过 `NewEngineWithParams` 支持数据库特别参数
* 修正部分Bug
* **v0.6.4**
* 自动读写分离支持
* Query/QueryString/QueryInterface 支持与 Where/And 合用
* `Get` 支持获取非结构体变量
* `Iterate` 支持 `BufferSize`
* 修正部分Bug
* **v0.6.3**
* 合并单元测试到主工程
* 新增 `Exist` 方法
* 新增 `SumInt` 方法
* Mysql新增读取和创建字段注释支持
* 新增 `SetConnMaxLifetime` 方法
* 修正了时间相关的Bug
* 修复了一些其它Bug
[更多更新日志...](https://github.com/go-xorm/manual-zh-CN/tree/master/chapter-16)
## 安装
go get github.com/go-xorm/xorm
## 文档
* [操作指南](http://xorm.io/docs)
* [GoWalker代码文档](http://gowalker.org/github.com/go-xorm/xorm)
* [Godoc代码文档](http://godoc.org/github.com/go-xorm/xorm)
# 快速开始
* 第一步创建引擎driverName, dataSourceName和database/sql接口相同
```Go
engine, err := xorm.NewEngine(driverName, dataSourceName)
```
* 定义一个和表同步的结构体,并且自动同步结构体到数据库
```Go
type User struct {
Id int64
Name string
Salt string
Age int
Passwd string `xorm:"varchar(200)"`
Created time.Time `xorm:"created"`
Updated time.Time `xorm:"updated"`
}
err := engine.Sync2(new(User))
```
* 创建Engine组
```Go
dataSourceNameSlice := []string{masterDataSourceName, slave1DataSourceName, slave2DataSourceName}
engineGroup, err := xorm.NewEngineGroup(driverName, dataSourceNameSlice)
```
```Go
masterEngine, err := xorm.NewEngine(driverName, masterDataSourceName)
slave1Engine, err := xorm.NewEngine(driverName, slave1DataSourceName)
slave2Engine, err := xorm.NewEngine(driverName, slave2DataSourceName)
engineGroup, err := xorm.NewEngineGroup(masterEngine, []*Engine{slave1Engine, slave2Engine})
```
所有使用 `engine` 都可以简单的用 `engineGroup` 来替换。
* `Query` 最原始的也支持SQL语句查询返回的结果类型为 []map[string][]byte。`QueryString` 返回 []map[string]string, `QueryInterface` 返回 `[]map[string]interface{}`.
```Go
results, err := engine.Query("select * from user")
results, err := engine.Where("a = 1").Query()
results, err := engine.QueryString("select * from user")
results, err := engine.Where("a = 1").QueryString()
results, err := engine.QueryInterface("select * from user")
results, err := engine.Where("a = 1").QueryInterface()
```
* `Exec` 执行一个SQL语句
```Go
affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
```
* `Insert` 插入一条或者多条记录
```Go
affected, err := engine.Insert(&user)
// INSERT INTO struct () values ()
affected, err := engine.Insert(&user1, &user2)
// INSERT INTO struct1 () values ()
// INSERT INTO struct2 () values ()
affected, err := engine.Insert(&users)
// INSERT INTO struct () values (),(),()
affected, err := engine.Insert(&user1, &users)
// INSERT INTO struct1 () values ()
// INSERT INTO struct2 () values (),(),()
```
* `Get` 查询单条记录
```Go
has, err := engine.Get(&user)
// SELECT * FROM user LIMIT 1
has, err := engine.Where("name = ?", name).Desc("id").Get(&user)
// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1
var name string
has, err := engine.Where("id = ?", id).Cols("name").Get(&name)
// SELECT name FROM user WHERE id = ?
var id int64
has, err := engine.Where("name = ?", name).Cols("id").Get(&id)
has, err := engine.SQL("select id from user").Get(&id)
// SELECT id FROM user WHERE name = ?
var valuesMap = make(map[string]string)
has, err := engine.Where("id = ?", id).Get(&valuesMap)
// SELECT * FROM user WHERE id = ?
var valuesSlice = make([]interface{}, len(cols))
has, err := engine.Where("id = ?", id).Cols(cols...).Get(&valuesSlice)
// SELECT col1, col2, col3 FROM user WHERE id = ?
```
* `Exist` 检测记录是否存在
```Go
has, err := testEngine.Exist(new(RecordExist))
// SELECT * FROM record_exist LIMIT 1
has, err = testEngine.Exist(&RecordExist{
Name: "test1",
})
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
has, err = testEngine.Where("name = ?", "test1").Exist(&RecordExist{})
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
has, err = testEngine.SQL("select * from record_exist where name = ?", "test1").Exist()
// select * from record_exist where name = ?
has, err = testEngine.Table("record_exist").Exist()
// SELECT * FROM record_exist LIMIT 1
has, err = testEngine.Table("record_exist").Where("name = ?", "test1").Exist()
// SELECT * FROM record_exist WHERE name = ? LIMIT 1
```
* `Find` 查询多条记录当然可以使用Join和extends来组合使用
```Go
var users []User
err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users)
// SELECT * FROM user WHERE name = ? AND age > 10 limit 10 offset 0
type Detail struct {
Id int64
UserId int64 `xorm:"index"`
}
type UserDetail struct {
User `xorm:"extends"`
Detail `xorm:"extends"`
}
var users []UserDetail
err := engine.Table("user").Select("user.*, detail.*")
Join("INNER", "detail", "detail.user_id = user.id").
Where("user.name = ?", name).Limit(10, 0).
Find(&users)
// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 10 offset 0
```
* `Iterate``Rows` 根据条件遍历数据库,可以有两种方式: Iterate and Rows
```Go
err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
user := bean.(*User)
return nil
})
// SELECT * FROM user
err := engine.BufferSize(100).Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
user := bean.(*User)
return nil
})
// SELECT * FROM user Limit 0, 100
// SELECT * FROM user Limit 101, 100
rows, err := engine.Rows(&User{Name:name})
// SELECT * FROM user
defer rows.Close()
bean := new(Struct)
for rows.Next() {
err = rows.Scan(bean)
}
```
* `Update` 更新数据除非使用Cols,AllCols函数指明默认只更新非空和非0的字段
```Go
affected, err := engine.ID(1).Update(&user)
// UPDATE user SET ... Where id = ?
affected, err := engine.Update(&user, &User{Name:name})
// UPDATE user SET ... Where name = ?
var ids = []int64{1, 2, 3}
affected, err := engine.In(ids).Update(&user)
// UPDATE user SET ... Where id IN (?, ?, ?)
// force update indicated columns by Cols
affected, err := engine.ID(1).Cols("age").Update(&User{Name:name, Age: 12})
// UPDATE user SET age = ?, updated=? Where id = ?
// force NOT update indicated columns by Omit
affected, err := engine.ID(1).Omit("name").Update(&User{Name:name, Age: 12})
// UPDATE user SET age = ?, updated=? Where id = ?
affected, err := engine.ID(1).AllCols().Update(&user)
// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ?
```
* `Delete` 删除记录需要注意删除必须至少有一个条件否则会报错。要清空数据库可以用EmptyTable
```Go
affected, err := engine.Where(...).Delete(&user)
// DELETE FROM user Where ...
affected, err := engine.ID(2).Delete(&user)
// DELETE FROM user Where id = ?
```
* `Count` 获取记录条数
```Go
counts, err := engine.Count(&user)
// SELECT count(*) AS total FROM user
```
* `Sum` 求和函数
```Go
agesFloat64, err := engine.Sum(&user, "age")
// SELECT sum(age) AS total FROM user
agesInt64, err := engine.SumInt(&user, "age")
// SELECT sum(age) AS total FROM user
sumFloat64Slice, err := engine.Sums(&user, "age", "score")
// SELECT sum(age), sum(score) FROM user
sumInt64Slice, err := engine.SumsInt(&user, "age", "score")
// SELECT sum(age), sum(score) FROM user
```
* 条件编辑器
```Go
err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))).Find(&users)
// SELECT id, name ... FROM user WHERE a NOT IN (?, ?) AND b IN (?, ?, ?)
```
* 在一个Go程中多次操作数据库但没有事务
```Go
session := engine.NewSession()
defer session.Close()
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
if _, err := session.Insert(&user1); err != nil {
return err
}
user2 := Userinfo{Username: "yyy"}
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
return err
}
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
return err
}
return nil
```
* 在一个Go程中有事务
```Go
session := engine.NewSession()
defer session.Close()
// add Begin() before any action
if err := session.Begin(); err != nil {
// if returned then will rollback automatically
return err
}
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
if _, err := session.Insert(&user1); err != nil {
return err
}
user2 := Userinfo{Username: "yyy"}
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
return err
}
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
return err
}
// add Commit() after all actions
return session.Commit()
```
# 案例
* [Go语言中文网](http://studygolang.com/) - [github.com/studygolang/studygolang](https://github.com/studygolang/studygolang)
* [Gitea](http://gitea.io) - [github.com/go-gitea/gitea](http://github.com/go-gitea/gitea)
* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs)
* [grafana](https://grafana.com/) - [github.com/grafana/grafana](http://github.com/grafana/grafana)
* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader)
* [Wego](http://github.com/go-tango/wego)
* [Docker.cn](https://docker.cn/)
* [Xorm Adapter](https://github.com/casbin/xorm-adapter) for [Casbin](https://github.com/casbin/casbin) - [github.com/casbin/xorm-adapter](https://github.com/casbin/xorm-adapter)
* [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker)
* [Gobuild.io](http://gobuild.io) - [github.com/shxsun/gobuild](http://github.com/shxsun/gobuild)
* [Sudo China](http://sudochina.com) - [github.com/insionng/toropress](http://github.com/insionng/toropress)
* [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily)
* [YouGam](http://www.yougam.com/)
* [GoCMS - github.com/zzboy/GoCMS](https://github.com/zzdboy/GoCMS)
* [GoBBS - gobbs.domolo.com](http://gobbs.domolo.com/)
* [go-blog](http://wangcheng.me) - [github.com/easykoo/go-blog](https://github.com/easykoo/go-blog)
## 讨论
请加入QQ群280360085 进行讨论。
## 贡献
如果您也想为Xorm贡献您的力量请查看 [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md)
## LICENSE
BSD License
[http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/)

View File

@ -1,284 +0,0 @@
// Copyright 2015 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 (
"container/list"
"fmt"
"sync"
"time"
"github.com/go-xorm/core"
)
// LRUCacher implments cache object facilities
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
MaxElementSize int
Expired time.Duration
GcInterval time.Duration
}
// NewLRUCacher creates a cacher
func NewLRUCacher(store core.CacheStore, maxElementSize int) *LRUCacher {
return NewLRUCacher2(store, 3600*time.Second, maxElementSize)
}
// NewLRUCacher2 creates a cache include different params
func NewLRUCacher2(store core.CacheStore, expired time.Duration, maxElementSize int) *LRUCacher {
cacher := &LRUCacher{store: store, idList: list.New(),
sqlList: list.New(), Expired: expired,
GcInterval: core.CacheGcInterval, MaxElementSize: maxElementSize,
sqlIndex: make(map[string]map[string]*list.Element),
idIndex: make(map[string]map[string]*list.Element),
}
cacher.RunGC()
return cacher
}
// RunGC run once every m.GcInterval
func (m *LRUCacher) RunGC() {
time.AfterFunc(m.GcInterval, func() {
m.RunGC()
m.GC()
})
}
// GC check ids lit and sql list to remove all element expired
func (m *LRUCacher) GC() {
m.mutex.Lock()
defer m.mutex.Unlock()
var removedNum int
for e := m.idList.Front(); e != nil; {
if removedNum <= core.CacheGcMaxRemoved &&
time.Now().Sub(e.Value.(*idNode).lastVisit) > m.Expired {
removedNum++
next := e.Next()
node := e.Value.(*idNode)
m.delBean(node.tbName, node.id)
e = next
} else {
break
}
}
removedNum = 0
for e := m.sqlList.Front(); e != nil; {
if removedNum <= core.CacheGcMaxRemoved &&
time.Now().Sub(e.Value.(*sqlNode).lastVisit) > m.Expired {
removedNum++
next := e.Next()
node := e.Value.(*sqlNode)
m.delIds(node.tbName, node.sql)
e = next
} else {
break
}
}
}
// GetIds returns all bean's ids according to sql and parameter from cache
func (m *LRUCacher) GetIds(tableName, sql string) interface{} {
m.mutex.Lock()
defer m.mutex.Unlock()
if _, ok := m.sqlIndex[tableName]; !ok {
m.sqlIndex[tableName] = make(map[string]*list.Element)
}
if v, err := m.store.Get(sql); err == nil {
if el, ok := m.sqlIndex[tableName][sql]; !ok {
el = m.sqlList.PushBack(newSQLNode(tableName, sql))
m.sqlIndex[tableName][sql] = el
} else {
lastTime := el.Value.(*sqlNode).lastVisit
// if expired, remove the node and return nil
if time.Now().Sub(lastTime) > m.Expired {
m.delIds(tableName, sql)
return nil
}
m.sqlList.MoveToBack(el)
el.Value.(*sqlNode).lastVisit = time.Now()
}
return v
}
m.delIds(tableName, sql)
return nil
}
// GetBean returns bean according tableName and id from cache
func (m *LRUCacher) GetBean(tableName string, id string) interface{} {
m.mutex.Lock()
defer m.mutex.Unlock()
if _, ok := m.idIndex[tableName]; !ok {
m.idIndex[tableName] = make(map[string]*list.Element)
}
tid := genID(tableName, id)
if v, err := m.store.Get(tid); err == nil {
if el, ok := m.idIndex[tableName][id]; ok {
lastTime := el.Value.(*idNode).lastVisit
// if expired, remove the node and return nil
if time.Now().Sub(lastTime) > m.Expired {
m.delBean(tableName, id)
return nil
}
m.idList.MoveToBack(el)
el.Value.(*idNode).lastVisit = time.Now()
} else {
el = m.idList.PushBack(newIDNode(tableName, id))
m.idIndex[tableName][id] = el
}
return v
}
// store bean is not exist, then remove memory's index
m.delBean(tableName, id)
return nil
}
// clearIds clears all sql-ids mapping on table tableName from cache
func (m *LRUCacher) clearIds(tableName string) {
if tis, ok := m.sqlIndex[tableName]; ok {
for sql, v := range tis {
m.sqlList.Remove(v)
m.store.Del(sql)
}
}
m.sqlIndex[tableName] = make(map[string]*list.Element)
}
// ClearIds clears all sql-ids mapping on table tableName from cache
func (m *LRUCacher) ClearIds(tableName string) {
m.mutex.Lock()
m.clearIds(tableName)
m.mutex.Unlock()
}
func (m *LRUCacher) clearBeans(tableName string) {
if tis, ok := m.idIndex[tableName]; ok {
for id, v := range tis {
m.idList.Remove(v)
tid := genID(tableName, id)
m.store.Del(tid)
}
}
m.idIndex[tableName] = make(map[string]*list.Element)
}
// ClearBeans clears all beans in some table
func (m *LRUCacher) ClearBeans(tableName string) {
m.mutex.Lock()
m.clearBeans(tableName)
m.mutex.Unlock()
}
// PutIds pus ids into table
func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) {
m.mutex.Lock()
if _, ok := m.sqlIndex[tableName]; !ok {
m.sqlIndex[tableName] = make(map[string]*list.Element)
}
if el, ok := m.sqlIndex[tableName][sql]; !ok {
el = m.sqlList.PushBack(newSQLNode(tableName, sql))
m.sqlIndex[tableName][sql] = el
} else {
el.Value.(*sqlNode).lastVisit = time.Now()
}
m.store.Put(sql, ids)
if m.sqlList.Len() > m.MaxElementSize {
e := m.sqlList.Front()
node := e.Value.(*sqlNode)
m.delIds(node.tbName, node.sql)
}
m.mutex.Unlock()
}
// PutBean puts beans into table
func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) {
m.mutex.Lock()
var el *list.Element
var ok bool
if el, ok = m.idIndex[tableName][id]; !ok {
el = m.idList.PushBack(newIDNode(tableName, id))
m.idIndex[tableName][id] = el
} else {
el.Value.(*idNode).lastVisit = time.Now()
}
m.store.Put(genID(tableName, id), obj)
if m.idList.Len() > m.MaxElementSize {
e := m.idList.Front()
node := e.Value.(*idNode)
m.delBean(node.tbName, node.id)
}
m.mutex.Unlock()
}
func (m *LRUCacher) delIds(tableName, sql string) {
if _, ok := m.sqlIndex[tableName]; ok {
if el, ok := m.sqlIndex[tableName][sql]; ok {
delete(m.sqlIndex[tableName], sql)
m.sqlList.Remove(el)
}
}
m.store.Del(sql)
}
// DelIds deletes ids
func (m *LRUCacher) DelIds(tableName, sql string) {
m.mutex.Lock()
m.delIds(tableName, sql)
m.mutex.Unlock()
}
func (m *LRUCacher) delBean(tableName string, id string) {
tid := genID(tableName, id)
if el, ok := m.idIndex[tableName][id]; ok {
delete(m.idIndex[tableName], id)
m.idList.Remove(el)
m.clearIds(tableName)
}
m.store.Del(tid)
}
// DelBean deletes beans in some table
func (m *LRUCacher) DelBean(tableName string, id string) {
m.mutex.Lock()
m.delBean(tableName, id)
m.mutex.Unlock()
}
type idNode struct {
tbName string
id string
lastVisit time.Time
}
type sqlNode struct {
tbName string
sql string
lastVisit time.Time
}
func genSQLKey(sql string, args interface{}) string {
return fmt.Sprintf("%v-%v", sql, args)
}
func genID(prefix string, id string) string {
return fmt.Sprintf("%v-%v", prefix, id)
}
func newIDNode(tbName string, id string) *idNode {
return &idNode{tbName, id, time.Now()}
}
func newSQLNode(tbName, sql string) *sqlNode {
return &sqlNode{tbName, sql, time.Now()}
}

View File

@ -1,51 +0,0 @@
// Copyright 2015 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 (
"sync"
"github.com/go-xorm/core"
)
var _ core.CacheStore = NewMemoryStore()
// MemoryStore represents in-memory store
type MemoryStore struct {
store map[interface{}]interface{}
mutex sync.RWMutex
}
// NewMemoryStore creates a new store in memory
func NewMemoryStore() *MemoryStore {
return &MemoryStore{store: make(map[interface{}]interface{})}
}
// Put puts object into store
func (s *MemoryStore) Put(key string, value interface{}) error {
s.mutex.Lock()
defer s.mutex.Unlock()
s.store[key] = value
return nil
}
// Get gets object from store
func (s *MemoryStore) Get(key string) (interface{}, error) {
s.mutex.RLock()
defer s.mutex.RUnlock()
if v, ok := s.store[key]; ok {
return v, nil
}
return nil, ErrNotExist
}
// Del deletes object
func (s *MemoryStore) Del(key string) error {
s.mutex.Lock()
defer s.mutex.Unlock()
delete(s.store, key)
return nil
}

View File

@ -1,41 +0,0 @@
dependencies:
override:
# './...' is a relative pattern which means all subdirectories
- go get -t -d -v ./...
- go get -t -d -v github.com/go-xorm/tests
- go get -u github.com/go-xorm/core
- go get -u github.com/go-xorm/builder
- go build -v
database:
override:
- mysql -u root -e "CREATE DATABASE xorm_test DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci"
- mysql -u root -e "CREATE DATABASE xorm_test1 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci"
- mysql -u root -e "CREATE DATABASE xorm_test2 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci"
- mysql -u root -e "CREATE DATABASE xorm_test3 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci"
- createdb -p 5432 -e -U postgres xorm_test
- createdb -p 5432 -e -U postgres xorm_test1
- createdb -p 5432 -e -U postgres xorm_test2
- createdb -p 5432 -e -U postgres xorm_test3
- psql xorm_test postgres -c "create schema xorm"
test:
override:
# './...' is a relative pattern which means all subdirectories
- 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
- go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic
- go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -schema=xorm -cache=true -coverprofile=coverage5-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 coverage5-1.txt coverage5-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 && ./mysql.sh
- cd /home/ubuntu/.go_workspace/src/github.com/go-xorm/tests && ./postgres.sh
post:
- bash <(curl -s https://codecov.io/bash)

View File

@ -1,26 +0,0 @@
// 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.
// +build go1.8
package xorm
import "context"
// PingContext tests if database is alive
func (engine *Engine) PingContext(ctx context.Context) error {
session := engine.NewSession()
defer session.Close()
return session.PingContext(ctx)
}
// PingContext test if database is ok
func (session *Session) PingContext(ctx context.Context) error {
if session.isAutoClose {
defer session.Close()
}
session.engine.logger.Infof("PING DATABASE %v", session.engine.DriverName())
return session.DB().PingContext(ctx)
}

View File

@ -1,348 +0,0 @@
// 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 (
"database/sql/driver"
"errors"
"fmt"
"reflect"
"strconv"
"time"
)
var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
func strconvErr(err error) error {
if ne, ok := err.(*strconv.NumError); ok {
return ne.Err
}
return err
}
func cloneBytes(b []byte) []byte {
if b == nil {
return nil
} else {
c := make([]byte, len(b))
copy(c, b)
return c
}
}
func asString(src interface{}) string {
switch v := src.(type) {
case string:
return v
case []byte:
return string(v)
}
rv := reflect.ValueOf(src)
switch rv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return strconv.FormatInt(rv.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return strconv.FormatUint(rv.Uint(), 10)
case reflect.Float64:
return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
case reflect.Float32:
return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
case reflect.Bool:
return strconv.FormatBool(rv.Bool())
}
return fmt.Sprintf("%v", src)
}
func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
switch rv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return strconv.AppendInt(buf, rv.Int(), 10), true
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return strconv.AppendUint(buf, rv.Uint(), 10), true
case reflect.Float32:
return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
case reflect.Float64:
return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
case reflect.Bool:
return strconv.AppendBool(buf, rv.Bool()), true
case reflect.String:
s := rv.String()
return append(buf, s...), true
}
return
}
// convertAssign copies to dest the value in src, converting it if possible.
// An error is returned if the copy would result in loss of information.
// dest should be a pointer type.
func convertAssign(dest, src interface{}) error {
// Common cases, without reflect.
switch s := src.(type) {
case string:
switch d := dest.(type) {
case *string:
if d == nil {
return errNilPtr
}
*d = s
return nil
case *[]byte:
if d == nil {
return errNilPtr
}
*d = []byte(s)
return nil
}
case []byte:
switch d := dest.(type) {
case *string:
if d == nil {
return errNilPtr
}
*d = string(s)
return nil
case *interface{}:
if d == nil {
return errNilPtr
}
*d = cloneBytes(s)
return nil
case *[]byte:
if d == nil {
return errNilPtr
}
*d = cloneBytes(s)
return nil
}
case time.Time:
switch d := dest.(type) {
case *string:
*d = s.Format(time.RFC3339Nano)
return nil
case *[]byte:
if d == nil {
return errNilPtr
}
*d = []byte(s.Format(time.RFC3339Nano))
return nil
}
case nil:
switch d := dest.(type) {
case *interface{}:
if d == nil {
return errNilPtr
}
*d = nil
return nil
case *[]byte:
if d == nil {
return errNilPtr
}
*d = nil
return nil
}
}
var sv reflect.Value
switch d := dest.(type) {
case *string:
sv = reflect.ValueOf(src)
switch sv.Kind() {
case reflect.Bool,
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64:
*d = asString(src)
return nil
}
case *[]byte:
sv = reflect.ValueOf(src)
if b, ok := asBytes(nil, sv); ok {
*d = b
return nil
}
case *bool:
bv, err := driver.Bool.ConvertValue(src)
if err == nil {
*d = bv.(bool)
}
return err
case *interface{}:
*d = src
return nil
}
dpv := reflect.ValueOf(dest)
if dpv.Kind() != reflect.Ptr {
return errors.New("destination not a pointer")
}
if dpv.IsNil() {
return errNilPtr
}
if !sv.IsValid() {
sv = reflect.ValueOf(src)
}
dv := reflect.Indirect(dpv)
if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
switch b := src.(type) {
case []byte:
dv.Set(reflect.ValueOf(cloneBytes(b)))
default:
dv.Set(sv)
}
return nil
}
if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
dv.Set(sv.Convert(dv.Type()))
return nil
}
switch dv.Kind() {
case reflect.Ptr:
if src == nil {
dv.Set(reflect.Zero(dv.Type()))
return nil
}
dv.Set(reflect.New(dv.Type().Elem()))
return convertAssign(dv.Interface(), src)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
s := asString(src)
i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
if err != nil {
err = strconvErr(err)
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
}
dv.SetInt(i64)
return nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
s := asString(src)
u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
if err != nil {
err = strconvErr(err)
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
}
dv.SetUint(u64)
return nil
case reflect.Float32, reflect.Float64:
s := asString(src)
f64, err := strconv.ParseFloat(s, dv.Type().Bits())
if err != nil {
err = strconvErr(err)
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
}
dv.SetFloat(f64)
return nil
case reflect.String:
dv.SetString(asString(src))
return nil
}
return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
}
func asKind(vv reflect.Value, tp reflect.Type) (interface{}, error) {
switch tp.Kind() {
case reflect.Int64:
return vv.Int(), nil
case reflect.Int:
return int(vv.Int()), nil
case reflect.Int32:
return int32(vv.Int()), nil
case reflect.Int16:
return int16(vv.Int()), nil
case reflect.Int8:
return int8(vv.Int()), nil
case reflect.Uint64:
return vv.Uint(), nil
case reflect.Uint:
return uint(vv.Uint()), nil
case reflect.Uint32:
return uint32(vv.Uint()), nil
case reflect.Uint16:
return uint16(vv.Uint()), nil
case reflect.Uint8:
return uint8(vv.Uint()), nil
case reflect.String:
return vv.String(), nil
case reflect.Slice:
if tp.Elem().Kind() == reflect.Uint8 {
v, err := strconv.ParseInt(string(vv.Interface().([]byte)), 10, 64)
if err != nil {
return nil, err
}
return v, nil
}
}
return nil, fmt.Errorf("unsupported primary key type: %v, %v", tp, vv)
}
func convertFloat(v interface{}) (float64, error) {
switch v.(type) {
case float32:
return float64(v.(float32)), nil
case float64:
return v.(float64), nil
case string:
i, err := strconv.ParseFloat(v.(string), 64)
if err != nil {
return 0, err
}
return i, nil
case []byte:
i, err := strconv.ParseFloat(string(v.([]byte)), 64)
if err != nil {
return 0, err
}
return i, nil
}
return 0, fmt.Errorf("unsupported type: %v", v)
}
func convertInt(v interface{}) (int64, error) {
switch v.(type) {
case int:
return int64(v.(int)), nil
case int8:
return int64(v.(int8)), nil
case int16:
return int64(v.(int16)), nil
case int32:
return int64(v.(int32)), nil
case int64:
return v.(int64), nil
case []byte:
i, err := strconv.ParseInt(string(v.([]byte)), 10, 64)
if err != nil {
return 0, err
}
return i, nil
case string:
i, err := strconv.ParseInt(v.(string), 10, 64)
if err != nil {
return 0, err
}
return i, nil
}
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))
}

View File

@ -1,562 +0,0 @@
// Copyright 2015 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 (
"errors"
"fmt"
"strconv"
"strings"
"github.com/go-xorm/core"
)
var (
mssqlReservedWords = map[string]bool{
"ADD": true,
"EXTERNAL": true,
"PROCEDURE": true,
"ALL": true,
"FETCH": true,
"PUBLIC": true,
"ALTER": true,
"FILE": true,
"RAISERROR": true,
"AND": true,
"FILLFACTOR": true,
"READ": true,
"ANY": true,
"FOR": true,
"READTEXT": true,
"AS": true,
"FOREIGN": true,
"RECONFIGURE": true,
"ASC": true,
"FREETEXT": true,
"REFERENCES": true,
"AUTHORIZATION": true,
"FREETEXTTABLE": true,
"REPLICATION": true,
"BACKUP": true,
"FROM": true,
"RESTORE": true,
"BEGIN": true,
"FULL": true,
"RESTRICT": true,
"BETWEEN": true,
"FUNCTION": true,
"RETURN": true,
"BREAK": true,
"GOTO": true,
"REVERT": true,
"BROWSE": true,
"GRANT": true,
"REVOKE": true,
"BULK": true,
"GROUP": true,
"RIGHT": true,
"BY": true,
"HAVING": true,
"ROLLBACK": true,
"CASCADE": true,
"HOLDLOCK": true,
"ROWCOUNT": true,
"CASE": true,
"IDENTITY": true,
"ROWGUIDCOL": true,
"CHECK": true,
"IDENTITY_INSERT": true,
"RULE": true,
"CHECKPOINT": true,
"IDENTITYCOL": true,
"SAVE": true,
"CLOSE": true,
"IF": true,
"SCHEMA": true,
"CLUSTERED": true,
"IN": true,
"SECURITYAUDIT": true,
"COALESCE": true,
"INDEX": true,
"SELECT": true,
"COLLATE": true,
"INNER": true,
"SEMANTICKEYPHRASETABLE": true,
"COLUMN": true,
"INSERT": true,
"SEMANTICSIMILARITYDETAILSTABLE": true,
"COMMIT": true,
"INTERSECT": true,
"SEMANTICSIMILARITYTABLE": true,
"COMPUTE": true,
"INTO": true,
"SESSION_USER": true,
"CONSTRAINT": true,
"IS": true,
"SET": true,
"CONTAINS": true,
"JOIN": true,
"SETUSER": true,
"CONTAINSTABLE": true,
"KEY": true,
"SHUTDOWN": true,
"CONTINUE": true,
"KILL": true,
"SOME": true,
"CONVERT": true,
"LEFT": true,
"STATISTICS": true,
"CREATE": true,
"LIKE": true,
"SYSTEM_USER": true,
"CROSS": true,
"LINENO": true,
"TABLE": true,
"CURRENT": true,
"LOAD": true,
"TABLESAMPLE": true,
"CURRENT_DATE": true,
"MERGE": true,
"TEXTSIZE": true,
"CURRENT_TIME": true,
"NATIONAL": true,
"THEN": true,
"CURRENT_TIMESTAMP": true,
"NOCHECK": true,
"TO": true,
"CURRENT_USER": true,
"NONCLUSTERED": true,
"TOP": true,
"CURSOR": true,
"NOT": true,
"TRAN": true,
"DATABASE": true,
"NULL": true,
"TRANSACTION": true,
"DBCC": true,
"NULLIF": true,
"TRIGGER": true,
"DEALLOCATE": true,
"OF": true,
"TRUNCATE": true,
"DECLARE": true,
"OFF": true,
"TRY_CONVERT": true,
"DEFAULT": true,
"OFFSETS": true,
"TSEQUAL": true,
"DELETE": true,
"ON": true,
"UNION": true,
"DENY": true,
"OPEN": true,
"UNIQUE": true,
"DESC": true,
"OPENDATASOURCE": true,
"UNPIVOT": true,
"DISK": true,
"OPENQUERY": true,
"UPDATE": true,
"DISTINCT": true,
"OPENROWSET": true,
"UPDATETEXT": true,
"DISTRIBUTED": true,
"OPENXML": true,
"USE": true,
"DOUBLE": true,
"OPTION": true,
"USER": true,
"DROP": true,
"OR": true,
"VALUES": true,
"DUMP": true,
"ORDER": true,
"VARYING": true,
"ELSE": true,
"OUTER": true,
"VIEW": true,
"END": true,
"OVER": true,
"WAITFOR": true,
"ERRLVL": true,
"PERCENT": true,
"WHEN": true,
"ESCAPE": true,
"PIVOT": true,
"WHERE": true,
"EXCEPT": true,
"PLAN": true,
"WHILE": true,
"EXEC": true,
"PRECISION": true,
"WITH": true,
"EXECUTE": true,
"PRIMARY": true,
"WITHIN": true,
"EXISTS": true,
"PRINT": true,
"WRITETEXT": true,
"EXIT": true,
"PROC": true,
}
)
type mssql struct {
core.Base
}
func (db *mssql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
return db.Base.Init(d, db, uri, drivername, dataSourceName)
}
func (db *mssql) SqlType(c *core.Column) string {
var res string
switch t := c.SQLType.Name; t {
case core.Bool:
res = core.Bit
if strings.EqualFold(c.Default, "true") {
c.Default = "1"
} else {
c.Default = "0"
}
case core.Serial:
c.IsAutoIncrement = true
c.IsPrimaryKey = true
c.Nullable = false
res = core.Int
case core.BigSerial:
c.IsAutoIncrement = true
c.IsPrimaryKey = true
c.Nullable = false
res = core.BigInt
case core.Bytea, core.Blob, core.Binary, core.TinyBlob, core.MediumBlob, core.LongBlob:
res = core.VarBinary
if c.Length == 0 {
c.Length = 50
}
case core.TimeStamp:
res = core.DateTime
case core.TimeStampz:
res = "DATETIMEOFFSET"
c.Length = 7
case core.MediumInt:
res = core.Int
case core.Text, core.MediumText, core.TinyText, core.LongText, core.Json:
res = core.Varchar + "(MAX)"
case core.Double:
res = core.Real
case core.Uuid:
res = core.Varchar
c.Length = 40
case core.TinyInt:
res = core.TinyInt
c.Length = 0
default:
res = t
}
if res == core.Int {
return core.Int
}
hasLen1 := (c.Length > 0)
hasLen2 := (c.Length2 > 0)
if hasLen2 {
res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
} else if hasLen1 {
res += "(" + strconv.Itoa(c.Length) + ")"
}
return res
}
func (db *mssql) SupportInsertMany() bool {
return true
}
func (db *mssql) IsReserved(name string) bool {
_, ok := mssqlReservedWords[name]
return ok
}
func (db *mssql) Quote(name string) string {
return "\"" + name + "\""
}
func (db *mssql) QuoteStr() string {
return "\""
}
func (db *mssql) SupportEngine() bool {
return false
}
func (db *mssql) AutoIncrStr() string {
return "IDENTITY"
}
func (db *mssql) DropTableSql(tableName string) string {
return fmt.Sprintf("IF EXISTS (SELECT * FROM sysobjects WHERE id = "+
"object_id(N'%s') and OBJECTPROPERTY(id, N'IsUserTable') = 1) "+
"DROP TABLE \"%s\"", tableName, tableName)
}
func (db *mssql) SupportCharset() bool {
return false
}
func (db *mssql) IndexOnTable() bool {
return true
}
func (db *mssql) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
args := []interface{}{idxName}
sql := "select name from sysindexes where id=object_id('" + tableName + "') and name=?"
return sql, args
}
/*func (db *mssql) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
args := []interface{}{tableName, colName}
sql := `SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "COLUMN_NAME" = ?`
return sql, args
}*/
func (db *mssql) IsColumnExist(tableName, colName string) (bool, error) {
query := `SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "COLUMN_NAME" = ?`
return db.HasRecords(query, tableName, colName)
}
func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) {
args := []interface{}{}
sql := "select * from sysobjects where id = object_id(N'" + tableName + "') and OBJECTPROPERTY(id, N'IsUserTable') = 1"
return sql, args
}
func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
args := []interface{}{}
s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale,a.is_nullable as nullable,
replace(replace(isnull(c.text,''),'(',''),')','') as vdefault,
ISNULL(i.is_primary_key, 0)
from sys.columns a
left join sys.types b on a.user_type_id=b.user_type_id
left join sys.syscomments c on a.default_object_id=c.id
LEFT OUTER JOIN
sys.index_columns ic ON ic.object_id = a.object_id AND ic.column_id = a.column_id
LEFT OUTER JOIN
sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
where a.object_id=object_id('` + tableName + `')`
db.LogSQL(s, args)
rows, err := db.DB().Query(s, args...)
if err != nil {
return nil, nil, err
}
defer rows.Close()
cols := make(map[string]*core.Column)
colSeq := make([]string, 0)
for rows.Next() {
var name, ctype, vdefault string
var maxLen, precision, scale int
var nullable, isPK bool
err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &vdefault, &isPK)
if err != nil {
return nil, nil, err
}
col := new(core.Column)
col.Indexes = make(map[string]int)
col.Name = strings.Trim(name, "` ")
col.Nullable = nullable
col.Default = vdefault
col.IsPrimaryKey = isPK
ct := strings.ToUpper(ctype)
if ct == "DECIMAL" {
col.Length = precision
col.Length2 = scale
} else {
col.Length = maxLen
}
switch ct {
case "DATETIMEOFFSET":
col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
case "NVARCHAR":
col.SQLType = core.SQLType{Name: core.NVarchar, DefaultLength: 0, DefaultLength2: 0}
case "IMAGE":
col.SQLType = core.SQLType{Name: core.VarBinary, DefaultLength: 0, DefaultLength2: 0}
default:
if _, ok := core.SqlTypes[ct]; ok {
col.SQLType = core.SQLType{Name: ct, DefaultLength: 0, DefaultLength2: 0}
} else {
return nil, nil, fmt.Errorf("Unknown colType %v for %v - %v", ct, tableName, col.Name)
}
}
if col.SQLType.IsText() || col.SQLType.IsTime() {
if col.Default != "" {
col.Default = "'" + col.Default + "'"
} else {
if col.DefaultIsEmpty {
col.Default = "''"
}
}
}
cols[col.Name] = col
colSeq = append(colSeq, col.Name)
}
return colSeq, cols, nil
}
func (db *mssql) GetTables() ([]*core.Table, error) {
args := []interface{}{}
s := `select name from sysobjects where xtype ='U'`
db.LogSQL(s, args)
rows, err := db.DB().Query(s, args...)
if err != nil {
return nil, err
}
defer rows.Close()
tables := make([]*core.Table, 0)
for rows.Next() {
table := core.NewEmptyTable()
var name string
err = rows.Scan(&name)
if err != nil {
return nil, err
}
table.Name = strings.Trim(name, "` ")
tables = append(tables, table)
}
return tables, nil
}
func (db *mssql) GetIndexes(tableName string) (map[string]*core.Index, error) {
args := []interface{}{tableName}
s := `SELECT
IXS.NAME AS [INDEX_NAME],
C.NAME AS [COLUMN_NAME],
IXS.is_unique AS [IS_UNIQUE]
FROM SYS.INDEXES IXS
INNER JOIN SYS.INDEX_COLUMNS IXCS
ON IXS.OBJECT_ID=IXCS.OBJECT_ID AND IXS.INDEX_ID = IXCS.INDEX_ID
INNER JOIN SYS.COLUMNS C ON IXS.OBJECT_ID=C.OBJECT_ID
AND IXCS.COLUMN_ID=C.COLUMN_ID
WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =?
`
db.LogSQL(s, args)
rows, err := db.DB().Query(s, args...)
if err != nil {
return nil, err
}
defer rows.Close()
indexes := make(map[string]*core.Index, 0)
for rows.Next() {
var indexType int
var indexName, colName, isUnique string
err = rows.Scan(&indexName, &colName, &isUnique)
if err != nil {
return nil, err
}
i, err := strconv.ParseBool(isUnique)
if err != nil {
return nil, err
}
if i {
indexType = core.UniqueType
} else {
indexType = core.IndexType
}
colName = strings.Trim(colName, "` ")
var isRegular bool
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
indexName = indexName[5+len(tableName):]
isRegular = true
}
var index *core.Index
var ok bool
if index, ok = indexes[indexName]; !ok {
index = new(core.Index)
index.Type = indexType
index.Name = indexName
index.IsRegular = isRegular
indexes[indexName] = index
}
index.AddColumn(colName)
}
return indexes, nil
}
func (db *mssql) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
var sql string
if tableName == "" {
tableName = table.Name
}
sql = "IF NOT EXISTS (SELECT [name] FROM sys.tables WHERE [name] = '" + tableName + "' ) CREATE TABLE "
sql += db.QuoteStr() + tableName + db.QuoteStr() + " ("
pkList := table.PrimaryKeys
for _, colName := range table.ColumnsSeq() {
col := table.GetColumn(colName)
if col.IsPrimaryKey && len(pkList) == 1 {
sql += col.String(db)
} else {
sql += col.StringNoPk(db)
}
sql = strings.TrimSpace(sql)
sql += ", "
}
if len(pkList) > 1 {
sql += "PRIMARY KEY ( "
sql += strings.Join(pkList, ",")
sql += " ), "
}
sql = sql[:len(sql)-2] + ")"
sql += ";"
return sql
}
func (db *mssql) ForUpdateSql(query string) string {
return query
}
func (db *mssql) Filters() []core.Filter {
return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}}
}
type odbcDriver struct {
}
func (p *odbcDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
kv := strings.Split(dataSourceName, ";")
var dbName string
for _, c := range kv {
vv := strings.Split(strings.TrimSpace(c), "=")
if len(vv) == 2 {
switch strings.ToLower(vv[0]) {
case "database":
dbName = vv[1]
}
}
}
if dbName == "" {
return nil, errors.New("no db name provided")
}
return &core.Uri{DbName: dbName, DbType: core.MSSQL}, nil
}

View File

@ -1,656 +0,0 @@
// Copyright 2015 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 (
"crypto/tls"
"errors"
"fmt"
"regexp"
"strconv"
"strings"
"time"
"github.com/go-xorm/core"
)
var (
mysqlReservedWords = map[string]bool{
"ADD": true,
"ALL": true,
"ALTER": true,
"ANALYZE": true,
"AND": true,
"AS": true,
"ASC": true,
"ASENSITIVE": true,
"BEFORE": true,
"BETWEEN": true,
"BIGINT": true,
"BINARY": true,
"BLOB": true,
"BOTH": true,
"BY": true,
"CALL": true,
"CASCADE": true,
"CASE": true,
"CHANGE": true,
"CHAR": true,
"CHARACTER": true,
"CHECK": true,
"COLLATE": true,
"COLUMN": true,
"CONDITION": true,
"CONNECTION": true,
"CONSTRAINT": true,
"CONTINUE": true,
"CONVERT": true,
"CREATE": true,
"CROSS": true,
"CURRENT_DATE": true,
"CURRENT_TIME": true,
"CURRENT_TIMESTAMP": true,
"CURRENT_USER": true,
"CURSOR": true,
"DATABASE": true,
"DATABASES": true,
"DAY_HOUR": true,
"DAY_MICROSECOND": true,
"DAY_MINUTE": true,
"DAY_SECOND": true,
"DEC": true,
"DECIMAL": true,
"DECLARE": true,
"DEFAULT": true,
"DELAYED": true,
"DELETE": true,
"DESC": true,
"DESCRIBE": true,
"DETERMINISTIC": true,
"DISTINCT": true,
"DISTINCTROW": true,
"DIV": true,
"DOUBLE": true,
"DROP": true,
"DUAL": true,
"EACH": true,
"ELSE": true,
"ELSEIF": true,
"ENCLOSED": true,
"ESCAPED": true,
"EXISTS": true,
"EXIT": true,
"EXPLAIN": true,
"FALSE": true,
"FETCH": true,
"FLOAT": true,
"FLOAT4": true,
"FLOAT8": true,
"FOR": true,
"FORCE": true,
"FOREIGN": true,
"FROM": true,
"FULLTEXT": true,
"GOTO": true,
"GRANT": true,
"GROUP": true,
"HAVING": true,
"HIGH_PRIORITY": true,
"HOUR_MICROSECOND": true,
"HOUR_MINUTE": true,
"HOUR_SECOND": true,
"IF": true,
"IGNORE": true,
"IN": true, "INDEX": true,
"INFILE": true, "INNER": true, "INOUT": true,
"INSENSITIVE": true, "INSERT": true, "INT": true,
"INT1": true, "INT2": true, "INT3": true,
"INT4": true, "INT8": true, "INTEGER": true,
"INTERVAL": true, "INTO": true, "IS": true,
"ITERATE": true, "JOIN": true, "KEY": true,
"KEYS": true, "KILL": true, "LABEL": true,
"LEADING": true, "LEAVE": true, "LEFT": true,
"LIKE": true, "LIMIT": true, "LINEAR": true,
"LINES": true, "LOAD": true, "LOCALTIME": true,
"LOCALTIMESTAMP": true, "LOCK": true, "LONG": true,
"LONGBLOB": true, "LONGTEXT": true, "LOOP": true,
"LOW_PRIORITY": true, "MATCH": true, "MEDIUMBLOB": true,
"MEDIUMINT": true, "MEDIUMTEXT": true, "MIDDLEINT": true,
"MINUTE_MICROSECOND": true, "MINUTE_SECOND": true, "MOD": true,
"MODIFIES": true, "NATURAL": true, "NOT": true,
"NO_WRITE_TO_BINLOG": true, "NULL": true, "NUMERIC": true,
"ON OPTIMIZE": true, "OPTION": true,
"OPTIONALLY": true, "OR": true, "ORDER": true,
"OUT": true, "OUTER": true, "OUTFILE": true,
"PRECISION": true, "PRIMARY": true, "PROCEDURE": true,
"PURGE": true, "RAID0": true, "RANGE": true,
"READ": true, "READS": true, "REAL": true,
"REFERENCES": true, "REGEXP": true, "RELEASE": true,
"RENAME": true, "REPEAT": true, "REPLACE": true,
"REQUIRE": true, "RESTRICT": true, "RETURN": true,
"REVOKE": true, "RIGHT": true, "RLIKE": true,
"SCHEMA": true, "SCHEMAS": true, "SECOND_MICROSECOND": true,
"SELECT": true, "SENSITIVE": true, "SEPARATOR": true,
"SET": true, "SHOW": true, "SMALLINT": true,
"SPATIAL": true, "SPECIFIC": true, "SQL": true,
"SQLEXCEPTION": true, "SQLSTATE": true, "SQLWARNING": true,
"SQL_BIG_RESULT": true, "SQL_CALC_FOUND_ROWS": true, "SQL_SMALL_RESULT": true,
"SSL": true, "STARTING": true, "STRAIGHT_JOIN": true,
"TABLE": true, "TERMINATED": true, "THEN": true,
"TINYBLOB": true, "TINYINT": true, "TINYTEXT": true,
"TO": true, "TRAILING": true, "TRIGGER": true,
"TRUE": true, "UNDO": true, "UNION": true,
"UNIQUE": true, "UNLOCK": true, "UNSIGNED": true,
"UPDATE": true, "USAGE": true, "USE": true,
"USING": true, "UTC_DATE": true, "UTC_TIME": true,
"UTC_TIMESTAMP": true, "VALUES": true, "VARBINARY": true,
"VARCHAR": true,
"VARCHARACTER": true,
"VARYING": true,
"WHEN": true,
"WHERE": true,
"WHILE": true,
"WITH": true,
"WRITE": true,
"X509": true,
"XOR": true,
"YEAR_MONTH": true,
"ZEROFILL": true,
}
)
type mysql struct {
core.Base
net string
addr string
params map[string]string
loc *time.Location
timeout time.Duration
tls *tls.Config
allowAllFiles bool
allowOldPasswords bool
clientFoundRows bool
rowFormat string
}
func (db *mysql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
return db.Base.Init(d, db, uri, drivername, dataSourceName)
}
func (db *mysql) SetParams(params map[string]string) {
rowFormat, ok := params["rowFormat"]
if ok {
var t = strings.ToUpper(rowFormat)
switch t {
case "COMPACT":
fallthrough
case "REDUNDANT":
fallthrough
case "DYNAMIC":
fallthrough
case "COMPRESSED":
db.rowFormat = t
break
default:
break
}
}
}
func (db *mysql) SqlType(c *core.Column) string {
var res string
switch t := c.SQLType.Name; t {
case core.Bool:
res = core.TinyInt
c.Length = 1
case core.Serial:
c.IsAutoIncrement = true
c.IsPrimaryKey = true
c.Nullable = false
res = core.Int
case core.BigSerial:
c.IsAutoIncrement = true
c.IsPrimaryKey = true
c.Nullable = false
res = core.BigInt
case core.Bytea:
res = core.Blob
case core.TimeStampz:
res = core.Char
c.Length = 64
case core.Enum: //mysql enum
res = core.Enum
res += "("
opts := ""
for v := range c.EnumOptions {
opts += fmt.Sprintf(",'%v'", v)
}
res += strings.TrimLeft(opts, ",")
res += ")"
case core.Set: //mysql set
res = core.Set
res += "("
opts := ""
for v := range c.SetOptions {
opts += fmt.Sprintf(",'%v'", v)
}
res += strings.TrimLeft(opts, ",")
res += ")"
case core.NVarchar:
res = core.Varchar
case core.Uuid:
res = core.Varchar
c.Length = 40
case core.Json:
res = core.Text
default:
res = t
}
hasLen1 := (c.Length > 0)
hasLen2 := (c.Length2 > 0)
if res == core.BigInt && !hasLen1 && !hasLen2 {
c.Length = 20
hasLen1 = true
}
if hasLen2 {
res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
} else if hasLen1 {
res += "(" + strconv.Itoa(c.Length) + ")"
}
return res
}
func (db *mysql) SupportInsertMany() bool {
return true
}
func (db *mysql) IsReserved(name string) bool {
_, ok := mysqlReservedWords[name]
return ok
}
func (db *mysql) Quote(name string) string {
return "`" + name + "`"
}
func (db *mysql) QuoteStr() string {
return "`"
}
func (db *mysql) SupportEngine() bool {
return true
}
func (db *mysql) AutoIncrStr() string {
return "AUTO_INCREMENT"
}
func (db *mysql) SupportCharset() bool {
return true
}
func (db *mysql) IndexOnTable() bool {
return true
}
func (db *mysql) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
args := []interface{}{db.DbName, tableName, idxName}
sql := "SELECT `INDEX_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS`"
sql += " WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `INDEX_NAME`=?"
return sql, args
}
/*func (db *mysql) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
args := []interface{}{db.DbName, tableName, colName}
sql := "SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `COLUMN_NAME` = ?"
return sql, args
}*/
func (db *mysql) TableCheckSql(tableName string) (string, []interface{}) {
args := []interface{}{db.DbName, tableName}
sql := "SELECT `TABLE_NAME` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? and `TABLE_NAME`=?"
return sql, args
}
func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
args := []interface{}{db.DbName, tableName}
s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," +
" `COLUMN_KEY`, `EXTRA`,`COLUMN_COMMENT` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
db.LogSQL(s, args)
rows, err := db.DB().Query(s, args...)
if err != nil {
return nil, nil, err
}
defer rows.Close()
cols := make(map[string]*core.Column)
colSeq := make([]string, 0)
for rows.Next() {
col := new(core.Column)
col.Indexes = make(map[string]int)
var columnName, isNullable, colType, colKey, extra, comment string
var colDefault *string
err = rows.Scan(&columnName, &isNullable, &colDefault, &colType, &colKey, &extra, &comment)
if err != nil {
return nil, nil, err
}
col.Name = strings.Trim(columnName, "` ")
col.Comment = comment
if "YES" == isNullable {
col.Nullable = true
}
if colDefault != nil {
col.Default = *colDefault
if col.Default == "" {
col.DefaultIsEmpty = true
}
}
cts := strings.Split(colType, "(")
colName := cts[0]
colType = strings.ToUpper(colName)
var len1, len2 int
if len(cts) == 2 {
idx := strings.Index(cts[1], ")")
if colType == core.Enum && cts[1][0] == '\'' { //enum
options := strings.Split(cts[1][0:idx], ",")
col.EnumOptions = make(map[string]int)
for k, v := range options {
v = strings.TrimSpace(v)
v = strings.Trim(v, "'")
col.EnumOptions[v] = k
}
} else if colType == core.Set && cts[1][0] == '\'' {
options := strings.Split(cts[1][0:idx], ",")
col.SetOptions = make(map[string]int)
for k, v := range options {
v = strings.TrimSpace(v)
v = strings.Trim(v, "'")
col.SetOptions[v] = k
}
} else {
lens := strings.Split(cts[1][0:idx], ",")
len1, err = strconv.Atoi(strings.TrimSpace(lens[0]))
if err != nil {
return nil, nil, err
}
if len(lens) == 2 {
len2, err = strconv.Atoi(lens[1])
if err != nil {
return nil, nil, err
}
}
}
}
if colType == "FLOAT UNSIGNED" {
colType = "FLOAT"
}
col.Length = len1
col.Length2 = len2
if _, ok := core.SqlTypes[colType]; ok {
col.SQLType = core.SQLType{Name: colType, DefaultLength: len1, DefaultLength2: len2}
} else {
return nil, nil, fmt.Errorf("Unknown colType %v", colType)
}
if colKey == "PRI" {
col.IsPrimaryKey = true
}
if colKey == "UNI" {
//col.is
}
if extra == "auto_increment" {
col.IsAutoIncrement = true
}
if col.SQLType.IsText() || col.SQLType.IsTime() {
if col.Default != "" {
col.Default = "'" + col.Default + "'"
} else {
if col.DefaultIsEmpty {
col.Default = "''"
}
}
}
cols[col.Name] = col
colSeq = append(colSeq, col.Name)
}
return colSeq, cols, nil
}
func (db *mysql) GetTables() ([]*core.Table, error) {
args := []interface{}{db.DbName}
s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT`, `TABLE_COMMENT` from " +
"`INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? AND (`ENGINE`='MyISAM' OR `ENGINE` = 'InnoDB' OR `ENGINE` = 'TokuDB')"
db.LogSQL(s, args)
rows, err := db.DB().Query(s, args...)
if err != nil {
return nil, err
}
defer rows.Close()
tables := make([]*core.Table, 0)
for rows.Next() {
table := core.NewEmptyTable()
var name, engine, tableRows, comment string
var autoIncr *string
err = rows.Scan(&name, &engine, &tableRows, &autoIncr, &comment)
if err != nil {
return nil, err
}
table.Name = name
table.Comment = comment
table.StoreEngine = engine
tables = append(tables, table)
}
return tables, nil
}
func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) {
args := []interface{}{db.DbName, tableName}
s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
db.LogSQL(s, args)
rows, err := db.DB().Query(s, args...)
if err != nil {
return nil, err
}
defer rows.Close()
indexes := make(map[string]*core.Index, 0)
for rows.Next() {
var indexType int
var indexName, colName, nonUnique string
err = rows.Scan(&indexName, &nonUnique, &colName)
if err != nil {
return nil, err
}
if indexName == "PRIMARY" {
continue
}
if "YES" == nonUnique || nonUnique == "1" {
indexType = core.IndexType
} else {
indexType = core.UniqueType
}
colName = strings.Trim(colName, "` ")
var isRegular bool
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
indexName = indexName[5+len(tableName):]
isRegular = true
}
var index *core.Index
var ok bool
if index, ok = indexes[indexName]; !ok {
index = new(core.Index)
index.IsRegular = isRegular
index.Type = indexType
index.Name = indexName
indexes[indexName] = index
}
index.AddColumn(colName)
}
return indexes, nil
}
func (db *mysql) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
var sql string
sql = "CREATE TABLE IF NOT EXISTS "
if tableName == "" {
tableName = table.Name
}
sql += db.Quote(tableName)
sql += " ("
if len(table.ColumnsSeq()) > 0 {
pkList := table.PrimaryKeys
for _, colName := range table.ColumnsSeq() {
col := table.GetColumn(colName)
if col.IsPrimaryKey && len(pkList) == 1 {
sql += col.String(db)
} else {
sql += col.StringNoPk(db)
}
sql = strings.TrimSpace(sql)
if len(col.Comment) > 0 {
sql += " COMMENT '" + col.Comment + "'"
}
sql += ", "
}
if len(pkList) > 1 {
sql += "PRIMARY KEY ( "
sql += db.Quote(strings.Join(pkList, db.Quote(",")))
sql += " ), "
}
sql = sql[:len(sql)-2]
}
sql += ")"
if storeEngine != "" {
sql += " ENGINE=" + storeEngine
}
if len(charset) == 0 {
charset = db.URI().Charset
} else if len(charset) > 0 {
sql += " DEFAULT CHARSET " + charset
}
if db.rowFormat != "" {
sql += " ROW_FORMAT=" + db.rowFormat
}
return sql
}
func (db *mysql) Filters() []core.Filter {
return []core.Filter{&core.IdFilter{}}
}
type mymysqlDriver struct {
}
func (p *mymysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
db := &core.Uri{DbType: core.MYSQL}
pd := strings.SplitN(dataSourceName, "*", 2)
if len(pd) == 2 {
// Parse protocol part of URI
p := strings.SplitN(pd[0], ":", 2)
if len(p) != 2 {
return nil, errors.New("Wrong protocol part of URI")
}
db.Proto = p[0]
options := strings.Split(p[1], ",")
db.Raddr = options[0]
for _, o := range options[1:] {
kv := strings.SplitN(o, "=", 2)
var k, v string
if len(kv) == 2 {
k, v = kv[0], kv[1]
} else {
k, v = o, "true"
}
switch k {
case "laddr":
db.Laddr = v
case "timeout":
to, err := time.ParseDuration(v)
if err != nil {
return nil, err
}
db.Timeout = to
default:
return nil, errors.New("Unknown option: " + k)
}
}
// Remove protocol part
pd = pd[1:]
}
// Parse database part of URI
dup := strings.SplitN(pd[0], "/", 3)
if len(dup) != 3 {
return nil, errors.New("Wrong database part of URI")
}
db.DbName = dup[0]
db.User = dup[1]
db.Passwd = dup[2]
return db, nil
}
type mysqlDriver struct {
}
func (p *mysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
dsnPattern := regexp.MustCompile(
`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
`\/(?P<dbname>.*?)` + // /dbname
`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1&paramN=valueN]
matches := dsnPattern.FindStringSubmatch(dataSourceName)
//tlsConfigRegister := make(map[string]*tls.Config)
names := dsnPattern.SubexpNames()
uri := &core.Uri{DbType: core.MYSQL}
for i, match := range matches {
switch names[i] {
case "dbname":
uri.DbName = match
case "params":
if len(match) > 0 {
kvs := strings.Split(match, "&")
for _, kv := range kvs {
splits := strings.Split(kv, "=")
if len(splits) == 2 {
switch splits[0] {
case "charset":
uri.Charset = splits[1]
}
}
}
}
}
}
return uri, nil
}

View File

@ -1,906 +0,0 @@
// Copyright 2015 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 (
"errors"
"fmt"
"regexp"
"strconv"
"strings"
"github.com/go-xorm/core"
)
var (
oracleReservedWords = map[string]bool{
"ACCESS": true,
"ACCOUNT": true,
"ACTIVATE": true,
"ADD": true,
"ADMIN": true,
"ADVISE": true,
"AFTER": true,
"ALL": true,
"ALL_ROWS": true,
"ALLOCATE": true,
"ALTER": true,
"ANALYZE": true,
"AND": true,
"ANY": true,
"ARCHIVE": true,
"ARCHIVELOG": true,
"ARRAY": true,
"AS": true,
"ASC": true,
"AT": true,
"AUDIT": true,
"AUTHENTICATED": true,
"AUTHORIZATION": true,
"AUTOEXTEND": true,
"AUTOMATIC": true,
"BACKUP": true,
"BECOME": true,
"BEFORE": true,
"BEGIN": true,
"BETWEEN": true,
"BFILE": true,
"BITMAP": true,
"BLOB": true,
"BLOCK": true,
"BODY": true,
"BY": true,
"CACHE": true,
"CACHE_INSTANCES": true,
"CANCEL": true,
"CASCADE": true,
"CAST": true,
"CFILE": true,
"CHAINED": true,
"CHANGE": true,
"CHAR": true,
"CHAR_CS": true,
"CHARACTER": true,
"CHECK": true,
"CHECKPOINT": true,
"CHOOSE": true,
"CHUNK": true,
"CLEAR": true,
"CLOB": true,
"CLONE": true,
"CLOSE": true,
"CLOSE_CACHED_OPEN_CURSORS": true,
"CLUSTER": true,
"COALESCE": true,
"COLUMN": true,
"COLUMNS": true,
"COMMENT": true,
"COMMIT": true,
"COMMITTED": true,
"COMPATIBILITY": true,
"COMPILE": true,
"COMPLETE": true,
"COMPOSITE_LIMIT": true,
"COMPRESS": true,
"COMPUTE": true,
"CONNECT": true,
"CONNECT_TIME": true,
"CONSTRAINT": true,
"CONSTRAINTS": true,
"CONTENTS": true,
"CONTINUE": true,
"CONTROLFILE": true,
"CONVERT": true,
"COST": true,
"CPU_PER_CALL": true,
"CPU_PER_SESSION": true,
"CREATE": true,
"CURRENT": true,
"CURRENT_SCHEMA": true,
"CURREN_USER": true,
"CURSOR": true,
"CYCLE": true,
"DANGLING": true,
"DATABASE": true,
"DATAFILE": true,
"DATAFILES": true,
"DATAOBJNO": true,
"DATE": true,
"DBA": true,
"DBHIGH": true,
"DBLOW": true,
"DBMAC": true,
"DEALLOCATE": true,
"DEBUG": true,
"DEC": true,
"DECIMAL": true,
"DECLARE": true,
"DEFAULT": true,
"DEFERRABLE": true,
"DEFERRED": true,
"DEGREE": true,
"DELETE": true,
"DEREF": true,
"DESC": true,
"DIRECTORY": true,
"DISABLE": true,
"DISCONNECT": true,
"DISMOUNT": true,
"DISTINCT": true,
"DISTRIBUTED": true,
"DML": true,
"DOUBLE": true,
"DROP": true,
"DUMP": true,
"EACH": true,
"ELSE": true,
"ENABLE": true,
"END": true,
"ENFORCE": true,
"ENTRY": true,
"ESCAPE": true,
"EXCEPT": true,
"EXCEPTIONS": true,
"EXCHANGE": true,
"EXCLUDING": true,
"EXCLUSIVE": true,
"EXECUTE": true,
"EXISTS": true,
"EXPIRE": true,
"EXPLAIN": true,
"EXTENT": true,
"EXTENTS": true,
"EXTERNALLY": true,
"FAILED_LOGIN_ATTEMPTS": true,
"FALSE": true,
"FAST": true,
"FILE": true,
"FIRST_ROWS": true,
"FLAGGER": true,
"FLOAT": true,
"FLOB": true,
"FLUSH": true,
"FOR": true,
"FORCE": true,
"FOREIGN": true,
"FREELIST": true,
"FREELISTS": true,
"FROM": true,
"FULL": true,
"FUNCTION": true,
"GLOBAL": true,
"GLOBALLY": true,
"GLOBAL_NAME": true,
"GRANT": true,
"GROUP": true,
"GROUPS": true,
"HASH": true,
"HASHKEYS": true,
"HAVING": true,
"HEADER": true,
"HEAP": true,
"IDENTIFIED": true,
"IDGENERATORS": true,
"IDLE_TIME": true,
"IF": true,
"IMMEDIATE": true,
"IN": true,
"INCLUDING": true,
"INCREMENT": true,
"INDEX": true,
"INDEXED": true,
"INDEXES": true,
"INDICATOR": true,
"IND_PARTITION": true,
"INITIAL": true,
"INITIALLY": true,
"INITRANS": true,
"INSERT": true,
"INSTANCE": true,
"INSTANCES": true,
"INSTEAD": true,
"INT": true,
"INTEGER": true,
"INTERMEDIATE": true,
"INTERSECT": true,
"INTO": true,
"IS": true,
"ISOLATION": true,
"ISOLATION_LEVEL": true,
"KEEP": true,
"KEY": true,
"KILL": true,
"LABEL": true,
"LAYER": true,
"LESS": true,
"LEVEL": true,
"LIBRARY": true,
"LIKE": true,
"LIMIT": true,
"LINK": true,
"LIST": true,
"LOB": true,
"LOCAL": true,
"LOCK": true,
"LOCKED": true,
"LOG": true,
"LOGFILE": true,
"LOGGING": true,
"LOGICAL_READS_PER_CALL": true,
"LOGICAL_READS_PER_SESSION": true,
"LONG": true,
"MANAGE": true,
"MASTER": true,
"MAX": true,
"MAXARCHLOGS": true,
"MAXDATAFILES": true,
"MAXEXTENTS": true,
"MAXINSTANCES": true,
"MAXLOGFILES": true,
"MAXLOGHISTORY": true,
"MAXLOGMEMBERS": true,
"MAXSIZE": true,
"MAXTRANS": true,
"MAXVALUE": true,
"MIN": true,
"MEMBER": true,
"MINIMUM": true,
"MINEXTENTS": true,
"MINUS": true,
"MINVALUE": true,
"MLSLABEL": true,
"MLS_LABEL_FORMAT": true,
"MODE": true,
"MODIFY": true,
"MOUNT": true,
"MOVE": true,
"MTS_DISPATCHERS": true,
"MULTISET": true,
"NATIONAL": true,
"NCHAR": true,
"NCHAR_CS": true,
"NCLOB": true,
"NEEDED": true,
"NESTED": true,
"NETWORK": true,
"NEW": true,
"NEXT": true,
"NOARCHIVELOG": true,
"NOAUDIT": true,
"NOCACHE": true,
"NOCOMPRESS": true,
"NOCYCLE": true,
"NOFORCE": true,
"NOLOGGING": true,
"NOMAXVALUE": true,
"NOMINVALUE": true,
"NONE": true,
"NOORDER": true,
"NOOVERRIDE": true,
"NOPARALLEL": true,
"NOREVERSE": true,
"NORMAL": true,
"NOSORT": true,
"NOT": true,
"NOTHING": true,
"NOWAIT": true,
"NULL": true,
"NUMBER": true,
"NUMERIC": true,
"NVARCHAR2": true,
"OBJECT": true,
"OBJNO": true,
"OBJNO_REUSE": true,
"OF": true,
"OFF": true,
"OFFLINE": true,
"OID": true,
"OIDINDEX": true,
"OLD": true,
"ON": true,
"ONLINE": true,
"ONLY": true,
"OPCODE": true,
"OPEN": true,
"OPTIMAL": true,
"OPTIMIZER_GOAL": true,
"OPTION": true,
"OR": true,
"ORDER": true,
"ORGANIZATION": true,
"OSLABEL": true,
"OVERFLOW": true,
"OWN": true,
"PACKAGE": true,
"PARALLEL": true,
"PARTITION": true,
"PASSWORD": true,
"PASSWORD_GRACE_TIME": true,
"PASSWORD_LIFE_TIME": true,
"PASSWORD_LOCK_TIME": true,
"PASSWORD_REUSE_MAX": true,
"PASSWORD_REUSE_TIME": true,
"PASSWORD_VERIFY_FUNCTION": true,
"PCTFREE": true,
"PCTINCREASE": true,
"PCTTHRESHOLD": true,
"PCTUSED": true,
"PCTVERSION": true,
"PERCENT": true,
"PERMANENT": true,
"PLAN": true,
"PLSQL_DEBUG": true,
"POST_TRANSACTION": true,
"PRECISION": true,
"PRESERVE": true,
"PRIMARY": true,
"PRIOR": true,
"PRIVATE": true,
"PRIVATE_SGA": true,
"PRIVILEGE": true,
"PRIVILEGES": true,
"PROCEDURE": true,
"PROFILE": true,
"PUBLIC": true,
"PURGE": true,
"QUEUE": true,
"QUOTA": true,
"RANGE": true,
"RAW": true,
"RBA": true,
"READ": true,
"READUP": true,
"REAL": true,
"REBUILD": true,
"RECOVER": true,
"RECOVERABLE": true,
"RECOVERY": true,
"REF": true,
"REFERENCES": true,
"REFERENCING": true,
"REFRESH": true,
"RENAME": true,
"REPLACE": true,
"RESET": true,
"RESETLOGS": true,
"RESIZE": true,
"RESOURCE": true,
"RESTRICTED": true,
"RETURN": true,
"RETURNING": true,
"REUSE": true,
"REVERSE": true,
"REVOKE": true,
"ROLE": true,
"ROLES": true,
"ROLLBACK": true,
"ROW": true,
"ROWID": true,
"ROWNUM": true,
"ROWS": true,
"RULE": true,
"SAMPLE": true,
"SAVEPOINT": true,
"SB4": true,
"SCAN_INSTANCES": true,
"SCHEMA": true,
"SCN": true,
"SCOPE": true,
"SD_ALL": true,
"SD_INHIBIT": true,
"SD_SHOW": true,
"SEGMENT": true,
"SEG_BLOCK": true,
"SEG_FILE": true,
"SELECT": true,
"SEQUENCE": true,
"SERIALIZABLE": true,
"SESSION": true,
"SESSION_CACHED_CURSORS": true,
"SESSIONS_PER_USER": true,
"SET": true,
"SHARE": true,
"SHARED": true,
"SHARED_POOL": true,
"SHRINK": true,
"SIZE": true,
"SKIP": true,
"SKIP_UNUSABLE_INDEXES": true,
"SMALLINT": true,
"SNAPSHOT": true,
"SOME": true,
"SORT": true,
"SPECIFICATION": true,
"SPLIT": true,
"SQL_TRACE": true,
"STANDBY": true,
"START": true,
"STATEMENT_ID": true,
"STATISTICS": true,
"STOP": true,
"STORAGE": true,
"STORE": true,
"STRUCTURE": true,
"SUCCESSFUL": true,
"SWITCH": true,
"SYS_OP_ENFORCE_NOT_NULL$": true,
"SYS_OP_NTCIMG$": true,
"SYNONYM": true,
"SYSDATE": true,
"SYSDBA": true,
"SYSOPER": true,
"SYSTEM": true,
"TABLE": true,
"TABLES": true,
"TABLESPACE": true,
"TABLESPACE_NO": true,
"TABNO": true,
"TEMPORARY": true,
"THAN": true,
"THE": true,
"THEN": true,
"THREAD": true,
"TIMESTAMP": true,
"TIME": true,
"TO": true,
"TOPLEVEL": true,
"TRACE": true,
"TRACING": true,
"TRANSACTION": true,
"TRANSITIONAL": true,
"TRIGGER": true,
"TRIGGERS": true,
"TRUE": true,
"TRUNCATE": true,
"TX": true,
"TYPE": true,
"UB2": true,
"UBA": true,
"UID": true,
"UNARCHIVED": true,
"UNDO": true,
"UNION": true,
"UNIQUE": true,
"UNLIMITED": true,
"UNLOCK": true,
"UNRECOVERABLE": true,
"UNTIL": true,
"UNUSABLE": true,
"UNUSED": true,
"UPDATABLE": true,
"UPDATE": true,
"USAGE": true,
"USE": true,
"USER": true,
"USING": true,
"VALIDATE": true,
"VALIDATION": true,
"VALUE": true,
"VALUES": true,
"VARCHAR": true,
"VARCHAR2": true,
"VARYING": true,
"VIEW": true,
"WHEN": true,
"WHENEVER": true,
"WHERE": true,
"WITH": true,
"WITHOUT": true,
"WORK": true,
"WRITE": true,
"WRITEDOWN": true,
"WRITEUP": true,
"XID": true,
"YEAR": true,
"ZONE": true,
}
)
type oracle struct {
core.Base
}
func (db *oracle) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
return db.Base.Init(d, db, uri, drivername, dataSourceName)
}
func (db *oracle) SqlType(c *core.Column) string {
var res string
switch t := c.SQLType.Name; t {
case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt, core.Bool, core.Serial, core.BigSerial:
res = "NUMBER"
case core.Binary, core.VarBinary, core.Blob, core.TinyBlob, core.MediumBlob, core.LongBlob, core.Bytea:
return core.Blob
case core.Time, core.DateTime, core.TimeStamp:
res = core.TimeStamp
case core.TimeStampz:
res = "TIMESTAMP WITH TIME ZONE"
case core.Float, core.Double, core.Numeric, core.Decimal:
res = "NUMBER"
case core.Text, core.MediumText, core.LongText, core.Json:
res = "CLOB"
case core.Char, core.Varchar, core.TinyText:
res = "VARCHAR2"
default:
res = t
}
hasLen1 := (c.Length > 0)
hasLen2 := (c.Length2 > 0)
if hasLen2 {
res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
} else if hasLen1 {
res += "(" + strconv.Itoa(c.Length) + ")"
}
return res
}
func (db *oracle) AutoIncrStr() string {
return "AUTO_INCREMENT"
}
func (db *oracle) SupportInsertMany() bool {
return true
}
func (db *oracle) IsReserved(name string) bool {
_, ok := oracleReservedWords[name]
return ok
}
func (db *oracle) Quote(name string) string {
return "\"" + name + "\""
}
func (db *oracle) QuoteStr() string {
return "\""
}
func (db *oracle) SupportEngine() bool {
return false
}
func (db *oracle) SupportCharset() bool {
return false
}
func (db *oracle) SupportDropIfExists() bool {
return false
}
func (db *oracle) IndexOnTable() bool {
return false
}
func (db *oracle) DropTableSql(tableName string) string {
return fmt.Sprintf("DROP TABLE `%s`", tableName)
}
func (db *oracle) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string {
var sql string
sql = "CREATE TABLE "
if tableName == "" {
tableName = table.Name
}
sql += db.Quote(tableName) + " ("
pkList := table.PrimaryKeys
for _, colName := range table.ColumnsSeq() {
col := table.GetColumn(colName)
/*if col.IsPrimaryKey && len(pkList) == 1 {
sql += col.String(b.dialect)
} else {*/
sql += col.StringNoPk(db)
//}
sql = strings.TrimSpace(sql)
sql += ", "
}
if len(pkList) > 0 {
sql += "PRIMARY KEY ( "
sql += db.Quote(strings.Join(pkList, db.Quote(",")))
sql += " ), "
}
sql = sql[:len(sql)-2] + ")"
if db.SupportEngine() && storeEngine != "" {
sql += " ENGINE=" + storeEngine
}
if db.SupportCharset() {
if len(charset) == 0 {
charset = db.URI().Charset
}
if len(charset) > 0 {
sql += " DEFAULT CHARSET " + charset
}
}
return sql
}
func (db *oracle) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
args := []interface{}{tableName, idxName}
return `SELECT INDEX_NAME FROM USER_INDEXES ` +
`WHERE TABLE_NAME = :1 AND INDEX_NAME = :2`, args
}
func (db *oracle) TableCheckSql(tableName string) (string, []interface{}) {
args := []interface{}{tableName}
return `SELECT table_name FROM user_tables WHERE table_name = :1`, args
}
func (db *oracle) MustDropTable(tableName string) error {
sql, args := db.TableCheckSql(tableName)
db.LogSQL(sql, args)
rows, err := db.DB().Query(sql, args...)
if err != nil {
return err
}
defer rows.Close()
if !rows.Next() {
return nil
}
sql = "Drop Table \"" + tableName + "\""
db.LogSQL(sql, args)
_, err = db.DB().Exec(sql)
return err
}
/*func (db *oracle) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
args := []interface{}{strings.ToUpper(tableName), strings.ToUpper(colName)}
return "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = ?" +
" AND column_name = ?", args
}*/
func (db *oracle) IsColumnExist(tableName, colName string) (bool, error) {
args := []interface{}{tableName, colName}
query := "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = :1" +
" AND column_name = :2"
db.LogSQL(query, args)
rows, err := db.DB().Query(query, args...)
if err != nil {
return false, err
}
defer rows.Close()
if rows.Next() {
return true, nil
}
return false, nil
}
func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
args := []interface{}{tableName}
s := "SELECT column_name,data_default,data_type,data_length,data_precision,data_scale," +
"nullable FROM USER_TAB_COLUMNS WHERE table_name = :1"
db.LogSQL(s, args)
rows, err := db.DB().Query(s, args...)
if err != nil {
return nil, nil, err
}
defer rows.Close()
cols := make(map[string]*core.Column)
colSeq := make([]string, 0)
for rows.Next() {
col := new(core.Column)
col.Indexes = make(map[string]int)
var colName, colDefault, nullable, dataType, dataPrecision, dataScale *string
var dataLen int
err = rows.Scan(&colName, &colDefault, &dataType, &dataLen, &dataPrecision,
&dataScale, &nullable)
if err != nil {
return nil, nil, err
}
col.Name = strings.Trim(*colName, `" `)
if colDefault != nil {
col.Default = *colDefault
col.DefaultIsEmpty = false
}
if *nullable == "Y" {
col.Nullable = true
} else {
col.Nullable = false
}
var ignore bool
var dt string
var len1, len2 int
dts := strings.Split(*dataType, "(")
dt = dts[0]
if len(dts) > 1 {
lens := strings.Split(dts[1][:len(dts[1])-1], ",")
if len(lens) > 1 {
len1, _ = strconv.Atoi(lens[0])
len2, _ = strconv.Atoi(lens[1])
} else {
len1, _ = strconv.Atoi(lens[0])
}
}
switch dt {
case "VARCHAR2":
col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: len1, DefaultLength2: len2}
case "NVARCHAR2":
col.SQLType = core.SQLType{Name: core.NVarchar, DefaultLength: len1, DefaultLength2: len2}
case "TIMESTAMP WITH TIME ZONE":
col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
case "NUMBER":
col.SQLType = core.SQLType{Name: core.Double, DefaultLength: len1, DefaultLength2: len2}
case "LONG", "LONG RAW":
col.SQLType = core.SQLType{Name: core.Text, DefaultLength: 0, DefaultLength2: 0}
case "RAW":
col.SQLType = core.SQLType{Name: core.Binary, DefaultLength: 0, DefaultLength2: 0}
case "ROWID":
col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: 18, DefaultLength2: 0}
case "AQ$_SUBSCRIBERS":
ignore = true
default:
col.SQLType = core.SQLType{Name: strings.ToUpper(dt), DefaultLength: len1, DefaultLength2: len2}
}
if ignore {
continue
}
if _, ok := core.SqlTypes[col.SQLType.Name]; !ok {
return nil, nil, fmt.Errorf("Unknown colType %v %v", *dataType, col.SQLType)
}
col.Length = dataLen
if col.SQLType.IsText() || col.SQLType.IsTime() {
if !col.DefaultIsEmpty {
col.Default = "'" + col.Default + "'"
}
}
cols[col.Name] = col
colSeq = append(colSeq, col.Name)
}
return colSeq, cols, nil
}
func (db *oracle) GetTables() ([]*core.Table, error) {
args := []interface{}{}
s := "SELECT table_name FROM user_tables"
db.LogSQL(s, args)
rows, err := db.DB().Query(s, args...)
if err != nil {
return nil, err
}
defer rows.Close()
tables := make([]*core.Table, 0)
for rows.Next() {
table := core.NewEmptyTable()
err = rows.Scan(&table.Name)
if err != nil {
return nil, err
}
tables = append(tables, table)
}
return tables, nil
}
func (db *oracle) GetIndexes(tableName string) (map[string]*core.Index, error) {
args := []interface{}{tableName}
s := "SELECT t.column_name,i.uniqueness,i.index_name FROM user_ind_columns t,user_indexes i " +
"WHERE t.index_name = i.index_name and t.table_name = i.table_name and t.table_name =:1"
db.LogSQL(s, args)
rows, err := db.DB().Query(s, args...)
if err != nil {
return nil, err
}
defer rows.Close()
indexes := make(map[string]*core.Index, 0)
for rows.Next() {
var indexType int
var indexName, colName, uniqueness string
err = rows.Scan(&colName, &uniqueness, &indexName)
if err != nil {
return nil, err
}
indexName = strings.Trim(indexName, `" `)
var isRegular bool
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
indexName = indexName[5+len(tableName):]
isRegular = true
}
if uniqueness == "UNIQUE" {
indexType = core.UniqueType
} else {
indexType = core.IndexType
}
var index *core.Index
var ok bool
if index, ok = indexes[indexName]; !ok {
index = new(core.Index)
index.Type = indexType
index.Name = indexName
index.IsRegular = isRegular
indexes[indexName] = index
}
index.AddColumn(colName)
}
return indexes, nil
}
func (db *oracle) Filters() []core.Filter {
return []core.Filter{&core.QuoteFilter{}, &core.SeqFilter{Prefix: ":", Start: 1}, &core.IdFilter{}}
}
type goracleDriver struct {
}
func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
db := &core.Uri{DbType: core.ORACLE}
dsnPattern := regexp.MustCompile(
`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
`\/(?P<dbname>.*?)` + // /dbname
`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1&paramN=valueN]
matches := dsnPattern.FindStringSubmatch(dataSourceName)
//tlsConfigRegister := make(map[string]*tls.Config)
names := dsnPattern.SubexpNames()
for i, match := range matches {
switch names[i] {
case "dbname":
db.DbName = match
}
}
if db.DbName == "" {
return nil, errors.New("dbname is empty")
}
return db, nil
}
type oci8Driver struct {
}
//dataSourceName=user/password@ipv4:port/dbname
//dataSourceName=user/password@[ipv6]:port/dbname
func (p *oci8Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
db := &core.Uri{DbType: core.ORACLE}
dsnPattern := regexp.MustCompile(
`^(?P<user>.*)\/(?P<password>.*)@` + // user:password@
`(?P<net>.*)` + // ip:port
`\/(?P<dbname>.*)`) // dbname
matches := dsnPattern.FindStringSubmatch(dataSourceName)
names := dsnPattern.SubexpNames()
for i, match := range matches {
switch names[i] {
case "dbname":
db.DbName = match
}
}
if db.DbName == "" {
return nil, errors.New("dbname is empty")
}
return db, nil
}

File diff suppressed because it is too large Load Diff

View File

@ -1,456 +0,0 @@
// Copyright 2015 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 (
"database/sql"
"errors"
"fmt"
"regexp"
"strings"
"github.com/go-xorm/core"
)
var (
sqlite3ReservedWords = map[string]bool{
"ABORT": true,
"ACTION": true,
"ADD": true,
"AFTER": true,
"ALL": true,
"ALTER": true,
"ANALYZE": true,
"AND": true,
"AS": true,
"ASC": true,
"ATTACH": true,
"AUTOINCREMENT": true,
"BEFORE": true,
"BEGIN": true,
"BETWEEN": true,
"BY": true,
"CASCADE": true,
"CASE": true,
"CAST": true,
"CHECK": true,
"COLLATE": true,
"COLUMN": true,
"COMMIT": true,
"CONFLICT": true,
"CONSTRAINT": true,
"CREATE": true,
"CROSS": true,
"CURRENT_DATE": true,
"CURRENT_TIME": true,
"CURRENT_TIMESTAMP": true,
"DATABASE": true,
"DEFAULT": true,
"DEFERRABLE": true,
"DEFERRED": true,
"DELETE": true,
"DESC": true,
"DETACH": true,
"DISTINCT": true,
"DROP": true,
"EACH": true,
"ELSE": true,
"END": true,
"ESCAPE": true,
"EXCEPT": true,
"EXCLUSIVE": true,
"EXISTS": true,
"EXPLAIN": true,
"FAIL": true,
"FOR": true,
"FOREIGN": true,
"FROM": true,
"FULL": true,
"GLOB": true,
"GROUP": true,
"HAVING": true,
"IF": true,
"IGNORE": true,
"IMMEDIATE": true,
"IN": true,
"INDEX": true,
"INDEXED": true,
"INITIALLY": true,
"INNER": true,
"INSERT": true,
"INSTEAD": true,
"INTERSECT": true,
"INTO": true,
"IS": true,
"ISNULL": true,
"JOIN": true,
"KEY": true,
"LEFT": true,
"LIKE": true,
"LIMIT": true,
"MATCH": true,
"NATURAL": true,
"NO": true,
"NOT": true,
"NOTNULL": true,
"NULL": true,
"OF": true,
"OFFSET": true,
"ON": true,
"OR": true,
"ORDER": true,
"OUTER": true,
"PLAN": true,
"PRAGMA": true,
"PRIMARY": true,
"QUERY": true,
"RAISE": true,
"RECURSIVE": true,
"REFERENCES": true,
"REGEXP": true,
"REINDEX": true,
"RELEASE": true,
"RENAME": true,
"REPLACE": true,
"RESTRICT": true,
"RIGHT": true,
"ROLLBACK": true,
"ROW": true,
"SAVEPOINT": true,
"SELECT": true,
"SET": true,
"TABLE": true,
"TEMP": true,
"TEMPORARY": true,
"THEN": true,
"TO": true,
"TRANSACTI": true,
"TRIGGER": true,
"UNION": true,
"UNIQUE": true,
"UPDATE": true,
"USING": true,
"VACUUM": true,
"VALUES": true,
"VIEW": true,
"VIRTUAL": true,
"WHEN": true,
"WHERE": true,
"WITH": true,
"WITHOUT": true,
}
)
type sqlite3 struct {
core.Base
}
func (db *sqlite3) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
return db.Base.Init(d, db, uri, drivername, dataSourceName)
}
func (db *sqlite3) SqlType(c *core.Column) string {
switch t := c.SQLType.Name; t {
case core.Bool:
if c.Default == "true" {
c.Default = "1"
} else if c.Default == "false" {
c.Default = "0"
}
return core.Integer
case core.Date, core.DateTime, core.TimeStamp, core.Time:
return core.DateTime
case core.TimeStampz:
return core.Text
case core.Char, core.Varchar, core.NVarchar, core.TinyText,
core.Text, core.MediumText, core.LongText, core.Json:
return core.Text
case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt:
return core.Integer
case core.Float, core.Double, core.Real:
return core.Real
case core.Decimal, core.Numeric:
return core.Numeric
case core.TinyBlob, core.Blob, core.MediumBlob, core.LongBlob, core.Bytea, core.Binary, core.VarBinary:
return core.Blob
case core.Serial, core.BigSerial:
c.IsPrimaryKey = true
c.IsAutoIncrement = true
c.Nullable = false
return core.Integer
default:
return t
}
}
func (db *sqlite3) FormatBytes(bs []byte) string {
return fmt.Sprintf("X'%x'", bs)
}
func (db *sqlite3) SupportInsertMany() bool {
return true
}
func (db *sqlite3) IsReserved(name string) bool {
_, ok := sqlite3ReservedWords[name]
return ok
}
func (db *sqlite3) Quote(name string) string {
return "`" + name + "`"
}
func (db *sqlite3) QuoteStr() string {
return "`"
}
func (db *sqlite3) AutoIncrStr() string {
return "AUTOINCREMENT"
}
func (db *sqlite3) SupportEngine() bool {
return false
}
func (db *sqlite3) SupportCharset() bool {
return false
}
func (db *sqlite3) IndexOnTable() bool {
return false
}
func (db *sqlite3) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
args := []interface{}{idxName}
return "SELECT name FROM sqlite_master WHERE type='index' and name = ?", args
}
func (db *sqlite3) TableCheckSql(tableName string) (string, []interface{}) {
args := []interface{}{tableName}
return "SELECT name FROM sqlite_master WHERE type='table' and name = ?", args
}
func (db *sqlite3) DropIndexSql(tableName string, index *core.Index) string {
//var unique string
quote := db.Quote
idxName := index.Name
if !strings.HasPrefix(idxName, "UQE_") &&
!strings.HasPrefix(idxName, "IDX_") {
if index.Type == core.UniqueType {
idxName = fmt.Sprintf("UQE_%v_%v", tableName, index.Name)
} else {
idxName = fmt.Sprintf("IDX_%v_%v", tableName, index.Name)
}
}
return fmt.Sprintf("DROP INDEX %v", quote(idxName))
}
func (db *sqlite3) ForUpdateSql(query string) string {
return query
}
/*func (db *sqlite3) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
args := []interface{}{tableName}
sql := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
return sql, args
}*/
func (db *sqlite3) IsColumnExist(tableName, colName string) (bool, error) {
args := []interface{}{tableName}
query := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
db.LogSQL(query, args)
rows, err := db.DB().Query(query, args...)
if err != nil {
return false, err
}
defer rows.Close()
if rows.Next() {
return true, nil
}
return false, nil
}
func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
args := []interface{}{tableName}
s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?"
db.LogSQL(s, args)
rows, err := db.DB().Query(s, args...)
if err != nil {
return nil, nil, err
}
defer rows.Close()
var name string
for rows.Next() {
err = rows.Scan(&name)
if err != nil {
return nil, nil, err
}
break
}
if name == "" {
return nil, nil, errors.New("no table named " + tableName)
}
nStart := strings.Index(name, "(")
nEnd := strings.LastIndex(name, ")")
reg := regexp.MustCompile(`[^\(,\)]*(\([^\(]*\))?`)
colCreates := reg.FindAllString(name[nStart+1:nEnd], -1)
cols := make(map[string]*core.Column)
colSeq := make([]string, 0)
for _, colStr := range colCreates {
reg = regexp.MustCompile(`,\s`)
colStr = reg.ReplaceAllString(colStr, ",")
if strings.HasPrefix(strings.TrimSpace(colStr), "PRIMARY KEY") {
parts := strings.Split(strings.TrimSpace(colStr), "(")
if len(parts) == 2 {
pkCols := strings.Split(strings.TrimRight(strings.TrimSpace(parts[1]), ")"), ",")
for _, pk := range pkCols {
if col, ok := cols[strings.Trim(strings.TrimSpace(pk), "`")]; ok {
col.IsPrimaryKey = true
}
}
}
continue
}
fields := strings.Fields(strings.TrimSpace(colStr))
col := new(core.Column)
col.Indexes = make(map[string]int)
col.Nullable = true
col.DefaultIsEmpty = true
for idx, field := range fields {
if idx == 0 {
col.Name = strings.Trim(strings.Trim(field, "`[] "), `"`)
continue
} else if idx == 1 {
col.SQLType = core.SQLType{Name: field, DefaultLength: 0, DefaultLength2: 0}
}
switch field {
case "PRIMARY":
col.IsPrimaryKey = true
case "AUTOINCREMENT":
col.IsAutoIncrement = true
case "NULL":
if fields[idx-1] == "NOT" {
col.Nullable = false
} else {
col.Nullable = true
}
case "DEFAULT":
col.Default = fields[idx+1]
col.DefaultIsEmpty = false
}
}
if !col.SQLType.IsNumeric() && !col.DefaultIsEmpty {
col.Default = "'" + col.Default + "'"
}
cols[col.Name] = col
colSeq = append(colSeq, col.Name)
}
return colSeq, cols, nil
}
func (db *sqlite3) GetTables() ([]*core.Table, error) {
args := []interface{}{}
s := "SELECT name FROM sqlite_master WHERE type='table'"
db.LogSQL(s, args)
rows, err := db.DB().Query(s, args...)
if err != nil {
return nil, err
}
defer rows.Close()
tables := make([]*core.Table, 0)
for rows.Next() {
table := core.NewEmptyTable()
err = rows.Scan(&table.Name)
if err != nil {
return nil, err
}
if table.Name == "sqlite_sequence" {
continue
}
tables = append(tables, table)
}
return tables, nil
}
func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error) {
args := []interface{}{tableName}
s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?"
db.LogSQL(s, args)
rows, err := db.DB().Query(s, args...)
if err != nil {
return nil, err
}
defer rows.Close()
indexes := make(map[string]*core.Index, 0)
for rows.Next() {
var tmpSQL sql.NullString
err = rows.Scan(&tmpSQL)
if err != nil {
return nil, err
}
if !tmpSQL.Valid {
continue
}
sql := tmpSQL.String
index := new(core.Index)
nNStart := strings.Index(sql, "INDEX")
nNEnd := strings.Index(sql, "ON")
if nNStart == -1 || nNEnd == -1 {
continue
}
indexName := strings.Trim(sql[nNStart+6:nNEnd], "` []")
var isRegular bool
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
index.Name = indexName[5+len(tableName):]
isRegular = true
} else {
index.Name = indexName
}
if strings.HasPrefix(sql, "CREATE UNIQUE INDEX") {
index.Type = core.UniqueType
} else {
index.Type = core.IndexType
}
nStart := strings.Index(sql, "(")
nEnd := strings.Index(sql, ")")
colIndexes := strings.Split(sql[nStart+1:nEnd], ",")
index.Cols = make([]string, 0)
for _, col := range colIndexes {
index.Cols = append(index.Cols, strings.Trim(col, "` []"))
}
index.IsRegular = isRegular
indexes[index.Name] = index
}
return indexes, nil
}
func (db *sqlite3) Filters() []core.Filter {
return []core.Filter{&core.IdFilter{}}
}
type sqlite3Driver struct {
}
func (p *sqlite3Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
return &core.Uri{DbType: core.SQLITE, DbName: dataSourceName}, nil
}

184
vendor/github.com/go-xorm/xorm/doc.go generated vendored
View File

@ -1,184 +0,0 @@
// Copyright 2013 - 2016 The XORM Authors. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.
/*
Package xorm is a simple and powerful ORM for Go.
Installation
Make sure you have installed Go 1.6+ and then:
go get github.com/go-xorm/xorm
Create Engine
Firstly, we should new an engine for a database
engine, err := xorm.NewEngine(driverName, dataSourceName)
Method NewEngine's parameters is the same as sql.Open. It depends
drivers' implementation.
Generally, one engine for an application is enough. You can set it as package variable.
Raw Methods
XORM also support raw SQL execution:
1. query a SQL string, the returned results is []map[string][]byte
results, err := engine.Query("select * from user")
2. execute a SQL string, the returned results
affected, err := engine.Exec("update user set .... where ...")
ORM Methods
There are 8 major ORM methods and many helpful methods to use to operate database.
1. Insert one or multiple records to database
affected, err := engine.Insert(&struct)
// INSERT INTO struct () values ()
affected, err := engine.Insert(&struct1, &struct2)
// INSERT INTO struct1 () values ()
// INSERT INTO struct2 () values ()
affected, err := engine.Insert(&sliceOfStruct)
// INSERT INTO struct () values (),(),()
affected, err := engine.Insert(&struct1, &sliceOfStruct2)
// INSERT INTO struct1 () values ()
// INSERT INTO struct2 () values (),(),()
2. Query one record or one variable from database
has, err := engine.Get(&user)
// SELECT * FROM user LIMIT 1
var id int64
has, err := engine.Table("user").Where("name = ?", name).Get(&id)
// SELECT id FROM user WHERE name = ? LIMIT 1
3. Query multiple records from database
var sliceOfStructs []Struct
err := engine.Find(&sliceOfStructs)
// SELECT * FROM user
var mapOfStructs = make(map[int64]Struct)
err := engine.Find(&mapOfStructs)
// SELECT * FROM user
var int64s []int64
err := engine.Table("user").Cols("id").Find(&int64s)
// SELECT id FROM user
4. Query multiple records and record by record handle, there two methods, one is Iterate,
another is Rows
err := engine.Iterate(...)
// SELECT * FROM user
rows, err := engine.Rows(...)
// SELECT * FROM user
defer rows.Close()
bean := new(Struct)
for rows.Next() {
err = rows.Scan(bean)
}
5. Update one or more records
affected, err := engine.ID(...).Update(&user)
// UPDATE user SET ...
6. Delete one or more records, Delete MUST has condition
affected, err := engine.Where(...).Delete(&user)
// DELETE FROM user Where ...
7. Count records
counts, err := engine.Count(&user)
// SELECT count(*) AS total FROM user
counts, err := engine.SQL("select count(*) FROM user").Count()
// select count(*) FROM user
8. Sum records
sumFloat64, err := engine.Sum(&user, "id")
// SELECT sum(id) from user
sumFloat64s, err := engine.Sums(&user, "id1", "id2")
// SELECT sum(id1), sum(id2) from user
sumInt64s, err := engine.SumsInt(&user, "id1", "id2")
// SELECT sum(id1), sum(id2) from user
Conditions
The above 8 methods could use with condition methods chainable.
Attention: the above 8 methods should be the last chainable method.
1. ID, In
engine.ID(1).Get(&user) // for single primary key
// SELECT * FROM user WHERE id = 1
engine.ID(core.PK{1, 2}).Get(&user) // for composite primary keys
// SELECT * FROM user WHERE id1 = 1 AND id2 = 2
engine.In("id", 1, 2, 3).Find(&users)
// SELECT * FROM user WHERE id IN (1, 2, 3)
engine.In("id", []int{1, 2, 3}).Find(&users)
// SELECT * FROM user WHERE id IN (1, 2, 3)
2. Where, And, Or
engine.Where().And().Or().Find()
// SELECT * FROM user WHERE (.. AND ..) OR ...
3. OrderBy, Asc, Desc
engine.Asc().Desc().Find()
// SELECT * FROM user ORDER BY .. ASC, .. DESC
engine.OrderBy().Find()
// SELECT * FROM user ORDER BY ..
4. Limit, Top
engine.Limit().Find()
// SELECT * FROM user LIMIT .. OFFSET ..
engine.Top(5).Find()
// SELECT TOP 5 * FROM user // for mssql
// SELECT * FROM user LIMIT .. OFFSET 0 //for other databases
5. SQL, let you custom SQL
var users []User
engine.SQL("select * from user").Find(&users)
6. Cols, Omit, Distinct
var users []*User
engine.Cols("col1, col2").Find(&users)
// SELECT col1, col2 FROM user
engine.Cols("col1", "col2").Where().Update(user)
// UPDATE user set col1 = ?, col2 = ? Where ...
engine.Omit("col1").Find(&users)
// SELECT col2, col3 FROM user
engine.Omit("col1").Insert(&user)
// INSERT INTO table (non-col1) VALUES ()
engine.Distinct("col1").Find(&users)
// SELECT DISTINCT col1 FROM user
7. Join, GroupBy, Having
engine.GroupBy("name").Having("name='xlw'").Find(&users)
//SELECT * FROM user GROUP BY name HAVING name='xlw'
engine.Join("LEFT", "userdetail", "user.id=userdetail.id").Find(&users)
//SELECT * FROM user LEFT JOIN userdetail ON user.id=userdetail.id
More usage, please visit http://xorm.io/docs
*/
package xorm

File diff suppressed because it is too large Load Diff

View File

@ -1,233 +0,0 @@
// 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 (
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"strings"
"time"
"github.com/go-xorm/builder"
"github.com/go-xorm/core"
)
func (engine *Engine) buildConds(table *core.Table, bean interface{},
includeVersion bool, includeUpdated bool, includeNil bool,
includeAutoIncr bool, allUseBool bool, useAllCols bool, unscoped bool,
mustColumnMap map[string]bool, tableName, aliasName string, addedTableName bool) (builder.Cond, error) {
var conds []builder.Cond
for _, col := range table.Columns() {
if !includeVersion && col.IsVersion {
continue
}
if !includeUpdated && col.IsUpdated {
continue
}
if !includeAutoIncr && col.IsAutoIncrement {
continue
}
if engine.dialect.DBType() == core.MSSQL && (col.SQLType.Name == core.Text || col.SQLType.IsBlob() || col.SQLType.Name == core.TimeStampz) {
continue
}
if col.SQLType.IsJson() {
continue
}
var colName string
if addedTableName {
var nm = tableName
if len(aliasName) > 0 {
nm = aliasName
}
colName = engine.Quote(nm) + "." + engine.Quote(col.Name)
} else {
colName = engine.Quote(col.Name)
}
fieldValuePtr, err := col.ValueOf(bean)
if err != nil {
if !strings.Contains(err.Error(), "is not valid") {
engine.logger.Warn(err)
}
continue
}
if col.IsDeleted && !unscoped { // tag "deleted" is enabled
conds = append(conds, engine.CondDeleted(colName))
}
fieldValue := *fieldValuePtr
if fieldValue.Interface() == nil {
continue
}
fieldType := reflect.TypeOf(fieldValue.Interface())
requiredField := useAllCols
if b, ok := getFlagForColumn(mustColumnMap, col); ok {
if b {
requiredField = true
} else {
continue
}
}
if fieldType.Kind() == reflect.Ptr {
if fieldValue.IsNil() {
if includeNil {
conds = append(conds, builder.Eq{colName: nil})
}
continue
} else if !fieldValue.IsValid() {
continue
} else {
// dereference ptr type to instance type
fieldValue = fieldValue.Elem()
fieldType = reflect.TypeOf(fieldValue.Interface())
requiredField = true
}
}
var val interface{}
switch fieldType.Kind() {
case reflect.Bool:
if allUseBool || requiredField {
val = fieldValue.Interface()
} else {
// if a bool in a struct, it will not be as a condition because it default is false,
// please use Where() instead
continue
}
case reflect.String:
if !requiredField && fieldValue.String() == "" {
continue
}
// for MyString, should convert to string or panic
if fieldType.String() != reflect.String.String() {
val = fieldValue.String()
} else {
val = fieldValue.Interface()
}
case reflect.Int8, reflect.Int16, reflect.Int, reflect.Int32, reflect.Int64:
if !requiredField && fieldValue.Int() == 0 {
continue
}
val = fieldValue.Interface()
case reflect.Float32, reflect.Float64:
if !requiredField && fieldValue.Float() == 0.0 {
continue
}
val = fieldValue.Interface()
case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64:
if !requiredField && fieldValue.Uint() == 0 {
continue
}
t := int64(fieldValue.Uint())
val = reflect.ValueOf(&t).Interface()
case reflect.Struct:
if fieldType.ConvertibleTo(core.TimeType) {
t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
continue
}
val = engine.formatColTime(col, t)
} else if _, ok := reflect.New(fieldType).Interface().(core.Conversion); ok {
continue
} else if valNul, ok := fieldValue.Interface().(driver.Valuer); ok {
val, _ = valNul.Value()
if val == nil {
continue
}
} else {
if col.SQLType.IsJson() {
if col.SQLType.IsText() {
bytes, err := json.Marshal(fieldValue.Interface())
if err != nil {
engine.logger.Error(err)
continue
}
val = string(bytes)
} else if col.SQLType.IsBlob() {
var bytes []byte
var err error
bytes, err = json.Marshal(fieldValue.Interface())
if err != nil {
engine.logger.Error(err)
continue
}
val = bytes
}
} else {
engine.autoMapType(fieldValue)
if table, ok := engine.Tables[fieldValue.Type()]; ok {
if len(table.PrimaryKeys) == 1 {
pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
// fix non-int pk issues
//if pkField.Int() != 0 {
if pkField.IsValid() && !isZero(pkField.Interface()) {
val = pkField.Interface()
} else {
continue
}
} else {
//TODO: how to handler?
return nil, fmt.Errorf("not supported %v as %v", fieldValue.Interface(), table.PrimaryKeys)
}
} else {
val = fieldValue.Interface()
}
}
}
case reflect.Array:
continue
case reflect.Slice, reflect.Map:
if fieldValue == reflect.Zero(fieldType) {
continue
}
if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
continue
}
if col.SQLType.IsText() {
bytes, err := json.Marshal(fieldValue.Interface())
if err != nil {
engine.logger.Error(err)
continue
}
val = string(bytes)
} else if col.SQLType.IsBlob() {
var bytes []byte
var err error
if (fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice) &&
fieldType.Elem().Kind() == reflect.Uint8 {
if fieldValue.Len() > 0 {
val = fieldValue.Bytes()
} else {
continue
}
} else {
bytes, err = json.Marshal(fieldValue.Interface())
if err != nil {
engine.logger.Error(err)
continue
}
val = bytes
}
} else {
continue
}
default:
val = fieldValue.Interface()
}
conds = append(conds, builder.Eq{colName: val})
}
return builder.And(conds...), nil
}

View File

@ -1,194 +0,0 @@
// 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 (
"github.com/go-xorm/core"
)
// EngineGroup defines an engine group
type EngineGroup struct {
*Engine
slaves []*Engine
policy GroupPolicy
}
// NewEngineGroup creates a new engine group
func NewEngineGroup(args1 interface{}, args2 interface{}, policies ...GroupPolicy) (*EngineGroup, error) {
var eg EngineGroup
if len(policies) > 0 {
eg.policy = policies[0]
} else {
eg.policy = RoundRobinPolicy()
}
driverName, ok1 := args1.(string)
conns, ok2 := args2.([]string)
if ok1 && ok2 {
engines := make([]*Engine, len(conns))
for i, conn := range conns {
engine, err := NewEngine(driverName, conn)
if err != nil {
return nil, err
}
engine.engineGroup = &eg
engines[i] = engine
}
eg.Engine = engines[0]
eg.slaves = engines[1:]
return &eg, nil
}
master, ok3 := args1.(*Engine)
slaves, ok4 := args2.([]*Engine)
if ok3 && ok4 {
master.engineGroup = &eg
for i := 0; i < len(slaves); i++ {
slaves[i].engineGroup = &eg
}
eg.Engine = master
eg.slaves = slaves
return &eg, nil
}
return nil, ErrParamsType
}
// Close the engine
func (eg *EngineGroup) Close() error {
err := eg.Engine.Close()
if err != nil {
return err
}
for i := 0; i < len(eg.slaves); i++ {
err := eg.slaves[i].Close()
if err != nil {
return err
}
}
return nil
}
// Master returns the master engine
func (eg *EngineGroup) Master() *Engine {
return eg.Engine
}
// Ping tests if database is alive
func (eg *EngineGroup) Ping() error {
if err := eg.Engine.Ping(); err != nil {
return err
}
for _, slave := range eg.slaves {
if err := slave.Ping(); err != nil {
return err
}
}
return nil
}
// SetColumnMapper set the column name mapping rule
func (eg *EngineGroup) SetColumnMapper(mapper core.IMapper) {
eg.Engine.ColumnMapper = mapper
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].ColumnMapper = mapper
}
}
// SetDefaultCacher set the default cacher
func (eg *EngineGroup) SetDefaultCacher(cacher core.Cacher) {
eg.Engine.SetDefaultCacher(cacher)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].SetDefaultCacher(cacher)
}
}
// SetLogger set the new logger
func (eg *EngineGroup) SetLogger(logger core.ILogger) {
eg.Engine.SetLogger(logger)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].SetLogger(logger)
}
}
// SetLogLevel sets the logger level
func (eg *EngineGroup) SetLogLevel(level core.LogLevel) {
eg.Engine.SetLogLevel(level)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].SetLogLevel(level)
}
}
// SetMapper set the name mapping rules
func (eg *EngineGroup) SetMapper(mapper core.IMapper) {
eg.Engine.SetMapper(mapper)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].SetMapper(mapper)
}
}
// SetMaxIdleConns set the max idle connections on pool, default is 2
func (eg *EngineGroup) SetMaxIdleConns(conns int) {
eg.Engine.db.SetMaxIdleConns(conns)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].db.SetMaxIdleConns(conns)
}
}
// SetMaxOpenConns is only available for go 1.2+
func (eg *EngineGroup) SetMaxOpenConns(conns int) {
eg.Engine.db.SetMaxOpenConns(conns)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].db.SetMaxOpenConns(conns)
}
}
// SetPolicy set the group policy
func (eg *EngineGroup) SetPolicy(policy GroupPolicy) *EngineGroup {
eg.policy = policy
return eg
}
// SetTableMapper set the table name mapping rule
func (eg *EngineGroup) SetTableMapper(mapper core.IMapper) {
eg.Engine.TableMapper = mapper
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].TableMapper = mapper
}
}
// ShowExecTime show SQL statement and execute time or not on logger if log level is great than INFO
func (eg *EngineGroup) ShowExecTime(show ...bool) {
eg.Engine.ShowExecTime(show...)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].ShowExecTime(show...)
}
}
// ShowSQL show SQL statement or not on logger if log level is great than INFO
func (eg *EngineGroup) ShowSQL(show ...bool) {
eg.Engine.ShowSQL(show...)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].ShowSQL(show...)
}
}
// Slave returns one of the physical databases which is a slave according the policy
func (eg *EngineGroup) Slave() *Engine {
switch len(eg.slaves) {
case 0:
return eg.Engine
case 1:
return eg.slaves[0]
}
return eg.policy.Slave(eg)
}
// Slaves returns all the slaves
func (eg *EngineGroup) Slaves() []*Engine {
return eg.slaves
}

View File

@ -1,116 +0,0 @@
// 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 (
"math/rand"
"sync"
"time"
)
// GroupPolicy is be used by chosing the current slave from slaves
type GroupPolicy interface {
Slave(*EngineGroup) *Engine
}
// GroupPolicyHandler should be used when a function is a GroupPolicy
type GroupPolicyHandler func(*EngineGroup) *Engine
// Slave implements the chosen of slaves
func (h GroupPolicyHandler) Slave(eg *EngineGroup) *Engine {
return h(eg)
}
// RandomPolicy implmentes randomly chose the slave of slaves
func RandomPolicy() GroupPolicyHandler {
var r = rand.New(rand.NewSource(time.Now().UnixNano()))
return func(g *EngineGroup) *Engine {
return g.Slaves()[r.Intn(len(g.Slaves()))]
}
}
// WeightRandomPolicy implmentes randomly chose the slave of slaves
func WeightRandomPolicy(weights []int) GroupPolicyHandler {
var rands = make([]int, 0, len(weights))
for i := 0; i < len(weights); i++ {
for n := 0; n < weights[i]; n++ {
rands = append(rands, i)
}
}
var r = rand.New(rand.NewSource(time.Now().UnixNano()))
return func(g *EngineGroup) *Engine {
var slaves = g.Slaves()
idx := rands[r.Intn(len(rands))]
if idx >= len(slaves) {
idx = len(slaves) - 1
}
return slaves[idx]
}
}
func RoundRobinPolicy() GroupPolicyHandler {
var pos = -1
var lock sync.Mutex
return func(g *EngineGroup) *Engine {
var slaves = g.Slaves()
lock.Lock()
defer lock.Unlock()
pos++
if pos >= len(slaves) {
pos = 0
}
return slaves[pos]
}
}
func WeightRoundRobinPolicy(weights []int) GroupPolicyHandler {
var rands = make([]int, 0, len(weights))
for i := 0; i < len(weights); i++ {
for n := 0; n < weights[i]; n++ {
rands = append(rands, i)
}
}
var pos = -1
var lock sync.Mutex
return func(g *EngineGroup) *Engine {
var slaves = g.Slaves()
lock.Lock()
defer lock.Unlock()
pos++
if pos >= len(rands) {
pos = 0
}
idx := rands[pos]
if idx >= len(slaves) {
idx = len(slaves) - 1
}
return slaves[idx]
}
}
// LeastConnPolicy implements GroupPolicy, every time will get the least connections slave
func LeastConnPolicy() GroupPolicyHandler {
return func(g *EngineGroup) *Engine {
var slaves = g.Slaves()
connections := 0
idx := 0
for i := 0; i < len(slaves); i++ {
openConnections := slaves[i].DB().Stats().OpenConnections
if i == 0 {
connections = openConnections
idx = i
} else if openConnections <= connections {
connections = openConnections
idx = i
}
}
return slaves[idx]
}
}

View File

@ -1,22 +0,0 @@
// 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.
// +build go1.6
package xorm
import "time"
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
func (engine *Engine) SetConnMaxLifetime(d time.Duration) {
engine.db.SetConnMaxLifetime(d)
}
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
func (eg *EngineGroup) SetConnMaxLifetime(d time.Duration) {
eg.Engine.SetConnMaxLifetime(d)
for i := 0; i < len(eg.slaves); i++ {
eg.slaves[i].SetConnMaxLifetime(d)
}
}

View File

@ -1,113 +0,0 @@
// Copyright 2018 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"
"strings"
"github.com/go-xorm/core"
)
// TableNameWithSchema will automatically add schema prefix on table name
func (engine *Engine) tbNameWithSchema(v string) string {
// Add schema name as prefix of table name.
// Only for postgres database.
if engine.dialect.DBType() == core.POSTGRES &&
engine.dialect.URI().Schema != "" &&
engine.dialect.URI().Schema != postgresPublicSchema &&
strings.Index(v, ".") == -1 {
return engine.dialect.URI().Schema + "." + v
}
return v
}
// TableName returns table name with schema prefix if has
func (engine *Engine) TableName(bean interface{}, includeSchema ...bool) string {
tbName := engine.tbNameNoSchema(bean)
if len(includeSchema) > 0 && includeSchema[0] {
tbName = engine.tbNameWithSchema(tbName)
}
return tbName
}
// tbName get some table's table name
func (session *Session) tbNameNoSchema(table *core.Table) string {
if len(session.statement.AltTableName) > 0 {
return session.statement.AltTableName
}
return table.Name
}
func (engine *Engine) tbNameForMap(v reflect.Value) string {
if v.Type().Implements(tpTableName) {
return v.Interface().(TableName).TableName()
}
if v.Kind() == reflect.Ptr {
v = v.Elem()
if v.Type().Implements(tpTableName) {
return v.Interface().(TableName).TableName()
}
}
return engine.TableMapper.Obj2Table(v.Type().Name())
}
func (engine *Engine) tbNameNoSchema(tablename interface{}) string {
switch tablename.(type) {
case []string:
t := tablename.([]string)
if len(t) > 1 {
return fmt.Sprintf("%v AS %v", engine.Quote(t[0]), engine.Quote(t[1]))
} else if len(t) == 1 {
return engine.Quote(t[0])
}
case []interface{}:
t := tablename.([]interface{})
l := len(t)
var table string
if l > 0 {
f := t[0]
switch f.(type) {
case string:
table = f.(string)
case TableName:
table = f.(TableName).TableName()
default:
v := rValue(f)
t := v.Type()
if t.Kind() == reflect.Struct {
table = engine.tbNameForMap(v)
} else {
table = engine.Quote(fmt.Sprintf("%v", f))
}
}
}
if l > 1 {
return fmt.Sprintf("%v AS %v", engine.Quote(table),
engine.Quote(fmt.Sprintf("%v", t[1])))
} else if l == 1 {
return engine.Quote(table)
}
case TableName:
return tablename.(TableName).TableName()
case string:
return tablename.(string)
case reflect.Value:
v := tablename.(reflect.Value)
return engine.tbNameForMap(v)
default:
v := rValue(tablename)
t := v.Type()
if t.Kind() == reflect.Struct {
return engine.tbNameForMap(v)
}
return engine.Quote(fmt.Sprintf("%v", tablename))
}
return ""
}

View File

@ -1,41 +0,0 @@
// Copyright 2015 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 (
"errors"
"fmt"
)
var (
// ErrParamsType params error
ErrParamsType = errors.New("Params type error")
// ErrTableNotFound table not found error
ErrTableNotFound = errors.New("Not found table")
// ErrUnSupportedType unsupported error
ErrUnSupportedType = errors.New("Unsupported type error")
// ErrNotExist record is not exist error
ErrNotExist = errors.New("Not exist error")
// ErrCacheFailed cache failed error
ErrCacheFailed = errors.New("Cache failed")
// ErrNeedDeletedCond delete needs less one condition error
ErrNeedDeletedCond = errors.New("Delete need at least one condition")
// ErrNotImplemented not implemented
ErrNotImplemented = errors.New("Not implemented")
// ErrConditionType condition type unsupported
ErrConditionType = errors.New("Unsupported conditon type")
// ErrColumnIsNotExist columns is not exist
ErrFieldIsNotExist = errors.New("Field is not exist")
)
// ErrFieldIsNotValid is not valid
type ErrFieldIsNotValid struct {
FieldName string
TableName string
}
func (e ErrFieldIsNotValid) Error() string {
return fmt.Sprintf("field %s is not valid on table %s", e.FieldName, e.TableName)
}

View File

@ -1,6 +0,0 @@
#!/bin/bash
if [ -f $1 ];then
cat $1| awk '{printf("\""$1"\":true,\n")}'
else
echo "argument $1 if not a file!"
fi

View File

@ -1,6 +0,0 @@
module "github.com/go-xorm/xorm"
require (
"github.com/go-xorm/builder" v0.0.0-20180322150003-a9b7ffcca3f0
"github.com/go-xorm/core" v0.0.0-20180322150003-0177c08cee88
)

View File

@ -1,311 +0,0 @@
// Copyright 2015 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 (
"errors"
"fmt"
"reflect"
"sort"
"strconv"
"strings"
"github.com/go-xorm/core"
)
// str2PK convert string value to primary key value according to tp
func str2PKValue(s string, tp reflect.Type) (reflect.Value, error) {
var err error
var result interface{}
var defReturn = reflect.Zero(tp)
switch tp.Kind() {
case reflect.Int:
result, err = strconv.Atoi(s)
if err != nil {
return defReturn, fmt.Errorf("convert %s as int: %s", s, err.Error())
}
case reflect.Int8:
x, err := strconv.Atoi(s)
if err != nil {
return defReturn, fmt.Errorf("convert %s as int8: %s", s, err.Error())
}
result = int8(x)
case reflect.Int16:
x, err := strconv.Atoi(s)
if err != nil {
return defReturn, fmt.Errorf("convert %s as int16: %s", s, err.Error())
}
result = int16(x)
case reflect.Int32:
x, err := strconv.Atoi(s)
if err != nil {
return defReturn, fmt.Errorf("convert %s as int32: %s", s, err.Error())
}
result = int32(x)
case reflect.Int64:
result, err = strconv.ParseInt(s, 10, 64)
if err != nil {
return defReturn, fmt.Errorf("convert %s as int64: %s", s, err.Error())
}
case reflect.Uint:
x, err := strconv.ParseUint(s, 10, 64)
if err != nil {
return defReturn, fmt.Errorf("convert %s as uint: %s", s, err.Error())
}
result = uint(x)
case reflect.Uint8:
x, err := strconv.ParseUint(s, 10, 64)
if err != nil {
return defReturn, fmt.Errorf("convert %s as uint8: %s", s, err.Error())
}
result = uint8(x)
case reflect.Uint16:
x, err := strconv.ParseUint(s, 10, 64)
if err != nil {
return defReturn, fmt.Errorf("convert %s as uint16: %s", s, err.Error())
}
result = uint16(x)
case reflect.Uint32:
x, err := strconv.ParseUint(s, 10, 64)
if err != nil {
return defReturn, fmt.Errorf("convert %s as uint32: %s", s, err.Error())
}
result = uint32(x)
case reflect.Uint64:
result, err = strconv.ParseUint(s, 10, 64)
if err != nil {
return defReturn, fmt.Errorf("convert %s as uint64: %s", s, err.Error())
}
case reflect.String:
result = s
default:
return defReturn, errors.New("unsupported convert type")
}
return reflect.ValueOf(result).Convert(tp), nil
}
func str2PK(s string, tp reflect.Type) (interface{}, error) {
v, err := str2PKValue(s, tp)
if err != nil {
return nil, err
}
return v.Interface(), nil
}
func splitTag(tag string) (tags []string) {
tag = strings.TrimSpace(tag)
var hasQuote = false
var lastIdx = 0
for i, t := range tag {
if t == '\'' {
hasQuote = !hasQuote
} else if t == ' ' {
if lastIdx < i && !hasQuote {
tags = append(tags, strings.TrimSpace(tag[lastIdx:i]))
lastIdx = i + 1
}
}
}
if lastIdx < len(tag) {
tags = append(tags, strings.TrimSpace(tag[lastIdx:]))
}
return
}
type zeroable interface {
IsZero() bool
}
func isZero(k interface{}) bool {
switch k.(type) {
case int:
return k.(int) == 0
case int8:
return k.(int8) == 0
case int16:
return k.(int16) == 0
case int32:
return k.(int32) == 0
case int64:
return k.(int64) == 0
case uint:
return k.(uint) == 0
case uint8:
return k.(uint8) == 0
case uint16:
return k.(uint16) == 0
case uint32:
return k.(uint32) == 0
case uint64:
return k.(uint64) == 0
case float32:
return k.(float32) == 0
case float64:
return k.(float64) == 0
case bool:
return k.(bool) == false
case string:
return k.(string) == ""
case zeroable:
return k.(zeroable).IsZero()
}
return false
}
func isStructZero(v reflect.Value) bool {
if !v.IsValid() {
return true
}
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
switch field.Kind() {
case reflect.Ptr:
field = field.Elem()
fallthrough
case reflect.Struct:
if !isStructZero(field) {
return false
}
default:
if field.CanInterface() && !isZero(field.Interface()) {
return false
}
}
}
return true
}
func isArrayValueZero(v reflect.Value) bool {
if !v.IsValid() || v.Len() == 0 {
return true
}
for i := 0; i < v.Len(); i++ {
if !isZero(v.Index(i).Interface()) {
return false
}
}
return true
}
func int64ToIntValue(id int64, tp reflect.Type) reflect.Value {
var v interface{}
kind := tp.Kind()
if kind == reflect.Ptr {
kind = tp.Elem().Kind()
}
switch kind {
case reflect.Int16:
temp := int16(id)
v = &temp
case reflect.Int32:
temp := int32(id)
v = &temp
case reflect.Int:
temp := int(id)
v = &temp
case reflect.Int64:
temp := id
v = &temp
case reflect.Uint16:
temp := uint16(id)
v = &temp
case reflect.Uint32:
temp := uint32(id)
v = &temp
case reflect.Uint64:
temp := uint64(id)
v = &temp
case reflect.Uint:
temp := uint(id)
v = &temp
}
if tp.Kind() == reflect.Ptr {
return reflect.ValueOf(v).Convert(tp)
}
return reflect.ValueOf(v).Elem().Convert(tp)
}
func int64ToInt(id int64, tp reflect.Type) interface{} {
return int64ToIntValue(id, tp).Interface()
}
func isPKZero(pk core.PK) bool {
for _, k := range pk {
if isZero(k) {
return true
}
}
return false
}
func indexNoCase(s, sep string) int {
return strings.Index(strings.ToLower(s), strings.ToLower(sep))
}
func splitNoCase(s, sep string) []string {
idx := indexNoCase(s, sep)
if idx < 0 {
return []string{s}
}
return strings.Split(s, s[idx:idx+len(sep)])
}
func splitNNoCase(s, sep string, n int) []string {
idx := indexNoCase(s, sep)
if idx < 0 {
return []string{s}
}
return strings.SplitN(s, s[idx:idx+len(sep)], n)
}
func makeArray(elem string, count int) []string {
res := make([]string, count)
for i := 0; i < count; i++ {
res[i] = elem
}
return res
}
func rValue(bean interface{}) reflect.Value {
return reflect.Indirect(reflect.ValueOf(bean))
}
func rType(bean interface{}) reflect.Type {
sliceValue := reflect.Indirect(reflect.ValueOf(bean))
//return reflect.TypeOf(sliceValue.Interface())
return sliceValue.Type()
}
func structName(v reflect.Type) string {
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
return v.Name()
}
func sliceEq(left, right []string) bool {
if len(left) != len(right) {
return false
}
sort.Sort(sort.StringSlice(left))
sort.Sort(sort.StringSlice(right))
for i := 0; i < len(left); i++ {
if left[i] != right[i] {
return false
}
}
return true
}
func indexName(tableName, idxName string) string {
return fmt.Sprintf("IDX_%v_%v", tableName, idxName)
}

View File

@ -1,21 +0,0 @@
// 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 "time"
const (
zeroTime0 = "0000-00-00 00:00:00"
zeroTime1 = "0001-01-01 00:00:00"
)
func formatTime(t time.Time) string {
return t.Format("2006-01-02 15:04:05")
}
func isTimeZero(t time.Time) bool {
return t.IsZero() || formatTime(t) == zeroTime0 ||
formatTime(t) == zeroTime1
}

View File

@ -1,109 +0,0 @@
// 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 (
"database/sql"
"reflect"
"time"
"github.com/go-xorm/core"
)
// Interface defines the interface which Engine, EngineGroup and Session will implementate.
type Interface interface {
AllCols() *Session
Alias(alias string) *Session
Asc(colNames ...string) *Session
BufferSize(size int) *Session
Cols(columns ...string) *Session
Count(...interface{}) (int64, error)
CreateIndexes(bean interface{}) error
CreateUniques(bean interface{}) error
Decr(column string, arg ...interface{}) *Session
Desc(...string) *Session
Delete(interface{}) (int64, error)
Distinct(columns ...string) *Session
DropIndexes(bean interface{}) error
Exec(string, ...interface{}) (sql.Result, error)
Exist(bean ...interface{}) (bool, error)
Find(interface{}, ...interface{}) error
FindAndCount(interface{}, ...interface{}) (int64, error)
Get(interface{}) (bool, error)
GroupBy(keys string) *Session
ID(interface{}) *Session
In(string, ...interface{}) *Session
Incr(column string, arg ...interface{}) *Session
Insert(...interface{}) (int64, error)
InsertOne(interface{}) (int64, error)
IsTableEmpty(bean interface{}) (bool, error)
IsTableExist(beanOrTableName interface{}) (bool, error)
Iterate(interface{}, IterFunc) error
Limit(int, ...int) *Session
MustCols(columns ...string) *Session
NoAutoCondition(...bool) *Session
NotIn(string, ...interface{}) *Session
Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session
Omit(columns ...string) *Session
OrderBy(order string) *Session
Ping() error
Query(sqlOrAgrs ...interface{}) (resultsSlice []map[string][]byte, err error)
QueryInterface(sqlorArgs ...interface{}) ([]map[string]interface{}, error)
QueryString(sqlorArgs ...interface{}) ([]map[string]string, error)
Rows(bean interface{}) (*Rows, error)
SetExpr(string, string) *Session
SQL(interface{}, ...interface{}) *Session
Sum(bean interface{}, colName string) (float64, error)
SumInt(bean interface{}, colName string) (int64, error)
Sums(bean interface{}, colNames ...string) ([]float64, error)
SumsInt(bean interface{}, colNames ...string) ([]int64, error)
Table(tableNameOrBean interface{}) *Session
Unscoped() *Session
Update(bean interface{}, condiBeans ...interface{}) (int64, error)
UseBool(...string) *Session
Where(interface{}, ...interface{}) *Session
}
// EngineInterface defines the interface which Engine, EngineGroup will implementate.
type EngineInterface interface {
Interface
Before(func(interface{})) *Session
Charset(charset string) *Session
CreateTables(...interface{}) error
DBMetas() ([]*core.Table, error)
Dialect() core.Dialect
DropTables(...interface{}) error
DumpAllToFile(fp string, tp ...core.DbType) error
GetCacher(string) core.Cacher
GetColumnMapper() core.IMapper
GetDefaultCacher() core.Cacher
GetTableMapper() core.IMapper
GetTZDatabase() *time.Location
GetTZLocation() *time.Location
NewSession() *Session
NoAutoTime() *Session
Quote(string) string
SetCacher(string, core.Cacher)
SetDefaultCacher(core.Cacher)
SetLogLevel(core.LogLevel)
SetMapper(core.IMapper)
SetSchema(string)
SetTZDatabase(tz *time.Location)
SetTZLocation(tz *time.Location)
ShowSQL(show ...bool)
Sync(...interface{}) error
Sync2(...interface{}) error
StoreEngine(storeEngine string) *Session
TableInfo(bean interface{}) *Table
TableName(interface{}, ...bool) string
UnMapType(reflect.Type)
}
var (
_ Interface = &Session{}
_ EngineInterface = &Engine{}
_ EngineInterface = &EngineGroup{}
)

View File

@ -1,187 +0,0 @@
// Copyright 2015 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"
"io"
"log"
"github.com/go-xorm/core"
)
// default log options
const (
DEFAULT_LOG_PREFIX = "[xorm]"
DEFAULT_LOG_FLAG = log.Ldate | log.Lmicroseconds
DEFAULT_LOG_LEVEL = core.LOG_DEBUG
)
var _ core.ILogger = DiscardLogger{}
// DiscardLogger don't log implementation for core.ILogger
type DiscardLogger struct{}
// Debug empty implementation
func (DiscardLogger) Debug(v ...interface{}) {}
// Debugf empty implementation
func (DiscardLogger) Debugf(format string, v ...interface{}) {}
// Error empty implementation
func (DiscardLogger) Error(v ...interface{}) {}
// Errorf empty implementation
func (DiscardLogger) Errorf(format string, v ...interface{}) {}
// Info empty implementation
func (DiscardLogger) Info(v ...interface{}) {}
// Infof empty implementation
func (DiscardLogger) Infof(format string, v ...interface{}) {}
// Warn empty implementation
func (DiscardLogger) Warn(v ...interface{}) {}
// Warnf empty implementation
func (DiscardLogger) Warnf(format string, v ...interface{}) {}
// Level empty implementation
func (DiscardLogger) Level() core.LogLevel {
return core.LOG_UNKNOWN
}
// SetLevel empty implementation
func (DiscardLogger) SetLevel(l core.LogLevel) {}
// ShowSQL empty implementation
func (DiscardLogger) ShowSQL(show ...bool) {}
// IsShowSQL empty implementation
func (DiscardLogger) IsShowSQL() bool {
return false
}
// SimpleLogger is the default implment of core.ILogger
type SimpleLogger struct {
DEBUG *log.Logger
ERR *log.Logger
INFO *log.Logger
WARN *log.Logger
level core.LogLevel
showSQL bool
}
var _ core.ILogger = &SimpleLogger{}
// NewSimpleLogger use a special io.Writer as logger output
func NewSimpleLogger(out io.Writer) *SimpleLogger {
return NewSimpleLogger2(out, DEFAULT_LOG_PREFIX, DEFAULT_LOG_FLAG)
}
// NewSimpleLogger2 let you customrize your logger prefix and flag
func NewSimpleLogger2(out io.Writer, prefix string, flag int) *SimpleLogger {
return NewSimpleLogger3(out, prefix, flag, DEFAULT_LOG_LEVEL)
}
// NewSimpleLogger3 let you customrize your logger prefix and flag and logLevel
func NewSimpleLogger3(out io.Writer, prefix string, flag int, l core.LogLevel) *SimpleLogger {
return &SimpleLogger{
DEBUG: log.New(out, fmt.Sprintf("%s [debug] ", prefix), flag),
ERR: log.New(out, fmt.Sprintf("%s [error] ", prefix), flag),
INFO: log.New(out, fmt.Sprintf("%s [info] ", prefix), flag),
WARN: log.New(out, fmt.Sprintf("%s [warn] ", prefix), flag),
level: l,
}
}
// Error implement core.ILogger
func (s *SimpleLogger) Error(v ...interface{}) {
if s.level <= core.LOG_ERR {
s.ERR.Output(2, fmt.Sprint(v...))
}
return
}
// Errorf implement core.ILogger
func (s *SimpleLogger) Errorf(format string, v ...interface{}) {
if s.level <= core.LOG_ERR {
s.ERR.Output(2, fmt.Sprintf(format, v...))
}
return
}
// Debug implement core.ILogger
func (s *SimpleLogger) Debug(v ...interface{}) {
if s.level <= core.LOG_DEBUG {
s.DEBUG.Output(2, fmt.Sprint(v...))
}
return
}
// Debugf implement core.ILogger
func (s *SimpleLogger) Debugf(format string, v ...interface{}) {
if s.level <= core.LOG_DEBUG {
s.DEBUG.Output(2, fmt.Sprintf(format, v...))
}
return
}
// Info implement core.ILogger
func (s *SimpleLogger) Info(v ...interface{}) {
if s.level <= core.LOG_INFO {
s.INFO.Output(2, fmt.Sprint(v...))
}
return
}
// Infof implement core.ILogger
func (s *SimpleLogger) Infof(format string, v ...interface{}) {
if s.level <= core.LOG_INFO {
s.INFO.Output(2, fmt.Sprintf(format, v...))
}
return
}
// Warn implement core.ILogger
func (s *SimpleLogger) Warn(v ...interface{}) {
if s.level <= core.LOG_WARNING {
s.WARN.Output(2, fmt.Sprint(v...))
}
return
}
// Warnf implement core.ILogger
func (s *SimpleLogger) Warnf(format string, v ...interface{}) {
if s.level <= core.LOG_WARNING {
s.WARN.Output(2, fmt.Sprintf(format, v...))
}
return
}
// Level implement core.ILogger
func (s *SimpleLogger) Level() core.LogLevel {
return s.level
}
// SetLevel implement core.ILogger
func (s *SimpleLogger) SetLevel(l core.LogLevel) {
s.level = l
return
}
// ShowSQL implement core.ILogger
func (s *SimpleLogger) ShowSQL(show ...bool) {
if len(show) == 0 {
s.showSQL = true
return
}
s.showSQL = show[0]
}
// IsShowSQL implement core.ILogger
func (s *SimpleLogger) IsShowSQL() bool {
return s.showSQL
}

View File

@ -1,746 +0,0 @@
A non-reserved non-reserved
ABORT non-reserved
ABS reserved reserved
ABSENT non-reserved non-reserved
ABSOLUTE non-reserved non-reserved non-reserved reserved
ACCESS non-reserved
ACCORDING non-reserved non-reserved
ACTION non-reserved non-reserved non-reserved reserved
ADA non-reserved non-reserved non-reserved
ADD non-reserved non-reserved non-reserved reserved
ADMIN non-reserved non-reserved non-reserved
AFTER non-reserved non-reserved non-reserved
AGGREGATE non-reserved
ALL reserved reserved reserved reserved
ALLOCATE reserved reserved reserved
ALSO non-reserved
ALTER non-reserved reserved reserved reserved
ALWAYS non-reserved non-reserved non-reserved
ANALYSE reserved
ANALYZE reserved
AND reserved reserved reserved reserved
ANY reserved reserved reserved reserved
ARE reserved reserved reserved
ARRAY reserved reserved reserved
ARRAY_AGG reserved reserved
ARRAY_MAX_CARDINALITY reserved
AS reserved reserved reserved reserved
ASC reserved non-reserved non-reserved reserved
ASENSITIVE reserved reserved
ASSERTION non-reserved non-reserved non-reserved reserved
ASSIGNMENT non-reserved non-reserved non-reserved
ASYMMETRIC reserved reserved reserved
AT non-reserved reserved reserved reserved
ATOMIC reserved reserved
ATTRIBUTE non-reserved non-reserved non-reserved
ATTRIBUTES non-reserved non-reserved
AUTHORIZATION reserved (can be function or type) reserved reserved reserved
AVG reserved reserved reserved
BACKWARD non-reserved
BASE64 non-reserved non-reserved
BEFORE non-reserved non-reserved non-reserved
BEGIN non-reserved reserved reserved reserved
BEGIN_FRAME reserved
BEGIN_PARTITION reserved
BERNOULLI non-reserved non-reserved
BETWEEN non-reserved (cannot be function or type) reserved reserved reserved
BIGINT non-reserved (cannot be function or type) reserved reserved
BINARY reserved (can be function or type) reserved reserved
BIT non-reserved (cannot be function or type) reserved
BIT_LENGTH reserved
BLOB reserved reserved
BLOCKED non-reserved non-reserved
BOM non-reserved non-reserved
BOOLEAN non-reserved (cannot be function or type) reserved reserved
BOTH reserved reserved reserved reserved
BREADTH non-reserved non-reserved
BY non-reserved reserved reserved reserved
C non-reserved non-reserved non-reserved
CACHE non-reserved
CALL reserved reserved
CALLED non-reserved reserved reserved
CARDINALITY reserved reserved
CASCADE non-reserved non-reserved non-reserved reserved
CASCADED non-reserved reserved reserved reserved
CASE reserved reserved reserved reserved
CAST reserved reserved reserved reserved
CATALOG non-reserved non-reserved non-reserved reserved
CATALOG_NAME non-reserved non-reserved non-reserved
CEIL reserved reserved
CEILING reserved reserved
CHAIN non-reserved non-reserved non-reserved
CHAR non-reserved (cannot be function or type) reserved reserved reserved
CHARACTER non-reserved (cannot be function or type) reserved reserved reserved
CHARACTERISTICS non-reserved non-reserved non-reserved
CHARACTERS non-reserved non-reserved
CHARACTER_LENGTH reserved reserved reserved
CHARACTER_SET_CATALOG non-reserved non-reserved non-reserved
CHARACTER_SET_NAME non-reserved non-reserved non-reserved
CHARACTER_SET_SCHEMA non-reserved non-reserved non-reserved
CHAR_LENGTH reserved reserved reserved
CHECK reserved reserved reserved reserved
CHECKPOINT non-reserved
CLASS non-reserved
CLASS_ORIGIN non-reserved non-reserved non-reserved
CLOB reserved reserved
CLOSE non-reserved reserved reserved reserved
CLUSTER non-reserved
COALESCE non-reserved (cannot be function or type) reserved reserved reserved
COBOL non-reserved non-reserved non-reserved
COLLATE reserved reserved reserved reserved
COLLATION reserved (can be function or type) non-reserved non-reserved reserved
COLLATION_CATALOG non-reserved non-reserved non-reserved
COLLATION_NAME non-reserved non-reserved non-reserved
COLLATION_SCHEMA non-reserved non-reserved non-reserved
COLLECT reserved reserved
COLUMN reserved reserved reserved reserved
COLUMNS non-reserved non-reserved
COLUMN_NAME non-reserved non-reserved non-reserved
COMMAND_FUNCTION non-reserved non-reserved non-reserved
COMMAND_FUNCTION_CODE non-reserved non-reserved
COMMENT non-reserved
COMMENTS non-reserved
COMMIT non-reserved reserved reserved reserved
COMMITTED non-reserved non-reserved non-reserved non-reserved
CONCURRENTLY reserved (can be function or type)
CONDITION reserved reserved
CONDITION_NUMBER non-reserved non-reserved non-reserved
CONFIGURATION non-reserved
CONNECT reserved reserved reserved
CONNECTION non-reserved non-reserved non-reserved reserved
CONNECTION_NAME non-reserved non-reserved non-reserved
CONSTRAINT reserved reserved reserved reserved
CONSTRAINTS non-reserved non-reserved non-reserved reserved
CONSTRAINT_CATALOG non-reserved non-reserved non-reserved
CONSTRAINT_NAME non-reserved non-reserved non-reserved
CONSTRAINT_SCHEMA non-reserved non-reserved non-reserved
CONSTRUCTOR non-reserved non-reserved
CONTAINS reserved non-reserved
CONTENT non-reserved non-reserved non-reserved
CONTINUE non-reserved non-reserved non-reserved reserved
CONTROL non-reserved non-reserved
CONVERSION non-reserved
CONVERT reserved reserved reserved
COPY non-reserved
CORR reserved reserved
CORRESPONDING reserved reserved reserved
COST non-reserved
COUNT reserved reserved reserved
COVAR_POP reserved reserved
COVAR_SAMP reserved reserved
CREATE reserved reserved reserved reserved
CROSS reserved (can be function or type) reserved reserved reserved
CSV non-reserved
CUBE reserved reserved
CUME_DIST reserved reserved
CURRENT non-reserved reserved reserved reserved
CURRENT_CATALOG reserved reserved reserved
CURRENT_DATE reserved reserved reserved reserved
CURRENT_DEFAULT_TRANSFORM_GROUP reserved reserved
CURRENT_PATH reserved reserved
CURRENT_ROLE reserved reserved reserved
CURRENT_ROW reserved
CURRENT_SCHEMA reserved (can be function or type) reserved reserved
CURRENT_TIME reserved reserved reserved reserved
CURRENT_TIMESTAMP reserved reserved reserved reserved
CURRENT_TRANSFORM_GROUP_FOR_TYPE reserved reserved
CURRENT_USER reserved reserved reserved reserved
CURSOR non-reserved reserved reserved reserved
CURSOR_NAME non-reserved non-reserved non-reserved
CYCLE non-reserved reserved reserved
DATA non-reserved non-reserved non-reserved non-reserved
DATABASE non-reserved
DATALINK reserved reserved
DATE reserved reserved reserved
DATETIME_INTERVAL_CODE non-reserved non-reserved non-reserved
DATETIME_INTERVAL_PRECISION non-reserved non-reserved non-reserved
DAY non-reserved reserved reserved reserved
DB non-reserved non-reserved
DEALLOCATE non-reserved reserved reserved reserved
DEC non-reserved (cannot be function or type) reserved reserved reserved
DECIMAL non-reserved (cannot be function or type) reserved reserved reserved
DECLARE non-reserved reserved reserved reserved
DEFAULT reserved reserved reserved reserved
DEFAULTS non-reserved non-reserved non-reserved
DEFERRABLE reserved non-reserved non-reserved reserved
DEFERRED non-reserved non-reserved non-reserved reserved
DEFINED non-reserved non-reserved
DEFINER non-reserved non-reserved non-reserved
DEGREE non-reserved non-reserved
DELETE non-reserved reserved reserved reserved
DELIMITER non-reserved
DELIMITERS non-reserved
DENSE_RANK reserved reserved
DEPTH non-reserved non-reserved
DEREF reserved reserved
DERIVED non-reserved non-reserved
DESC reserved non-reserved non-reserved reserved
DESCRIBE reserved reserved reserved
DESCRIPTOR non-reserved non-reserved reserved
DETERMINISTIC reserved reserved
DIAGNOSTICS non-reserved non-reserved reserved
DICTIONARY non-reserved
DISABLE non-reserved
DISCARD non-reserved
DISCONNECT reserved reserved reserved
DISPATCH non-reserved non-reserved
DISTINCT reserved reserved reserved reserved
DLNEWCOPY reserved reserved
DLPREVIOUSCOPY reserved reserved
DLURLCOMPLETE reserved reserved
DLURLCOMPLETEONLY reserved reserved
DLURLCOMPLETEWRITE reserved reserved
DLURLPATH reserved reserved
DLURLPATHONLY reserved reserved
DLURLPATHWRITE reserved reserved
DLURLSCHEME reserved reserved
DLURLSERVER reserved reserved
DLVALUE reserved reserved
DO reserved
DOCUMENT non-reserved non-reserved non-reserved
DOMAIN non-reserved non-reserved non-reserved reserved
DOUBLE non-reserved reserved reserved reserved
DROP non-reserved reserved reserved reserved
DYNAMIC reserved reserved
DYNAMIC_FUNCTION non-reserved non-reserved non-reserved
DYNAMIC_FUNCTION_CODE non-reserved non-reserved
EACH non-reserved reserved reserved
ELEMENT reserved reserved
ELSE reserved reserved reserved reserved
EMPTY non-reserved non-reserved
ENABLE non-reserved
ENCODING non-reserved non-reserved non-reserved
ENCRYPTED non-reserved
END reserved reserved reserved reserved
END-EXEC reserved reserved reserved
END_FRAME reserved
END_PARTITION reserved
ENFORCED non-reserved
ENUM non-reserved
EQUALS reserved non-reserved
ESCAPE non-reserved reserved reserved reserved
EVENT non-reserved
EVERY reserved reserved
EXCEPT reserved reserved reserved reserved
EXCEPTION reserved
EXCLUDE non-reserved non-reserved non-reserved
EXCLUDING non-reserved non-reserved non-reserved
EXCLUSIVE non-reserved
EXEC reserved reserved reserved
EXECUTE non-reserved reserved reserved reserved
EXISTS non-reserved (cannot be function or type) reserved reserved reserved
EXP reserved reserved
EXPLAIN non-reserved
EXPRESSION non-reserved
EXTENSION non-reserved
EXTERNAL non-reserved reserved reserved reserved
EXTRACT non-reserved (cannot be function or type) reserved reserved reserved
FALSE reserved reserved reserved reserved
FAMILY non-reserved
FETCH reserved reserved reserved reserved
FILE non-reserved non-reserved
FILTER reserved reserved
FINAL non-reserved non-reserved
FIRST non-reserved non-reserved non-reserved reserved
FIRST_VALUE reserved reserved
FLAG non-reserved non-reserved
FLOAT non-reserved (cannot be function or type) reserved reserved reserved
FLOOR reserved reserved
FOLLOWING non-reserved non-reserved non-reserved
FOR reserved reserved reserved reserved
FORCE non-reserved
FOREIGN reserved reserved reserved reserved
FORTRAN non-reserved non-reserved non-reserved
FORWARD non-reserved
FOUND non-reserved non-reserved reserved
FRAME_ROW reserved
FREE reserved reserved
FREEZE reserved (can be function or type)
FROM reserved reserved reserved reserved
FS non-reserved non-reserved
FULL reserved (can be function or type) reserved reserved reserved
FUNCTION non-reserved reserved reserved
FUNCTIONS non-reserved
FUSION reserved reserved
G non-reserved non-reserved
GENERAL non-reserved non-reserved
GENERATED non-reserved non-reserved
GET reserved reserved reserved
GLOBAL non-reserved reserved reserved reserved
GO non-reserved non-reserved reserved
GOTO non-reserved non-reserved reserved
GRANT reserved reserved reserved reserved
GRANTED non-reserved non-reserved non-reserved
GREATEST non-reserved (cannot be function or type)
GROUP reserved reserved reserved reserved
GROUPING reserved reserved
GROUPS reserved
HANDLER non-reserved
HAVING reserved reserved reserved reserved
HEADER non-reserved
HEX non-reserved non-reserved
HIERARCHY non-reserved non-reserved
HOLD non-reserved reserved reserved
HOUR non-reserved reserved reserved reserved
ID non-reserved non-reserved
IDENTITY non-reserved reserved reserved reserved
IF non-reserved
IGNORE non-reserved non-reserved
ILIKE reserved (can be function or type)
IMMEDIATE non-reserved non-reserved non-reserved reserved
IMMEDIATELY non-reserved
IMMUTABLE non-reserved
IMPLEMENTATION non-reserved non-reserved
IMPLICIT non-reserved
IMPORT reserved reserved
IN reserved reserved reserved reserved
INCLUDING non-reserved non-reserved non-reserved
INCREMENT non-reserved non-reserved non-reserved
INDENT non-reserved non-reserved
INDEX non-reserved
INDEXES non-reserved
INDICATOR reserved reserved reserved
INHERIT non-reserved
INHERITS non-reserved
INITIALLY reserved non-reserved non-reserved reserved
INLINE non-reserved
INNER reserved (can be function or type) reserved reserved reserved
INOUT non-reserved (cannot be function or type) reserved reserved
INPUT non-reserved non-reserved non-reserved reserved
INSENSITIVE non-reserved reserved reserved reserved
INSERT non-reserved reserved reserved reserved
INSTANCE non-reserved non-reserved
INSTANTIABLE non-reserved non-reserved
INSTEAD non-reserved non-reserved non-reserved
INT non-reserved (cannot be function or type) reserved reserved reserved
INTEGER non-reserved (cannot be function or type) reserved reserved reserved
INTEGRITY non-reserved non-reserved
INTERSECT reserved reserved reserved reserved
INTERSECTION reserved reserved
INTERVAL non-reserved (cannot be function or type) reserved reserved reserved
INTO reserved reserved reserved reserved
INVOKER non-reserved non-reserved non-reserved
IS reserved (can be function or type) reserved reserved reserved
ISNULL reserved (can be function or type)
ISOLATION non-reserved non-reserved non-reserved reserved
JOIN reserved (can be function or type) reserved reserved reserved
K non-reserved non-reserved
KEY non-reserved non-reserved non-reserved reserved
KEY_MEMBER non-reserved non-reserved
KEY_TYPE non-reserved non-reserved
LABEL non-reserved
LAG reserved reserved
LANGUAGE non-reserved reserved reserved reserved
LARGE non-reserved reserved reserved
LAST non-reserved non-reserved non-reserved reserved
LAST_VALUE reserved reserved
LATERAL reserved reserved reserved
LC_COLLATE non-reserved
LC_CTYPE non-reserved
LEAD reserved reserved
LEADING reserved reserved reserved reserved
LEAKPROOF non-reserved
LEAST non-reserved (cannot be function or type)
LEFT reserved (can be function or type) reserved reserved reserved
LENGTH non-reserved non-reserved non-reserved
LEVEL non-reserved non-reserved non-reserved reserved
LIBRARY non-reserved non-reserved
LIKE reserved (can be function or type) reserved reserved reserved
LIKE_REGEX reserved reserved
LIMIT reserved non-reserved non-reserved
LINK non-reserved non-reserved
LISTEN non-reserved
LN reserved reserved
LOAD non-reserved
LOCAL non-reserved reserved reserved reserved
LOCALTIME reserved reserved reserved
LOCALTIMESTAMP reserved reserved reserved
LOCATION non-reserved non-reserved non-reserved
LOCATOR non-reserved non-reserved
LOCK non-reserved
LOWER reserved reserved reserved
M non-reserved non-reserved
MAP non-reserved non-reserved
MAPPING non-reserved non-reserved non-reserved
MATCH non-reserved reserved reserved reserved
MATCHED non-reserved non-reserved
MATERIALIZED non-reserved
MAX reserved reserved reserved
MAXVALUE non-reserved non-reserved non-reserved
MAX_CARDINALITY reserved
MEMBER reserved reserved
MERGE reserved reserved
MESSAGE_LENGTH non-reserved non-reserved non-reserved
MESSAGE_OCTET_LENGTH non-reserved non-reserved non-reserved
MESSAGE_TEXT non-reserved non-reserved non-reserved
METHOD reserved reserved
MIN reserved reserved reserved
MINUTE non-reserved reserved reserved reserved
MINVALUE non-reserved non-reserved non-reserved
MOD reserved reserved
MODE non-reserved
MODIFIES reserved reserved
MODULE reserved reserved reserved
MONTH non-reserved reserved reserved reserved
MORE non-reserved non-reserved non-reserved
MOVE non-reserved
MULTISET reserved reserved
MUMPS non-reserved non-reserved non-reserved
NAME non-reserved non-reserved non-reserved non-reserved
NAMES non-reserved non-reserved non-reserved reserved
NAMESPACE non-reserved non-reserved
NATIONAL non-reserved (cannot be function or type) reserved reserved reserved
NATURAL reserved (can be function or type) reserved reserved reserved
NCHAR non-reserved (cannot be function or type) reserved reserved reserved
NCLOB reserved reserved
NESTING non-reserved non-reserved
NEW reserved reserved
NEXT non-reserved non-reserved non-reserved reserved
NFC non-reserved non-reserved
NFD non-reserved non-reserved
NFKC non-reserved non-reserved
NFKD non-reserved non-reserved
NIL non-reserved non-reserved
NO non-reserved reserved reserved reserved
NONE non-reserved (cannot be function or type) reserved reserved
NORMALIZE reserved reserved
NORMALIZED non-reserved non-reserved
NOT reserved reserved reserved reserved
NOTHING non-reserved
NOTIFY non-reserved
NOTNULL reserved (can be function or type)
NOWAIT non-reserved
NTH_VALUE reserved reserved
NTILE reserved reserved
NULL reserved reserved reserved reserved
NULLABLE non-reserved non-reserved non-reserved
NULLIF non-reserved (cannot be function or type) reserved reserved reserved
NULLS non-reserved non-reserved non-reserved
NUMBER non-reserved non-reserved non-reserved
NUMERIC non-reserved (cannot be function or type) reserved reserved reserved
OBJECT non-reserved non-reserved non-reserved
OCCURRENCES_REGEX reserved reserved
OCTETS non-reserved non-reserved
OCTET_LENGTH reserved reserved reserved
OF non-reserved reserved reserved reserved
OFF non-reserved non-reserved non-reserved
OFFSET reserved reserved reserved
OIDS non-reserved
OLD reserved reserved
ON reserved reserved reserved reserved
ONLY reserved reserved reserved reserved
OPEN reserved reserved reserved
OPERATOR non-reserved
OPTION non-reserved non-reserved non-reserved reserved
OPTIONS non-reserved non-reserved non-reserved
OR reserved reserved reserved reserved
ORDER reserved reserved reserved reserved
ORDERING non-reserved non-reserved
ORDINALITY non-reserved non-reserved
OTHERS non-reserved non-reserved
OUT non-reserved (cannot be function or type) reserved reserved
OUTER reserved (can be function or type) reserved reserved reserved
OUTPUT non-reserved non-reserved reserved
OVER reserved (can be function or type) reserved reserved
OVERLAPS reserved (can be function or type) reserved reserved reserved
OVERLAY non-reserved (cannot be function or type) reserved reserved
OVERRIDING non-reserved non-reserved
OWNED non-reserved
OWNER non-reserved
P non-reserved non-reserved
PAD non-reserved non-reserved reserved
PARAMETER reserved reserved
PARAMETER_MODE non-reserved non-reserved
PARAMETER_NAME non-reserved non-reserved
PARAMETER_ORDINAL_POSITION non-reserved non-reserved
PARAMETER_SPECIFIC_CATALOG non-reserved non-reserved
PARAMETER_SPECIFIC_NAME non-reserved non-reserved
PARAMETER_SPECIFIC_SCHEMA non-reserved non-reserved
PARSER non-reserved
PARTIAL non-reserved non-reserved non-reserved reserved
PARTITION non-reserved reserved reserved
PASCAL non-reserved non-reserved non-reserved
PASSING non-reserved non-reserved non-reserved
PASSTHROUGH non-reserved non-reserved
PASSWORD non-reserved
PATH non-reserved non-reserved
PERCENT reserved
PERCENTILE_CONT reserved reserved
PERCENTILE_DISC reserved reserved
PERCENT_RANK reserved reserved
PERIOD reserved
PERMISSION non-reserved non-reserved
PLACING reserved non-reserved non-reserved
PLANS non-reserved
PLI non-reserved non-reserved non-reserved
PORTION reserved
POSITION non-reserved (cannot be function or type) reserved reserved reserved
POSITION_REGEX reserved reserved
POWER reserved reserved
PRECEDES reserved
PRECEDING non-reserved non-reserved non-reserved
PRECISION non-reserved (cannot be function or type) reserved reserved reserved
PREPARE non-reserved reserved reserved reserved
PREPARED non-reserved
PRESERVE non-reserved non-reserved non-reserved reserved
PRIMARY reserved reserved reserved reserved
PRIOR non-reserved non-reserved non-reserved reserved
PRIVILEGES non-reserved non-reserved non-reserved reserved
PROCEDURAL non-reserved
PROCEDURE non-reserved reserved reserved reserved
PROGRAM non-reserved
PUBLIC non-reserved non-reserved reserved
QUOTE non-reserved
RANGE non-reserved reserved reserved
RANK reserved reserved
READ non-reserved non-reserved non-reserved reserved
READS reserved reserved
REAL non-reserved (cannot be function or type) reserved reserved reserved
REASSIGN non-reserved
RECHECK non-reserved
RECOVERY non-reserved non-reserved
RECURSIVE non-reserved reserved reserved
REF non-reserved reserved reserved
REFERENCES reserved reserved reserved reserved
REFERENCING reserved reserved
REFRESH non-reserved
REGR_AVGX reserved reserved
REGR_AVGY reserved reserved
REGR_COUNT reserved reserved
REGR_INTERCEPT reserved reserved
REGR_R2 reserved reserved
REGR_SLOPE reserved reserved
REGR_SXX reserved reserved
REGR_SXY reserved reserved
REGR_SYY reserved reserved
REINDEX non-reserved
RELATIVE non-reserved non-reserved non-reserved reserved
RELEASE non-reserved reserved reserved
RENAME non-reserved
REPEATABLE non-reserved non-reserved non-reserved non-reserved
REPLACE non-reserved
REPLICA non-reserved
REQUIRING non-reserved non-reserved
RESET non-reserved
RESPECT non-reserved non-reserved
RESTART non-reserved non-reserved non-reserved
RESTORE non-reserved non-reserved
RESTRICT non-reserved non-reserved non-reserved reserved
RESULT reserved reserved
RETURN reserved reserved
RETURNED_CARDINALITY non-reserved non-reserved
RETURNED_LENGTH non-reserved non-reserved non-reserved
RETURNED_OCTET_LENGTH non-reserved non-reserved non-reserved
RETURNED_SQLSTATE non-reserved non-reserved non-reserved
RETURNING reserved non-reserved non-reserved
RETURNS non-reserved reserved reserved
REVOKE non-reserved reserved reserved reserved
RIGHT reserved (can be function or type) reserved reserved reserved
ROLE non-reserved non-reserved non-reserved
ROLLBACK non-reserved reserved reserved reserved
ROLLUP reserved reserved
ROUTINE non-reserved non-reserved
ROUTINE_CATALOG non-reserved non-reserved
ROUTINE_NAME non-reserved non-reserved
ROUTINE_SCHEMA non-reserved non-reserved
ROW non-reserved (cannot be function or type) reserved reserved
ROWS non-reserved reserved reserved reserved
ROW_COUNT non-reserved non-reserved non-reserved
ROW_NUMBER reserved reserved
RULE non-reserved
SAVEPOINT non-reserved reserved reserved
SCALE non-reserved non-reserved non-reserved
SCHEMA non-reserved non-reserved non-reserved reserved
SCHEMA_NAME non-reserved non-reserved non-reserved
SCOPE reserved reserved
SCOPE_CATALOG non-reserved non-reserved
SCOPE_NAME non-reserved non-reserved
SCOPE_SCHEMA non-reserved non-reserved
SCROLL non-reserved reserved reserved reserved
SEARCH non-reserved reserved reserved
SECOND non-reserved reserved reserved reserved
SECTION non-reserved non-reserved reserved
SECURITY non-reserved non-reserved non-reserved
SELECT reserved reserved reserved reserved
SELECTIVE non-reserved non-reserved
SELF non-reserved non-reserved
SENSITIVE reserved reserved
SEQUENCE non-reserved non-reserved non-reserved
SEQUENCES non-reserved
SERIALIZABLE non-reserved non-reserved non-reserved non-reserved
SERVER non-reserved non-reserved non-reserved
SERVER_NAME non-reserved non-reserved non-reserved
SESSION non-reserved non-reserved non-reserved reserved
SESSION_USER reserved reserved reserved reserved
SET non-reserved reserved reserved reserved
SETOF non-reserved (cannot be function or type)
SETS non-reserved non-reserved
SHARE non-reserved
SHOW non-reserved
SIMILAR reserved (can be function or type) reserved reserved
SIMPLE non-reserved non-reserved non-reserved
SIZE non-reserved non-reserved reserved
SMALLINT non-reserved (cannot be function or type) reserved reserved reserved
SNAPSHOT non-reserved
SOME reserved reserved reserved reserved
SOURCE non-reserved non-reserved
SPACE non-reserved non-reserved reserved
SPECIFIC reserved reserved
SPECIFICTYPE reserved reserved
SPECIFIC_NAME non-reserved non-reserved
SQL reserved reserved reserved
SQLCODE reserved
SQLERROR reserved
SQLEXCEPTION reserved reserved
SQLSTATE reserved reserved reserved
SQLWARNING reserved reserved
SQRT reserved reserved
STABLE non-reserved
STANDALONE non-reserved non-reserved non-reserved
START non-reserved reserved reserved
STATE non-reserved non-reserved
STATEMENT non-reserved non-reserved non-reserved
STATIC reserved reserved
STATISTICS non-reserved
STDDEV_POP reserved reserved
STDDEV_SAMP reserved reserved
STDIN non-reserved
STDOUT non-reserved
STORAGE non-reserved
STRICT non-reserved
STRIP non-reserved non-reserved non-reserved
STRUCTURE non-reserved non-reserved
STYLE non-reserved non-reserved
SUBCLASS_ORIGIN non-reserved non-reserved non-reserved
SUBMULTISET reserved reserved
SUBSTRING non-reserved (cannot be function or type) reserved reserved reserved
SUBSTRING_REGEX reserved reserved
SUCCEEDS reserved
SUM reserved reserved reserved
SYMMETRIC reserved reserved reserved
SYSID non-reserved
SYSTEM non-reserved reserved reserved
SYSTEM_TIME reserved
SYSTEM_USER reserved reserved reserved
T non-reserved non-reserved
TABLE reserved reserved reserved reserved
TABLES non-reserved
TABLESAMPLE reserved reserved
TABLESPACE non-reserved
TABLE_NAME non-reserved non-reserved non-reserved
TEMP non-reserved
TEMPLATE non-reserved
TEMPORARY non-reserved non-reserved non-reserved reserved
TEXT non-reserved
THEN reserved reserved reserved reserved
TIES non-reserved non-reserved
TIME non-reserved (cannot be function or type) reserved reserved reserved
TIMESTAMP non-reserved (cannot be function or type) reserved reserved reserved
TIMEZONE_HOUR reserved reserved reserved
TIMEZONE_MINUTE reserved reserved reserved
TO reserved reserved reserved reserved
TOKEN non-reserved non-reserved
TOP_LEVEL_COUNT non-reserved non-reserved
TRAILING reserved reserved reserved reserved
TRANSACTION non-reserved non-reserved non-reserved reserved
TRANSACTIONS_COMMITTED non-reserved non-reserved
TRANSACTIONS_ROLLED_BACK non-reserved non-reserved
TRANSACTION_ACTIVE non-reserved non-reserved
TRANSFORM non-reserved non-reserved
TRANSFORMS non-reserved non-reserved
TRANSLATE reserved reserved reserved
TRANSLATE_REGEX reserved reserved
TRANSLATION reserved reserved reserved
TREAT non-reserved (cannot be function or type) reserved reserved
TRIGGER non-reserved reserved reserved
TRIGGER_CATALOG non-reserved non-reserved
TRIGGER_NAME non-reserved non-reserved
TRIGGER_SCHEMA non-reserved non-reserved
TRIM non-reserved (cannot be function or type) reserved reserved reserved
TRIM_ARRAY reserved reserved
TRUE reserved reserved reserved reserved
TRUNCATE non-reserved reserved reserved
TRUSTED non-reserved
TYPE non-reserved non-reserved non-reserved non-reserved
TYPES non-reserved
UESCAPE reserved reserved
UNBOUNDED non-reserved non-reserved non-reserved
UNCOMMITTED non-reserved non-reserved non-reserved non-reserved
UNDER non-reserved non-reserved
UNENCRYPTED non-reserved
UNION reserved reserved reserved reserved
UNIQUE reserved reserved reserved reserved
UNKNOWN non-reserved reserved reserved reserved
UNLINK non-reserved non-reserved
UNLISTEN non-reserved
UNLOGGED non-reserved
UNNAMED non-reserved non-reserved non-reserved
UNNEST reserved reserved
UNTIL non-reserved
UNTYPED non-reserved non-reserved
UPDATE non-reserved reserved reserved reserved
UPPER reserved reserved reserved
URI non-reserved non-reserved
USAGE non-reserved non-reserved reserved
USER reserved reserved reserved reserved
USER_DEFINED_TYPE_CATALOG non-reserved non-reserved
USER_DEFINED_TYPE_CODE non-reserved non-reserved
USER_DEFINED_TYPE_NAME non-reserved non-reserved
USER_DEFINED_TYPE_SCHEMA non-reserved non-reserved
USING reserved reserved reserved reserved
VACUUM non-reserved
VALID non-reserved non-reserved non-reserved
VALIDATE non-reserved
VALIDATOR non-reserved
VALUE non-reserved reserved reserved reserved
VALUES non-reserved (cannot be function or type) reserved reserved reserved
VALUE_OF reserved
VARBINARY reserved reserved
VARCHAR non-reserved (cannot be function or type) reserved reserved reserved
VARIADIC reserved
VARYING non-reserved reserved reserved reserved
VAR_POP reserved reserved
VAR_SAMP reserved reserved
VERBOSE reserved (can be function or type)
VERSION non-reserved non-reserved non-reserved
VERSIONING reserved
VIEW non-reserved non-reserved non-reserved reserved
VOLATILE non-reserved
WHEN reserved reserved reserved reserved
WHENEVER reserved reserved reserved
WHERE reserved reserved reserved reserved
WHITESPACE non-reserved non-reserved non-reserved
WIDTH_BUCKET reserved reserved
WINDOW reserved reserved reserved
WITH reserved reserved reserved reserved
WITHIN reserved reserved
WITHOUT non-reserved reserved reserved
WORK non-reserved non-reserved non-reserved reserved
WRAPPER non-reserved non-reserved non-reserved
WRITE non-reserved non-reserved non-reserved reserved
XML non-reserved reserved reserved
XMLAGG reserved reserved
XMLATTRIBUTES non-reserved (cannot be function or type) reserved reserved
XMLBINARY reserved reserved
XMLCAST reserved reserved
XMLCOMMENT reserved reserved
XMLCONCAT non-reserved (cannot be function or type) reserved reserved
XMLDECLARATION non-reserved non-reserved
XMLDOCUMENT reserved reserved
XMLELEMENT non-reserved (cannot be function or type) reserved reserved
XMLEXISTS non-reserved (cannot be function or type) reserved reserved
XMLFOREST non-reserved (cannot be function or type) reserved reserved
XMLITERATE reserved reserved
XMLNAMESPACES reserved reserved
XMLPARSE non-reserved (cannot be function or type) reserved reserved
XMLPI non-reserved (cannot be function or type) reserved reserved
XMLQUERY reserved reserved
XMLROOT non-reserved (cannot be function or type)
XMLSCHEMA non-reserved non-reserved
XMLSERIALIZE non-reserved (cannot be function or type) reserved reserved
XMLTABLE reserved reserved
XMLTEXT reserved reserved
XMLVALIDATE reserved reserved
YEAR non-reserved reserved reserved reserved
YES non-reserved non-reserved non-reserved
ZONE non-reserved non-reserved non-reserved reserved

View File

@ -1,78 +0,0 @@
// Copyright 2015 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
// BeforeInsertProcessor executed before an object is initially persisted to the database
type BeforeInsertProcessor interface {
BeforeInsert()
}
// BeforeUpdateProcessor executed before an object is updated
type BeforeUpdateProcessor interface {
BeforeUpdate()
}
// BeforeDeleteProcessor executed before an object is deleted
type BeforeDeleteProcessor interface {
BeforeDelete()
}
// BeforeSetProcessor executed before data set to the struct fields
type BeforeSetProcessor interface {
BeforeSet(string, Cell)
}
// AfterSetProcessor executed after data set to the struct fields
type AfterSetProcessor interface {
AfterSet(string, Cell)
}
// AfterInsertProcessor executed after an object is persisted to the database
type AfterInsertProcessor interface {
AfterInsert()
}
// AfterUpdateProcessor executed after an object has been updated
type AfterUpdateProcessor interface {
AfterUpdate()
}
// AfterDeleteProcessor executed after an object has been deleted
type AfterDeleteProcessor interface {
AfterDelete()
}
// AfterLoadProcessor executed after an ojbect has been loaded from database
type AfterLoadProcessor interface {
AfterLoad()
}
// AfterLoadSessionProcessor executed after an ojbect has been loaded from database with session parameter
type AfterLoadSessionProcessor interface {
AfterLoad(*Session)
}
type executedProcessorFunc func(*Session, interface{}) error
type executedProcessor struct {
fun executedProcessorFunc
session *Session
bean interface{}
}
func (executor *executedProcessor) execute() error {
return executor.fun(executor.session, executor.bean)
}
func (session *Session) executeProcessors() error {
processors := session.afterProcessors
session.afterProcessors = make([]executedProcessor, 0)
for _, processor := range processors {
if err := processor.execute(); err != nil {
return err
}
}
return nil
}

View File

@ -1,134 +0,0 @@
// Copyright 2015 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 (
"database/sql"
"fmt"
"reflect"
"github.com/go-xorm/core"
)
// Rows rows wrapper a rows to
type Rows struct {
NoTypeCheck bool
session *Session
rows *core.Rows
fields []string
beanType reflect.Type
lastError error
}
func newRows(session *Session, bean interface{}) (*Rows, error) {
rows := new(Rows)
rows.session = session
rows.beanType = reflect.Indirect(reflect.ValueOf(bean)).Type()
var sqlStr string
var args []interface{}
var err error
if err = rows.session.statement.setRefBean(bean); err != nil {
return nil, err
}
if len(session.statement.TableName()) <= 0 {
return nil, ErrTableNotFound
}
if rows.session.statement.RawSQL == "" {
sqlStr, args, err = rows.session.statement.genGetSQL(bean)
if err != nil {
return nil, err
}
} else {
sqlStr = rows.session.statement.RawSQL
args = rows.session.statement.RawParams
}
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()
if err != nil {
rows.lastError = err
rows.Close()
return nil, err
}
return rows, nil
}
// Next move cursor to next record, return false if end has reached
func (rows *Rows) Next() bool {
if rows.lastError == nil && rows.rows != nil {
hasNext := rows.rows.Next()
if !hasNext {
rows.lastError = sql.ErrNoRows
}
return hasNext
}
return false
}
// Err returns the error, if any, that was encountered during iteration. Err may be called after an explicit or implicit Close.
func (rows *Rows) Err() error {
return rows.lastError
}
// Scan row record to bean properties
func (rows *Rows) Scan(bean interface{}) error {
if rows.lastError != nil {
return rows.lastError
}
if !rows.NoTypeCheck && reflect.Indirect(reflect.ValueOf(bean)).Type() != rows.beanType {
return fmt.Errorf("scan arg is incompatible type to [%v]", rows.beanType)
}
if err := rows.session.statement.setRefBean(bean); err != nil {
return err
}
scanResults, err := rows.session.row2Slice(rows.rows, rows.fields, bean)
if err != nil {
return err
}
dataStruct := rValue(bean)
_, err = rows.session.slice2Bean(scanResults, rows.fields, bean, &dataStruct, rows.session.statement.RefTable)
if err != nil {
return err
}
return rows.session.executeProcessors()
}
// Close session if session.IsAutoClose is true, and claimed any opened resources
func (rows *Rows) Close() error {
if rows.session.isAutoClose {
defer rows.session.Close()
}
if rows.lastError == nil {
if rows.rows != nil {
rows.lastError = rows.rows.Close()
if rows.lastError != nil {
return rows.lastError
}
}
} else {
if rows.rows != nil {
defer rows.rows.Close()
}
}
return rows.lastError
}

View File

@ -1,841 +0,0 @@
// Copyright 2015 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 (
"database/sql"
"encoding/json"
"errors"
"fmt"
"hash/crc32"
"reflect"
"strings"
"time"
"github.com/go-xorm/core"
)
// Session keep a pointer to sql.DB and provides all execution of all
// kind of database operations.
type Session struct {
db *core.DB
engine *Engine
tx *core.Tx
statement Statement
isAutoCommit bool
isCommitedOrRollbacked bool
isAutoClose bool
// Automatically reset the statement after operations that execute a SQL
// query such as Count(), Find(), Get(), ...
autoResetStatement bool
// !nashtsai! storing these beans due to yet committed tx
afterInsertBeans map[interface{}]*[]func(interface{})
afterUpdateBeans map[interface{}]*[]func(interface{})
afterDeleteBeans map[interface{}]*[]func(interface{})
// --
beforeClosures []func(interface{})
afterClosures []func(interface{})
afterProcessors []executedProcessor
prepareStmt bool
stmtCache map[uint32]*core.Stmt //key: hash.Hash32 of (queryStr, len(queryStr))
// !evalphobia! stored the last executed query on this session
//beforeSQLExec func(string, ...interface{})
lastSQL string
lastSQLArgs []interface{}
err error
}
// Clone copy all the session's content and return a new session
func (session *Session) Clone() *Session {
var sess = *session
return &sess
}
// Init reset the session as the init status.
func (session *Session) Init() {
session.statement.Init()
session.statement.Engine = session.engine
session.isAutoCommit = true
session.isCommitedOrRollbacked = false
session.isAutoClose = false
session.autoResetStatement = true
session.prepareStmt = false
// !nashtsai! is lazy init better?
session.afterInsertBeans = make(map[interface{}]*[]func(interface{}), 0)
session.afterUpdateBeans = make(map[interface{}]*[]func(interface{}), 0)
session.afterDeleteBeans = make(map[interface{}]*[]func(interface{}), 0)
session.beforeClosures = make([]func(interface{}), 0)
session.afterClosures = make([]func(interface{}), 0)
session.stmtCache = make(map[uint32]*core.Stmt)
session.afterProcessors = make([]executedProcessor, 0)
session.lastSQL = ""
session.lastSQLArgs = []interface{}{}
}
// Close release the connection from pool
func (session *Session) Close() {
for _, v := range session.stmtCache {
v.Close()
}
if session.db != nil {
// When Close be called, if session is a transaction and do not call
// Commit or Rollback, then call Rollback.
if session.tx != nil && !session.isCommitedOrRollbacked {
session.Rollback()
}
session.tx = nil
session.stmtCache = nil
session.db = nil
}
}
// IsClosed returns if session is closed
func (session *Session) IsClosed() bool {
return session.db == nil
}
func (session *Session) resetStatement() {
if session.autoResetStatement {
session.statement.Init()
}
}
// Prepare set a flag to session that should be prepare statement before execute query
func (session *Session) Prepare() *Session {
session.prepareStmt = true
return session
}
// Before Apply before Processor, affected bean is passed to closure arg
func (session *Session) Before(closures func(interface{})) *Session {
if closures != nil {
session.beforeClosures = append(session.beforeClosures, closures)
}
return session
}
// After Apply after Processor, affected bean is passed to closure arg
func (session *Session) After(closures func(interface{})) *Session {
if closures != nil {
session.afterClosures = append(session.afterClosures, closures)
}
return session
}
// Table can input a string or pointer to struct for special a table to operate.
func (session *Session) Table(tableNameOrBean interface{}) *Session {
session.statement.Table(tableNameOrBean)
return session
}
// Alias set the table alias
func (session *Session) Alias(alias string) *Session {
session.statement.Alias(alias)
return session
}
// NoCascade indicate that no cascade load child object
func (session *Session) NoCascade() *Session {
session.statement.UseCascade = false
return session
}
// ForUpdate Set Read/Write locking for UPDATE
func (session *Session) ForUpdate() *Session {
session.statement.IsForUpdate = true
return session
}
// NoAutoCondition disable generate SQL condition from beans
func (session *Session) NoAutoCondition(no ...bool) *Session {
session.statement.NoAutoCondition(no...)
return session
}
// Limit provide limit and offset query condition
func (session *Session) Limit(limit int, start ...int) *Session {
session.statement.Limit(limit, start...)
return session
}
// OrderBy provide order by query condition, the input parameter is the content
// after order by on a sql statement.
func (session *Session) OrderBy(order string) *Session {
session.statement.OrderBy(order)
return session
}
// Desc provide desc order by query condition, the input parameters are columns.
func (session *Session) Desc(colNames ...string) *Session {
session.statement.Desc(colNames...)
return session
}
// Asc provide asc order by query condition, the input parameters are columns.
func (session *Session) Asc(colNames ...string) *Session {
session.statement.Asc(colNames...)
return session
}
// StoreEngine is only avialble mysql dialect currently
func (session *Session) StoreEngine(storeEngine string) *Session {
session.statement.StoreEngine = storeEngine
return session
}
// Charset is only avialble mysql dialect currently
func (session *Session) Charset(charset string) *Session {
session.statement.Charset = charset
return session
}
// Cascade indicates if loading sub Struct
func (session *Session) Cascade(trueOrFalse ...bool) *Session {
if len(trueOrFalse) >= 1 {
session.statement.UseCascade = trueOrFalse[0]
}
return session
}
// NoCache ask this session do not retrieve data from cache system and
// get data from database directly.
func (session *Session) NoCache() *Session {
session.statement.UseCache = false
return session
}
// Join join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
func (session *Session) Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session {
session.statement.Join(joinOperator, tablename, condition, args...)
return session
}
// GroupBy Generate Group By statement
func (session *Session) GroupBy(keys string) *Session {
session.statement.GroupBy(keys)
return session
}
// Having Generate Having statement
func (session *Session) Having(conditions string) *Session {
session.statement.Having(conditions)
return session
}
// DB db return the wrapper of sql.DB
func (session *Session) DB() *core.DB {
if session.db == nil {
session.db = session.engine.db
session.stmtCache = make(map[uint32]*core.Stmt, 0)
}
return session.db
}
func cleanupProcessorsClosures(slices *[]func(interface{})) {
if len(*slices) > 0 {
*slices = make([]func(interface{}), 0)
}
}
func (session *Session) canCache() bool {
if session.statement.RefTable == nil ||
session.statement.JoinStr != "" ||
session.statement.RawSQL != "" ||
!session.statement.UseCache ||
session.statement.IsForUpdate ||
session.tx != nil ||
len(session.statement.selectStr) > 0 {
return false
}
return true
}
func (session *Session) doPrepare(db *core.DB, sqlStr string) (stmt *core.Stmt, err error) {
crc := crc32.ChecksumIEEE([]byte(sqlStr))
// TODO try hash(sqlStr+len(sqlStr))
var has bool
stmt, has = session.stmtCache[crc]
if !has {
stmt, err = db.Prepare(sqlStr)
if err != nil {
return nil, err
}
session.stmtCache[crc] = stmt
}
return
}
func (session *Session) getField(dataStruct *reflect.Value, key string, table *core.Table, idx int) (*reflect.Value, error) {
var col *core.Column
if col = table.GetColumnIdx(key, idx); col == nil {
return nil, ErrFieldIsNotExist
}
fieldValue, err := col.ValueOfV(dataStruct)
if err != nil {
return nil, err
}
if !fieldValue.IsValid() || !fieldValue.CanSet() {
return nil, ErrFieldIsNotValid{key, table.Name}
}
return fieldValue, nil
}
// Cell cell is a result of one column field
type Cell *interface{}
func (session *Session) rows2Beans(rows *core.Rows, fields []string,
table *core.Table, newElemFunc func([]string) reflect.Value,
sliceValueSetFunc func(*reflect.Value, core.PK) error) error {
for rows.Next() {
var newValue = newElemFunc(fields)
bean := newValue.Interface()
dataStruct := newValue.Elem()
// handle beforeClosures
scanResults, err := session.row2Slice(rows, fields, bean)
if err != nil {
return err
}
pk, err := session.slice2Bean(scanResults, fields, bean, &dataStruct, table)
if err != nil {
return err
}
session.afterProcessors = append(session.afterProcessors, executedProcessor{
fun: func(*Session, interface{}) error {
return sliceValueSetFunc(&newValue, pk)
},
session: session,
bean: bean,
})
}
return nil
}
func (session *Session) row2Slice(rows *core.Rows, fields []string, bean interface{}) ([]interface{}, error) {
for _, closure := range session.beforeClosures {
closure(bean)
}
scanResults := make([]interface{}, len(fields))
for i := 0; i < len(fields); i++ {
var cell interface{}
scanResults[i] = &cell
}
if err := rows.Scan(scanResults...); err != nil {
return nil, err
}
if b, hasBeforeSet := bean.(BeforeSetProcessor); hasBeforeSet {
for ii, key := range fields {
b.BeforeSet(key, Cell(scanResults[ii].(*interface{})))
}
}
return scanResults, nil
}
func (session *Session) slice2Bean(scanResults []interface{}, fields []string, bean interface{}, dataStruct *reflect.Value, table *core.Table) (core.PK, error) {
defer func() {
if b, hasAfterSet := bean.(AfterSetProcessor); hasAfterSet {
for ii, key := range fields {
b.AfterSet(key, Cell(scanResults[ii].(*interface{})))
}
}
}()
// handle afterClosures
for _, closure := range session.afterClosures {
session.afterProcessors = append(session.afterProcessors, executedProcessor{
fun: func(sess *Session, bean interface{}) error {
closure(bean)
return nil
},
session: session,
bean: bean,
})
}
if a, has := bean.(AfterLoadProcessor); has {
session.afterProcessors = append(session.afterProcessors, executedProcessor{
fun: func(sess *Session, bean interface{}) error {
a.AfterLoad()
return nil
},
session: session,
bean: bean,
})
}
if a, has := bean.(AfterLoadSessionProcessor); has {
session.afterProcessors = append(session.afterProcessors, executedProcessor{
fun: func(sess *Session, bean interface{}) error {
a.AfterLoad(sess)
return nil
},
session: session,
bean: bean,
})
}
var tempMap = make(map[string]int)
var pk core.PK
for ii, key := range fields {
var idx int
var ok bool
var lKey = strings.ToLower(key)
if idx, ok = tempMap[lKey]; !ok {
idx = 0
} else {
idx = idx + 1
}
tempMap[lKey] = idx
fieldValue, err := session.getField(dataStruct, key, table, idx)
if err != nil {
if !strings.Contains(err.Error(), "is not valid") {
session.engine.logger.Warn(err)
}
continue
}
if fieldValue == nil {
continue
}
rawValue := reflect.Indirect(reflect.ValueOf(scanResults[ii]))
// if row is null then ignore
if rawValue.Interface() == nil {
continue
}
if fieldValue.CanAddr() {
if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
if data, err := value2Bytes(&rawValue); err == nil {
if err := structConvert.FromDB(data); err != nil {
return nil, err
}
} else {
return nil, err
}
continue
}
}
if _, ok := fieldValue.Interface().(core.Conversion); ok {
if data, err := value2Bytes(&rawValue); err == nil {
if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() {
fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
}
fieldValue.Interface().(core.Conversion).FromDB(data)
} else {
return nil, err
}
continue
}
rawValueType := reflect.TypeOf(rawValue.Interface())
vv := reflect.ValueOf(rawValue.Interface())
col := table.GetColumnIdx(key, idx)
if col.IsPrimaryKey {
pk = append(pk, rawValue.Interface())
}
fieldType := fieldValue.Type()
hasAssigned := false
if col.SQLType.IsJson() {
var bs []byte
if rawValueType.Kind() == reflect.String {
bs = []byte(vv.String())
} else if rawValueType.ConvertibleTo(core.BytesType) {
bs = vv.Bytes()
} else {
return nil, fmt.Errorf("unsupported database data type: %s %v", key, rawValueType.Kind())
}
hasAssigned = true
if len(bs) > 0 {
if fieldType.Kind() == reflect.String {
fieldValue.SetString(string(bs))
continue
}
if fieldValue.CanAddr() {
err := json.Unmarshal(bs, fieldValue.Addr().Interface())
if err != nil {
return nil, err
}
} else {
x := reflect.New(fieldType)
err := json.Unmarshal(bs, x.Interface())
if err != nil {
return nil, err
}
fieldValue.Set(x.Elem())
}
}
continue
}
switch fieldType.Kind() {
case reflect.Complex64, reflect.Complex128:
// TODO: reimplement this
var bs []byte
if rawValueType.Kind() == reflect.String {
bs = []byte(vv.String())
} else if rawValueType.ConvertibleTo(core.BytesType) {
bs = vv.Bytes()
}
hasAssigned = true
if len(bs) > 0 {
if fieldValue.CanAddr() {
err := json.Unmarshal(bs, fieldValue.Addr().Interface())
if err != nil {
return nil, err
}
} else {
x := reflect.New(fieldType)
err := json.Unmarshal(bs, x.Interface())
if err != nil {
return nil, err
}
fieldValue.Set(x.Elem())
}
}
case reflect.Slice, reflect.Array:
switch rawValueType.Kind() {
case reflect.Slice, reflect.Array:
switch rawValueType.Elem().Kind() {
case reflect.Uint8:
if fieldType.Elem().Kind() == reflect.Uint8 {
hasAssigned = true
if col.SQLType.IsText() {
x := reflect.New(fieldType)
err := json.Unmarshal(vv.Bytes(), x.Interface())
if err != nil {
return nil, err
}
fieldValue.Set(x.Elem())
} else {
if fieldValue.Len() > 0 {
for i := 0; i < fieldValue.Len(); i++ {
if i < vv.Len() {
fieldValue.Index(i).Set(vv.Index(i))
}
}
} else {
for i := 0; i < vv.Len(); i++ {
fieldValue.Set(reflect.Append(*fieldValue, vv.Index(i)))
}
}
}
}
}
}
case reflect.String:
if rawValueType.Kind() == reflect.String {
hasAssigned = true
fieldValue.SetString(vv.String())
}
case reflect.Bool:
if rawValueType.Kind() == reflect.Bool {
hasAssigned = true
fieldValue.SetBool(vv.Bool())
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
switch rawValueType.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
hasAssigned = true
fieldValue.SetInt(vv.Int())
}
case reflect.Float32, reflect.Float64:
switch rawValueType.Kind() {
case reflect.Float32, reflect.Float64:
hasAssigned = true
fieldValue.SetFloat(vv.Float())
}
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
switch rawValueType.Kind() {
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
hasAssigned = true
fieldValue.SetUint(vv.Uint())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
hasAssigned = true
fieldValue.SetUint(uint64(vv.Int()))
}
case reflect.Struct:
if fieldType.ConvertibleTo(core.TimeType) {
dbTZ := session.engine.DatabaseTZ
if col.TimeZone != nil {
dbTZ = col.TimeZone
}
if rawValueType == core.TimeType {
hasAssigned = true
t := vv.Convert(core.TimeType).Interface().(time.Time)
z, _ := t.Zone()
// set new location if database don't save timezone or give an incorrect timezone
if len(z) == 0 || t.Year() == 0 || t.Location().String() != dbTZ.String() { // !nashtsai! HACK tmp work around for lib/pq doesn't properly time with location
session.engine.logger.Debugf("empty zone key[%v] : %v | zone: %v | location: %+v\n", key, t, z, *t.Location())
t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(),
t.Minute(), t.Second(), t.Nanosecond(), dbTZ)
}
t = t.In(session.engine.TZLocation)
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
} else if rawValueType == core.IntType || rawValueType == core.Int64Type ||
rawValueType == core.Int32Type {
hasAssigned = true
t := time.Unix(vv.Int(), 0).In(session.engine.TZLocation)
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
} else {
if d, ok := vv.Interface().([]uint8); ok {
hasAssigned = true
t, err := session.byte2Time(col, d)
if err != nil {
session.engine.logger.Error("byte2Time error:", err.Error())
hasAssigned = false
} else {
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
}
} else if d, ok := vv.Interface().(string); ok {
hasAssigned = true
t, err := session.str2Time(col, d)
if err != nil {
session.engine.logger.Error("byte2Time error:", err.Error())
hasAssigned = false
} else {
fieldValue.Set(reflect.ValueOf(t).Convert(fieldType))
}
} else {
return nil, fmt.Errorf("rawValueType is %v, value is %v", rawValueType, vv.Interface())
}
}
} else if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
// !<winxxp>! 增加支持sql.Scanner接口的结构如sql.NullString
hasAssigned = true
if err := nulVal.Scan(vv.Interface()); err != nil {
session.engine.logger.Error("sql.Sanner error:", err.Error())
hasAssigned = false
}
} else if col.SQLType.IsJson() {
if rawValueType.Kind() == reflect.String {
hasAssigned = true
x := reflect.New(fieldType)
if len([]byte(vv.String())) > 0 {
err := json.Unmarshal([]byte(vv.String()), x.Interface())
if err != nil {
return nil, err
}
fieldValue.Set(x.Elem())
}
} else if rawValueType.Kind() == reflect.Slice {
hasAssigned = true
x := reflect.New(fieldType)
if len(vv.Bytes()) > 0 {
err := json.Unmarshal(vv.Bytes(), x.Interface())
if err != nil {
return nil, err
}
fieldValue.Set(x.Elem())
}
}
} else if session.statement.UseCascade {
table, err := session.engine.autoMapType(*fieldValue)
if err != nil {
return nil, err
}
hasAssigned = true
if len(table.PrimaryKeys) != 1 {
return nil, errors.New("unsupported non or composited primary key cascade")
}
var pk = make(core.PK, len(table.PrimaryKeys))
pk[0], err = asKind(vv, rawValueType)
if err != nil {
return nil, err
}
if !isPKZero(pk) {
// !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
// property to be fetched lazily
structInter := reflect.New(fieldValue.Type())
has, err := session.ID(pk).NoCascade().get(structInter.Interface())
if err != nil {
return nil, err
}
if has {
fieldValue.Set(structInter.Elem())
} else {
return nil, errors.New("cascade obj is not exist")
}
}
}
case reflect.Ptr:
// !nashtsai! TODO merge duplicated codes above
switch fieldType {
// following types case matching ptr's native type, therefore assign ptr directly
case core.PtrStringType:
if rawValueType.Kind() == reflect.String {
x := vv.String()
hasAssigned = true
fieldValue.Set(reflect.ValueOf(&x))
}
case core.PtrBoolType:
if rawValueType.Kind() == reflect.Bool {
x := vv.Bool()
hasAssigned = true
fieldValue.Set(reflect.ValueOf(&x))
}
case core.PtrTimeType:
if rawValueType == core.PtrTimeType {
hasAssigned = true
var x = rawValue.Interface().(time.Time)
fieldValue.Set(reflect.ValueOf(&x))
}
case core.PtrFloat64Type:
if rawValueType.Kind() == reflect.Float64 {
x := vv.Float()
hasAssigned = true
fieldValue.Set(reflect.ValueOf(&x))
}
case core.PtrUint64Type:
if rawValueType.Kind() == reflect.Int64 {
var x = uint64(vv.Int())
hasAssigned = true
fieldValue.Set(reflect.ValueOf(&x))
}
case core.PtrInt64Type:
if rawValueType.Kind() == reflect.Int64 {
x := vv.Int()
hasAssigned = true
fieldValue.Set(reflect.ValueOf(&x))
}
case core.PtrFloat32Type:
if rawValueType.Kind() == reflect.Float64 {
var x = float32(vv.Float())
hasAssigned = true
fieldValue.Set(reflect.ValueOf(&x))
}
case core.PtrIntType:
if rawValueType.Kind() == reflect.Int64 {
var x = int(vv.Int())
hasAssigned = true
fieldValue.Set(reflect.ValueOf(&x))
}
case core.PtrInt32Type:
if rawValueType.Kind() == reflect.Int64 {
var x = int32(vv.Int())
hasAssigned = true
fieldValue.Set(reflect.ValueOf(&x))
}
case core.PtrInt8Type:
if rawValueType.Kind() == reflect.Int64 {
var x = int8(vv.Int())
hasAssigned = true
fieldValue.Set(reflect.ValueOf(&x))
}
case core.PtrInt16Type:
if rawValueType.Kind() == reflect.Int64 {
var x = int16(vv.Int())
hasAssigned = true
fieldValue.Set(reflect.ValueOf(&x))
}
case core.PtrUintType:
if rawValueType.Kind() == reflect.Int64 {
var x = uint(vv.Int())
hasAssigned = true
fieldValue.Set(reflect.ValueOf(&x))
}
case core.PtrUint32Type:
if rawValueType.Kind() == reflect.Int64 {
var x = uint32(vv.Int())
hasAssigned = true
fieldValue.Set(reflect.ValueOf(&x))
}
case core.Uint8Type:
if rawValueType.Kind() == reflect.Int64 {
var x = uint8(vv.Int())
hasAssigned = true
fieldValue.Set(reflect.ValueOf(&x))
}
case core.Uint16Type:
if rawValueType.Kind() == reflect.Int64 {
var x = uint16(vv.Int())
hasAssigned = true
fieldValue.Set(reflect.ValueOf(&x))
}
case core.Complex64Type:
var x complex64
if len([]byte(vv.String())) > 0 {
err := json.Unmarshal([]byte(vv.String()), &x)
if err != nil {
return nil, err
}
fieldValue.Set(reflect.ValueOf(&x))
}
hasAssigned = true
case core.Complex128Type:
var x complex128
if len([]byte(vv.String())) > 0 {
err := json.Unmarshal([]byte(vv.String()), &x)
if err != nil {
return nil, err
}
fieldValue.Set(reflect.ValueOf(&x))
}
hasAssigned = true
} // switch fieldType
} // switch fieldType.Kind()
// !nashtsai! for value can't be assigned directly fallback to convert to []byte then back to value
if !hasAssigned {
data, err := value2Bytes(&rawValue)
if err != nil {
return nil, err
}
if err = session.bytes2Value(col, fieldValue, data); err != nil {
return nil, err
}
}
}
return pk, nil
}
// saveLastSQL stores executed query information
func (session *Session) saveLastSQL(sql string, args ...interface{}) {
session.lastSQL = sql
session.lastSQLArgs = args
session.engine.logSQL(sql, args...)
}
// LastSQL returns last query information
func (session *Session) LastSQL() (string, []interface{}) {
return session.lastSQL, session.lastSQLArgs
}
// Unscoped always disable struct tag "deleted"
func (session *Session) Unscoped() *Session {
session.statement.Unscoped()
return session
}

View File

@ -1,191 +0,0 @@
// 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 (
"reflect"
"strings"
"time"
"github.com/go-xorm/core"
)
type incrParam struct {
colName string
arg interface{}
}
type decrParam struct {
colName string
arg interface{}
}
type exprParam struct {
colName string
expr string
}
type columnMap []string
func (m columnMap) contain(colName string) bool {
if len(m) == 0 {
return false
}
n := len(colName)
for _, mk := range m {
if len(mk) != n {
continue
}
if strings.EqualFold(mk, colName) {
return true
}
}
return false
}
func setColumnInt(bean interface{}, col *core.Column, t int64) {
v, err := col.ValueOf(bean)
if err != nil {
return
}
if v.CanSet() {
switch v.Type().Kind() {
case reflect.Int, reflect.Int64, reflect.Int32:
v.SetInt(t)
case reflect.Uint, reflect.Uint64, reflect.Uint32:
v.SetUint(uint64(t))
}
}
}
func setColumnTime(bean interface{}, col *core.Column, t time.Time) {
v, err := col.ValueOf(bean)
if err != nil {
return
}
if v.CanSet() {
switch v.Type().Kind() {
case reflect.Struct:
v.Set(reflect.ValueOf(t).Convert(v.Type()))
case reflect.Int, reflect.Int64, reflect.Int32:
v.SetInt(t.Unix())
case reflect.Uint, reflect.Uint64, reflect.Uint32:
v.SetUint(uint64(t.Unix()))
}
}
}
func getFlagForColumn(m map[string]bool, col *core.Column) (val bool, has bool) {
if len(m) == 0 {
return false, false
}
n := len(col.Name)
for mk := range m {
if len(mk) != n {
continue
}
if strings.EqualFold(mk, col.Name) {
return m[mk], true
}
}
return false, false
}
func col2NewCols(columns ...string) []string {
newColumns := make([]string, 0, len(columns))
for _, col := range columns {
col = strings.Replace(col, "`", "", -1)
col = strings.Replace(col, `"`, "", -1)
ccols := strings.Split(col, ",")
for _, c := range ccols {
newColumns = append(newColumns, strings.TrimSpace(c))
}
}
return newColumns
}
// Incr provides a query string like "count = count + 1"
func (session *Session) Incr(column string, arg ...interface{}) *Session {
session.statement.Incr(column, arg...)
return session
}
// Decr provides a query string like "count = count - 1"
func (session *Session) Decr(column string, arg ...interface{}) *Session {
session.statement.Decr(column, arg...)
return session
}
// SetExpr provides a query string like "column = {expression}"
func (session *Session) SetExpr(column string, expression string) *Session {
session.statement.SetExpr(column, expression)
return session
}
// Select provides some columns to special
func (session *Session) Select(str string) *Session {
session.statement.Select(str)
return session
}
// Cols provides some columns to special
func (session *Session) Cols(columns ...string) *Session {
session.statement.Cols(columns...)
return session
}
// AllCols ask all columns
func (session *Session) AllCols() *Session {
session.statement.AllCols()
return session
}
// MustCols specify some columns must use even if they are empty
func (session *Session) MustCols(columns ...string) *Session {
session.statement.MustCols(columns...)
return session
}
// UseBool automatically retrieve condition according struct, but
// if struct has bool field, it will ignore them. So use UseBool
// to tell system to do not ignore them.
// If no parameters, it will use all the bool field of struct, or
// it will use parameters's columns
func (session *Session) UseBool(columns ...string) *Session {
session.statement.UseBool(columns...)
return session
}
// Distinct use for distinct columns. Caution: when you are using cache,
// distinct will not be cached because cache system need id,
// but distinct will not provide id
func (session *Session) Distinct(columns ...string) *Session {
session.statement.Distinct(columns...)
return session
}
// Omit Only not use the parameters as select or update columns
func (session *Session) Omit(columns ...string) *Session {
session.statement.Omit(columns...)
return session
}
// Nullable Set null when column is zero-value and nullable for update
func (session *Session) Nullable(columns ...string) *Session {
session.statement.Nullable(columns...)
return session
}
// NoAutoTime means do not automatically give created field and updated field
// the current time on the current session temporarily
func (session *Session) NoAutoTime() *Session {
session.statement.UseAutoTime = false
return session
}

View File

@ -1,70 +0,0 @@
// 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 "github.com/go-xorm/builder"
// 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.
//
// Deprecated: use SQL instead.
func (session *Session) Sql(query string, args ...interface{}) *Session {
return session.SQL(query, args...)
}
// 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.
func (session *Session) SQL(query interface{}, args ...interface{}) *Session {
session.statement.SQL(query, args...)
return session
}
// Where provides custom query condition.
func (session *Session) Where(query interface{}, args ...interface{}) *Session {
session.statement.Where(query, args...)
return session
}
// And provides custom query condition.
func (session *Session) And(query interface{}, args ...interface{}) *Session {
session.statement.And(query, args...)
return session
}
// Or provides custom query condition.
func (session *Session) Or(query interface{}, args ...interface{}) *Session {
session.statement.Or(query, args...)
return session
}
// Id provides converting id as a query condition
//
// Deprecated: use ID instead
func (session *Session) Id(id interface{}) *Session {
return session.ID(id)
}
// ID provides converting id as a query condition
func (session *Session) ID(id interface{}) *Session {
session.statement.ID(id)
return session
}
// In provides a query string like "id in (1, 2, 3)"
func (session *Session) In(column string, args ...interface{}) *Session {
session.statement.In(column, args...)
return session
}
// NotIn provides a query string like "id in (1, 2, 3)"
func (session *Session) NotIn(column string, args ...interface{}) *Session {
session.statement.NotIn(column, args...)
return session
}
// Conds returns session query conditions except auto bean conditions
func (session *Session) Conds() builder.Cond {
return session.statement.cond
}

View File

@ -1,662 +0,0 @@
// 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 (
"database/sql"
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"time"
"github.com/go-xorm/core"
)
func (session *Session) str2Time(col *core.Column, data string) (outTime time.Time, outErr error) {
sdata := strings.TrimSpace(data)
var x time.Time
var err error
var parseLoc = session.engine.DatabaseTZ
if col.TimeZone != nil {
parseLoc = col.TimeZone
}
if sdata == zeroTime0 || sdata == zeroTime1 {
} else if !strings.ContainsAny(sdata, "- :") { // !nashtsai! has only found that mymysql driver is using this for time type column
// time stamp
sd, err := strconv.ParseInt(sdata, 10, 64)
if err == nil {
x = time.Unix(sd, 0)
//session.engine.logger.Debugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
} else {
//session.engine.logger.Debugf("time(0) err key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
}
} else if len(sdata) > 19 && strings.Contains(sdata, "-") {
x, err = time.ParseInLocation(time.RFC3339Nano, sdata, parseLoc)
session.engine.logger.Debugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
if err != nil {
x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, parseLoc)
//session.engine.logger.Debugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
}
if err != nil {
x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, parseLoc)
//session.engine.logger.Debugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
}
} else if len(sdata) == 19 && strings.Contains(sdata, "-") {
x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, parseLoc)
//session.engine.logger.Debugf("time(4) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
} else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' {
x, err = time.ParseInLocation("2006-01-02", sdata, parseLoc)
//session.engine.logger.Debugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
} else if col.SQLType.Name == core.Time {
if strings.Contains(sdata, " ") {
ssd := strings.Split(sdata, " ")
sdata = ssd[1]
}
sdata = strings.TrimSpace(sdata)
if session.engine.dialect.DBType() == core.MYSQL && len(sdata) > 8 {
sdata = sdata[len(sdata)-8:]
}
st := fmt.Sprintf("2006-01-02 %v", sdata)
x, err = time.ParseInLocation("2006-01-02 15:04:05", st, parseLoc)
//session.engine.logger.Debugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
} else {
outErr = fmt.Errorf("unsupported time format %v", sdata)
return
}
if err != nil {
outErr = fmt.Errorf("unsupported time format %v: %v", sdata, err)
return
}
outTime = x.In(session.engine.TZLocation)
return
}
func (session *Session) byte2Time(col *core.Column, data []byte) (outTime time.Time, outErr error) {
return session.str2Time(col, string(data))
}
// convert a db data([]byte) to a field value
func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, data []byte) error {
if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
return structConvert.FromDB(data)
}
if structConvert, ok := fieldValue.Interface().(core.Conversion); ok {
return structConvert.FromDB(data)
}
var v interface{}
key := col.Name
fieldType := fieldValue.Type()
switch fieldType.Kind() {
case reflect.Complex64, reflect.Complex128:
x := reflect.New(fieldType)
if len(data) > 0 {
err := json.Unmarshal(data, x.Interface())
if err != nil {
session.engine.logger.Error(err)
return err
}
fieldValue.Set(x.Elem())
}
case reflect.Slice, reflect.Array, reflect.Map:
v = data
t := fieldType.Elem()
k := t.Kind()
if col.SQLType.IsText() {
x := reflect.New(fieldType)
if len(data) > 0 {
err := json.Unmarshal(data, x.Interface())
if err != nil {
session.engine.logger.Error(err)
return err
}
fieldValue.Set(x.Elem())
}
} else if col.SQLType.IsBlob() {
if k == reflect.Uint8 {
fieldValue.Set(reflect.ValueOf(v))
} else {
x := reflect.New(fieldType)
if len(data) > 0 {
err := json.Unmarshal(data, x.Interface())
if err != nil {
session.engine.logger.Error(err)
return err
}
fieldValue.Set(x.Elem())
}
}
} else {
return ErrUnSupportedType
}
case reflect.String:
fieldValue.SetString(string(data))
case reflect.Bool:
v, err := asBool(data)
if err != nil {
return fmt.Errorf("arg %v as bool: %s", key, err.Error())
}
fieldValue.Set(reflect.ValueOf(v))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
sdata := string(data)
var x int64
var err error
// for mysql, when use bit, it returned \x01
if col.SQLType.Name == core.Bit &&
session.engine.dialect.DBType() == core.MYSQL { // !nashtsai! TODO dialect needs to provide conversion interface API
if len(data) == 1 {
x = int64(data[0])
} else {
x = 0
}
} else if strings.HasPrefix(sdata, "0x") {
x, err = strconv.ParseInt(sdata, 16, 64)
} else if strings.HasPrefix(sdata, "0") {
x, err = strconv.ParseInt(sdata, 8, 64)
} else if strings.EqualFold(sdata, "true") {
x = 1
} else if strings.EqualFold(sdata, "false") {
x = 0
} else {
x, err = strconv.ParseInt(sdata, 10, 64)
}
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
fieldValue.SetInt(x)
case reflect.Float32, reflect.Float64:
x, err := strconv.ParseFloat(string(data), 64)
if err != nil {
return fmt.Errorf("arg %v as float64: %s", key, err.Error())
}
fieldValue.SetFloat(x)
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
x, err := strconv.ParseUint(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
fieldValue.SetUint(x)
//Currently only support Time type
case reflect.Struct:
// !<winxxp>! 增加支持sql.Scanner接口的结构如sql.NullString
if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
if err := nulVal.Scan(data); err != nil {
return fmt.Errorf("sql.Scan(%v) failed: %s ", data, err.Error())
}
} else {
if fieldType.ConvertibleTo(core.TimeType) {
x, err := session.byte2Time(col, data)
if err != nil {
return err
}
v = x
fieldValue.Set(reflect.ValueOf(v).Convert(fieldType))
} else if session.statement.UseCascade {
table, err := session.engine.autoMapType(*fieldValue)
if err != nil {
return err
}
// TODO: current only support 1 primary key
if len(table.PrimaryKeys) > 1 {
return errors.New("unsupported composited primary key cascade")
}
var pk = make(core.PK, len(table.PrimaryKeys))
rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
pk[0], err = str2PK(string(data), rawValueType)
if err != nil {
return err
}
if !isPKZero(pk) {
// !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
// property to be fetched lazily
structInter := reflect.New(fieldValue.Type())
has, err := session.ID(pk).NoCascade().get(structInter.Interface())
if err != nil {
return err
}
if has {
v = structInter.Elem().Interface()
fieldValue.Set(reflect.ValueOf(v))
} else {
return errors.New("cascade obj is not exist")
}
}
}
}
case reflect.Ptr:
// !nashtsai! TODO merge duplicated codes above
//typeStr := fieldType.String()
switch fieldType.Elem().Kind() {
// case "*string":
case core.StringType.Kind():
x := string(data)
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
// case "*bool":
case core.BoolType.Kind():
d := string(data)
v, err := strconv.ParseBool(d)
if err != nil {
return fmt.Errorf("arg %v as bool: %s", key, err.Error())
}
fieldValue.Set(reflect.ValueOf(&v).Convert(fieldType))
// case "*complex64":
case core.Complex64Type.Kind():
var x complex64
if len(data) > 0 {
err := json.Unmarshal(data, &x)
if err != nil {
session.engine.logger.Error(err)
return err
}
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
}
// case "*complex128":
case core.Complex128Type.Kind():
var x complex128
if len(data) > 0 {
err := json.Unmarshal(data, &x)
if err != nil {
session.engine.logger.Error(err)
return err
}
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
}
// case "*float64":
case core.Float64Type.Kind():
x, err := strconv.ParseFloat(string(data), 64)
if err != nil {
return fmt.Errorf("arg %v as float64: %s", key, err.Error())
}
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
// case "*float32":
case core.Float32Type.Kind():
var x float32
x1, err := strconv.ParseFloat(string(data), 32)
if err != nil {
return fmt.Errorf("arg %v as float32: %s", key, err.Error())
}
x = float32(x1)
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
// case "*uint64":
case core.Uint64Type.Kind():
var x uint64
x, err := strconv.ParseUint(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
// case "*uint":
case core.UintType.Kind():
var x uint
x1, err := strconv.ParseUint(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
x = uint(x1)
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
// case "*uint32":
case core.Uint32Type.Kind():
var x uint32
x1, err := strconv.ParseUint(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
x = uint32(x1)
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
// case "*uint8":
case core.Uint8Type.Kind():
var x uint8
x1, err := strconv.ParseUint(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
x = uint8(x1)
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
// case "*uint16":
case core.Uint16Type.Kind():
var x uint16
x1, err := strconv.ParseUint(string(data), 10, 64)
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
x = uint16(x1)
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
// case "*int64":
case core.Int64Type.Kind():
sdata := string(data)
var x int64
var err error
// for mysql, when use bit, it returned \x01
if col.SQLType.Name == core.Bit &&
strings.Contains(session.engine.DriverName(), "mysql") {
if len(data) == 1 {
x = int64(data[0])
} else {
x = 0
}
} else if strings.HasPrefix(sdata, "0x") {
x, err = strconv.ParseInt(sdata, 16, 64)
} else if strings.HasPrefix(sdata, "0") {
x, err = strconv.ParseInt(sdata, 8, 64)
} else {
x, err = strconv.ParseInt(sdata, 10, 64)
}
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
// case "*int":
case core.IntType.Kind():
sdata := string(data)
var x int
var x1 int64
var err error
// for mysql, when use bit, it returned \x01
if col.SQLType.Name == core.Bit &&
strings.Contains(session.engine.DriverName(), "mysql") {
if len(data) == 1 {
x = int(data[0])
} else {
x = 0
}
} else if strings.HasPrefix(sdata, "0x") {
x1, err = strconv.ParseInt(sdata, 16, 64)
x = int(x1)
} else if strings.HasPrefix(sdata, "0") {
x1, err = strconv.ParseInt(sdata, 8, 64)
x = int(x1)
} else {
x1, err = strconv.ParseInt(sdata, 10, 64)
x = int(x1)
}
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
// case "*int32":
case core.Int32Type.Kind():
sdata := string(data)
var x int32
var x1 int64
var err error
// for mysql, when use bit, it returned \x01
if col.SQLType.Name == core.Bit &&
session.engine.dialect.DBType() == core.MYSQL {
if len(data) == 1 {
x = int32(data[0])
} else {
x = 0
}
} else if strings.HasPrefix(sdata, "0x") {
x1, err = strconv.ParseInt(sdata, 16, 64)
x = int32(x1)
} else if strings.HasPrefix(sdata, "0") {
x1, err = strconv.ParseInt(sdata, 8, 64)
x = int32(x1)
} else {
x1, err = strconv.ParseInt(sdata, 10, 64)
x = int32(x1)
}
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
// case "*int8":
case core.Int8Type.Kind():
sdata := string(data)
var x int8
var x1 int64
var err error
// for mysql, when use bit, it returned \x01
if col.SQLType.Name == core.Bit &&
strings.Contains(session.engine.DriverName(), "mysql") {
if len(data) == 1 {
x = int8(data[0])
} else {
x = 0
}
} else if strings.HasPrefix(sdata, "0x") {
x1, err = strconv.ParseInt(sdata, 16, 64)
x = int8(x1)
} else if strings.HasPrefix(sdata, "0") {
x1, err = strconv.ParseInt(sdata, 8, 64)
x = int8(x1)
} else {
x1, err = strconv.ParseInt(sdata, 10, 64)
x = int8(x1)
}
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
// case "*int16":
case core.Int16Type.Kind():
sdata := string(data)
var x int16
var x1 int64
var err error
// for mysql, when use bit, it returned \x01
if col.SQLType.Name == core.Bit &&
strings.Contains(session.engine.DriverName(), "mysql") {
if len(data) == 1 {
x = int16(data[0])
} else {
x = 0
}
} else if strings.HasPrefix(sdata, "0x") {
x1, err = strconv.ParseInt(sdata, 16, 64)
x = int16(x1)
} else if strings.HasPrefix(sdata, "0") {
x1, err = strconv.ParseInt(sdata, 8, 64)
x = int16(x1)
} else {
x1, err = strconv.ParseInt(sdata, 10, 64)
x = int16(x1)
}
if err != nil {
return fmt.Errorf("arg %v as int: %s", key, err.Error())
}
fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
// case "*SomeStruct":
case reflect.Struct:
switch fieldType {
// case "*.time.Time":
case core.PtrTimeType:
x, err := session.byte2Time(col, data)
if err != nil {
return err
}
v = x
fieldValue.Set(reflect.ValueOf(&x))
default:
if session.statement.UseCascade {
structInter := reflect.New(fieldType.Elem())
table, err := session.engine.autoMapType(structInter.Elem())
if err != nil {
return err
}
if len(table.PrimaryKeys) > 1 {
return errors.New("unsupported composited primary key cascade")
}
var pk = make(core.PK, len(table.PrimaryKeys))
rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
pk[0], err = str2PK(string(data), rawValueType)
if err != nil {
return err
}
if !isPKZero(pk) {
// !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
// property to be fetched lazily
has, err := session.ID(pk).NoCascade().get(structInter.Interface())
if err != nil {
return err
}
if has {
v = structInter.Interface()
fieldValue.Set(reflect.ValueOf(v))
} else {
return errors.New("cascade obj is not exist")
}
}
} else {
return fmt.Errorf("unsupported struct type in Scan: %s", fieldValue.Type().String())
}
}
default:
return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String())
}
default:
return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String())
}
return nil
}
// convert a field value of a struct to interface for put into db
func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Value) (interface{}, error) {
if fieldValue.CanAddr() {
if fieldConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
data, err := fieldConvert.ToDB()
if err != nil {
return 0, err
}
if col.SQLType.IsBlob() {
return data, nil
}
return string(data), nil
}
}
if fieldConvert, ok := fieldValue.Interface().(core.Conversion); ok {
data, err := fieldConvert.ToDB()
if err != nil {
return 0, err
}
if col.SQLType.IsBlob() {
return data, nil
}
return string(data), nil
}
fieldType := fieldValue.Type()
k := fieldType.Kind()
if k == reflect.Ptr {
if fieldValue.IsNil() {
return nil, nil
} else if !fieldValue.IsValid() {
session.engine.logger.Warn("the field[", col.FieldName, "] is invalid")
return nil, nil
} else {
// !nashtsai! deference pointer type to instance type
fieldValue = fieldValue.Elem()
fieldType = fieldValue.Type()
k = fieldType.Kind()
}
}
switch k {
case reflect.Bool:
return fieldValue.Bool(), nil
case reflect.String:
return fieldValue.String(), nil
case reflect.Struct:
if fieldType.ConvertibleTo(core.TimeType) {
t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
tf := session.engine.formatColTime(col, t)
return tf, nil
}
if !col.SQLType.IsJson() {
// !<winxxp>! 增加支持driver.Valuer接口的结构如sql.NullString
if v, ok := fieldValue.Interface().(driver.Valuer); ok {
return v.Value()
}
fieldTable, err := session.engine.autoMapType(fieldValue)
if err != nil {
return nil, err
}
if len(fieldTable.PrimaryKeys) == 1 {
pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumns()[0].FieldName)
return pkField.Interface(), nil
}
return 0, fmt.Errorf("no primary key for col %v", col.Name)
}
if col.SQLType.IsText() {
bytes, err := json.Marshal(fieldValue.Interface())
if err != nil {
session.engine.logger.Error(err)
return 0, err
}
return string(bytes), nil
} else if col.SQLType.IsBlob() {
bytes, err := json.Marshal(fieldValue.Interface())
if err != nil {
session.engine.logger.Error(err)
return 0, err
}
return bytes, nil
}
return nil, fmt.Errorf("Unsupported type %v", fieldValue.Type())
case reflect.Complex64, reflect.Complex128:
bytes, err := json.Marshal(fieldValue.Interface())
if err != nil {
session.engine.logger.Error(err)
return 0, err
}
return string(bytes), nil
case reflect.Array, reflect.Slice, reflect.Map:
if !fieldValue.IsValid() {
return fieldValue.Interface(), nil
}
if col.SQLType.IsText() {
bytes, err := json.Marshal(fieldValue.Interface())
if err != nil {
session.engine.logger.Error(err)
return 0, err
}
return string(bytes), nil
} else if col.SQLType.IsBlob() {
var bytes []byte
var err error
if (k == reflect.Array || k == reflect.Slice) &&
(fieldValue.Type().Elem().Kind() == reflect.Uint8) {
bytes = fieldValue.Bytes()
} else {
bytes, err = json.Marshal(fieldValue.Interface())
if err != nil {
session.engine.logger.Error(err)
return 0, err
}
}
return bytes, nil
}
return nil, ErrUnSupportedType
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
return int64(fieldValue.Uint()), nil
default:
return fieldValue.Interface(), nil
}
}

View File

@ -1,240 +0,0 @@
// Copyright 2016 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 (
"errors"
"fmt"
"strconv"
"github.com/go-xorm/core"
)
func (session *Session) cacheDelete(table *core.Table, tableName, sqlStr string, args ...interface{}) error {
if table == nil ||
session.tx != nil {
return ErrCacheFailed
}
for _, filter := range session.engine.dialect.Filters() {
sqlStr = filter.Do(sqlStr, session.engine.dialect, table)
}
newsql := session.statement.convertIDSQL(sqlStr)
if newsql == "" {
return ErrCacheFailed
}
cacher := session.engine.getCacher(tableName)
pkColumns := table.PKColumns()
ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
if err != nil {
resultsSlice, err := session.queryBytes(newsql, args...)
if err != nil {
return err
}
ids = make([]core.PK, 0)
if len(resultsSlice) > 0 {
for _, data := range resultsSlice {
var id int64
var pk core.PK = make([]interface{}, 0)
for _, col := range pkColumns {
if v, ok := data[col.Name]; !ok {
return errors.New("no id")
} else if col.SQLType.IsText() {
pk = append(pk, string(v))
} else if col.SQLType.IsNumeric() {
id, err = strconv.ParseInt(string(v), 10, 64)
if err != nil {
return err
}
pk = append(pk, id)
} else {
return errors.New("not supported primary key type")
}
}
ids = append(ids, pk)
}
}
}
for _, id := range ids {
session.engine.logger.Debug("[cacheDelete] delete cache obj:", tableName, id)
sid, err := id.ToString()
if err != nil {
return err
}
cacher.DelBean(tableName, sid)
}
session.engine.logger.Debug("[cacheDelete] clear cache table:", tableName)
cacher.ClearIds(tableName)
return nil
}
// Delete records, bean's non-empty fields are conditions
func (session *Session) Delete(bean interface{}) (int64, error) {
if session.isAutoClose {
defer session.Close()
}
if err := session.statement.setRefBean(bean); err != nil {
return 0, err
}
// handle before delete processors
for _, closure := range session.beforeClosures {
closure(bean)
}
cleanupProcessorsClosures(&session.beforeClosures)
if processor, ok := interface{}(bean).(BeforeDeleteProcessor); ok {
processor.BeforeDelete()
}
condSQL, condArgs, err := session.statement.genConds(bean)
if err != nil {
return 0, err
}
if len(condSQL) == 0 && session.statement.LimitN == 0 {
return 0, ErrNeedDeletedCond
}
var tableNameNoQuote = session.statement.TableName()
var tableName = session.engine.Quote(tableNameNoQuote)
var table = session.statement.RefTable
var deleteSQL string
if len(condSQL) > 0 {
deleteSQL = fmt.Sprintf("DELETE FROM %v WHERE %v", tableName, condSQL)
} else {
deleteSQL = fmt.Sprintf("DELETE FROM %v", tableName)
}
var orderSQL string
if len(session.statement.OrderStr) > 0 {
orderSQL += fmt.Sprintf(" ORDER BY %s", session.statement.OrderStr)
}
if session.statement.LimitN > 0 {
orderSQL += fmt.Sprintf(" LIMIT %d", session.statement.LimitN)
}
if len(orderSQL) > 0 {
switch session.engine.dialect.DBType() {
case core.POSTGRES:
inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL)
if len(condSQL) > 0 {
deleteSQL += " AND " + inSQL
} else {
deleteSQL += " WHERE " + inSQL
}
case core.SQLITE:
inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL)
if len(condSQL) > 0 {
deleteSQL += " AND " + inSQL
} else {
deleteSQL += " WHERE " + inSQL
}
// TODO: how to handle delete limit on mssql?
case core.MSSQL:
return 0, ErrNotImplemented
default:
deleteSQL += orderSQL
}
}
var realSQL string
argsForCache := make([]interface{}, 0, len(condArgs)*2)
if session.statement.unscoped || table.DeletedColumn() == nil { // tag "deleted" is disabled
realSQL = deleteSQL
copy(argsForCache, condArgs)
argsForCache = append(condArgs, argsForCache...)
} else {
// !oinume! sqlStrForCache and argsForCache is needed to behave as executing "DELETE FROM ..." for cache.
copy(argsForCache, condArgs)
argsForCache = append(condArgs, argsForCache...)
deletedColumn := table.DeletedColumn()
realSQL = fmt.Sprintf("UPDATE %v SET %v = ? WHERE %v",
session.engine.Quote(session.statement.TableName()),
session.engine.Quote(deletedColumn.Name),
condSQL)
if len(orderSQL) > 0 {
switch session.engine.dialect.DBType() {
case core.POSTGRES:
inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL)
if len(condSQL) > 0 {
realSQL += " AND " + inSQL
} else {
realSQL += " WHERE " + inSQL
}
case core.SQLITE:
inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL)
if len(condSQL) > 0 {
realSQL += " AND " + inSQL
} else {
realSQL += " WHERE " + inSQL
}
// TODO: how to handle delete limit on mssql?
case core.MSSQL:
return 0, ErrNotImplemented
default:
realSQL += orderSQL
}
}
// !oinume! Insert nowTime to the head of session.statement.Params
condArgs = append(condArgs, "")
paramsLen := len(condArgs)
copy(condArgs[1:paramsLen], condArgs[0:paramsLen-1])
val, t := session.engine.nowTime(deletedColumn)
condArgs[0] = val
var colName = deletedColumn.Name
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
col := table.GetColumn(colName)
setColumnTime(bean, col, t)
})
}
if cacher := session.engine.getCacher(tableName); cacher != nil && session.statement.UseCache {
session.cacheDelete(table, tableNameNoQuote, deleteSQL, argsForCache...)
}
session.statement.RefTable = table
res, err := session.exec(realSQL, condArgs...)
if err != nil {
return 0, err
}
// handle after delete processors
if session.isAutoCommit {
for _, closure := range session.afterClosures {
closure(bean)
}
if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
processor.AfterDelete()
}
} else {
lenAfterClosures := len(session.afterClosures)
if lenAfterClosures > 0 {
if value, has := session.afterDeleteBeans[bean]; has && value != nil {
*value = append(*value, session.afterClosures...)
} else {
afterClosures := make([]func(interface{}), lenAfterClosures)
copy(afterClosures, session.afterClosures)
session.afterDeleteBeans[bean] = &afterClosures
}
} else {
if _, ok := interface{}(bean).(AfterDeleteProcessor); ok {
session.afterDeleteBeans[bean] = nil
}
}
}
cleanupProcessorsClosures(&session.afterClosures)
// --
return res.RowsAffected()
}

View File

@ -1,86 +0,0 @@
// 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 (
"errors"
"fmt"
"reflect"
"github.com/go-xorm/builder"
"github.com/go-xorm/core"
)
// Exist returns true if the record exist otherwise return false
func (session *Session) Exist(bean ...interface{}) (bool, error) {
if session.isAutoClose {
defer session.Close()
}
var sqlStr string
var args []interface{}
var err error
if session.statement.RawSQL == "" {
if len(bean) == 0 {
tableName := session.statement.TableName()
if len(tableName) <= 0 {
return false, ErrTableNotFound
}
if session.statement.cond.IsValid() {
condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
if err != nil {
return false, err
}
if session.engine.dialect.DBType() == core.MSSQL {
sqlStr = fmt.Sprintf("SELECT top 1 * FROM %s WHERE %s", tableName, condSQL)
} else {
sqlStr = fmt.Sprintf("SELECT * FROM %s WHERE %s LIMIT 1", tableName, condSQL)
}
args = condArgs
} else {
if session.engine.dialect.DBType() == core.MSSQL {
sqlStr = fmt.Sprintf("SELECT top 1 * FROM %s", tableName)
} else {
sqlStr = fmt.Sprintf("SELECT * FROM %s LIMIT 1", tableName)
}
args = []interface{}{}
}
} else {
beanValue := reflect.ValueOf(bean[0])
if beanValue.Kind() != reflect.Ptr {
return false, errors.New("needs a pointer")
}
if beanValue.Elem().Kind() == reflect.Struct {
if err := session.statement.setRefBean(bean[0]); err != nil {
return false, err
}
}
if len(session.statement.TableName()) <= 0 {
return false, ErrTableNotFound
}
session.statement.Limit(1)
sqlStr, args, err = session.statement.genGetSQL(bean[0])
if err != nil {
return false, err
}
}
} else {
sqlStr = session.statement.RawSQL
args = session.statement.RawParams
}
rows, err := session.queryRows(sqlStr, args...)
if err != nil {
return false, err
}
defer rows.Close()
return rows.Next(), nil
}

View File

@ -1,499 +0,0 @@
// Copyright 2016 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 (
"errors"
"fmt"
"reflect"
"strings"
"github.com/go-xorm/builder"
"github.com/go-xorm/core"
)
const (
tpStruct = iota
tpNonStruct
)
// Find retrieve records from table, condiBeans's non-empty fields
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
// map[int64]*Struct
func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
if session.isAutoClose {
defer session.Close()
}
return session.find(rowsSlicePtr, condiBean...)
}
// FindAndCount find the results and also return the counts
func (session *Session) FindAndCount(rowsSlicePtr interface{}, condiBean ...interface{}) (int64, error) {
if session.isAutoClose {
defer session.Close()
}
session.autoResetStatement = false
err := session.find(rowsSlicePtr, condiBean...)
if err != nil {
return 0, err
}
sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map {
return 0, errors.New("needs a pointer to a slice or a map")
}
sliceElementType := sliceValue.Type().Elem()
if sliceElementType.Kind() == reflect.Ptr {
sliceElementType = sliceElementType.Elem()
}
session.autoResetStatement = true
if session.statement.selectStr != "" {
session.statement.selectStr = ""
}
if session.statement.OrderStr != "" {
session.statement.OrderStr = ""
}
return session.Count(reflect.New(sliceElementType).Interface())
}
func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map {
return errors.New("needs a pointer to a slice or a map")
}
sliceElementType := sliceValue.Type().Elem()
var tp = tpStruct
if session.statement.RefTable == nil {
if sliceElementType.Kind() == reflect.Ptr {
if sliceElementType.Elem().Kind() == reflect.Struct {
pv := reflect.New(sliceElementType.Elem())
if err := session.statement.setRefValue(pv); err != nil {
return err
}
} else {
tp = tpNonStruct
}
} else if sliceElementType.Kind() == reflect.Struct {
pv := reflect.New(sliceElementType)
if err := session.statement.setRefValue(pv); err != nil {
return err
}
} else {
tp = tpNonStruct
}
}
var table = session.statement.RefTable
var addedTableName = (len(session.statement.JoinStr) > 0)
var autoCond builder.Cond
if tp == tpStruct {
if !session.statement.noAutoCondition && len(condiBean) > 0 {
var err error
autoCond, err = session.statement.buildConds(table, condiBean[0], true, true, false, true, addedTableName)
if err != nil {
return err
}
} else {
// !oinume! Add "<col> IS NULL" to WHERE whatever condiBean is given.
// See https://github.com/go-xorm/xorm/issues/179
if col := table.DeletedColumn(); col != nil && !session.statement.unscoped { // tag "deleted" is enabled
var colName = session.engine.Quote(col.Name)
if addedTableName {
var nm = session.statement.TableName()
if len(session.statement.TableAlias) > 0 {
nm = session.statement.TableAlias
}
colName = session.engine.Quote(nm) + "." + colName
}
autoCond = session.engine.CondDeleted(colName)
}
}
}
var sqlStr string
var args []interface{}
var err error
if session.statement.RawSQL == "" {
if len(session.statement.TableName()) <= 0 {
return ErrTableNotFound
}
var columnStr = session.statement.ColumnStr
if len(session.statement.selectStr) > 0 {
columnStr = session.statement.selectStr
} else {
if session.statement.JoinStr == "" {
if columnStr == "" {
if session.statement.GroupByStr != "" {
columnStr = session.statement.Engine.Quote(strings.Replace(session.statement.GroupByStr, ",", session.engine.Quote(","), -1))
} else {
columnStr = session.statement.genColumnStr()
}
}
} else {
if columnStr == "" {
if session.statement.GroupByStr != "" {
columnStr = session.statement.Engine.Quote(strings.Replace(session.statement.GroupByStr, ",", session.engine.Quote(","), -1))
} else {
columnStr = "*"
}
}
}
if columnStr == "" {
columnStr = "*"
}
}
session.statement.cond = session.statement.cond.And(autoCond)
condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
if err != nil {
return err
}
args = append(session.statement.joinArgs, condArgs...)
sqlStr, err = session.statement.genSelectSQL(columnStr, condSQL, true, true)
if err != nil {
return err
}
// for mssql and use limit
qs := strings.Count(sqlStr, "?")
if len(args)*2 == qs {
args = append(args, args...)
}
} else {
sqlStr = session.statement.RawSQL
args = session.statement.RawParams
}
if session.canCache() {
if cacher := session.engine.getCacher(table.Name); cacher != nil &&
!session.statement.IsDistinct &&
!session.statement.unscoped {
err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...)
if err != ErrCacheFailed {
return err
}
err = nil // !nashtsai! reset err to nil for ErrCacheFailed
session.engine.logger.Warn("Cache Find Failed")
}
}
return session.noCacheFind(table, sliceValue, sqlStr, args...)
}
func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Value, sqlStr string, args ...interface{}) error {
rows, err := session.queryRows(sqlStr, args...)
if err != nil {
return err
}
defer rows.Close()
fields, err := rows.Columns()
if err != nil {
return err
}
var newElemFunc func(fields []string) reflect.Value
elemType := containerValue.Type().Elem()
var isPointer bool
if elemType.Kind() == reflect.Ptr {
isPointer = true
elemType = elemType.Elem()
}
if elemType.Kind() == reflect.Ptr {
return errors.New("pointer to pointer is not supported")
}
newElemFunc = func(fields []string) reflect.Value {
switch elemType.Kind() {
case reflect.Slice:
slice := reflect.MakeSlice(elemType, len(fields), len(fields))
x := reflect.New(slice.Type())
x.Elem().Set(slice)
return x
case reflect.Map:
mp := reflect.MakeMap(elemType)
x := reflect.New(mp.Type())
x.Elem().Set(mp)
return x
}
return reflect.New(elemType)
}
var containerValueSetFunc func(*reflect.Value, core.PK) error
if containerValue.Kind() == reflect.Slice {
containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error {
if isPointer {
containerValue.Set(reflect.Append(containerValue, newValue.Elem().Addr()))
} else {
containerValue.Set(reflect.Append(containerValue, newValue.Elem()))
}
return nil
}
} else {
keyType := containerValue.Type().Key()
if len(table.PrimaryKeys) == 0 {
return errors.New("don't support multiple primary key's map has non-slice key type")
}
if len(table.PrimaryKeys) > 1 && keyType.Kind() != reflect.Slice {
return errors.New("don't support multiple primary key's map has non-slice key type")
}
containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error {
keyValue := reflect.New(keyType)
err := convertPKToValue(table, keyValue.Interface(), pk)
if err != nil {
return err
}
if isPointer {
containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem().Addr())
} else {
containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem())
}
return nil
}
}
if elemType.Kind() == reflect.Struct {
var newValue = newElemFunc(fields)
dataStruct := rValue(newValue.Interface())
tb, err := session.engine.autoMapType(dataStruct)
if err != nil {
return err
}
err = session.rows2Beans(rows, fields, tb, newElemFunc, containerValueSetFunc)
rows.Close()
if err != nil {
return err
}
return session.executeProcessors()
}
for rows.Next() {
var newValue = newElemFunc(fields)
bean := newValue.Interface()
switch elemType.Kind() {
case reflect.Slice:
err = rows.ScanSlice(bean)
case reflect.Map:
err = rows.ScanMap(bean)
default:
err = rows.Scan(bean)
}
if err != nil {
return err
}
if err := containerValueSetFunc(&newValue, nil); err != nil {
return err
}
}
return nil
}
func convertPKToValue(table *core.Table, dst interface{}, pk core.PK) error {
cols := table.PKColumns()
if len(cols) == 1 {
return convertAssign(dst, pk[0])
}
dst = pk
return nil
}
func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr interface{}, args ...interface{}) (err error) {
if !session.canCache() ||
indexNoCase(sqlStr, "having") != -1 ||
indexNoCase(sqlStr, "group by") != -1 {
return ErrCacheFailed
}
tableName := session.statement.TableName()
cacher := session.engine.getCacher(tableName)
if cacher == nil {
return nil
}
for _, filter := range session.engine.dialect.Filters() {
sqlStr = filter.Do(sqlStr, session.engine.dialect, session.statement.RefTable)
}
newsql := session.statement.convertIDSQL(sqlStr)
if newsql == "" {
return ErrCacheFailed
}
table := session.statement.RefTable
ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
if err != nil {
rows, err := session.queryRows(newsql, args...)
if err != nil {
return err
}
defer rows.Close()
var i int
ids = make([]core.PK, 0)
for rows.Next() {
i++
if i > 500 {
session.engine.logger.Debug("[cacheFind] ids length > 500, no cache")
return ErrCacheFailed
}
var res = make([]string, len(table.PrimaryKeys))
err = rows.ScanSlice(&res)
if err != nil {
return err
}
var pk core.PK = make([]interface{}, len(table.PrimaryKeys))
for i, col := range table.PKColumns() {
pk[i], err = session.engine.idTypeAssertion(col, res[i])
if err != nil {
return err
}
}
ids = append(ids, pk)
}
session.engine.logger.Debug("[cacheFind] cache sql:", ids, tableName, sqlStr, newsql, args)
err = core.PutCacheSql(cacher, ids, tableName, newsql, args)
if err != nil {
return err
}
} else {
session.engine.logger.Debug("[cacheFind] cache hit sql:", tableName, sqlStr, newsql, args)
}
sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
ididxes := make(map[string]int)
var ides []core.PK
var temps = make([]interface{}, len(ids))
for idx, id := range ids {
sid, err := id.ToString()
if err != nil {
return err
}
bean := cacher.GetBean(tableName, sid)
if bean == nil || reflect.ValueOf(bean).Elem().Type() != t {
ides = append(ides, id)
ididxes[sid] = idx
} else {
session.engine.logger.Debug("[cacheFind] cache hit bean:", tableName, id, bean)
pk := session.engine.IdOf(bean)
xid, err := pk.ToString()
if err != nil {
return err
}
if sid != xid {
session.engine.logger.Error("[cacheFind] error cache", xid, sid, bean)
return ErrCacheFailed
}
temps[idx] = bean
}
}
if len(ides) > 0 {
slices := reflect.New(reflect.SliceOf(t))
beans := slices.Interface()
if len(table.PrimaryKeys) == 1 {
ff := make([]interface{}, 0, len(ides))
for _, ie := range ides {
ff = append(ff, ie[0])
}
session.In("`"+table.PrimaryKeys[0]+"`", ff...)
} else {
for _, ie := range ides {
cond := builder.NewCond()
for i, name := range table.PrimaryKeys {
cond = cond.And(builder.Eq{"`" + name + "`": ie[i]})
}
session.Or(cond)
}
}
err = session.NoCache().Table(tableName).find(beans)
if err != nil {
return err
}
vs := reflect.Indirect(reflect.ValueOf(beans))
for i := 0; i < vs.Len(); i++ {
rv := vs.Index(i)
if rv.Kind() != reflect.Ptr {
rv = rv.Addr()
}
id, err := session.engine.idOfV(rv)
if err != nil {
return err
}
sid, err := id.ToString()
if err != nil {
return err
}
bean := rv.Interface()
temps[ididxes[sid]] = bean
session.engine.logger.Debug("[cacheFind] cache bean:", tableName, id, bean, temps)
cacher.PutBean(tableName, sid, bean)
}
}
for j := 0; j < len(temps); j++ {
bean := temps[j]
if bean == nil {
session.engine.logger.Warn("[cacheFind] cache no hit:", tableName, ids[j], temps)
// return errors.New("cache error") // !nashtsai! no need to return error, but continue instead
continue
}
if sliceValue.Kind() == reflect.Slice {
if t.Kind() == reflect.Ptr {
sliceValue.Set(reflect.Append(sliceValue, reflect.ValueOf(bean)))
} else {
sliceValue.Set(reflect.Append(sliceValue, reflect.Indirect(reflect.ValueOf(bean))))
}
} else if sliceValue.Kind() == reflect.Map {
var key = ids[j]
keyType := sliceValue.Type().Key()
var ikey interface{}
if len(key) == 1 {
ikey, err = str2PK(fmt.Sprintf("%v", key[0]), keyType)
if err != nil {
return err
}
} else {
if keyType.Kind() != reflect.Slice {
return errors.New("table have multiple primary keys, key is not core.PK or slice")
}
ikey = key
}
if t.Kind() == reflect.Ptr {
sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.ValueOf(bean))
} else {
sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.Indirect(reflect.ValueOf(bean)))
}
}
}
return nil
}

View File

@ -1,212 +0,0 @@
// Copyright 2016 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 (
"database/sql"
"errors"
"reflect"
"strconv"
"github.com/go-xorm/core"
)
// Get retrieve one record from database, bean's non-empty fields
// will be as conditions
func (session *Session) Get(bean interface{}) (bool, error) {
if session.isAutoClose {
defer session.Close()
}
return session.get(bean)
}
func (session *Session) get(bean interface{}) (bool, error) {
beanValue := reflect.ValueOf(bean)
if beanValue.Kind() != reflect.Ptr {
return false, errors.New("needs a pointer to a value")
} else if beanValue.Elem().Kind() == reflect.Ptr {
return false, errors.New("a pointer to a pointer is not allowed")
}
if beanValue.Elem().Kind() == reflect.Struct {
if err := session.statement.setRefBean(bean); err != nil {
return false, err
}
}
var sqlStr string
var args []interface{}
var err error
if session.statement.RawSQL == "" {
if len(session.statement.TableName()) <= 0 {
return false, ErrTableNotFound
}
session.statement.Limit(1)
sqlStr, args, err = session.statement.genGetSQL(bean)
if err != nil {
return false, err
}
} else {
sqlStr = session.statement.RawSQL
args = session.statement.RawParams
}
table := session.statement.RefTable
if session.canCache() && beanValue.Elem().Kind() == reflect.Struct {
if cacher := session.engine.getCacher(table.Name); cacher != nil &&
!session.statement.unscoped {
has, err := session.cacheGet(bean, sqlStr, args...)
if err != ErrCacheFailed {
return has, err
}
}
}
return session.nocacheGet(beanValue.Elem().Kind(), table, bean, 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 {
return false, err
}
defer rows.Close()
if !rows.Next() {
return false, nil
}
switch bean.(type) {
case sql.NullInt64, sql.NullBool, sql.NullFloat64, sql.NullString:
return true, rows.Scan(&bean)
case *sql.NullInt64, *sql.NullBool, *sql.NullFloat64, *sql.NullString:
return true, rows.Scan(bean)
}
switch beanKind {
case reflect.Struct:
fields, err := rows.Columns()
if err != nil {
// WARN: Alougth rows return true, but get fields failed
return true, err
}
scanResults, err := session.row2Slice(rows, fields, bean)
if err != nil {
return false, err
}
// close it before covert data
rows.Close()
dataStruct := rValue(bean)
_, err = session.slice2Bean(scanResults, fields, bean, &dataStruct, table)
if err != nil {
return true, err
}
return true, session.executeProcessors()
case reflect.Slice:
err = rows.ScanSlice(bean)
case reflect.Map:
err = rows.ScanMap(bean)
default:
err = rows.Scan(bean)
}
return true, err
}
func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interface{}) (has bool, err error) {
// if has no reftable, then don't use cache currently
if !session.canCache() {
return false, ErrCacheFailed
}
for _, filter := range session.engine.dialect.Filters() {
sqlStr = filter.Do(sqlStr, session.engine.dialect, session.statement.RefTable)
}
newsql := session.statement.convertIDSQL(sqlStr)
if newsql == "" {
return false, ErrCacheFailed
}
tableName := session.statement.TableName()
cacher := session.engine.getCacher(tableName)
session.engine.logger.Debug("[cacheGet] find sql:", newsql, args)
table := session.statement.RefTable
ids, err := core.GetCacheSql(cacher, tableName, newsql, args)
if err != nil {
var res = make([]string, len(table.PrimaryKeys))
rows, err := session.NoCache().queryRows(newsql, args...)
if err != nil {
return false, err
}
defer rows.Close()
if rows.Next() {
err = rows.ScanSlice(&res)
if err != nil {
return false, err
}
} else {
return false, ErrCacheFailed
}
var pk core.PK = make([]interface{}, len(table.PrimaryKeys))
for i, col := range table.PKColumns() {
if col.SQLType.IsText() {
pk[i] = res[i]
} else if col.SQLType.IsNumeric() {
n, err := strconv.ParseInt(res[i], 10, 64)
if err != nil {
return false, err
}
pk[i] = n
} else {
return false, errors.New("unsupported")
}
}
ids = []core.PK{pk}
session.engine.logger.Debug("[cacheGet] cache ids:", newsql, ids)
err = core.PutCacheSql(cacher, ids, tableName, newsql, args)
if err != nil {
return false, err
}
} else {
session.engine.logger.Debug("[cacheGet] cache hit sql:", newsql, ids)
}
if len(ids) > 0 {
structValue := reflect.Indirect(reflect.ValueOf(bean))
id := ids[0]
session.engine.logger.Debug("[cacheGet] get bean:", tableName, id)
sid, err := id.ToString()
if err != nil {
return false, err
}
cacheBean := cacher.GetBean(tableName, sid)
if cacheBean == nil {
cacheBean = bean
has, err = session.nocacheGet(reflect.Struct, table, cacheBean, sqlStr, args...)
if err != nil || !has {
return has, err
}
session.engine.logger.Debug("[cacheGet] cache bean:", tableName, id, cacheBean)
cacher.PutBean(tableName, sid, cacheBean)
} else {
session.engine.logger.Debug("[cacheGet] cache hit bean:", tableName, id, cacheBean)
has = true
}
structValue.Set(reflect.Indirect(reflect.ValueOf(cacheBean)))
return has, nil
}
return false, nil
}

View File

@ -1,626 +0,0 @@
// Copyright 2016 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 (
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"github.com/go-xorm/core"
)
// Insert insert one or more beans
func (session *Session) Insert(beans ...interface{}) (int64, error) {
var affected int64
var err error
if session.isAutoClose {
defer session.Close()
}
for _, bean := range beans {
sliceValue := reflect.Indirect(reflect.ValueOf(bean))
if sliceValue.Kind() == reflect.Slice {
size := sliceValue.Len()
if size > 0 {
if session.engine.SupportInsertMany() {
cnt, err := session.innerInsertMulti(bean)
if err != nil {
return affected, err
}
affected += cnt
} else {
for i := 0; i < size; i++ {
cnt, err := session.innerInsert(sliceValue.Index(i).Interface())
if err != nil {
return affected, err
}
affected += cnt
}
}
}
} else {
cnt, err := session.innerInsert(bean)
if err != nil {
return affected, err
}
affected += cnt
}
}
return affected, err
}
func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error) {
sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
if sliceValue.Kind() != reflect.Slice {
return 0, errors.New("needs a pointer to a slice")
}
if sliceValue.Len() <= 0 {
return 0, errors.New("could not insert a empty slice")
}
if err := session.statement.setRefBean(sliceValue.Index(0).Interface()); err != nil {
return 0, err
}
tableName := session.statement.TableName()
if len(tableName) <= 0 {
return 0, ErrTableNotFound
}
table := session.statement.RefTable
size := sliceValue.Len()
var colNames []string
var colMultiPlaces []string
var args []interface{}
var cols []*core.Column
for i := 0; i < size; i++ {
v := sliceValue.Index(i)
vv := reflect.Indirect(v)
elemValue := v.Interface()
var colPlaces []string
// handle BeforeInsertProcessor
// !nashtsai! does user expect it's same slice to passed closure when using Before()/After() when insert multi??
for _, closure := range session.beforeClosures {
closure(elemValue)
}
if processor, ok := interface{}(elemValue).(BeforeInsertProcessor); ok {
processor.BeforeInsert()
}
// --
if i == 0 {
for _, col := range table.Columns() {
ptrFieldValue, err := col.ValueOfV(&vv)
if err != nil {
return 0, err
}
fieldValue := *ptrFieldValue
if col.IsAutoIncrement && isZero(fieldValue.Interface()) {
continue
}
if col.MapType == core.ONLYFROMDB {
continue
}
if col.IsDeleted {
continue
}
if session.statement.omitColumnMap.contain(col.Name) {
continue
}
if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
continue
}
if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime {
val, t := session.engine.nowTime(col)
args = append(args, val)
var colName = col.Name
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
col := table.GetColumn(colName)
setColumnTime(bean, col, t)
})
} else if col.IsVersion && session.statement.checkVersion {
args = append(args, 1)
var colName = col.Name
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
col := table.GetColumn(colName)
setColumnInt(bean, col, 1)
})
} else {
arg, err := session.value2Interface(col, fieldValue)
if err != nil {
return 0, err
}
args = append(args, arg)
}
colNames = append(colNames, col.Name)
cols = append(cols, col)
colPlaces = append(colPlaces, "?")
}
} else {
for _, col := range cols {
ptrFieldValue, err := col.ValueOfV(&vv)
if err != nil {
return 0, err
}
fieldValue := *ptrFieldValue
if col.IsAutoIncrement && isZero(fieldValue.Interface()) {
continue
}
if col.MapType == core.ONLYFROMDB {
continue
}
if col.IsDeleted {
continue
}
if session.statement.omitColumnMap.contain(col.Name) {
continue
}
if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
continue
}
if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime {
val, t := session.engine.nowTime(col)
args = append(args, val)
var colName = col.Name
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
col := table.GetColumn(colName)
setColumnTime(bean, col, t)
})
} else if col.IsVersion && session.statement.checkVersion {
args = append(args, 1)
var colName = col.Name
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
col := table.GetColumn(colName)
setColumnInt(bean, col, 1)
})
} else {
arg, err := session.value2Interface(col, fieldValue)
if err != nil {
return 0, err
}
args = append(args, arg)
}
colPlaces = append(colPlaces, "?")
}
}
colMultiPlaces = append(colMultiPlaces, strings.Join(colPlaces, ", "))
}
cleanupProcessorsClosures(&session.beforeClosures)
var sql = "INSERT INTO %s (%v%v%v) VALUES (%v)"
var statement string
if session.engine.dialect.DBType() == core.ORACLE {
sql = "INSERT ALL INTO %s (%v%v%v) VALUES (%v) SELECT 1 FROM DUAL"
temp := fmt.Sprintf(") INTO %s (%v%v%v) VALUES (",
session.engine.Quote(tableName),
session.engine.QuoteStr(),
strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
session.engine.QuoteStr())
statement = fmt.Sprintf(sql,
session.engine.Quote(tableName),
session.engine.QuoteStr(),
strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
session.engine.QuoteStr(),
strings.Join(colMultiPlaces, temp))
} else {
statement = fmt.Sprintf(sql,
session.engine.Quote(tableName),
session.engine.QuoteStr(),
strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
session.engine.QuoteStr(),
strings.Join(colMultiPlaces, "),("))
}
res, err := session.exec(statement, args...)
if err != nil {
return 0, err
}
session.cacheInsert(tableName)
lenAfterClosures := len(session.afterClosures)
for i := 0; i < size; i++ {
elemValue := reflect.Indirect(sliceValue.Index(i)).Addr().Interface()
// handle AfterInsertProcessor
if session.isAutoCommit {
// !nashtsai! does user expect it's same slice to passed closure when using Before()/After() when insert multi??
for _, closure := range session.afterClosures {
closure(elemValue)
}
if processor, ok := interface{}(elemValue).(AfterInsertProcessor); ok {
processor.AfterInsert()
}
} else {
if lenAfterClosures > 0 {
if value, has := session.afterInsertBeans[elemValue]; has && value != nil {
*value = append(*value, session.afterClosures...)
} else {
afterClosures := make([]func(interface{}), lenAfterClosures)
copy(afterClosures, session.afterClosures)
session.afterInsertBeans[elemValue] = &afterClosures
}
} else {
if _, ok := interface{}(elemValue).(AfterInsertProcessor); ok {
session.afterInsertBeans[elemValue] = nil
}
}
}
}
cleanupProcessorsClosures(&session.afterClosures)
return res.RowsAffected()
}
// InsertMulti insert multiple records
func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) {
if session.isAutoClose {
defer session.Close()
}
sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
if sliceValue.Kind() != reflect.Slice {
return 0, ErrParamsType
}
if sliceValue.Len() <= 0 {
return 0, nil
}
return session.innerInsertMulti(rowsSlicePtr)
}
func (session *Session) innerInsert(bean interface{}) (int64, error) {
if err := session.statement.setRefBean(bean); err != nil {
return 0, err
}
if len(session.statement.TableName()) <= 0 {
return 0, ErrTableNotFound
}
table := session.statement.RefTable
// handle BeforeInsertProcessor
for _, closure := range session.beforeClosures {
closure(bean)
}
cleanupProcessorsClosures(&session.beforeClosures) // cleanup after used
if processor, ok := interface{}(bean).(BeforeInsertProcessor); ok {
processor.BeforeInsert()
}
colNames, args, err := session.genInsertColumns(bean)
if err != nil {
return 0, err
}
// insert expr columns, override if exists
exprColumns := session.statement.getExpr()
exprColVals := make([]string, 0, len(exprColumns))
for _, v := range exprColumns {
// remove the expr columns
for i, colName := range colNames {
if colName == v.colName {
colNames = append(colNames[:i], colNames[i+1:]...)
args = append(args[:i], args[i+1:]...)
}
}
// append expr column to the end
colNames = append(colNames, v.colName)
exprColVals = append(exprColVals, v.expr)
}
colPlaces := strings.Repeat("?, ", len(colNames)-len(exprColumns))
if len(exprColVals) > 0 {
colPlaces = colPlaces + strings.Join(exprColVals, ", ")
} else {
if len(colPlaces) > 0 {
colPlaces = colPlaces[0 : len(colPlaces)-2]
}
}
var sqlStr string
var tableName = session.statement.TableName()
if len(colPlaces) > 0 {
sqlStr = fmt.Sprintf("INSERT INTO %s (%v%v%v) VALUES (%v)",
session.engine.Quote(tableName),
session.engine.QuoteStr(),
strings.Join(colNames, session.engine.Quote(", ")),
session.engine.QuoteStr(),
colPlaces)
} else {
if session.engine.dialect.DBType() == core.MYSQL {
sqlStr = fmt.Sprintf("INSERT INTO %s VALUES ()", session.engine.Quote(tableName))
} else {
sqlStr = fmt.Sprintf("INSERT INTO %s DEFAULT VALUES", session.engine.Quote(tableName))
}
}
handleAfterInsertProcessorFunc := func(bean interface{}) {
if session.isAutoCommit {
for _, closure := range session.afterClosures {
closure(bean)
}
if processor, ok := interface{}(bean).(AfterInsertProcessor); ok {
processor.AfterInsert()
}
} else {
lenAfterClosures := len(session.afterClosures)
if lenAfterClosures > 0 {
if value, has := session.afterInsertBeans[bean]; has && value != nil {
*value = append(*value, session.afterClosures...)
} else {
afterClosures := make([]func(interface{}), lenAfterClosures)
copy(afterClosures, session.afterClosures)
session.afterInsertBeans[bean] = &afterClosures
}
} else {
if _, ok := interface{}(bean).(AfterInsertProcessor); ok {
session.afterInsertBeans[bean] = nil
}
}
}
cleanupProcessorsClosures(&session.afterClosures) // cleanup after used
}
// for postgres, many of them didn't implement lastInsertId, so we should
// implemented it ourself.
if session.engine.dialect.DBType() == core.ORACLE && len(table.AutoIncrement) > 0 {
res, err := session.queryBytes("select seq_atable.currval from dual", args...)
if err != nil {
return 0, err
}
defer handleAfterInsertProcessorFunc(bean)
session.cacheInsert(tableName)
if table.Version != "" && session.statement.checkVersion {
verValue, err := table.VersionColumn().ValueOf(bean)
if err != nil {
session.engine.logger.Error(err)
} else if verValue.IsValid() && verValue.CanSet() {
verValue.SetInt(1)
}
}
if len(res) < 1 {
return 0, errors.New("insert no error but not returned id")
}
idByte := res[0][table.AutoIncrement]
id, err := strconv.ParseInt(string(idByte), 10, 64)
if err != nil || id <= 0 {
return 1, err
}
aiValue, err := table.AutoIncrColumn().ValueOf(bean)
if err != nil {
session.engine.logger.Error(err)
}
if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() {
return 1, nil
}
aiValue.Set(int64ToIntValue(id, aiValue.Type()))
return 1, nil
} else if session.engine.dialect.DBType() == core.POSTGRES && len(table.AutoIncrement) > 0 {
//assert table.AutoIncrement != ""
sqlStr = sqlStr + " RETURNING " + session.engine.Quote(table.AutoIncrement)
res, err := session.queryBytes(sqlStr, args...)
if err != nil {
return 0, err
}
defer handleAfterInsertProcessorFunc(bean)
session.cacheInsert(tableName)
if table.Version != "" && session.statement.checkVersion {
verValue, err := table.VersionColumn().ValueOf(bean)
if err != nil {
session.engine.logger.Error(err)
} else if verValue.IsValid() && verValue.CanSet() {
verValue.SetInt(1)
}
}
if len(res) < 1 {
return 0, errors.New("insert no error but not returned id")
}
idByte := res[0][table.AutoIncrement]
id, err := strconv.ParseInt(string(idByte), 10, 64)
if err != nil || id <= 0 {
return 1, err
}
aiValue, err := table.AutoIncrColumn().ValueOf(bean)
if err != nil {
session.engine.logger.Error(err)
}
if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() {
return 1, nil
}
aiValue.Set(int64ToIntValue(id, aiValue.Type()))
return 1, nil
} else {
res, err := session.exec(sqlStr, args...)
if err != nil {
return 0, err
}
defer handleAfterInsertProcessorFunc(bean)
session.cacheInsert(tableName)
if table.Version != "" && session.statement.checkVersion {
verValue, err := table.VersionColumn().ValueOf(bean)
if err != nil {
session.engine.logger.Error(err)
} else if verValue.IsValid() && verValue.CanSet() {
verValue.SetInt(1)
}
}
if table.AutoIncrement == "" {
return res.RowsAffected()
}
var id int64
id, err = res.LastInsertId()
if err != nil || id <= 0 {
return res.RowsAffected()
}
aiValue, err := table.AutoIncrColumn().ValueOf(bean)
if err != nil {
session.engine.logger.Error(err)
}
if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() {
return res.RowsAffected()
}
aiValue.Set(int64ToIntValue(id, aiValue.Type()))
return res.RowsAffected()
}
}
// InsertOne insert only one struct into database as a record.
// The in parameter bean must a struct or a point to struct. The return
// parameter is inserted and error
func (session *Session) InsertOne(bean interface{}) (int64, error) {
if session.isAutoClose {
defer session.Close()
}
return session.innerInsert(bean)
}
func (session *Session) cacheInsert(table string) error {
if !session.statement.UseCache {
return nil
}
cacher := session.engine.getCacher(table)
if cacher == nil {
return nil
}
session.engine.logger.Debug("[cache] clear sql:", table)
cacher.ClearIds(table)
return nil
}
// genInsertColumns generates insert needed columns
func (session *Session) genInsertColumns(bean interface{}) ([]string, []interface{}, error) {
table := session.statement.RefTable
colNames := make([]string, 0, len(table.ColumnsSeq()))
args := make([]interface{}, 0, len(table.ColumnsSeq()))
for _, col := range table.Columns() {
if col.MapType == core.ONLYFROMDB {
continue
}
if col.IsDeleted {
continue
}
if session.statement.omitColumnMap.contain(col.Name) {
continue
}
if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) {
continue
}
if _, ok := session.statement.incrColumns[col.Name]; ok {
continue
} else if _, ok := session.statement.decrColumns[col.Name]; ok {
continue
}
fieldValuePtr, err := col.ValueOf(bean)
if err != nil {
return nil, nil, err
}
fieldValue := *fieldValuePtr
if col.IsAutoIncrement {
switch fieldValue.Type().Kind() {
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
if fieldValue.Int() == 0 {
continue
}
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
if fieldValue.Uint() == 0 {
continue
}
case reflect.String:
if len(fieldValue.String()) == 0 {
continue
}
case reflect.Ptr:
if fieldValue.Pointer() == 0 {
continue
}
}
}
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
if col.Nullable && isZero(fieldValue.Interface()) {
var nilValue *int
fieldValue = reflect.ValueOf(nilValue)
}
}
if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
// if time is non-empty, then set to auto time
val, t := session.engine.nowTime(col)
args = append(args, val)
var colName = col.Name
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
col := table.GetColumn(colName)
setColumnTime(bean, col, t)
})
} else if col.IsVersion && session.statement.checkVersion {
args = append(args, 1)
} else {
arg, err := session.value2Interface(col, fieldValue)
if err != nil {
return colNames, args, err
}
args = append(args, arg)
}
colNames = append(colNames, col.Name)
}
return colNames, args, nil
}

View File

@ -1,96 +0,0 @@
// Copyright 2016 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 "reflect"
// IterFunc only use by Iterate
type IterFunc func(idx int, bean interface{}) error
// Rows return sql.Rows compatible Rows obj, as a forward Iterator object for iterating record by record, bean's non-empty fields
// are conditions.
func (session *Session) Rows(bean interface{}) (*Rows, error) {
return newRows(session, bean)
}
// Iterate record by record handle records from table, condiBeans's non-empty fields
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
// map[int64]*Struct
func (session *Session) Iterate(bean interface{}, fun IterFunc) error {
if session.isAutoClose {
defer session.Close()
}
if session.statement.bufferSize > 0 {
return session.bufferIterate(bean, fun)
}
rows, err := session.Rows(bean)
if err != nil {
return err
}
defer rows.Close()
i := 0
for rows.Next() {
b := reflect.New(rows.beanType).Interface()
err = rows.Scan(b)
if err != nil {
return err
}
err = fun(i, b)
if err != nil {
return err
}
i++
}
return err
}
// BufferSize sets the buffersize for iterate
func (session *Session) BufferSize(size int) *Session {
session.statement.bufferSize = size
return session
}
func (session *Session) bufferIterate(bean interface{}, fun IterFunc) error {
if session.isAutoClose {
defer session.Close()
}
var bufferSize = session.statement.bufferSize
var limit = session.statement.LimitN
if limit > 0 && bufferSize > limit {
bufferSize = limit
}
var start = session.statement.Start
v := rValue(bean)
sliceType := reflect.SliceOf(v.Type())
var idx = 0
for {
slice := reflect.New(sliceType)
if err := session.Limit(bufferSize, start).find(slice.Interface(), bean); err != nil {
return err
}
for i := 0; i < slice.Elem().Len(); i++ {
if err := fun(idx, slice.Elem().Index(i).Addr().Interface()); err != nil {
return err
}
idx++
}
start = start + slice.Elem().Len()
if limit > 0 && idx+bufferSize > limit {
bufferSize = limit - idx
}
if bufferSize <= 0 || slice.Elem().Len() < bufferSize || idx == limit {
break
}
}
return nil
}

View File

@ -1,266 +0,0 @@
// 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"
"strings"
"time"
"github.com/go-xorm/builder"
"github.com/go-xorm/core"
)
func (session *Session) genQuerySQL(sqlorArgs ...interface{}) (string, []interface{}, error) {
if len(sqlorArgs) > 0 {
switch sqlorArgs[0].(type) {
case string:
return sqlorArgs[0].(string), sqlorArgs[1:], nil
case *builder.Builder:
return sqlorArgs[0].(*builder.Builder).ToSQL()
case builder.Builder:
bd := sqlorArgs[0].(builder.Builder)
return bd.ToSQL()
default:
return "", nil, ErrUnSupportedType
}
}
if session.statement.RawSQL != "" {
return session.statement.RawSQL, session.statement.RawParams, nil
}
if len(session.statement.TableName()) <= 0 {
return "", nil, ErrTableNotFound
}
var columnStr = session.statement.ColumnStr
if len(session.statement.selectStr) > 0 {
columnStr = session.statement.selectStr
} else {
if session.statement.JoinStr == "" {
if columnStr == "" {
if session.statement.GroupByStr != "" {
columnStr = session.statement.Engine.Quote(strings.Replace(session.statement.GroupByStr, ",", session.engine.Quote(","), -1))
} else {
columnStr = session.statement.genColumnStr()
}
}
} else {
if columnStr == "" {
if session.statement.GroupByStr != "" {
columnStr = session.statement.Engine.Quote(strings.Replace(session.statement.GroupByStr, ",", session.engine.Quote(","), -1))
} else {
columnStr = "*"
}
}
}
if columnStr == "" {
columnStr = "*"
}
}
if err := session.statement.processIDParam(); err != nil {
return "", nil, err
}
condSQL, condArgs, err := builder.ToSQL(session.statement.cond)
if err != nil {
return "", nil, err
}
args := append(session.statement.joinArgs, condArgs...)
sqlStr, err := session.statement.genSelectSQL(columnStr, condSQL, true, true)
if err != nil {
return "", nil, err
}
// for mssql and use limit
qs := strings.Count(sqlStr, "?")
if len(args)*2 == qs {
args = append(args, args...)
}
return sqlStr, args, nil
}
// Query runs a raw sql and return records as []map[string][]byte
func (session *Session) Query(sqlorArgs ...interface{}) ([]map[string][]byte, error) {
if session.isAutoClose {
defer session.Close()
}
sqlStr, args, err := session.genQuerySQL(sqlorArgs...)
if err != nil {
return nil, err
}
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(sqlorArgs ...interface{}) ([]map[string]string, error) {
if session.isAutoClose {
defer session.Close()
}
sqlStr, args, err := session.genQuerySQL(sqlorArgs...)
if err != nil {
return nil, err
}
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(sqlorArgs ...interface{}) ([]map[string]interface{}, error) {
if session.isAutoClose {
defer session.Close()
}
sqlStr, args, err := session.genQuerySQL(sqlorArgs...)
if err != nil {
return nil, err
}
rows, err := session.queryRows(sqlStr, args...)
if err != nil {
return nil, err
}
defer rows.Close()
return rows2Interfaces(rows)
}

View File

@ -1,203 +0,0 @@
// Copyright 2016 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 (
"database/sql"
"reflect"
"time"
"github.com/go-xorm/core"
)
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.lastSQL = *sqlStr
session.lastSQLArgs = paramStr
}
func (session *Session) queryRows(sqlStr string, args ...interface{}) (*core.Rows, error) {
defer session.resetStatement()
session.queryPreprocess(&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 {
var db *core.DB
if session.engine.engineGroup != nil {
db = session.engine.engineGroup.Slave().DB()
} else {
db = session.DB()
}
if session.prepareStmt {
// don't clear stmt since session will cache them
stmt, err := session.doPrepare(db, sqlStr)
if err != nil {
return nil, err
}
rows, err := stmt.Query(args...)
if err != nil {
return nil, err
}
return rows, nil
}
rows, err := db.Query(sqlStr, args...)
if err != nil {
return nil, err
}
return rows, nil
}
rows, err := session.tx.Query(sqlStr, args...)
if err != nil {
return nil, err
}
return rows, nil
}
func (session *Session) queryRow(sqlStr string, args ...interface{}) *core.Row {
return core.NewRow(session.queryRows(sqlStr, args...))
}
func value2Bytes(rawValue *reflect.Value) ([]byte, error) {
str, err := value2String(rawValue)
if err != nil {
return nil, err
}
return []byte(str), nil
}
func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, err error) {
result := make(map[string][]byte)
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 {
result[key] = []byte{}
continue
}
if data, err := value2Bytes(&rawValue); err == nil {
result[key] = data
} else {
return nil, err // !nashtsai! REVIEW, should return err or just error log?
}
}
return result, nil
}
func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) {
fields, err := rows.Columns()
if err != nil {
return nil, err
}
for rows.Next() {
result, err := row2map(rows, fields)
if err != nil {
return nil, err
}
resultsSlice = append(resultsSlice, result)
}
return resultsSlice, nil
}
func (session *Session) queryBytes(sqlStr string, args ...interface{}) ([]map[string][]byte, error) {
rows, err := session.queryRows(sqlStr, args...)
if err != nil {
return nil, err
}
defer rows.Close()
return rows2maps(rows)
}
func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) {
defer session.resetStatement()
session.queryPreprocess(&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...)
}
if session.prepareStmt {
stmt, err := session.doPrepare(session.DB(), sqlStr)
if err != nil {
return nil, err
}
res, err := stmt.Exec(args...)
if err != nil {
return nil, err
}
return res, nil
}
return session.DB().Exec(sqlStr, args...)
}
// Exec raw sql
func (session *Session) Exec(sqlStr string, args ...interface{}) (sql.Result, error) {
if session.isAutoClose {
defer session.Close()
}
return session.exec(sqlStr, args...)
}

View File

@ -1,421 +0,0 @@
// Copyright 2016 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 (
"database/sql"
"fmt"
"strings"
"github.com/go-xorm/core"
)
// Ping test if database is ok
func (session *Session) Ping() error {
if session.isAutoClose {
defer session.Close()
}
session.engine.logger.Infof("PING DATABASE %v", session.engine.DriverName())
return session.DB().Ping()
}
// CreateTable create a table according a bean
func (session *Session) CreateTable(bean interface{}) error {
if session.isAutoClose {
defer session.Close()
}
return session.createTable(bean)
}
func (session *Session) createTable(bean interface{}) error {
if err := session.statement.setRefBean(bean); err != nil {
return err
}
sqlStr := session.statement.genCreateTableSQL()
_, err := session.exec(sqlStr)
return err
}
// CreateIndexes create indexes
func (session *Session) CreateIndexes(bean interface{}) error {
if session.isAutoClose {
defer session.Close()
}
return session.createIndexes(bean)
}
func (session *Session) createIndexes(bean interface{}) error {
if err := session.statement.setRefBean(bean); err != nil {
return err
}
sqls := session.statement.genIndexSQL()
for _, sqlStr := range sqls {
_, err := session.exec(sqlStr)
if err != nil {
return err
}
}
return nil
}
// CreateUniques create uniques
func (session *Session) CreateUniques(bean interface{}) error {
if session.isAutoClose {
defer session.Close()
}
return session.createUniques(bean)
}
func (session *Session) createUniques(bean interface{}) error {
if err := session.statement.setRefBean(bean); err != nil {
return err
}
sqls := session.statement.genUniqueSQL()
for _, sqlStr := range sqls {
_, err := session.exec(sqlStr)
if err != nil {
return err
}
}
return nil
}
// DropIndexes drop indexes
func (session *Session) DropIndexes(bean interface{}) error {
if session.isAutoClose {
defer session.Close()
}
return session.dropIndexes(bean)
}
func (session *Session) dropIndexes(bean interface{}) error {
if err := session.statement.setRefBean(bean); err != nil {
return err
}
sqls := session.statement.genDelIndexSQL()
for _, sqlStr := range sqls {
_, err := session.exec(sqlStr)
if err != nil {
return err
}
}
return nil
}
// DropTable drop table will drop table if exist, if drop failed, it will return error
func (session *Session) DropTable(beanOrTableName interface{}) error {
if session.isAutoClose {
defer session.Close()
}
return session.dropTable(beanOrTableName)
}
func (session *Session) dropTable(beanOrTableName interface{}) error {
tableName := session.engine.tbNameNoSchema(beanOrTableName)
var needDrop = true
if !session.engine.dialect.SupportDropIfExists() {
sqlStr, args := session.engine.dialect.TableCheckSql(tableName)
results, err := session.queryBytes(sqlStr, args...)
if err != nil {
return err
}
needDrop = len(results) > 0
}
if needDrop {
sqlStr := session.engine.Dialect().DropTableSql(session.engine.TableName(tableName, true))
_, err := session.exec(sqlStr)
return err
}
return nil
}
// IsTableExist if a table is exist
func (session *Session) IsTableExist(beanOrTableName interface{}) (bool, error) {
if session.isAutoClose {
defer session.Close()
}
tableName := session.engine.tbNameNoSchema(beanOrTableName)
return session.isTableExist(tableName)
}
func (session *Session) isTableExist(tableName string) (bool, error) {
sqlStr, args := session.engine.dialect.TableCheckSql(tableName)
results, err := session.queryBytes(sqlStr, args...)
return len(results) > 0, err
}
// IsTableEmpty if table have any records
func (session *Session) IsTableEmpty(bean interface{}) (bool, error) {
if session.isAutoClose {
defer session.Close()
}
return session.isTableEmpty(session.engine.tbNameNoSchema(bean))
}
func (session *Session) isTableEmpty(tableName string) (bool, error) {
var total int64
sqlStr := fmt.Sprintf("select count(*) from %s", session.engine.Quote(session.engine.TableName(tableName, true)))
err := session.queryRow(sqlStr).Scan(&total)
if err != nil {
if err == sql.ErrNoRows {
err = nil
}
return true, err
}
return total == 0, nil
}
// find if index is exist according cols
func (session *Session) isIndexExist2(tableName string, cols []string, unique bool) (bool, error) {
indexes, err := session.engine.dialect.GetIndexes(tableName)
if err != nil {
return false, err
}
for _, index := range indexes {
if sliceEq(index.Cols, cols) {
if unique {
return index.Type == core.UniqueType, nil
}
return index.Type == core.IndexType, nil
}
}
return false, nil
}
func (session *Session) addColumn(colName string) error {
col := session.statement.RefTable.GetColumn(colName)
sql, args := session.statement.genAddColumnStr(col)
_, err := session.exec(sql, args...)
return err
}
func (session *Session) addIndex(tableName, idxName string) error {
index := session.statement.RefTable.Indexes[idxName]
sqlStr := session.engine.dialect.CreateIndexSql(tableName, index)
_, err := session.exec(sqlStr)
return err
}
func (session *Session) addUnique(tableName, uqeName string) error {
index := session.statement.RefTable.Indexes[uqeName]
sqlStr := session.engine.dialect.CreateIndexSql(tableName, index)
_, err := session.exec(sqlStr)
return err
}
// Sync2 synchronize structs to database tables
func (session *Session) Sync2(beans ...interface{}) error {
engine := session.engine
if session.isAutoClose {
session.isAutoClose = false
defer session.Close()
}
tables, err := engine.DBMetas()
if err != nil {
return err
}
session.autoResetStatement = false
defer func() {
session.autoResetStatement = true
session.resetStatement()
}()
var structTables []*core.Table
for _, bean := range beans {
v := rValue(bean)
table, err := engine.mapType(v)
if err != nil {
return err
}
structTables = append(structTables, table)
tbName := session.tbNameNoSchema(table)
tbNameWithSchema := engine.TableName(tbName, true)
var oriTable *core.Table
for _, tb := range tables {
if strings.EqualFold(tb.Name, tbName) {
oriTable = tb
break
}
}
if oriTable == nil {
err = session.StoreEngine(session.statement.StoreEngine).createTable(bean)
if err != nil {
return err
}
err = session.createUniques(bean)
if err != nil {
return err
}
err = session.createIndexes(bean)
if err != nil {
return err
}
} else {
for _, col := range table.Columns() {
var oriCol *core.Column
for _, col2 := range oriTable.Columns() {
if strings.EqualFold(col.Name, col2.Name) {
oriCol = col2
break
}
}
if oriCol != nil {
expectedType := engine.dialect.SqlType(col)
curType := engine.dialect.SqlType(oriCol)
if expectedType != curType {
if expectedType == core.Text &&
strings.HasPrefix(curType, core.Varchar) {
// currently only support mysql & postgres
if engine.dialect.DBType() == core.MYSQL ||
engine.dialect.DBType() == core.POSTGRES {
engine.logger.Infof("Table %s column %s change type from %s to %s\n",
tbNameWithSchema, col.Name, curType, expectedType)
_, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col))
} else {
engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s\n",
tbNameWithSchema, col.Name, curType, expectedType)
}
} else if strings.HasPrefix(curType, core.Varchar) && strings.HasPrefix(expectedType, core.Varchar) {
if engine.dialect.DBType() == core.MYSQL {
if oriCol.Length < col.Length {
engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n",
tbNameWithSchema, col.Name, oriCol.Length, col.Length)
_, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col))
}
}
} else {
if !(strings.HasPrefix(curType, expectedType) && curType[len(expectedType)] == '(') {
engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s",
tbNameWithSchema, col.Name, curType, expectedType)
}
}
} else if expectedType == core.Varchar {
if engine.dialect.DBType() == core.MYSQL {
if oriCol.Length < col.Length {
engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n",
tbNameWithSchema, col.Name, oriCol.Length, col.Length)
_, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col))
}
}
}
if col.Default != oriCol.Default {
engine.logger.Warnf("Table %s Column %s db default is %s, struct default is %s",
tbName, col.Name, oriCol.Default, col.Default)
}
if col.Nullable != oriCol.Nullable {
engine.logger.Warnf("Table %s Column %s db nullable is %v, struct nullable is %v",
tbName, col.Name, oriCol.Nullable, col.Nullable)
}
} else {
session.statement.RefTable = table
session.statement.tableName = tbNameWithSchema
err = session.addColumn(col.Name)
}
if err != nil {
return err
}
}
var foundIndexNames = make(map[string]bool)
var addedNames = make(map[string]*core.Index)
for name, index := range table.Indexes {
var oriIndex *core.Index
for name2, index2 := range oriTable.Indexes {
if index.Equal(index2) {
oriIndex = index2
foundIndexNames[name2] = true
break
}
}
if oriIndex != nil {
if oriIndex.Type != index.Type {
sql := engine.dialect.DropIndexSql(tbNameWithSchema, oriIndex)
_, err = session.exec(sql)
if err != nil {
return err
}
oriIndex = nil
}
}
if oriIndex == nil {
addedNames[name] = index
}
}
for name2, index2 := range oriTable.Indexes {
if _, ok := foundIndexNames[name2]; !ok {
sql := engine.dialect.DropIndexSql(tbNameWithSchema, index2)
_, err = session.exec(sql)
if err != nil {
return err
}
}
}
for name, index := range addedNames {
if index.Type == core.UniqueType {
session.statement.RefTable = table
session.statement.tableName = tbNameWithSchema
err = session.addUnique(tbNameWithSchema, name)
} else if index.Type == core.IndexType {
session.statement.RefTable = table
session.statement.tableName = tbNameWithSchema
err = session.addIndex(tbNameWithSchema, name)
}
if err != nil {
return err
}
}
}
}
for _, table := range tables {
var oriTable *core.Table
for _, structTable := range structTables {
if strings.EqualFold(table.Name, session.tbNameNoSchema(structTable)) {
oriTable = structTable
break
}
}
if oriTable == nil {
//engine.LogWarnf("Table %s has no struct to mapping it", table.Name)
continue
}
for _, colName := range table.ColumnsSeq() {
if oriTable.GetColumn(colName) == nil {
engine.logger.Warnf("Table %s has column %s but struct has not related field", engine.TableName(table.Name, true), colName)
}
}
}
return nil
}

View File

@ -1,98 +0,0 @@
// Copyright 2016 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 (
"database/sql"
"errors"
"reflect"
)
// Count counts the records. bean's non-empty fields
// are conditions.
func (session *Session) Count(bean ...interface{}) (int64, error) {
if session.isAutoClose {
defer session.Close()
}
var sqlStr string
var args []interface{}
var err error
if session.statement.RawSQL == "" {
sqlStr, args, err = session.statement.genCountSQL(bean...)
if err != nil {
return 0, err
}
} else {
sqlStr = session.statement.RawSQL
args = session.statement.RawParams
}
var total int64
err = session.queryRow(sqlStr, args...).Scan(&total)
if err == sql.ErrNoRows || err == nil {
return total, nil
}
return 0, err
}
// sum call sum some column. bean's non-empty fields are conditions.
func (session *Session) sum(res interface{}, bean interface{}, columnNames ...string) error {
if session.isAutoClose {
defer session.Close()
}
v := reflect.ValueOf(res)
if v.Kind() != reflect.Ptr {
return errors.New("need a pointer to a variable")
}
var isSlice = v.Elem().Kind() == reflect.Slice
var sqlStr string
var args []interface{}
var err error
if len(session.statement.RawSQL) == 0 {
sqlStr, args, err = session.statement.genSumSQL(bean, columnNames...)
if err != nil {
return err
}
} else {
sqlStr = session.statement.RawSQL
args = session.statement.RawParams
}
if isSlice {
err = session.queryRow(sqlStr, args...).ScanSlice(res)
} else {
err = session.queryRow(sqlStr, args...).Scan(res)
}
if err == sql.ErrNoRows || err == nil {
return nil
}
return err
}
// Sum call sum some column. bean's non-empty fields are conditions.
func (session *Session) Sum(bean interface{}, columnName string) (res float64, err error) {
return res, session.sum(&res, bean, columnName)
}
// SumInt call sum some column. bean's non-empty fields are conditions.
func (session *Session) SumInt(bean interface{}, columnName string) (res int64, err error) {
return res, session.sum(&res, bean, columnName)
}
// Sums call sum some columns. bean's non-empty fields are conditions.
func (session *Session) Sums(bean interface{}, columnNames ...string) ([]float64, error) {
var res = make([]float64, len(columnNames), len(columnNames))
return res, session.sum(&res, bean, columnNames...)
}
// SumsInt sum specify columns and return as []int64 instead of []float64
func (session *Session) SumsInt(bean interface{}, columnNames ...string) ([]int64, error) {
var res = make([]int64, len(columnNames), len(columnNames))
return res, session.sum(&res, bean, columnNames...)
}

View File

@ -1,81 +0,0 @@
// Copyright 2016 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
// Begin a transaction
func (session *Session) Begin() error {
if session.isAutoCommit {
tx, err := session.DB().Begin()
if err != nil {
return err
}
session.isAutoCommit = false
session.isCommitedOrRollbacked = false
session.tx = tx
session.saveLastSQL("BEGIN TRANSACTION")
}
return nil
}
// Rollback When using transaction, you can rollback if any error
func (session *Session) Rollback() error {
if !session.isAutoCommit && !session.isCommitedOrRollbacked {
session.saveLastSQL(session.engine.dialect.RollBackStr())
session.isCommitedOrRollbacked = true
return session.tx.Rollback()
}
return nil
}
// Commit When using transaction, Commit will commit all operations.
func (session *Session) Commit() error {
if !session.isAutoCommit && !session.isCommitedOrRollbacked {
session.saveLastSQL("COMMIT")
session.isCommitedOrRollbacked = true
var err error
if err = session.tx.Commit(); err == nil {
// handle processors after tx committed
closureCallFunc := func(closuresPtr *[]func(interface{}), bean interface{}) {
if closuresPtr != nil {
for _, closure := range *closuresPtr {
closure(bean)
}
}
}
for bean, closuresPtr := range session.afterInsertBeans {
closureCallFunc(closuresPtr, bean)
if processor, ok := interface{}(bean).(AfterInsertProcessor); ok {
processor.AfterInsert()
}
}
for bean, closuresPtr := range session.afterUpdateBeans {
closureCallFunc(closuresPtr, bean)
if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok {
processor.AfterUpdate()
}
}
for bean, closuresPtr := range session.afterDeleteBeans {
closureCallFunc(closuresPtr, bean)
if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok {
processor.AfterDelete()
}
}
cleanUpFunc := func(slices *map[interface{}]*[]func(interface{})) {
if len(*slices) > 0 {
*slices = make(map[interface{}]*[]func(interface{}), 0)
}
}
cleanUpFunc(&session.afterInsertBeans)
cleanUpFunc(&session.afterUpdateBeans)
cleanUpFunc(&session.afterDeleteBeans)
}
return err
}
return nil
}

View File

@ -1,491 +0,0 @@
// Copyright 2016 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 (
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"github.com/go-xorm/builder"
"github.com/go-xorm/core"
)
func (session *Session) cacheUpdate(table *core.Table, tableName, sqlStr string, args ...interface{}) error {
if table == nil ||
session.tx != nil {
return ErrCacheFailed
}
oldhead, newsql := session.statement.convertUpdateSQL(sqlStr)
if newsql == "" {
return ErrCacheFailed
}
for _, filter := range session.engine.dialect.Filters() {
newsql = filter.Do(newsql, session.engine.dialect, table)
}
session.engine.logger.Debug("[cacheUpdate] new sql", oldhead, newsql)
var nStart int
if len(args) > 0 {
if strings.Index(sqlStr, "?") > -1 {
nStart = strings.Count(oldhead, "?")
} else {
// only for pq, TODO: if any other databse?
nStart = strings.Count(oldhead, "$")
}
}
cacher := session.engine.getCacher(tableName)
session.engine.logger.Debug("[cacheUpdate] get cache sql", newsql, args[nStart:])
ids, err := core.GetCacheSql(cacher, tableName, newsql, args[nStart:])
if err != nil {
rows, err := session.NoCache().queryRows(newsql, args[nStart:]...)
if err != nil {
return err
}
defer rows.Close()
ids = make([]core.PK, 0)
for rows.Next() {
var res = make([]string, len(table.PrimaryKeys))
err = rows.ScanSlice(&res)
if err != nil {
return err
}
var pk core.PK = make([]interface{}, len(table.PrimaryKeys))
for i, col := range table.PKColumns() {
if col.SQLType.IsNumeric() {
n, err := strconv.ParseInt(res[i], 10, 64)
if err != nil {
return err
}
pk[i] = n
} else if col.SQLType.IsText() {
pk[i] = res[i]
} else {
return errors.New("not supported")
}
}
ids = append(ids, pk)
}
session.engine.logger.Debug("[cacheUpdate] find updated id", ids)
} /*else {
session.engine.LogDebug("[xorm:cacheUpdate] del cached sql:", tableName, newsql, args)
cacher.DelIds(tableName, genSqlKey(newsql, args))
}*/
for _, id := range ids {
sid, err := id.ToString()
if err != nil {
return err
}
if bean := cacher.GetBean(tableName, sid); bean != nil {
sqls := splitNNoCase(sqlStr, "where", 2)
if len(sqls) == 0 || len(sqls) > 2 {
return ErrCacheFailed
}
sqls = splitNNoCase(sqls[0], "set", 2)
if len(sqls) != 2 {
return ErrCacheFailed
}
kvs := strings.Split(strings.TrimSpace(sqls[1]), ",")
for idx, kv := range kvs {
sps := strings.SplitN(kv, "=", 2)
sps2 := strings.Split(sps[0], ".")
colName := sps2[len(sps2)-1]
if strings.Contains(colName, "`") {
colName = strings.TrimSpace(strings.Replace(colName, "`", "", -1))
} else if strings.Contains(colName, session.engine.QuoteStr()) {
colName = strings.TrimSpace(strings.Replace(colName, session.engine.QuoteStr(), "", -1))
} else {
session.engine.logger.Debug("[cacheUpdate] cannot find column", tableName, colName)
return ErrCacheFailed
}
if col := table.GetColumn(colName); col != nil {
fieldValue, err := col.ValueOf(bean)
if err != nil {
session.engine.logger.Error(err)
} else {
session.engine.logger.Debug("[cacheUpdate] set bean field", bean, colName, fieldValue.Interface())
if col.IsVersion && session.statement.checkVersion {
fieldValue.SetInt(fieldValue.Int() + 1)
} else {
fieldValue.Set(reflect.ValueOf(args[idx]))
}
}
} else {
session.engine.logger.Errorf("[cacheUpdate] ERROR: column %v is not table %v's",
colName, table.Name)
}
}
session.engine.logger.Debug("[cacheUpdate] update cache", tableName, id, bean)
cacher.PutBean(tableName, sid, bean)
}
}
session.engine.logger.Debug("[cacheUpdate] clear cached table sql:", tableName)
cacher.ClearIds(tableName)
return nil
}
// Update records, bean's non-empty fields are updated contents,
// condiBean' non-empty filds are conditions
// CAUTION:
// 1.bool will defaultly be updated content nor conditions
// You should call UseBool if you have bool to use.
// 2.float32 & float64 may be not inexact as conditions
func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int64, error) {
if session.isAutoClose {
defer session.Close()
}
v := rValue(bean)
t := v.Type()
var colNames []string
var args []interface{}
// handle before update processors
for _, closure := range session.beforeClosures {
closure(bean)
}
cleanupProcessorsClosures(&session.beforeClosures) // cleanup after used
if processor, ok := interface{}(bean).(BeforeUpdateProcessor); ok {
processor.BeforeUpdate()
}
// --
var err error
var isMap = t.Kind() == reflect.Map
var isStruct = t.Kind() == reflect.Struct
if isStruct {
if err := session.statement.setRefBean(bean); err != nil {
return 0, err
}
if len(session.statement.TableName()) <= 0 {
return 0, ErrTableNotFound
}
if session.statement.ColumnStr == "" {
colNames, args = session.statement.buildUpdates(bean, false, false,
false, false, true)
} else {
colNames, args, err = session.genUpdateColumns(bean)
if err != nil {
return 0, err
}
}
} else if isMap {
colNames = make([]string, 0)
args = make([]interface{}, 0)
bValue := reflect.Indirect(reflect.ValueOf(bean))
for _, v := range bValue.MapKeys() {
colNames = append(colNames, session.engine.Quote(v.String())+" = ?")
args = append(args, bValue.MapIndex(v).Interface())
}
} else {
return 0, ErrParamsType
}
table := session.statement.RefTable
if session.statement.UseAutoTime && table != nil && table.Updated != "" {
if !session.statement.columnMap.contain(table.Updated) &&
!session.statement.omitColumnMap.contain(table.Updated) {
colNames = append(colNames, session.engine.Quote(table.Updated)+" = ?")
col := table.UpdatedColumn()
val, t := session.engine.nowTime(col)
args = append(args, val)
var colName = col.Name
if isStruct {
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
col := table.GetColumn(colName)
setColumnTime(bean, col, t)
})
}
}
}
//for update action to like "column = column + ?"
incColumns := session.statement.getInc()
for _, v := range incColumns {
colNames = append(colNames, session.engine.Quote(v.colName)+" = "+session.engine.Quote(v.colName)+" + ?")
args = append(args, v.arg)
}
//for update action to like "column = column - ?"
decColumns := session.statement.getDec()
for _, v := range decColumns {
colNames = append(colNames, session.engine.Quote(v.colName)+" = "+session.engine.Quote(v.colName)+" - ?")
args = append(args, v.arg)
}
//for update action to like "column = expression"
exprColumns := session.statement.getExpr()
for _, v := range exprColumns {
colNames = append(colNames, session.engine.Quote(v.colName)+" = "+v.expr)
}
if err = session.statement.processIDParam(); err != nil {
return 0, err
}
var autoCond builder.Cond
if !session.statement.noAutoCondition && len(condiBean) > 0 {
if c, ok := condiBean[0].(map[string]interface{}); ok {
autoCond = builder.Eq(c)
} else {
ct := reflect.TypeOf(condiBean[0])
k := ct.Kind()
if k == reflect.Ptr {
k = ct.Elem().Kind()
}
if k == reflect.Struct {
var err error
autoCond, err = session.statement.buildConds(session.statement.RefTable, condiBean[0], true, true, false, true, false)
if err != nil {
return 0, err
}
} else {
return 0, ErrConditionType
}
}
}
st := &session.statement
var sqlStr string
var condArgs []interface{}
var condSQL string
cond := session.statement.cond.And(autoCond)
var doIncVer = (table != nil && table.Version != "" && session.statement.checkVersion)
var verValue *reflect.Value
if doIncVer {
verValue, err = table.VersionColumn().ValueOf(bean)
if err != nil {
return 0, err
}
cond = cond.And(builder.Eq{session.engine.Quote(table.Version): verValue.Interface()})
colNames = append(colNames, session.engine.Quote(table.Version)+" = "+session.engine.Quote(table.Version)+" + 1")
}
condSQL, condArgs, err = builder.ToSQL(cond)
if err != nil {
return 0, err
}
if len(condSQL) > 0 {
condSQL = "WHERE " + condSQL
}
if st.OrderStr != "" {
condSQL = condSQL + fmt.Sprintf(" ORDER BY %v", st.OrderStr)
}
var tableName = session.statement.TableName()
// TODO: Oracle support needed
var top string
if st.LimitN > 0 {
if st.Engine.dialect.DBType() == core.MYSQL {
condSQL = condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN)
} else if st.Engine.dialect.DBType() == core.SQLITE {
tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN)
cond = cond.And(builder.Expr(fmt.Sprintf("rowid IN (SELECT rowid FROM %v %v)",
session.engine.Quote(tableName), tempCondSQL), condArgs...))
condSQL, condArgs, err = builder.ToSQL(cond)
if err != nil {
return 0, err
}
if len(condSQL) > 0 {
condSQL = "WHERE " + condSQL
}
} else if st.Engine.dialect.DBType() == core.POSTGRES {
tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN)
cond = cond.And(builder.Expr(fmt.Sprintf("CTID IN (SELECT CTID FROM %v %v)",
session.engine.Quote(tableName), tempCondSQL), condArgs...))
condSQL, condArgs, err = builder.ToSQL(cond)
if err != nil {
return 0, err
}
if len(condSQL) > 0 {
condSQL = "WHERE " + condSQL
}
} else if st.Engine.dialect.DBType() == core.MSSQL {
if st.OrderStr != "" && st.Engine.dialect.DBType() == core.MSSQL &&
table != nil && len(table.PrimaryKeys) == 1 {
cond = builder.Expr(fmt.Sprintf("%s IN (SELECT TOP (%d) %s FROM %v%v)",
table.PrimaryKeys[0], st.LimitN, table.PrimaryKeys[0],
session.engine.Quote(tableName), condSQL), condArgs...)
condSQL, condArgs, err = builder.ToSQL(cond)
if err != nil {
return 0, err
}
if len(condSQL) > 0 {
condSQL = "WHERE " + condSQL
}
} else {
top = fmt.Sprintf("TOP (%d) ", st.LimitN)
}
}
}
if len(colNames) <= 0 {
return 0, errors.New("No content found to be updated")
}
sqlStr = fmt.Sprintf("UPDATE %v%v SET %v %v",
top,
session.engine.Quote(tableName),
strings.Join(colNames, ", "),
condSQL)
res, err := session.exec(sqlStr, append(args, condArgs...)...)
if err != nil {
return 0, err
} else if doIncVer {
if verValue != nil && verValue.IsValid() && verValue.CanSet() {
verValue.SetInt(verValue.Int() + 1)
}
}
if cacher := session.engine.getCacher(tableName); cacher != nil && session.statement.UseCache {
//session.cacheUpdate(table, tableName, sqlStr, args...)
session.engine.logger.Debug("[cacheUpdate] clear table ", tableName)
cacher.ClearIds(tableName)
cacher.ClearBeans(tableName)
}
// handle after update processors
if session.isAutoCommit {
for _, closure := range session.afterClosures {
closure(bean)
}
if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok {
session.engine.logger.Debug("[event]", tableName, " has after update processor")
processor.AfterUpdate()
}
} else {
lenAfterClosures := len(session.afterClosures)
if lenAfterClosures > 0 {
if value, has := session.afterUpdateBeans[bean]; has && value != nil {
*value = append(*value, session.afterClosures...)
} else {
afterClosures := make([]func(interface{}), lenAfterClosures)
copy(afterClosures, session.afterClosures)
// FIXME: if bean is a map type, it will panic because map cannot be as map key
session.afterUpdateBeans[bean] = &afterClosures
}
} else {
if _, ok := interface{}(bean).(AfterUpdateProcessor); ok {
session.afterUpdateBeans[bean] = nil
}
}
}
cleanupProcessorsClosures(&session.afterClosures) // cleanup after used
// --
return res.RowsAffected()
}
func (session *Session) genUpdateColumns(bean interface{}) ([]string, []interface{}, error) {
table := session.statement.RefTable
colNames := make([]string, 0, len(table.ColumnsSeq()))
args := make([]interface{}, 0, len(table.ColumnsSeq()))
for _, col := range table.Columns() {
if !col.IsVersion && !col.IsCreated && !col.IsUpdated {
if session.statement.omitColumnMap.contain(col.Name) {
continue
}
}
if col.MapType == core.ONLYFROMDB {
continue
}
fieldValuePtr, err := col.ValueOf(bean)
if err != nil {
return nil, nil, err
}
fieldValue := *fieldValuePtr
if col.IsAutoIncrement {
switch fieldValue.Type().Kind() {
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
if fieldValue.Int() == 0 {
continue
}
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
if fieldValue.Uint() == 0 {
continue
}
case reflect.String:
if len(fieldValue.String()) == 0 {
continue
}
case reflect.Ptr:
if fieldValue.Pointer() == 0 {
continue
}
}
}
if col.IsDeleted || col.IsCreated {
continue
}
if len(session.statement.columnMap) > 0 {
if !session.statement.columnMap.contain(col.Name) {
continue
} else if _, ok := session.statement.incrColumns[col.Name]; ok {
continue
} else if _, ok := session.statement.decrColumns[col.Name]; ok {
continue
}
}
// !evalphobia! set fieldValue as nil when column is nullable and zero-value
if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok {
if col.Nullable && isZero(fieldValue.Interface()) {
var nilValue *int
fieldValue = reflect.ValueOf(nilValue)
}
}
if col.IsUpdated && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ {
// if time is non-empty, then set to auto time
val, t := session.engine.nowTime(col)
args = append(args, val)
var colName = col.Name
session.afterClosures = append(session.afterClosures, func(bean interface{}) {
col := table.GetColumn(colName)
setColumnTime(bean, col, t)
})
} else if col.IsVersion && session.statement.checkVersion {
args = append(args, 1)
} else {
arg, err := session.value2Interface(col, fieldValue)
if err != nil {
return colNames, args, err
}
args = append(args, arg)
}
colNames = append(colNames, session.engine.Quote(col.Name)+" = ?")
}
return colNames, args, nil
}

File diff suppressed because it is too large Load Diff

View File

@ -1,89 +0,0 @@
// Copyright 2015 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.
// +build !windows,!nacl,!plan9
package xorm
import (
"fmt"
"log/syslog"
"github.com/go-xorm/core"
)
var _ core.ILogger = &SyslogLogger{}
// SyslogLogger will be depricated
type SyslogLogger struct {
w *syslog.Writer
showSQL bool
}
// NewSyslogLogger implements core.ILogger
func NewSyslogLogger(w *syslog.Writer) *SyslogLogger {
return &SyslogLogger{w: w}
}
// Debug log content as Debug
func (s *SyslogLogger) Debug(v ...interface{}) {
s.w.Debug(fmt.Sprint(v...))
}
// Debugf log content as Debug and format
func (s *SyslogLogger) Debugf(format string, v ...interface{}) {
s.w.Debug(fmt.Sprintf(format, v...))
}
// Error log content as Error
func (s *SyslogLogger) Error(v ...interface{}) {
s.w.Err(fmt.Sprint(v...))
}
// Errorf log content as Errorf and format
func (s *SyslogLogger) Errorf(format string, v ...interface{}) {
s.w.Err(fmt.Sprintf(format, v...))
}
// Info log content as Info
func (s *SyslogLogger) Info(v ...interface{}) {
s.w.Info(fmt.Sprint(v...))
}
// Infof log content as Infof and format
func (s *SyslogLogger) Infof(format string, v ...interface{}) {
s.w.Info(fmt.Sprintf(format, v...))
}
// Warn log content as Warn
func (s *SyslogLogger) Warn(v ...interface{}) {
s.w.Warning(fmt.Sprint(v...))
}
// Warnf log content as Warnf and format
func (s *SyslogLogger) Warnf(format string, v ...interface{}) {
s.w.Warning(fmt.Sprintf(format, v...))
}
// Level shows log level
func (s *SyslogLogger) Level() core.LogLevel {
return core.LOG_UNKNOWN
}
// SetLevel always return error, as current log/syslog package doesn't allow to set priority level after syslog.Writer created
func (s *SyslogLogger) SetLevel(l core.LogLevel) {}
// ShowSQL set if logging SQL
func (s *SyslogLogger) ShowSQL(show ...bool) {
if len(show) == 0 {
s.showSQL = true
return
}
s.showSQL = show[0]
}
// IsShowSQL if logging SQL
func (s *SyslogLogger) IsShowSQL() bool {
return s.showSQL
}

290
vendor/github.com/go-xorm/xorm/tag.go generated vendored
View File

@ -1,290 +0,0 @@
// 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"
"strings"
"time"
"github.com/go-xorm/core"
)
type tagContext struct {
tagName string
params []string
preTag, nextTag string
table *core.Table
col *core.Column
fieldValue reflect.Value
isIndex bool
isUnique bool
indexNames map[string]int
engine *Engine
hasCacheTag bool
hasNoCacheTag bool
ignoreNext bool
}
// tagHandler describes tag handler for XORM
type tagHandler func(ctx *tagContext) error
var (
// defaultTagHandlers enumerates all the default tag handler
defaultTagHandlers = map[string]tagHandler{
"<-": OnlyFromDBTagHandler,
"->": OnlyToDBTagHandler,
"PK": PKTagHandler,
"NULL": NULLTagHandler,
"NOT": IgnoreTagHandler,
"AUTOINCR": AutoIncrTagHandler,
"DEFAULT": DefaultTagHandler,
"CREATED": CreatedTagHandler,
"UPDATED": UpdatedTagHandler,
"DELETED": DeletedTagHandler,
"VERSION": VersionTagHandler,
"UTC": UTCTagHandler,
"LOCAL": LocalTagHandler,
"NOTNULL": NotNullTagHandler,
"INDEX": IndexTagHandler,
"UNIQUE": UniqueTagHandler,
"CACHE": CacheTagHandler,
"NOCACHE": NoCacheTagHandler,
"COMMENT": CommentTagHandler,
}
)
func init() {
for k := range core.SqlTypes {
defaultTagHandlers[k] = SQLTypeTagHandler
}
}
// IgnoreTagHandler describes ignored tag handler
func IgnoreTagHandler(ctx *tagContext) error {
return nil
}
// OnlyFromDBTagHandler describes mapping direction tag handler
func OnlyFromDBTagHandler(ctx *tagContext) error {
ctx.col.MapType = core.ONLYFROMDB
return nil
}
// OnlyToDBTagHandler describes mapping direction tag handler
func OnlyToDBTagHandler(ctx *tagContext) error {
ctx.col.MapType = core.ONLYTODB
return nil
}
// PKTagHandler decribes primary key tag handler
func PKTagHandler(ctx *tagContext) error {
ctx.col.IsPrimaryKey = true
ctx.col.Nullable = false
return nil
}
// NULLTagHandler describes null tag handler
func NULLTagHandler(ctx *tagContext) error {
ctx.col.Nullable = (strings.ToUpper(ctx.preTag) != "NOT")
return nil
}
// NotNullTagHandler describes notnull tag handler
func NotNullTagHandler(ctx *tagContext) error {
ctx.col.Nullable = false
return nil
}
// AutoIncrTagHandler describes autoincr tag handler
func AutoIncrTagHandler(ctx *tagContext) error {
ctx.col.IsAutoIncrement = true
/*
if len(ctx.params) > 0 {
autoStartInt, err := strconv.Atoi(ctx.params[0])
if err != nil {
return err
}
ctx.col.AutoIncrStart = autoStartInt
} else {
ctx.col.AutoIncrStart = 1
}
*/
return nil
}
// DefaultTagHandler describes default tag handler
func DefaultTagHandler(ctx *tagContext) error {
if len(ctx.params) > 0 {
ctx.col.Default = ctx.params[0]
} else {
ctx.col.Default = ctx.nextTag
ctx.ignoreNext = true
}
return nil
}
// CreatedTagHandler describes created tag handler
func CreatedTagHandler(ctx *tagContext) error {
ctx.col.IsCreated = true
return nil
}
// VersionTagHandler describes version tag handler
func VersionTagHandler(ctx *tagContext) error {
ctx.col.IsVersion = true
ctx.col.Default = "1"
return nil
}
// UTCTagHandler describes utc tag handler
func UTCTagHandler(ctx *tagContext) error {
ctx.col.TimeZone = time.UTC
return nil
}
// LocalTagHandler describes local tag handler
func LocalTagHandler(ctx *tagContext) error {
if len(ctx.params) == 0 {
ctx.col.TimeZone = time.Local
} else {
var err error
ctx.col.TimeZone, err = time.LoadLocation(ctx.params[0])
if err != nil {
return err
}
}
return nil
}
// UpdatedTagHandler describes updated tag handler
func UpdatedTagHandler(ctx *tagContext) error {
ctx.col.IsUpdated = true
return nil
}
// DeletedTagHandler describes deleted tag handler
func DeletedTagHandler(ctx *tagContext) error {
ctx.col.IsDeleted = true
return nil
}
// IndexTagHandler describes index tag handler
func IndexTagHandler(ctx *tagContext) error {
if len(ctx.params) > 0 {
ctx.indexNames[ctx.params[0]] = core.IndexType
} else {
ctx.isIndex = true
}
return nil
}
// UniqueTagHandler describes unique tag handler
func UniqueTagHandler(ctx *tagContext) error {
if len(ctx.params) > 0 {
ctx.indexNames[ctx.params[0]] = core.UniqueType
} else {
ctx.isUnique = true
}
return nil
}
// CommentTagHandler add comment to column
func CommentTagHandler(ctx *tagContext) error {
if len(ctx.params) > 0 {
ctx.col.Comment = strings.Trim(ctx.params[0], "' ")
}
return nil
}
// SQLTypeTagHandler describes SQL Type tag handler
func SQLTypeTagHandler(ctx *tagContext) error {
ctx.col.SQLType = core.SQLType{Name: ctx.tagName}
if len(ctx.params) > 0 {
if ctx.tagName == core.Enum {
ctx.col.EnumOptions = make(map[string]int)
for k, v := range ctx.params {
v = strings.TrimSpace(v)
v = strings.Trim(v, "'")
ctx.col.EnumOptions[v] = k
}
} else if ctx.tagName == core.Set {
ctx.col.SetOptions = make(map[string]int)
for k, v := range ctx.params {
v = strings.TrimSpace(v)
v = strings.Trim(v, "'")
ctx.col.SetOptions[v] = k
}
} else {
var err error
if len(ctx.params) == 2 {
ctx.col.Length, err = strconv.Atoi(ctx.params[0])
if err != nil {
return err
}
ctx.col.Length2, err = strconv.Atoi(ctx.params[1])
if err != nil {
return err
}
} else if len(ctx.params) == 1 {
ctx.col.Length, err = strconv.Atoi(ctx.params[0])
if err != nil {
return err
}
}
}
}
return nil
}
// ExtendsTagHandler describes extends tag handler
func ExtendsTagHandler(ctx *tagContext) error {
var fieldValue = ctx.fieldValue
switch fieldValue.Kind() {
case reflect.Ptr:
f := fieldValue.Type().Elem()
if f.Kind() == reflect.Struct {
fieldPtr := fieldValue
fieldValue = fieldValue.Elem()
if !fieldValue.IsValid() || fieldPtr.IsNil() {
fieldValue = reflect.New(f).Elem()
}
}
fallthrough
case reflect.Struct:
parentTable, err := ctx.engine.mapType(fieldValue)
if err != nil {
return err
}
for _, col := range parentTable.Columns() {
col.FieldName = fmt.Sprintf("%v.%v", ctx.col.FieldName, col.FieldName)
ctx.table.AddColumn(col)
for indexName, indexType := range col.Indexes {
addIndex(indexName, ctx.table, col, indexType)
}
}
default:
//TODO: warning
}
return nil
}
// CacheTagHandler describes cache tag handler
func CacheTagHandler(ctx *tagContext) error {
if !ctx.hasCacheTag {
ctx.hasCacheTag = true
}
return nil
}
// NoCacheTagHandler describes nocache tag handler
func NoCacheTagHandler(ctx *tagContext) error {
if !ctx.hasNoCacheTag {
ctx.hasNoCacheTag = true
}
return nil
}

View File

@ -1 +0,0 @@
go test -db=mssql -conn_str="server=192.168.1.58;user id=sa;password=123456;database=xorm_test"

View File

@ -1 +0,0 @@
go test -db=mssql -conn_str="server=192.168.1.58;user id=sa;password=123456;database=xorm_test" -cache=true

View File

@ -1 +0,0 @@
go test -db=mymysql -conn_str="xorm_test/root/"

View File

@ -1 +0,0 @@
go test -db=mymysql -conn_str="xorm_test/root/" -cache=true

Some files were not shown because too many files have changed in this diff Show More