We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
There was an error while loading. Please reload this page.
1 parent 3e1b131 commit c97c5a1Copy full SHA for c97c5a1
5 files changed
ext/csv/csv.go
@@ -85,7 +85,8 @@ func RegisterFS(db *sqlite3.Conn, fsys fs.FS) error {
85
header: header,
86
}
87
88
- if schema == "" {
+ hadSchema := schema != ""
89
+ if !hadSchema {
90
var row []string
91
if header || columns < 0 {
92
csv, c, err := t.newReader()
@@ -99,17 +100,14 @@ func RegisterFS(db *sqlite3.Conn, fsys fs.FS) error {
99
100
101
102
schema = getSchema(header, columns, row)
- } else {
103
- t.typs, err = getColumnAffinities(db, schema)
104
- if err != nil {
105
- return nil, err
106
- }
107
108
-
109
err = db.DeclareVTab(schema)
110
if err == nil {
111
err = db.VTabConfig(sqlite3.VTAB_DIRECTONLY)
112
+ if err == nil && hadSchema {
+ t.typs, err = getColumnAffinities(schema)
+ }
113
if err != nil {
114
return nil, err
115
@@ -123,7 +121,7 @@ type table struct {
123
121
fsys fs.FS
124
122
name string
125
data string
126
- typs []affinity
+ typs []sql3util.Affinity
127
comma rune
128
comment rune
129
header bool
@@ -242,24 +240,24 @@ func (c *cursor) RowID() (int64, error) {
242
240
243
241
func (c *cursor) Column(ctx sqlite3.Context, col int) error {
244
if col < len(c.row) {
245
- typ := text
+ typ := sql3util.TEXT
246
if col < len(c.table.typs) {
247
typ = c.table.typs[col]
248
249
250
txt := c.row[col]
251
- if txt == "" && typ != text {
+ if txt == "" && typ != sql3util.TEXT {
252
return nil
253
254
255
switch typ {
256
- case numeric, integer:
+ case sql3util.NUMERIC, sql3util.INTEGER:
257
if i, err := strconv.ParseInt(txt, 10, 64); err == nil {
258
ctx.ResultInt64(i)
259
260
261
fallthrough
262
- case real:
+ case sql3util.REAL:
263
if f, ok := sql3util.ParseFloat(txt); ok {
264
ctx.ResultFloat(f)
265
ext/csv/types.go
@@ -1,64 +1,17 @@
1
package csv
2
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
25
26
27
- stmt.Close()
28
- if tail != "" {
29
- return nil, util.TailErr
30
+import "github.com/ncruces/go-sqlite3/util/sql3util"
31
+func getColumnAffinities(schema string) ([]sql3util.Affinity, error) {
32
tab, err := sql3util.ParseTable(schema)
33
34
35
36
37
columns := tab.Columns
38
- types := make([]affinity, len(columns))
+ types := make([]sql3util.Affinity, len(columns))
39
for i, col := range columns {
40
- types[i] = getAffinity(col.Type)
+ types[i] = sql3util.GetAffinity(col.Type)
41
42
return types, nil
43
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
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
util/sql3util/util.go
@@ -74,3 +74,39 @@ func ParseTimeShift(s string) (years, months, days int, duration time.Duration,
74
func ValidPageSize(s int) bool {
75
return util.ValidPageSize(s)
76
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
+ NUMERIC
+ INTEGER
+ REAL
+ BLOB
+)
+// GetAffinity determines the affinity of a column by the declared type of the column.
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)
+ if strings.Contains(name, "INT") {
+ return INTEGER
+ if strings.Contains(name, "CHAR") || strings.Contains(name, "CLOB") || strings.Contains(name, "TEXT") {
+ return TEXT
+ if strings.Contains(name, "BLOB") {
+ if strings.Contains(name, "REAL") || strings.Contains(name, "FLOA") || strings.Contains(name, "DOUB") {
+ return REAL
+ return NUMERIC
+}
util/sql3util/util_test.go
@@ -29,3 +29,32 @@ func TestUnquote(t *testing.T) {
})
+func TestGetAffinity(t *testing.T) {
+ tests := []struct {
+ decl string
+ want sql3util.Affinity
+ }{
+ {"", sql3util.BLOB},
+ {"INTEGER", sql3util.INTEGER},
+ {"TINYINT", sql3util.INTEGER},
+ {"TEXT", sql3util.TEXT},
+ {"CHAR", sql3util.TEXT},
+ {"CLOB", sql3util.TEXT},
+ {"BLOB", sql3util.BLOB},
+ {"REAL", sql3util.REAL},
+ {"FLOAT", sql3util.REAL},
+ {"DOUBLE", sql3util.REAL},
+ {"NUMERIC", sql3util.NUMERIC},
+ {"DECIMAL", sql3util.NUMERIC},
+ {"BOOLEAN", sql3util.NUMERIC},
+ {"DATETIME", sql3util.NUMERIC},
+ for _, tt := range tests {
+ t.Run(tt.decl, func(t *testing.T) {
+ if got := sql3util.GetAffinity(tt.decl); got != tt.want {
+ t.Errorf("GetAffinity() = %v, want %v", got, tt.want)
+ })
0 commit comments