Skip to content

Commit 9276933

Browse files
committed
Fix schema change handling.
1 parent 7e4061b commit 9276933

File tree

1 file changed

+85
-53
lines changed

1 file changed

+85
-53
lines changed

go1/sqlite3/sqlite3.go

Lines changed: 85 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ static int bind_blob(sqlite3_stmt *s, int i, const void *p, int n, int copy) {
5252
return sqlite3_bind_zeroblob(s, i, 0);
5353
}
5454
55+
// Faster retrieval of column data types (1 cgo call instead of n).
56+
static void column_types(sqlite3_stmt *s, unsigned char *p, int n) {
57+
int i = 0;
58+
for (; i < n; ++i, ++p) {
59+
*p = sqlite3_column_type(s, i);
60+
}
61+
}
62+
5563
// Macro for creating callback setter functions.
5664
#define SET(x) \
5765
static void set_##x(sqlite3 *db, void *conn, int enable) { \
@@ -489,6 +497,14 @@ func (c *Conn) exec(sql *C.char) error {
489497
}
490498

491499
// Stmt is a prepared statement handle.
500+
//
501+
// SQLite automatically recompiles prepared statements when the database schema
502+
// changes. A query like "SELECT * FROM x" may return a different number of
503+
// columns from one execution to the next if the table is altered. The
504+
// recompilation, if required, only happens at the start of execution (during a
505+
// call to Exec or Query). Statements that are already running (Busy() == true)
506+
// are not recompiled. Thus, the safest way of obtaining column information is
507+
// to call Exec or Query first, followed by NumColumns, Columns, DeclTypes, etc.
492508
// [http://www.sqlite.org/c3ref/stmt.html]
493509
type Stmt struct {
494510
Tail string // Uncompiled portion of the SQL string passed to Conn.Prepare
@@ -498,13 +514,13 @@ type Stmt struct {
498514

499515
text string // SQL text used to create this statement (minus the Tail)
500516
nVars int // Number of bound parameters (or maximum ?NNN value)
501-
nCols int // Number of columns in each row
517+
nCols int // Number of columns in each row (for the current run)
502518
haveRow bool // Flag indicating row availability
503519

504-
varNames []string // Names of bound parameters (or unnamedVars)
520+
varNames []string // Names of bound parameters
505521
colNames []string // Names of columns in the result set
506522
colDecls []string // Column type declarations in upper case
507-
colTypes []byte // Data type codes for all columns in the current row
523+
colTypes []uint8 // Data type codes for all columns in the current row
508524
}
509525

510526
// newStmt creates a new prepared statement.
@@ -524,9 +540,6 @@ func newStmt(c *Conn, sql string) (*Stmt, error) {
524540
if stmt != nil {
525541
s.nVars = int(C.sqlite3_bind_parameter_count(stmt))
526542
s.nCols = int(C.sqlite3_column_count(stmt))
527-
if s.nCols > 0 {
528-
s.colTypes = make([]byte, s.nCols)
529-
}
530543
runtime.SetFinalizer(s, (*Stmt).Close)
531544
}
532545
if tail != nil {
@@ -638,12 +651,12 @@ func (s *Stmt) Params() []string {
638651
// Columns returns the names of columns produced by the prepared statement.
639652
// [http://www.sqlite.org/c3ref/column_name.html]
640653
func (s *Stmt) Columns() []string {
641-
if s.colNames == nil && s.nCols > 0 {
642-
names := make([]string, s.nCols)
643-
for i := range names {
644-
name := C.sqlite3_column_name(s.stmt, C.int(i))
645-
if name != nil {
646-
names[i] = C.GoString(name)
654+
if len(s.colNames) != s.nCols {
655+
names := resize(s.colNames, s.nCols)
656+
for i, old := range names {
657+
new := goStr(C.sqlite3_column_name(s.stmt, C.int(i)))
658+
if old != new {
659+
names[i] = raw(new).Copy()
647660
}
648661
}
649662
s.colNames = names
@@ -655,12 +668,16 @@ func (s *Stmt) Columns() []string {
655668
// statement. The type declarations are normalized to upper case.
656669
// [http://www.sqlite.org/c3ref/column_decltype.html]
657670
func (s *Stmt) DeclTypes() []string {
658-
if s.colDecls == nil && s.nCols > 0 {
659-
decls := make([]string, s.nCols)
660-
for i := range decls {
661-
decl := C.sqlite3_column_decltype(s.stmt, C.int(i))
662-
if decl != nil {
663-
decls[i] = strings.ToUpper(C.GoString(decl))
671+
if len(s.colDecls) != s.nCols {
672+
decls := resize(s.colDecls, s.nCols)
673+
for i, old := range decls {
674+
new := goStr(C.sqlite3_column_decltype(s.stmt, C.int(i)))
675+
if !strings.EqualFold(old, new) {
676+
norm := strings.ToUpper(new)
677+
if cStr(new) == cStr(norm) {
678+
norm = raw(norm).Copy() // ToUpper didn't reallocate
679+
}
680+
decls[i] = norm
664681
}
665682
}
666683
s.colDecls = decls
@@ -670,17 +687,15 @@ func (s *Stmt) DeclTypes() []string {
670687

671688
// DataTypes returns the data type codes of columns in the current row. Possible
672689
// data types are INTEGER, FLOAT, TEXT, BLOB, and NULL. These represent the
673-
// actual storage classes used by SQLite to store each value. The returned slice
674-
// should not be modified.
690+
// actual storage classes used by SQLite to store each value before any
691+
// conversion. The returned slice should not be modified.
675692
// [http://www.sqlite.org/c3ref/column_blob.html]
676-
func (s *Stmt) DataTypes() []byte {
677-
if !s.haveRow {
678-
return nil
679-
}
680-
for i, typ := range s.colTypes {
681-
if typ == 0 {
682-
s.colTypes[i] = byte(C.sqlite3_column_type(s.stmt, C.int(i)))
693+
func (s *Stmt) DataTypes() []uint8 {
694+
if len(s.colTypes) == 0 {
695+
if !s.haveRow || s.nCols == 0 {
696+
return nil
683697
}
698+
s.colType(0)
684699
}
685700
return s.colTypes
686701
}
@@ -803,27 +818,33 @@ func (s *Stmt) exec(args []interface{}) (err error) {
803818
} else {
804819
err = s.bindUnnamed(args)
805820
}
806-
if err != nil {
807-
if s.nVars > 0 {
808-
C.sqlite3_clear_bindings(s.stmt)
821+
if err == nil {
822+
err = s.step()
823+
if s.nCols > 0 {
824+
// If the statement was recompiled (v2 interface, no indication),
825+
// then column counts, names, and declarations may have changed and
826+
// need to be reloaded.
827+
s.nCols = int(C.sqlite3_column_count(s.stmt))
828+
s.colNames = s.colNames[:0]
829+
s.colDecls = s.colDecls[:0]
809830
}
810-
return
831+
} else if s.nVars > 0 {
832+
C.sqlite3_clear_bindings(s.stmt)
811833
}
812-
return s.step()
834+
return
813835
}
814836

815837
// bindNamed binds statement parameters using the name/value pairs in args.
816838
func (s *Stmt) bindNamed(args NamedArgs) error {
817-
if s.nVars == 0 {
818-
return nil
819-
}
820-
names := s.Params()
821-
if names == nil {
822-
return pkgErr(MISUSE, "statement does not accept named arguments")
823-
}
824-
for i, name := range names {
825-
if err := s.bind(C.int(i+1), args[name], name); err != nil {
826-
return err
839+
if s.nVars > 0 {
840+
names := s.Params()
841+
if names == nil {
842+
return pkgErr(MISUSE, "statement does not accept named arguments")
843+
}
844+
for i, name := range names {
845+
if err := s.bind(C.int(i+1), args[name], name); err != nil {
846+
return err
847+
}
827848
}
828849
}
829850
return nil
@@ -886,13 +907,9 @@ func (s *Stmt) bind(i C.int, v interface{}, name string) error {
886907
// step evaluates the next step in the statement's program, automatically
887908
// resetting the statement if the result is anything other than SQLITE_ROW.
888909
func (s *Stmt) step() error {
910+
s.colTypes = s.colTypes[:0]
889911
s.haveRow = C.sqlite3_step(s.stmt) == ROW
890-
if s.haveRow {
891-
// Clear previous data types and reload new ones on demand
892-
for i := range s.colTypes {
893-
s.colTypes[i] = 0
894-
}
895-
} else {
912+
if !s.haveRow {
896913
// If step returned DONE, reset returns OK. Otherwise, reset returns the
897914
// same error code as step (v2 interface).
898915
rc := C.sqlite3_reset(s.stmt)
@@ -910,12 +927,17 @@ func (s *Stmt) step() error {
910927
// INTEGER, FLOAT, TEXT, BLOB, or NULL). The value becomes undefined after a
911928
// type conversion, so this method must be called for column i to cache the
912929
// original value before using any other sqlite3_column_* functions.
913-
func (s *Stmt) colType(i C.int) (typ byte) {
914-
if typ = s.colTypes[i]; typ == 0 {
915-
typ = byte(C.sqlite3_column_type(s.stmt, i))
916-
s.colTypes[i] = typ
930+
func (s *Stmt) colType(i C.int) byte {
931+
if len(s.colTypes) == 0 {
932+
n := s.nCols
933+
if cap(s.colTypes) < n {
934+
s.colTypes = make([]uint8, n)
935+
} else {
936+
s.colTypes = s.colTypes[:n]
937+
}
938+
C.column_types(s.stmt, (*C.uchar)(cBytes(s.colTypes)), C.int(n))
917939
}
918-
return
940+
return s.colTypes[i]
919941
}
920942

921943
// scan scans the value of column i (starting at 0) into v.
@@ -1033,6 +1055,16 @@ func namedArgs(args []interface{}) (named NamedArgs) {
10331055
return
10341056
}
10351057

1058+
// resize changes len(s) to n, reallocating s if needed.
1059+
func resize(s []string, n int) []string {
1060+
if n <= cap(s) {
1061+
return s[:n]
1062+
}
1063+
tmp := make([]string, n)
1064+
copy(tmp, s[:cap(s)])
1065+
return tmp
1066+
}
1067+
10361068
// text returns the value of column i as a UTF-8 string. If copy is false, the
10371069
// string will point to memory allocated by SQLite.
10381070
func text(stmt *C.sqlite3_stmt, i C.int, copy bool) string {

0 commit comments

Comments
 (0)