Improve quote policy #1567
11
.drone.yml
11
.drone.yml
|
@ -22,9 +22,10 @@ steps:
|
||||||
commands:
|
commands:
|
||||||
- make test-sqlite
|
- make test-sqlite
|
||||||
- TEST_CACHE_ENABLE=true make test-sqlite
|
- TEST_CACHE_ENABLE=true make test-sqlite
|
||||||
|
- TEST_QUOTE_POLICY=reserved make test-sqlite
|
||||||
- go test ./caches/... ./contexts/... ./convert/... ./core/... ./dialects/... \
|
- go test ./caches/... ./contexts/... ./convert/... ./core/... ./dialects/... \
|
||||||
|
./log/... ./migrate/... ./names/... ./schemas/... ./tags/... \
|
||||||
./internal/json/... ./internal/statements/... ./internal/utils/... \
|
./internal/json/... ./internal/statements/... ./internal/utils/... \
|
||||||
./log/... ./migrate/... ./names/... ./schemas/... ./tags/...
|
|
||||||
|
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
|
@ -44,6 +45,7 @@ steps:
|
||||||
commands:
|
commands:
|
||||||
- make test-mysql
|
- make test-mysql
|
||||||
- TEST_CACHE_ENABLE=true make test-mysql
|
- TEST_CACHE_ENABLE=true make test-mysql
|
||||||
|
- TEST_QUOTE_POLICY=reserved make test-mysql
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
|
@ -62,6 +64,7 @@ steps:
|
||||||
commands:
|
commands:
|
||||||
- make test-mysql
|
- make test-mysql
|
||||||
- TEST_CACHE_ENABLE=true make test-mysql
|
- TEST_CACHE_ENABLE=true make test-mysql
|
||||||
|
- TEST_QUOTE_POLICY=reserved make test-mysql
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
|
@ -82,6 +85,7 @@ steps:
|
||||||
commands:
|
commands:
|
||||||
- make test-mysql
|
- make test-mysql
|
||||||
- TEST_CACHE_ENABLE=true make test-mysql
|
- TEST_CACHE_ENABLE=true make test-mysql
|
||||||
|
- TEST_QUOTE_POLICY=reserved make test-mysql
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
|
@ -102,6 +106,7 @@ steps:
|
||||||
commands:
|
commands:
|
||||||
- make test-mymysql
|
- make test-mymysql
|
||||||
- TEST_CACHE_ENABLE=true make test-mymysql
|
- TEST_CACHE_ENABLE=true make test-mymysql
|
||||||
|
- TEST_QUOTE_POLICY=reserved make test-mymysql
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
|
@ -120,6 +125,7 @@ steps:
|
||||||
commands:
|
commands:
|
||||||
- make test-postgres
|
- make test-postgres
|
||||||
- TEST_CACHE_ENABLE=true make test-postgres
|
- TEST_CACHE_ENABLE=true make test-postgres
|
||||||
|
- TEST_QUOTE_POLICY=reserved make test-postgres
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
|
@ -141,6 +147,7 @@ steps:
|
||||||
commands:
|
commands:
|
||||||
- make test-postgres
|
- make test-postgres
|
||||||
- TEST_CACHE_ENABLE=true make test-postgres
|
- TEST_CACHE_ENABLE=true make test-postgres
|
||||||
|
- TEST_QUOTE_POLICY=reserved make test-postgres
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
|
@ -159,6 +166,7 @@ steps:
|
||||||
commands:
|
commands:
|
||||||
- make test-mssql
|
- make test-mssql
|
||||||
- TEST_CACHE_ENABLE=true make test-mssql
|
- TEST_CACHE_ENABLE=true make test-mssql
|
||||||
|
- TEST_QUOTE_POLICY=reserved make test-mssql
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
|
@ -177,6 +185,7 @@ steps:
|
||||||
commands:
|
commands:
|
||||||
- make test-tidb
|
- make test-tidb
|
||||||
- TEST_CACHE_ENABLE=true make test-tidb
|
- TEST_CACHE_ENABLE=true make test-tidb
|
||||||
|
- TEST_QUOTE_POLICY=reserved make test-tidb
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
|
|
37
Makefile
37
Makefile
|
@ -39,6 +39,7 @@ TEST_TIDB_USERNAME ?= root
|
||||||
TEST_TIDB_PASSWORD ?=
|
TEST_TIDB_PASSWORD ?=
|
||||||
|
|
||||||
TEST_CACHE_ENABLE ?= false
|
TEST_CACHE_ENABLE ?= false
|
||||||
|
TEST_QUOTE_POLICY ?= always
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: build
|
all: build
|
||||||
|
@ -135,73 +136,73 @@ test-cockroach\#%: go-check
|
||||||
|
|
||||||
.PNONY: test-mssql
|
.PNONY: test-mssql
|
||||||
test-mssql: go-check
|
test-mssql: go-check
|
||||||
$(GO) test -v -race -db=mssql -cache=$(TEST_CACHE_ENABLE) \
|
$(GO) test -v -race -db=mssql -cache=$(TEST_CACHE_ENABLE) -quote=$(TEST_QUOTE_POLICY) \
|
||||||
-conn_str="server=$(TEST_MSSQL_HOST);user id=$(TEST_MSSQL_USERNAME);password=$(TEST_MSSQL_PASSWORD);database=$(TEST_MSSQL_DBNAME)" \
|
-conn_str="server=$(TEST_MSSQL_HOST);user id=$(TEST_MSSQL_USERNAME);password=$(TEST_MSSQL_PASSWORD);database=$(TEST_MSSQL_DBNAME)" \
|
||||||
-coverprofile=mssql.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
-coverprofile=mssql.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||||
|
|
||||||
.PNONY: test-mssql\#%
|
.PNONY: test-mssql\#%
|
||||||
test-mssql\#%: go-check
|
test-mssql\#%: go-check
|
||||||
$(GO) test -v -race -run $* -db=mssql -cache=$(TEST_CACHE_ENABLE) \
|
$(GO) test -v -race -run $* -db=mssql -cache=$(TEST_CACHE_ENABLE) -quote=$(TEST_QUOTE_POLICY) \
|
||||||
-conn_str="server=$(TEST_MSSQL_HOST);user id=$(TEST_MSSQL_USERNAME);password=$(TEST_MSSQL_PASSWORD);database=$(TEST_MSSQL_DBNAME)" \
|
-conn_str="server=$(TEST_MSSQL_HOST);user id=$(TEST_MSSQL_USERNAME);password=$(TEST_MSSQL_PASSWORD);database=$(TEST_MSSQL_DBNAME)" \
|
||||||
-coverprofile=mssql.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
-coverprofile=mssql.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||||
|
|
||||||
.PNONY: test-mymysql
|
.PNONY: test-mymysql
|
||||||
test-mymysql: go-check
|
test-mymysql: go-check
|
||||||
$(GO) test -v -race -db=mymysql -cache=$(TEST_CACHE_ENABLE) \
|
$(GO) test -v -race -db=mymysql -cache=$(TEST_CACHE_ENABLE) -quote=$(TEST_QUOTE_POLICY) \
|
||||||
-conn_str="tcp:$(TEST_MYSQL_HOST)*$(TEST_MYSQL_DBNAME)/$(TEST_MYSQL_USERNAME)/$(TEST_MYSQL_PASSWORD)" \
|
-conn_str="tcp:$(TEST_MYSQL_HOST)*$(TEST_MYSQL_DBNAME)/$(TEST_MYSQL_USERNAME)/$(TEST_MYSQL_PASSWORD)" \
|
||||||
-coverprofile=mymysql.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
-coverprofile=mymysql.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||||
|
|
||||||
.PNONY: test-mymysql\#%
|
.PNONY: test-mymysql\#%
|
||||||
test-mymysql\#%: go-check
|
test-mymysql\#%: go-check
|
||||||
$(GO) test -v -race -run $* -db=mymysql -cache=$(TEST_CACHE_ENABLE) \
|
$(GO) test -v -race -run $* -db=mymysql -cache=$(TEST_CACHE_ENABLE) -quote=$(TEST_QUOTE_POLICY) \
|
||||||
-conn_str="tcp:$(TEST_MYSQL_HOST)*$(TEST_MYSQL_DBNAME)/$(TEST_MYSQL_USERNAME)/$(TEST_MYSQL_PASSWORD)" \
|
-conn_str="tcp:$(TEST_MYSQL_HOST)*$(TEST_MYSQL_DBNAME)/$(TEST_MYSQL_USERNAME)/$(TEST_MYSQL_PASSWORD)" \
|
||||||
-coverprofile=mymysql.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
-coverprofile=mymysql.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||||
|
|
||||||
.PNONY: test-mysql
|
.PNONY: test-mysql
|
||||||
test-mysql: go-check
|
test-mysql: go-check
|
||||||
$(GO) test -v -race -db=mysql -cache=$(TEST_CACHE_ENABLE) \
|
$(GO) test -v -race -db=mysql -cache=$(TEST_CACHE_ENABLE) -quote=$(TEST_QUOTE_POLICY) \
|
||||||
-conn_str="$(TEST_MYSQL_USERNAME):$(TEST_MYSQL_PASSWORD)@tcp($(TEST_MYSQL_HOST))/$(TEST_MYSQL_DBNAME)?charset=$(TEST_MYSQL_CHARSET)" \
|
-conn_str="$(TEST_MYSQL_USERNAME):$(TEST_MYSQL_PASSWORD)@tcp($(TEST_MYSQL_HOST))/$(TEST_MYSQL_DBNAME)?charset=$(TEST_MYSQL_CHARSET)" \
|
||||||
-coverprofile=mysql.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
-coverprofile=mysql.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||||
|
|
||||||
.PHONY: test-mysql\#%
|
.PHONY: test-mysql\#%
|
||||||
test-mysql\#%: go-check
|
test-mysql\#%: go-check
|
||||||
$(GO) test -v -race -run $* -db=mysql -cache=$(TEST_CACHE_ENABLE) \
|
$(GO) test -v -race -run $* -db=mysql -cache=$(TEST_CACHE_ENABLE) -quote=$(TEST_QUOTE_POLICY) \
|
||||||
-conn_str="$(TEST_MYSQL_USERNAME):$(TEST_MYSQL_PASSWORD)@tcp($(TEST_MYSQL_HOST))/$(TEST_MYSQL_DBNAME)?charset=$(TEST_MYSQL_CHARSET)" \
|
-conn_str="$(TEST_MYSQL_USERNAME):$(TEST_MYSQL_PASSWORD)@tcp($(TEST_MYSQL_HOST))/$(TEST_MYSQL_DBNAME)?charset=$(TEST_MYSQL_CHARSET)" \
|
||||||
-coverprofile=mysql.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
-coverprofile=mysql.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||||
|
|
||||||
.PNONY: test-postgres
|
.PNONY: test-postgres
|
||||||
test-postgres: go-check
|
test-postgres: go-check
|
||||||
$(GO) test -v -race -db=postgres -schema='$(TEST_PGSQL_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \
|
$(GO) test -v -race -db=postgres -schema='$(TEST_PGSQL_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \
|
||||||
-conn_str="postgres://$(TEST_PGSQL_USERNAME):$(TEST_PGSQL_PASSWORD)@$(TEST_PGSQL_HOST)/$(TEST_PGSQL_DBNAME)?sslmode=disable" \
|
-conn_str="postgres://$(TEST_PGSQL_USERNAME):$(TEST_PGSQL_PASSWORD)@$(TEST_PGSQL_HOST)/$(TEST_PGSQL_DBNAME)?sslmode=disable" \
|
||||||
-coverprofile=postgres.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
-quote=$(TEST_QUOTE_POLICY) -coverprofile=postgres.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||||
|
|
||||||
.PHONY: test-postgres\#%
|
.PHONY: test-postgres\#%
|
||||||
test-postgres\#%: go-check
|
test-postgres\#%: go-check
|
||||||
$(GO) test -v -race -run $* -db=postgres -schema='$(TEST_PGSQL_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \
|
$(GO) test -v -race -run $* -db=postgres -schema='$(TEST_PGSQL_SCHEMA)' -cache=$(TEST_CACHE_ENABLE) \
|
||||||
-conn_str="postgres://$(TEST_PGSQL_USERNAME):$(TEST_PGSQL_PASSWORD)@$(TEST_PGSQL_HOST)/$(TEST_PGSQL_DBNAME)?sslmode=disable" \
|
-conn_str="postgres://$(TEST_PGSQL_USERNAME):$(TEST_PGSQL_PASSWORD)@$(TEST_PGSQL_HOST)/$(TEST_PGSQL_DBNAME)?sslmode=disable" \
|
||||||
-coverprofile=postgres.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
-quote=$(TEST_QUOTE_POLICY) -coverprofile=postgres.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||||
|
|
||||||
.PHONY: test-sqlite
|
.PHONY: test-sqlite
|
||||||
test-sqlite: go-check
|
test-sqlite: go-check
|
||||||
$(GO) test -v -race -cache=$(TEST_CACHE_ENABLE) -db=sqlite3 -conn_str="./test.db?cache=shared&mode=rwc" \
|
$(GO) test -v -race -cache=$(TEST_CACHE_ENABLE) -db=sqlite3 -conn_str="./test.db?cache=shared&mode=rwc" \
|
||||||
-coverprofile=sqlite.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
-quote=$(TEST_QUOTE_POLICY) -coverprofile=sqlite.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||||
|
|
||||||
.PHONY: test-sqlite\#%
|
.PHONY: test-sqlite\#%
|
||||||
test-sqlite\#%: go-check
|
test-sqlite\#%: go-check
|
||||||
$(GO) test -v -race -run $* -cache=$(TEST_CACHE_ENABLE) -db=sqlite3 -conn_str="./test.db?cache=shared&mode=rwc" \
|
$(GO) test -v -race -run $* -cache=$(TEST_CACHE_ENABLE) -db=sqlite3 -conn_str="./test.db?cache=shared&mode=rwc" \
|
||||||
-coverprofile=sqlite.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
-quote=$(TEST_QUOTE_POLICY) -coverprofile=sqlite.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||||
|
|
||||||
.PNONY: test-tidb
|
.PNONY: test-tidb
|
||||||
test-tidb: go-check
|
test-tidb: go-check
|
||||||
$(GO) test -v -race -db=mysql -cache=$(TEST_CACHE_ENABLE) -ignore_select_update=true \
|
$(GO) test -v -race -db=mysql -cache=$(TEST_CACHE_ENABLE) -ignore_select_update=true \
|
||||||
-conn_str="$(TEST_TIDB_USERNAME):$(TEST_TIDB_PASSWORD)@tcp($(TEST_TIDB_HOST))/$(TEST_TIDB_DBNAME)" \
|
-conn_str="$(TEST_TIDB_USERNAME):$(TEST_TIDB_PASSWORD)@tcp($(TEST_TIDB_HOST))/$(TEST_TIDB_DBNAME)" \
|
||||||
-coverprofile=tidb.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
-quote=$(TEST_QUOTE_POLICY) -coverprofile=tidb.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||||
|
|
||||||
.PHONY: test-tidb\#%
|
.PHONY: test-tidb\#%
|
||||||
test-tidb\#%: go-check
|
test-tidb\#%: go-check
|
||||||
$(GO) test -v -race -run $* -db=mysql -cache=$(TEST_CACHE_ENABLE) -ignore_select_update=true \
|
$(GO) test -v -race -run $* -db=mysql -cache=$(TEST_CACHE_ENABLE) -ignore_select_update=true \
|
||||||
-conn_str="$(TEST_TIDB_USERNAME):$(TEST_TIDB_PASSWORD)@tcp($(TEST_TIDB_HOST))/$(TEST_TIDB_DBNAME)" \
|
-conn_str="$(TEST_TIDB_USERNAME):$(TEST_TIDB_PASSWORD)@tcp($(TEST_TIDB_HOST))/$(TEST_TIDB_DBNAME)" \
|
||||||
-coverprofile=tidb.$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
-quote=$(TEST_QUOTE_POLICY) -coverprofile=tidb.$(TEST_QUOTE_POLICY).$(TEST_CACHE_ENABLE).coverage.out -covermode=atomic
|
||||||
|
|
||||||
.PHONY: vet
|
.PHONY: vet
|
||||||
vet:
|
vet:
|
||||||
|
|
|
@ -30,15 +30,24 @@ func (s *QuoteFilter) Do(sql string) string {
|
||||||
buf.Grow(len(sql))
|
buf.Grow(len(sql))
|
||||||
|
|
||||||
var beginSingleQuote bool
|
var beginSingleQuote bool
|
||||||
var prefix = true
|
|
||||||
for i := 0; i < len(sql); i++ {
|
for i := 0; i < len(sql); i++ {
|
||||||
if !beginSingleQuote && sql[i] == '`' {
|
if !beginSingleQuote && sql[i] == '`' {
|
||||||
if prefix {
|
var j = i + 1
|
||||||
|
for ; j < len(sql); j++ {
|
||||||
|
if sql[j] == '`' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
word := sql[i+1 : j]
|
||||||
|
isReserved := s.quoter.IsReserved(word)
|
||||||
|
if isReserved {
|
||||||
buf.WriteByte(s.quoter.Prefix)
|
buf.WriteByte(s.quoter.Prefix)
|
||||||
} else {
|
}
|
||||||
|
buf.WriteString(word)
|
||||||
|
if isReserved {
|
||||||
buf.WriteByte(s.quoter.Suffix)
|
buf.WriteByte(s.quoter.Suffix)
|
||||||
}
|
}
|
||||||
prefix = !prefix
|
i = j
|
||||||
} else {
|
} else {
|
||||||
if sql[i] == '\'' {
|
if sql[i] == '\'' {
|
||||||
beginSingleQuote = !beginSingleQuote
|
beginSingleQuote = !beginSingleQuote
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestQuoteFilter_Do(t *testing.T) {
|
func TestQuoteFilter_Do(t *testing.T) {
|
||||||
f := QuoteFilter{schemas.Quoter{'[', ']', schemas.AlwaysReverse}}
|
f := QuoteFilter{schemas.Quoter{'[', ']', schemas.AlwaysReserve}}
|
||||||
var kases = []struct {
|
var kases = []struct {
|
||||||
source string
|
source string
|
||||||
expected string
|
expected string
|
||||||
|
|
|
@ -205,7 +205,7 @@ var (
|
||||||
"PROC": true,
|
"PROC": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
mssqlQuoter = schemas.Quoter{'[', ']', schemas.AlwaysReverse}
|
mssqlQuoter = schemas.Quoter{'[', ']', schemas.AlwaysReserve}
|
||||||
)
|
)
|
||||||
|
|
||||||
type mssql struct {
|
type mssql struct {
|
||||||
|
@ -294,11 +294,11 @@ func (db *mssql) SetQuotePolicy(quotePolicy QuotePolicy) {
|
||||||
switch quotePolicy {
|
switch quotePolicy {
|
||||||
case QuotePolicyNone:
|
case QuotePolicyNone:
|
||||||
var q = mssqlQuoter
|
var q = mssqlQuoter
|
||||||
q.IsReverse = schemas.AlwaysNoReverse
|
q.IsReserved = schemas.AlwaysNoReserve
|
||||||
db.quoter = q
|
db.quoter = q
|
||||||
case QuotePolicyReserved:
|
case QuotePolicyReserved:
|
||||||
var q = mssqlQuoter
|
var q = mssqlQuoter
|
||||||
q.IsReverse = db.IsReserved
|
q.IsReserved = db.IsReserved
|
||||||
db.quoter = q
|
db.quoter = q
|
||||||
case QuotePolicyAlways:
|
case QuotePolicyAlways:
|
||||||
fallthrough
|
fallthrough
|
||||||
|
|
|
@ -162,7 +162,7 @@ var (
|
||||||
"ZEROFILL": true,
|
"ZEROFILL": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
mysqlQuoter = schemas.Quoter{'`', '`', schemas.AlwaysReverse}
|
mysqlQuoter = schemas.Quoter{'`', '`', schemas.AlwaysReserve}
|
||||||
)
|
)
|
||||||
|
|
||||||
type mysql struct {
|
type mysql struct {
|
||||||
|
@ -461,11 +461,11 @@ func (db *mysql) SetQuotePolicy(quotePolicy QuotePolicy) {
|
||||||
switch quotePolicy {
|
switch quotePolicy {
|
||||||
case QuotePolicyNone:
|
case QuotePolicyNone:
|
||||||
var q = mysqlQuoter
|
var q = mysqlQuoter
|
||||||
q.IsReverse = schemas.AlwaysNoReverse
|
q.IsReserved = schemas.AlwaysNoReserve
|
||||||
db.quoter = q
|
db.quoter = q
|
||||||
case QuotePolicyReserved:
|
case QuotePolicyReserved:
|
||||||
var q = mysqlQuoter
|
var q = mysqlQuoter
|
||||||
q.IsReverse = db.IsReserved
|
q.IsReserved = db.IsReserved
|
||||||
db.quoter = q
|
db.quoter = q
|
||||||
case QuotePolicyAlways:
|
case QuotePolicyAlways:
|
||||||
fallthrough
|
fallthrough
|
||||||
|
|
|
@ -499,7 +499,7 @@ var (
|
||||||
"ZONE": true,
|
"ZONE": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
oracleQuoter = schemas.Quoter{'[', ']', schemas.AlwaysReverse}
|
oracleQuoter = schemas.Quoter{'[', ']', schemas.AlwaysReserve}
|
||||||
)
|
)
|
||||||
|
|
||||||
type oracle struct {
|
type oracle struct {
|
||||||
|
@ -623,11 +623,11 @@ func (db *oracle) SetQuotePolicy(quotePolicy QuotePolicy) {
|
||||||
switch quotePolicy {
|
switch quotePolicy {
|
||||||
case QuotePolicyNone:
|
case QuotePolicyNone:
|
||||||
var q = oracleQuoter
|
var q = oracleQuoter
|
||||||
q.IsReverse = schemas.AlwaysNoReverse
|
q.IsReserved = schemas.AlwaysNoReserve
|
||||||
db.quoter = q
|
db.quoter = q
|
||||||
case QuotePolicyReserved:
|
case QuotePolicyReserved:
|
||||||
var q = oracleQuoter
|
var q = oracleQuoter
|
||||||
q.IsReverse = db.IsReserved
|
q.IsReserved = db.IsReserved
|
||||||
db.quoter = q
|
db.quoter = q
|
||||||
case QuotePolicyAlways:
|
case QuotePolicyAlways:
|
||||||
fallthrough
|
fallthrough
|
||||||
|
|
|
@ -767,7 +767,7 @@ var (
|
||||||
"ZONE": true,
|
"ZONE": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
postgresQuoter = schemas.Quoter{'"', '"', schemas.AlwaysReverse}
|
postgresQuoter = schemas.Quoter{'"', '"', schemas.AlwaysReserve}
|
||||||
)
|
)
|
||||||
|
|
||||||
const postgresPublicSchema = "public"
|
const postgresPublicSchema = "public"
|
||||||
|
@ -792,11 +792,11 @@ func (db *postgres) SetQuotePolicy(quotePolicy QuotePolicy) {
|
||||||
switch quotePolicy {
|
switch quotePolicy {
|
||||||
case QuotePolicyNone:
|
case QuotePolicyNone:
|
||||||
var q = postgresQuoter
|
var q = postgresQuoter
|
||||||
q.IsReverse = schemas.AlwaysNoReverse
|
q.IsReserved = schemas.AlwaysNoReserve
|
||||||
db.quoter = q
|
db.quoter = q
|
||||||
case QuotePolicyReserved:
|
case QuotePolicyReserved:
|
||||||
var q = postgresQuoter
|
var q = postgresQuoter
|
||||||
q.IsReverse = db.IsReserved
|
q.IsReserved = db.IsReserved
|
||||||
db.quoter = q
|
db.quoter = q
|
||||||
case QuotePolicyAlways:
|
case QuotePolicyAlways:
|
||||||
fallthrough
|
fallthrough
|
||||||
|
|
|
@ -144,7 +144,7 @@ var (
|
||||||
"WITHOUT": true,
|
"WITHOUT": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3Quoter = schemas.Quoter{'`', '`', schemas.AlwaysReverse}
|
sqlite3Quoter = schemas.Quoter{'`', '`', schemas.AlwaysReserve}
|
||||||
)
|
)
|
||||||
|
|
||||||
type sqlite3 struct {
|
type sqlite3 struct {
|
||||||
|
@ -160,11 +160,11 @@ func (db *sqlite3) SetQuotePolicy(quotePolicy QuotePolicy) {
|
||||||
switch quotePolicy {
|
switch quotePolicy {
|
||||||
case QuotePolicyNone:
|
case QuotePolicyNone:
|
||||||
var q = sqlite3Quoter
|
var q = sqlite3Quoter
|
||||||
q.IsReverse = schemas.AlwaysNoReverse
|
q.IsReserved = schemas.AlwaysNoReserve
|
||||||
db.quoter = q
|
db.quoter = q
|
||||||
case QuotePolicyReserved:
|
case QuotePolicyReserved:
|
||||||
var q = sqlite3Quoter
|
var q = sqlite3Quoter
|
||||||
q.IsReverse = db.IsReserved
|
q.IsReserved = db.IsReserved
|
||||||
db.quoter = q
|
db.quoter = q
|
||||||
case QuotePolicyAlways:
|
case QuotePolicyAlways:
|
||||||
fallthrough
|
fallthrough
|
||||||
|
@ -266,18 +266,24 @@ func (db *sqlite3) ForUpdateSQL(query string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *sqlite3) IsColumnExist(ctx context.Context, tableName, colName string) (bool, error) {
|
func (db *sqlite3) IsColumnExist(ctx context.Context, tableName, colName string) (bool, error) {
|
||||||
args := []interface{}{tableName}
|
query := "SELECT * FROM " + tableName + " LIMIT 0"
|
||||||
query := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
|
rows, err := db.DB().QueryContext(ctx, query)
|
||||||
|
|
||||||
rows, err := db.DB().QueryContext(ctx, query, args...)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
if rows.Next() {
|
cols, err := rows.Columns()
|
||||||
return true, nil
|
if err != nil {
|
||||||
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, col := range cols {
|
||||||
|
if strings.EqualFold(col, colName) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"xorm.io/xorm/caches"
|
"xorm.io/xorm/caches"
|
||||||
|
"xorm.io/xorm/dialects"
|
||||||
"xorm.io/xorm/log"
|
"xorm.io/xorm/log"
|
||||||
"xorm.io/xorm/names"
|
"xorm.io/xorm/names"
|
||||||
)
|
)
|
||||||
|
@ -180,6 +181,13 @@ func (eg *EngineGroup) SetPolicy(policy GroupPolicy) *EngineGroup {
|
||||||
return eg
|
return eg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (eg *EngineGroup) SetQuotePolicy(quotePolicy dialects.QuotePolicy) {
|
||||||
|
eg.Engine.SetQuotePolicy(quotePolicy)
|
||||||
|
for i := 0; i < len(eg.slaves); i++ {
|
||||||
|
eg.slaves[i].SetQuotePolicy(quotePolicy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SetTableMapper set the table name mapping rule
|
// SetTableMapper set the table name mapping rule
|
||||||
func (eg *EngineGroup) SetTableMapper(mapper names.Mapper) {
|
func (eg *EngineGroup) SetTableMapper(mapper names.Mapper) {
|
||||||
eg.Engine.SetTableMapper(mapper)
|
eg.Engine.SetTableMapper(mapper)
|
||||||
|
|
|
@ -104,6 +104,7 @@ type EngineInterface interface {
|
||||||
SetMapper(names.Mapper)
|
SetMapper(names.Mapper)
|
||||||
SetMaxOpenConns(int)
|
SetMaxOpenConns(int)
|
||||||
SetMaxIdleConns(int)
|
SetMaxIdleConns(int)
|
||||||
|
SetQuotePolicy(dialects.QuotePolicy)
|
||||||
SetSchema(string)
|
SetSchema(string)
|
||||||
SetTableMapper(names.Mapper)
|
SetTableMapper(names.Mapper)
|
||||||
SetTZDatabase(tz *time.Location)
|
SetTZDatabase(tz *time.Location)
|
||||||
|
|
|
@ -10,23 +10,23 @@ import (
|
||||||
|
|
||||||
// Quoter represents a quoter to the SQL table name and column name
|
// Quoter represents a quoter to the SQL table name and column name
|
||||||
type Quoter struct {
|
type Quoter struct {
|
||||||
Prefix byte
|
Prefix byte
|
||||||
Suffix byte
|
Suffix byte
|
||||||
IsReverse func(string) bool
|
IsReserved func(string) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// AlwaysFalseReverse always think it's not a reverse word
|
// AlwaysFalseReverse always think it's not a reverse word
|
||||||
AlwaysNoReverse = func(string) bool { return false }
|
AlwaysNoReserve = func(string) bool { return false }
|
||||||
|
|
||||||
// AlwaysReverse always reverse the word
|
// AlwaysReverse always reverse the word
|
||||||
AlwaysReverse = func(string) bool { return true }
|
AlwaysReserve = func(string) bool { return true }
|
||||||
|
|
||||||
// CommanQuoteMark represnets the common quote mark
|
// CommanQuoteMark represnets the common quote mark
|
||||||
CommanQuoteMark byte = '`'
|
CommanQuoteMark byte = '`'
|
||||||
|
|
||||||
// CommonQuoter represetns a common quoter
|
// CommonQuoter represetns a common quoter
|
||||||
CommonQuoter = Quoter{CommanQuoteMark, CommanQuoteMark, AlwaysReverse}
|
CommonQuoter = Quoter{CommanQuoteMark, CommanQuoteMark, AlwaysReserve}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (q Quoter) IsEmpty() bool {
|
func (q Quoter) IsEmpty() bool {
|
||||||
|
@ -141,8 +141,8 @@ func (q Quoter) quoteWordTo(buf *strings.Builder, word string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
isReverse := q.IsReverse(realWord)
|
isReserved := q.IsReserved(realWord)
|
||||||
if isReverse {
|
if isReserved {
|
||||||
if err := buf.WriteByte(q.Prefix); err != nil {
|
if err := buf.WriteByte(q.Prefix); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,7 @@ func (q Quoter) quoteWordTo(buf *strings.Builder, word string) error {
|
||||||
if _, err := buf.WriteString(realWord); err != nil {
|
if _, err := buf.WriteString(realWord); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if isReverse {
|
if isReserved {
|
||||||
return buf.WriteByte(q.Suffix)
|
return buf.WriteByte(q.Suffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ type NullType struct {
|
||||||
Age sql.NullInt64
|
Age sql.NullInt64
|
||||||
Height sql.NullFloat64
|
Height sql.NullFloat64
|
||||||
IsMan sql.NullBool `xorm:"null"`
|
IsMan sql.NullBool `xorm:"null"`
|
||||||
CustomStruct CustomStruct `xorm:"valchar(64) null"`
|
CustomStruct CustomStruct `xorm:"varchar(64) null"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CustomStruct struct {
|
type CustomStruct struct {
|
||||||
|
@ -58,14 +58,12 @@ func (m CustomStruct) Value() (driver.Value, error) {
|
||||||
|
|
||||||
func TestCreateNullStructTable(t *testing.T) {
|
func TestCreateNullStructTable(t *testing.T) {
|
||||||
assert.NoError(t, prepareEngine())
|
assert.NoError(t, prepareEngine())
|
||||||
|
|
||||||
err := testEngine.CreateTables(new(NullType))
|
err := testEngine.CreateTables(new(NullType))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDropNullStructTable(t *testing.T) {
|
func TestDropNullStructTable(t *testing.T) {
|
||||||
assert.NoError(t, prepareEngine())
|
assert.NoError(t, prepareEngine())
|
||||||
|
|
||||||
err := testEngine.DropTables(new(NullType))
|
err := testEngine.DropTables(new(NullType))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -78,7 +76,7 @@ func TestNullStructInsert(t *testing.T) {
|
||||||
item := new(NullType)
|
item := new(NullType)
|
||||||
_, err := testEngine.Insert(item)
|
_, err := testEngine.Insert(item)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, item.Id, 1)
|
assert.EqualValues(t, 1, item.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if true {
|
if true {
|
||||||
|
@ -90,12 +88,11 @@ func TestNullStructInsert(t *testing.T) {
|
||||||
}
|
}
|
||||||
_, err := testEngine.Insert(&item)
|
_, err := testEngine.Insert(&item)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, item.Id, 2)
|
assert.EqualValues(t, 2, item.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if true {
|
if true {
|
||||||
items := []NullType{}
|
items := []NullType{}
|
||||||
|
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < 5; i++ {
|
||||||
item := NullType{
|
item := NullType{
|
||||||
Name: sql.NullString{String: "haolei_" + fmt.Sprint(i+1), Valid: true},
|
Name: sql.NullString{String: "haolei_" + fmt.Sprint(i+1), Valid: true},
|
||||||
|
@ -152,7 +149,7 @@ func TestNullStructUpdate(t *testing.T) {
|
||||||
|
|
||||||
affected, err := testEngine.ID(2).Cols("age", "height", "is_man").Update(item)
|
affected, err := testEngine.ID(2).Cols("age", "height", "is_man").Update(item)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, affected, 1)
|
assert.EqualValues(t, 1, affected)
|
||||||
}
|
}
|
||||||
|
|
||||||
if true { // 测试In update
|
if true { // 测试In update
|
||||||
|
@ -160,7 +157,7 @@ func TestNullStructUpdate(t *testing.T) {
|
||||||
item.Age = sql.NullInt64{Int64: 23, Valid: true}
|
item.Age = sql.NullInt64{Int64: 23, Valid: true}
|
||||||
affected, err := testEngine.In("id", 3, 4).Cols("age", "height", "is_man").Update(item)
|
affected, err := testEngine.In("id", 3, 4).Cols("age", "height", "is_man").Update(item)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, affected, 2)
|
assert.EqualValues(t, 2, affected)
|
||||||
}
|
}
|
||||||
|
|
||||||
if true { // 测试where
|
if true { // 测试where
|
||||||
|
@ -183,9 +180,7 @@ func TestNullStructUpdate(t *testing.T) {
|
||||||
|
|
||||||
_, err := testEngine.AllCols().ID(6).Update(item)
|
_, err := testEngine.AllCols().ID(6).Update(item)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
fmt.Println(item)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNullStructFind(t *testing.T) {
|
func TestNullStructFind(t *testing.T) {
|
||||||
|
@ -274,9 +269,8 @@ func TestNullStructCount(t *testing.T) {
|
||||||
|
|
||||||
if true {
|
if true {
|
||||||
item := new(NullType)
|
item := new(NullType)
|
||||||
total, err := testEngine.Where("age IS NOT NULL").Count(item)
|
_, err := testEngine.Where("age IS NOT NULL").Count(item)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
fmt.Println(total)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,7 +286,6 @@ func TestNullStructRows(t *testing.T) {
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
err = rows.Scan(item)
|
err = rows.Scan(item)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
fmt.Println(item)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
10
xorm_test.go
10
xorm_test.go
|
@ -18,6 +18,7 @@ import (
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
_ "github.com/ziutek/mymysql/godrv"
|
_ "github.com/ziutek/mymysql/godrv"
|
||||||
"xorm.io/xorm/caches"
|
"xorm.io/xorm/caches"
|
||||||
|
"xorm.io/xorm/dialects"
|
||||||
"xorm.io/xorm/log"
|
"xorm.io/xorm/log"
|
||||||
"xorm.io/xorm/names"
|
"xorm.io/xorm/names"
|
||||||
"xorm.io/xorm/schemas"
|
"xorm.io/xorm/schemas"
|
||||||
|
@ -38,6 +39,7 @@ var (
|
||||||
schema = flag.String("schema", "", "specify the schema")
|
schema = flag.String("schema", "", "specify the schema")
|
||||||
ignoreSelectUpdate = flag.Bool("ignore_select_update", false, "ignore select update if implementation difference, only for tidb")
|
ignoreSelectUpdate = flag.Bool("ignore_select_update", false, "ignore select update if implementation difference, only for tidb")
|
||||||
ingoreUpdateLimit = flag.Bool("ignore_update_limit", false, "ignore update limit if implementation difference, only for cockroach")
|
ingoreUpdateLimit = flag.Bool("ignore_update_limit", false, "ignore update limit if implementation difference, only for cockroach")
|
||||||
|
quotePolicyStr = flag.String("quote", "always", "quote could be always, none, reversed")
|
||||||
tableMapper names.Mapper
|
tableMapper names.Mapper
|
||||||
colMapper names.Mapper
|
colMapper names.Mapper
|
||||||
)
|
)
|
||||||
|
@ -131,6 +133,14 @@ func createEngine(dbType, connStr string) error {
|
||||||
testEngine.SetMapper(names.LintGonicMapper)
|
testEngine.SetMapper(names.LintGonicMapper)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *quotePolicyStr == "none" {
|
||||||
|
testEngine.SetQuotePolicy(dialects.QuotePolicyNone)
|
||||||
|
} else if *quotePolicyStr == "reserved" {
|
||||||
|
testEngine.SetQuotePolicy(dialects.QuotePolicyReserved)
|
||||||
|
} else {
|
||||||
|
testEngine.SetQuotePolicy(dialects.QuotePolicyAlways)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tableMapper = testEngine.GetTableMapper()
|
tableMapper = testEngine.GetTableMapper()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user