Skip to content

Commit c97c5a1

Browse files
committed
Type affinity.
1 parent 3e1b131 commit c97c5a1

5 files changed

Lines changed: 79 additions & 95 deletions

File tree

ext/csv/csv.go

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ func RegisterFS(db *sqlite3.Conn, fsys fs.FS) error {
8585
header: header,
8686
}
8787

88-
if schema == "" {
88+
hadSchema := schema != ""
89+
if !hadSchema {
8990
var row []string
9091
if header || columns < 0 {
9192
csv, c, err := t.newReader()
@@ -99,17 +100,14 @@ func RegisterFS(db *sqlite3.Conn, fsys fs.FS) error {
99100
}
100101
}
101102
schema = getSchema(header, columns, row)
102-
} else {
103-
t.typs, err = getColumnAffinities(db, schema)
104-
if err != nil {
105-
return nil, err
106-
}
107103
}
108-
109104
err = db.DeclareVTab(schema)
110105
if err == nil {
111106
err = db.VTabConfig(sqlite3.VTAB_DIRECTONLY)
112107
}
108+
if err == nil && hadSchema {
109+
t.typs, err = getColumnAffinities(schema)
110+
}
113111
if err != nil {
114112
return nil, err
115113
}
@@ -123,7 +121,7 @@ type table struct {
123121
fsys fs.FS
124122
name string
125123
data string
126-
typs []affinity
124+
typs []sql3util.Affinity
127125
comma rune
128126
comment rune
129127
header bool
@@ -242,24 +240,24 @@ func (c *cursor) RowID() (int64, error) {
242240

243241
func (c *cursor) Column(ctx sqlite3.Context, col int) error {
244242
if col < len(c.row) {
245-
typ := text
243+
typ := sql3util.TEXT
246244
if col < len(c.table.typs) {
247245
typ = c.table.typs[col]
248246
}
249247

250248
txt := c.row[col]
251-
if txt == "" && typ != text {
249+
if txt == "" && typ != sql3util.TEXT {
252250
return nil
253251
}
254252

255253
switch typ {
256-
case numeric, integer:
254+
case sql3util.NUMERIC, sql3util.INTEGER:
257255
if i, err := strconv.ParseInt(txt, 10, 64); err == nil {
258256
ctx.ResultInt64(i)
259257
return nil
260258
}
261259
fallthrough
262-
case real:
260+
case sql3util.REAL:
263261
if f, ok := sql3util.ParseFloat(txt); ok {
264262
ctx.ResultFloat(f)
265263
return nil

ext/csv/types.go

Lines changed: 4 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,17 @@
11
package csv
22

3-
import (
4-
"strings"
5-
6-
"github.com/ncruces/go-sqlite3"
7-
"github.com/ncruces/go-sqlite3/internal/util"
8-
"github.com/ncruces/go-sqlite3/util/sql3util"
9-
)
10-
11-
type affinity byte
12-
13-
const (
14-
blob affinity = 0
15-
text affinity = 1
16-
numeric affinity = 2
17-
integer affinity = 3
18-
real affinity = 4
19-
)
20-
21-
func getColumnAffinities(db *sqlite3.Conn, schema string) ([]affinity, error) {
22-
stmt, tail, err := db.PrepareFlags(schema,
23-
sqlite3.PREPARE_DONT_LOG|sqlite3.PREPARE_NO_VTAB|sqlite3.PREPARE_FROM_DDL)
24-
if err != nil {
25-
return nil, err
26-
}
27-
stmt.Close()
28-
if tail != "" {
29-
return nil, util.TailErr
30-
}
3+
import "github.com/ncruces/go-sqlite3/util/sql3util"
314

5+
func getColumnAffinities(schema string) ([]sql3util.Affinity, error) {
326
tab, err := sql3util.ParseTable(schema)
337
if err != nil {
348
return nil, err
359
}
3610

3711
columns := tab.Columns
38-
types := make([]affinity, len(columns))
12+
types := make([]sql3util.Affinity, len(columns))
3913
for i, col := range columns {
40-
types[i] = getAffinity(col.Type)
14+
types[i] = sql3util.GetAffinity(col.Type)
4115
}
4216
return types, nil
4317
}
44-
45-
func getAffinity(declType string) affinity {
46-
// https://sqlite.org/datatype3.html#determination_of_column_affinity
47-
if declType == "" {
48-
return blob
49-
}
50-
name := strings.ToUpper(declType)
51-
if strings.Contains(name, "INT") {
52-
return integer
53-
}
54-
if strings.Contains(name, "CHAR") || strings.Contains(name, "CLOB") || strings.Contains(name, "TEXT") {
55-
return text
56-
}
57-
if strings.Contains(name, "BLOB") {
58-
return blob
59-
}
60-
if strings.Contains(name, "REAL") || strings.Contains(name, "FLOA") || strings.Contains(name, "DOUB") {
61-
return real
62-
}
63-
return numeric
64-
}

ext/csv/types_test.go

Lines changed: 0 additions & 32 deletions
This file was deleted.

util/sql3util/util.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,39 @@ func ParseTimeShift(s string) (years, months, days int, duration time.Duration,
7474
func ValidPageSize(s int) bool {
7575
return util.ValidPageSize(s)
7676
}
77+
78+
// Affinity is the type affinity of a column.
79+
//
80+
// https://sqlite.org/datatype3.html#type_affinity
81+
type Affinity byte
82+
83+
const (
84+
TEXT Affinity = iota
85+
NUMERIC
86+
INTEGER
87+
REAL
88+
BLOB
89+
)
90+
91+
// GetAffinity determines the affinity of a column by the declared type of the column.
92+
//
93+
// https://sqlite.org/datatype3.html#determination_of_column_affinity
94+
func GetAffinity(declType string) Affinity {
95+
if declType == "" {
96+
return BLOB
97+
}
98+
name := strings.ToUpper(declType)
99+
if strings.Contains(name, "INT") {
100+
return INTEGER
101+
}
102+
if strings.Contains(name, "CHAR") || strings.Contains(name, "CLOB") || strings.Contains(name, "TEXT") {
103+
return TEXT
104+
}
105+
if strings.Contains(name, "BLOB") {
106+
return BLOB
107+
}
108+
if strings.Contains(name, "REAL") || strings.Contains(name, "FLOA") || strings.Contains(name, "DOUB") {
109+
return REAL
110+
}
111+
return NUMERIC
112+
}

util/sql3util/util_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,32 @@ func TestUnquote(t *testing.T) {
2929
})
3030
}
3131
}
32+
33+
func TestGetAffinity(t *testing.T) {
34+
tests := []struct {
35+
decl string
36+
want sql3util.Affinity
37+
}{
38+
{"", sql3util.BLOB},
39+
{"INTEGER", sql3util.INTEGER},
40+
{"TINYINT", sql3util.INTEGER},
41+
{"TEXT", sql3util.TEXT},
42+
{"CHAR", sql3util.TEXT},
43+
{"CLOB", sql3util.TEXT},
44+
{"BLOB", sql3util.BLOB},
45+
{"REAL", sql3util.REAL},
46+
{"FLOAT", sql3util.REAL},
47+
{"DOUBLE", sql3util.REAL},
48+
{"NUMERIC", sql3util.NUMERIC},
49+
{"DECIMAL", sql3util.NUMERIC},
50+
{"BOOLEAN", sql3util.NUMERIC},
51+
{"DATETIME", sql3util.NUMERIC},
52+
}
53+
for _, tt := range tests {
54+
t.Run(tt.decl, func(t *testing.T) {
55+
if got := sql3util.GetAffinity(tt.decl); got != tt.want {
56+
t.Errorf("GetAffinity() = %v, want %v", got, tt.want)
57+
}
58+
})
59+
}
60+
}

0 commit comments

Comments
 (0)