-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsqlite.go
100 lines (87 loc) · 2.66 KB
/
sqlite.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package main
import (
"database/sql"
"log"
_ "github.com/mattn/go-sqlite3"
)
func querySqlite(db *sql.DB, query string) (*sql.Rows, error) {
rows, err := db.Query(query)
if err != nil {
return nil, err
}
return rows, nil
}
func ExecSqlite(db *sql.DB, query string) (int64, error) {
result, err := db.Exec(query)
if err != nil {
return 0, err
}
return result.RowsAffected()
}
func querySqliteRowDescription(db *sql.DB, query string) (map[string]string, error) {
rows, err := querySqlite(db, query)
if err != nil {
return nil, err
}
// get column names
cols, err := rows.Columns()
if err != nil {
return nil, err
}
columnTypes, err := rows.ColumnTypes()
if err != nil {
return nil, err
}
// NOTE: This is assuming that the column names and column types are returned in the same order
// If they aren't in the same order then we have to query the catalog table such as sqlite_master
// SELECT * FROM sqlite_master WHERE type='table' and name='$tableName';
output := make(map[string]string, len(cols))
for index, col := range cols {
output[col] = columnTypes[index].DatabaseTypeName()
}
return output, nil
}
// prepareDataRow returns a result set for a given query
func prepareDataRow(db *sql.DB, query string) ([][][]byte, error) {
rows, err := querySqlite(db, query)
if err != nil {
return nil, err
}
// get column names
cols, err := rows.Columns()
if err != nil {
return nil, err
}
// since we don't know the number of rows without actually scanning it
// create an output slice of byte which represents result set
var output [][][]byte
for rows.Next() {
// refer on how to dynamically get sql output https://betterprogramming.pub/dynamic-sql-query-with-go-8aeedaa02907
// row is the storage for row.Scans.
// for printing, []byte is sufficient for most of the data type,
// including NULLABLE column, which will be empty
row := make([][]byte, len(cols))
log.Println("row:", len(row))
// through rowPtr, we can scan data to row.
// without rowPtr, we need to do very complex type assertion
// and dereference when printing (e.g. *(rowPtr[i].(*[]byte)))
// rowPtr... expands rowPtr slice to individual arguments
// row.Scan accepts variadic POINTER (of any type) arguments.
// to make it able to take dynamic number of arguments,
// we need a []any variable and use it in ellipsis operator.
// rowPtr is just a slice of pointers pointing to every element in row
rowPtr := make([]any, len(cols))
for i := range row {
rowPtr[i] = &row[i]
}
err := rows.Scan(rowPtr...)
if err != nil {
return nil, err
}
output = append(output, row)
}
if err = rows.Err(); err != nil {
return nil, err
}
return output, err
}