Skip to content
This repository was archived by the owner on Sep 7, 2021. It is now read-only.
This repository is currently being migrated. It's locked while the migration is in progress.

Commit a5702e5

Browse files
authored
Fix default value parse bugs (#1437)
* fix default value * fix default value tags * fix postgres default * fix default on postgres * fix default on postgres * fix mssql default
1 parent d6963b7 commit a5702e5

File tree

10 files changed

+321
-131
lines changed

10 files changed

+321
-131
lines changed

dialect_mssql.go

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) {
338338
func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
339339
args := []interface{}{}
340340
s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale,a.is_nullable as nullable,
341+
"default_is_null" = (CASE WHEN c.text is null THEN 1 ELSE 0 END),
341342
replace(replace(isnull(c.text,''),'(',''),')','') as vdefault,
342343
ISNULL(i.is_primary_key, 0)
343344
from sys.columns a
@@ -361,8 +362,8 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column
361362
for rows.Next() {
362363
var name, ctype, vdefault string
363364
var maxLen, precision, scale int
364-
var nullable, isPK bool
365-
err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &vdefault, &isPK)
365+
var nullable, isPK, defaultIsNull bool
366+
err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &defaultIsNull, &vdefault, &isPK)
366367
if err != nil {
367368
return nil, nil, err
368369
}
@@ -371,7 +372,10 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column
371372
col.Indexes = make(map[string]int)
372373
col.Name = strings.Trim(name, "` ")
373374
col.Nullable = nullable
374-
col.Default = vdefault
375+
col.DefaultIsEmpty = defaultIsNull
376+
if !defaultIsNull {
377+
col.Default = vdefault
378+
}
375379
col.IsPrimaryKey = isPK
376380
ct := strings.ToUpper(ctype)
377381
if ct == "DECIMAL" {
@@ -395,15 +399,6 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column
395399
}
396400
}
397401

398-
if col.SQLType.IsText() || col.SQLType.IsTime() {
399-
if col.Default != "" {
400-
col.Default = "'" + col.Default + "'"
401-
} else {
402-
if col.DefaultIsEmpty {
403-
col.Default = "''"
404-
}
405-
}
406-
}
407402
cols[col.Name] = col
408403
colSeq = append(colSeq, col.Name)
409404
}

dialect_mysql.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -345,9 +345,9 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column
345345

346346
if colDefault != nil {
347347
col.Default = *colDefault
348-
if col.Default == "" {
349-
col.DefaultIsEmpty = true
350-
}
348+
col.DefaultIsEmpty = false
349+
} else {
350+
col.DefaultIsEmpty = true
351351
}
352352

353353
cts := strings.Split(colType, "(")
@@ -411,13 +411,11 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column
411411
col.IsAutoIncrement = true
412412
}
413413

414-
if col.SQLType.IsText() || col.SQLType.IsTime() {
415-
if col.Default != "" {
414+
if !col.DefaultIsEmpty {
415+
if col.SQLType.IsText() {
416+
col.Default = "'" + col.Default + "'"
417+
} else if col.SQLType.IsTime() && col.Default != "CURRENT_TIMESTAMP" {
416418
col.Default = "'" + col.Default + "'"
417-
} else {
418-
if col.DefaultIsEmpty {
419-
col.Default = "''"
420-
}
421419
}
422420
}
423421
cols[col.Name] = col

dialect_postgres.go

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,16 +1005,18 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att
10051005

10061006
col.Name = strings.Trim(colName, `" `)
10071007

1008-
if colDefault != nil || isPK {
1009-
if isPK {
1010-
col.IsPrimaryKey = true
1011-
} else {
1012-
col.Default = *colDefault
1008+
if colDefault != nil {
1009+
col.Default = *colDefault
1010+
col.DefaultIsEmpty = false
1011+
if strings.HasPrefix(col.Default, "nextval(") {
1012+
col.IsAutoIncrement = true
10131013
}
1014+
} else {
1015+
col.DefaultIsEmpty = true
10141016
}
10151017

1016-
if colDefault != nil && strings.HasPrefix(*colDefault, "nextval(") {
1017-
col.IsAutoIncrement = true
1018+
if isPK {
1019+
col.IsPrimaryKey = true
10181020
}
10191021

10201022
col.Nullable = (isNullable == "YES")
@@ -1043,12 +1045,16 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att
10431045

10441046
col.Length = maxLen
10451047

1046-
if col.SQLType.IsText() || col.SQLType.IsTime() {
1047-
if col.Default != "" {
1048-
col.Default = "'" + col.Default + "'"
1049-
} else {
1050-
if col.DefaultIsEmpty {
1051-
col.Default = "''"
1048+
if !col.DefaultIsEmpty {
1049+
if col.SQLType.IsText() {
1050+
if strings.HasSuffix(col.Default, "::character varying") {
1051+
col.Default = strings.TrimRight(col.Default, "::character varying")
1052+
} else if !strings.HasPrefix(col.Default, "'") {
1053+
col.Default = "'" + col.Default + "'"
1054+
}
1055+
} else if col.SQLType.IsTime() {
1056+
if strings.HasSuffix(col.Default, "::timestamp without time zone") {
1057+
col.Default = strings.TrimRight(col.Default, "::timestamp without time zone")
10521058
}
10531059
}
10541060
}

dialect_sqlite3.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,34 @@ func (db *sqlite3) IsColumnExist(tableName, colName string) (bool, error) {
270270
return false, nil
271271
}
272272

273+
// splitColStr splits a sqlite col strings as fields
274+
func splitColStr(colStr string) []string {
275+
colStr = strings.TrimSpace(colStr)
276+
var results = make([]string, 0, 10)
277+
var lastIdx int
278+
var hasC, hasQuote bool
279+
for i, c := range colStr {
280+
if c == ' ' && !hasQuote {
281+
if hasC {
282+
results = append(results, colStr[lastIdx:i])
283+
hasC = false
284+
}
285+
} else {
286+
if c == '\'' {
287+
hasQuote = !hasQuote
288+
}
289+
if !hasC {
290+
lastIdx = i
291+
}
292+
hasC = true
293+
if i == len(colStr)-1 {
294+
results = append(results, colStr[lastIdx:i+1])
295+
}
296+
}
297+
}
298+
return results
299+
}
300+
273301
func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
274302
args := []interface{}{tableName}
275303
s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?"
@@ -315,7 +343,7 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Colu
315343
continue
316344
}
317345

318-
fields := strings.Fields(strings.TrimSpace(colStr))
346+
fields := splitColStr(colStr)
319347
col := new(core.Column)
320348
col.Indexes = make(map[string]int)
321349
col.Nullable = true
@@ -344,9 +372,6 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Colu
344372
col.DefaultIsEmpty = false
345373
}
346374
}
347-
if !col.SQLType.IsNumeric() && !col.DefaultIsEmpty {
348-
col.Default = "'" + col.Default + "'"
349-
}
350375
cols[col.Name] = col
351376
colSeq = append(colSeq, col.Name)
352377
}

dialect_sqlite3_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2019 The Xorm Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package xorm
6+
7+
import (
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestSplitColStr(t *testing.T) {
14+
var kases = []struct {
15+
colStr string
16+
fields []string
17+
}{
18+
{
19+
colStr: "`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL",
20+
fields: []string{
21+
"`id`", "INTEGER", "PRIMARY", "KEY", "AUTOINCREMENT", "NOT", "NULL",
22+
},
23+
},
24+
{
25+
colStr: "`created` DATETIME DEFAULT '2006-01-02 15:04:05' NULL",
26+
fields: []string{
27+
"`created`", "DATETIME", "DEFAULT", "'2006-01-02 15:04:05'", "NULL",
28+
},
29+
},
30+
}
31+
32+
for _, kase := range kases {
33+
assert.EqualValues(t, kase.fields, splitColStr(kase.colStr))
34+
}
35+
}

engine.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -907,8 +907,15 @@ func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) {
907907
fieldType := fieldValue.Type()
908908

909909
if ormTagStr != "" {
910-
col = &core.Column{FieldName: t.Field(i).Name, Nullable: true, IsPrimaryKey: false,
911-
IsAutoIncrement: false, MapType: core.TWOSIDES, Indexes: make(map[string]int)}
910+
col = &core.Column{
911+
FieldName: t.Field(i).Name,
912+
Nullable: true,
913+
IsPrimaryKey: false,
914+
IsAutoIncrement: false,
915+
MapType: core.TWOSIDES,
916+
Indexes: make(map[string]int),
917+
DefaultIsEmpty: true,
918+
}
912919
tags := splitTag(ormTagStr)
913920

914921
if len(tags) > 0 {

helpers_test.go

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,6 @@ import (
1010
"github.com/stretchr/testify/assert"
1111
)
1212

13-
func TestSplitTag(t *testing.T) {
14-
var cases = []struct {
15-
tag string
16-
tags []string
17-
}{
18-
{"not null default '2000-01-01 00:00:00' TIMESTAMP", []string{"not", "null", "default", "'2000-01-01 00:00:00'", "TIMESTAMP"}},
19-
{"TEXT", []string{"TEXT"}},
20-
{"default('2000-01-01 00:00:00')", []string{"default('2000-01-01 00:00:00')"}},
21-
{"json binary", []string{"json", "binary"}},
22-
}
23-
24-
for _, kase := range cases {
25-
tags := splitTag(kase.tag)
26-
if !sliceEq(tags, kase.tags) {
27-
t.Fatalf("[%d]%v is not equal [%d]%v", len(tags), tags, len(kase.tags), kase.tags)
28-
}
29-
}
30-
}
31-
3213
func TestEraseAny(t *testing.T) {
3314
raw := "SELECT * FROM `table`.[table_name]"
3415
assert.EqualValues(t, raw, eraseAny(raw))

tag.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ func DefaultTagHandler(ctx *tagContext) error {
125125
ctx.col.Default = ctx.nextTag
126126
ctx.ignoreNext = true
127127
}
128+
ctx.col.DefaultIsEmpty = false
128129
return nil
129130
}
130131

0 commit comments

Comments
 (0)