ql support
This commit is contained in:
parent
182428e13d
commit
ff3a06b3dc
|
@ -23,6 +23,7 @@ const (
|
|||
MSSQL = "mssql"
|
||||
|
||||
ORACLE_OCI = "oci8"
|
||||
QL = "ql"
|
||||
)
|
||||
|
||||
// a dialect is a driver's wrapper
|
||||
|
|
|
@ -0,0 +1,232 @@
|
|||
package xorm
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ql struct {
|
||||
base
|
||||
}
|
||||
|
||||
type qlParser struct {
|
||||
}
|
||||
|
||||
func (p *qlParser) parse(driverName, dataSourceName string) (*uri, error) {
|
||||
return &uri{dbType: QL, dbName: dataSourceName}, nil
|
||||
}
|
||||
|
||||
func (db *ql) Init(drivername, dataSourceName string) error {
|
||||
return db.base.init(&qlParser{}, drivername, dataSourceName)
|
||||
}
|
||||
|
||||
func (db *ql) SqlType(c *Column) string {
|
||||
switch t := c.SQLType.Name; t {
|
||||
case Date, DateTime, TimeStamp, Time:
|
||||
return Numeric
|
||||
case TimeStampz:
|
||||
return Text
|
||||
case Char, Varchar, TinyText, Text, MediumText, LongText:
|
||||
return Text
|
||||
case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, BigInt, Bool:
|
||||
return Integer
|
||||
case Float, Double, Real:
|
||||
return Real
|
||||
case Decimal, Numeric:
|
||||
return Numeric
|
||||
case TinyBlob, Blob, MediumBlob, LongBlob, Bytea, Binary, VarBinary:
|
||||
return Blob
|
||||
case Serial, BigSerial:
|
||||
c.IsPrimaryKey = true
|
||||
c.IsAutoIncrement = true
|
||||
c.Nullable = false
|
||||
return Integer
|
||||
default:
|
||||
return t
|
||||
}
|
||||
}
|
||||
|
||||
func (db *ql) SupportInsertMany() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (db *ql) QuoteStr() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (db *ql) AutoIncrStr() string {
|
||||
return "AUTOINCREMENT"
|
||||
}
|
||||
|
||||
func (db *ql) SupportEngine() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *ql) SupportCharset() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *ql) IndexOnTable() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *ql) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
|
||||
args := []interface{}{idxName}
|
||||
return "SELECT name FROM sqlite_master WHERE type='index' and name = ?", args
|
||||
}
|
||||
|
||||
func (db *ql) TableCheckSql(tableName string) (string, []interface{}) {
|
||||
args := []interface{}{tableName}
|
||||
return "SELECT name FROM sqlite_master WHERE type='table' and name = ?", args
|
||||
}
|
||||
|
||||
func (db *ql) 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 *ql) GetColumns(tableName string) ([]string, map[string]*Column, error) {
|
||||
args := []interface{}{tableName}
|
||||
s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?"
|
||||
cnn, err := sql.Open(db.driverName, db.dataSourceName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer cnn.Close()
|
||||
res, err := query(cnn, s, args...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var sql string
|
||||
for _, record := range res {
|
||||
for name, content := range record {
|
||||
if name == "sql" {
|
||||
sql = string(content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nStart := strings.Index(sql, "(")
|
||||
nEnd := strings.Index(sql, ")")
|
||||
colCreates := strings.Split(sql[nStart+1:nEnd], ",")
|
||||
cols := make(map[string]*Column)
|
||||
colSeq := make([]string, 0)
|
||||
for _, colStr := range colCreates {
|
||||
fields := strings.Fields(strings.TrimSpace(colStr))
|
||||
col := new(Column)
|
||||
col.Indexes = make(map[string]bool)
|
||||
col.Nullable = true
|
||||
for idx, field := range fields {
|
||||
if idx == 0 {
|
||||
col.Name = strings.Trim(field, "`[] ")
|
||||
continue
|
||||
} else if idx == 1 {
|
||||
col.SQLType = SQLType{field, 0, 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
|
||||
}
|
||||
}
|
||||
}
|
||||
cols[col.Name] = col
|
||||
colSeq = append(colSeq, col.Name)
|
||||
}
|
||||
return colSeq, cols, nil
|
||||
}
|
||||
|
||||
func (db *ql) GetTables() ([]*Table, error) {
|
||||
args := []interface{}{}
|
||||
s := "SELECT name FROM sqlite_master WHERE type='table'"
|
||||
|
||||
cnn, err := sql.Open(db.driverName, db.dataSourceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cnn.Close()
|
||||
res, err := query(cnn, s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tables := make([]*Table, 0)
|
||||
for _, record := range res {
|
||||
table := new(Table)
|
||||
for name, content := range record {
|
||||
switch name {
|
||||
case "name":
|
||||
table.Name = string(content)
|
||||
}
|
||||
}
|
||||
if table.Name == "sqlite_sequence" {
|
||||
continue
|
||||
}
|
||||
tables = append(tables, table)
|
||||
}
|
||||
return tables, nil
|
||||
}
|
||||
|
||||
func (db *ql) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||
args := []interface{}{tableName}
|
||||
s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?"
|
||||
cnn, err := sql.Open(db.driverName, db.dataSourceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cnn.Close()
|
||||
res, err := query(cnn, s, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
indexes := make(map[string]*Index, 0)
|
||||
for _, record := range res {
|
||||
index := new(Index)
|
||||
sql := string(record["sql"])
|
||||
|
||||
if sql == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
nNStart := strings.Index(sql, "INDEX")
|
||||
nNEnd := strings.Index(sql, "ON")
|
||||
if nNStart == -1 || nNEnd == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
indexName := strings.Trim(sql[nNStart+6:nNEnd], "` []")
|
||||
//fmt.Println(indexName)
|
||||
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
|
||||
index.Name = indexName[5+len(tableName) : len(indexName)]
|
||||
} else {
|
||||
index.Name = indexName
|
||||
}
|
||||
|
||||
if strings.HasPrefix(sql, "CREATE UNIQUE INDEX") {
|
||||
index.Type = UniqueType
|
||||
} else {
|
||||
index.Type = 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, "` []"))
|
||||
}
|
||||
indexes[index.Name] = index
|
||||
}
|
||||
|
||||
return indexes, nil
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
package xorm
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
_ "github.com/mattn/ql-driver"
|
||||
)
|
||||
|
||||
func newQlEngine() (*Engine, error) {
|
||||
os.Remove("./ql.db")
|
||||
return NewEngine("ql", "./ql.db")
|
||||
}
|
||||
|
||||
func newQlDriverDB() (*sql.DB, error) {
|
||||
os.Remove("./ql.db")
|
||||
return sql.Open("ql", "./ql.db")
|
||||
}
|
||||
|
||||
func TestQl(t *testing.T) {
|
||||
engine, err := newQlEngine()
|
||||
defer engine.Close()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
engine.ShowSQL = showTestSql
|
||||
engine.ShowErr = showTestSql
|
||||
engine.ShowWarn = showTestSql
|
||||
engine.ShowDebug = showTestSql
|
||||
|
||||
testAll(engine, t)
|
||||
testAll2(engine, t)
|
||||
testAll3(engine, t)
|
||||
}
|
||||
|
||||
func TestQlWithCache(t *testing.T) {
|
||||
engine, err := newQlEngine()
|
||||
defer engine.Close()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
engine.SetDefaultCacher(NewLRUCacher(NewMemoryStore(), 1000))
|
||||
engine.ShowSQL = showTestSql
|
||||
engine.ShowErr = showTestSql
|
||||
engine.ShowWarn = showTestSql
|
||||
engine.ShowDebug = showTestSql
|
||||
|
||||
testAll(engine, t)
|
||||
testAll2(engine, t)
|
||||
}
|
||||
|
||||
const (
|
||||
createTableQl = "CREATE TABLE IF NOT EXISTS `big_struct` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NULL, `title` TEXT NULL, `age` TEXT NULL, `alias` TEXT NULL, `nick_name` TEXT NULL);"
|
||||
dropTableQl = "DROP TABLE IF EXISTS `big_struct`;"
|
||||
)
|
||||
|
||||
func BenchmarkQlDriverInsert(t *testing.B) {
|
||||
doBenchDriver(newQlDriverDB, createTableQl, dropTableQl,
|
||||
doBenchDriverInsert, t)
|
||||
}
|
||||
|
||||
func BenchmarkQlDriverFind(t *testing.B) {
|
||||
doBenchDriver(newQlDriverDB, createTableQl, dropTableQl,
|
||||
doBenchDriverFind, t)
|
||||
}
|
||||
|
||||
func BenchmarkQlNoCacheInsert(t *testing.B) {
|
||||
t.StopTimer()
|
||||
engine, err := newQlEngine()
|
||||
defer engine.Close()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
//engine.ShowSQL = true
|
||||
doBenchInsert(engine, t)
|
||||
}
|
||||
|
||||
func BenchmarkQlNoCacheFind(t *testing.B) {
|
||||
t.StopTimer()
|
||||
engine, err := newQlEngine()
|
||||
defer engine.Close()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
//engine.ShowSQL = true
|
||||
doBenchFind(engine, t)
|
||||
}
|
||||
|
||||
func BenchmarkQlNoCacheFindPtr(t *testing.B) {
|
||||
t.StopTimer()
|
||||
engine, err := newQlEngine()
|
||||
defer engine.Close()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
//engine.ShowSQL = true
|
||||
doBenchFindPtr(engine, t)
|
||||
}
|
||||
|
||||
func BenchmarkQlCacheInsert(t *testing.B) {
|
||||
t.StopTimer()
|
||||
engine, err := newQlEngine()
|
||||
defer engine.Close()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
engine.SetDefaultCacher(NewLRUCacher(NewMemoryStore(), 1000))
|
||||
doBenchInsert(engine, t)
|
||||
}
|
||||
|
||||
func BenchmarkQlCacheFind(t *testing.B) {
|
||||
t.StopTimer()
|
||||
engine, err := newQlEngine()
|
||||
defer engine.Close()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
engine.SetDefaultCacher(NewLRUCacher(NewMemoryStore(), 1000))
|
||||
doBenchFind(engine, t)
|
||||
}
|
||||
|
||||
func BenchmarkQlCacheFindPtr(t *testing.B) {
|
||||
t.StopTimer()
|
||||
engine, err := newQlEngine()
|
||||
defer engine.Close()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
engine.SetDefaultCacher(NewLRUCacher(NewMemoryStore(), 1000))
|
||||
doBenchFindPtr(engine, t)
|
||||
}
|
4
xorm.go
4
xorm.go
|
@ -40,6 +40,10 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
|
|||
} else if driverName == ORACLE_OCI {
|
||||
engine.dialect = &oracle{}
|
||||
engine.Filters = append(engine.Filters, &QuoteFilter{})
|
||||
} else if driverName == QL {
|
||||
engine.dialect = &ql{}
|
||||
engine.Filters = append(engine.Filters, &PgSeqFilter{})
|
||||
engine.Filters = append(engine.Filters, &QuoteFilter{})
|
||||
} else {
|
||||
return nil, errors.New(fmt.Sprintf("Unsupported driver name: %v", driverName))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue