1
+ // Copyright (C) 2022 Yasuhiro Matsumoto <[email protected] >.
2
+ //
3
+ // Use of this source code is governed by an MIT-style
4
+ // license that can be found in the LICENSE file.
5
+
6
+ package sqlite3
7
+
8
+ /*
9
+ #ifndef USE_LIBSQLITE3
10
+ #include "sqlite3-binding.h"
11
+ #else
12
+ #include <sqlite3.h>
13
+ #endif
14
+ #include <stdlib.h>
15
+ */
16
+ import "C"
17
+
18
+ import (
19
+ "errors"
20
+ "fmt"
21
+ "io"
22
+ "math"
23
+ "runtime"
24
+ "unsafe"
25
+ )
26
+
27
+ // SQLiteBlob implements the SQLite Blob I/O interface.
28
+ type SQLiteBlob struct {
29
+ conn * SQLiteConn
30
+ blob * C.sqlite3_blob
31
+ size int
32
+ offset int
33
+ }
34
+
35
+ // Blob opens a blob.
36
+ //
37
+ // See https://www.sqlite.org/c3ref/blob_open.html for usage.
38
+ //
39
+ // Should only be used with conn.Raw.
40
+ func (conn * SQLiteConn ) Blob (database , table , column string , rowid int64 , flags int ) (* SQLiteBlob , error ) {
41
+ databaseptr := C .CString (database )
42
+ defer C .free (unsafe .Pointer (databaseptr ))
43
+
44
+ tableptr := C .CString (table )
45
+ defer C .free (unsafe .Pointer (tableptr ))
46
+
47
+ columnptr := C .CString (column )
48
+ defer C .free (unsafe .Pointer (columnptr ))
49
+
50
+ var blob * C.sqlite3_blob
51
+ ret := C .sqlite3_blob_open (conn .db , databaseptr , tableptr , columnptr , C .longlong (rowid ), C .int (flags ), & blob )
52
+
53
+ if ret != C .SQLITE_OK {
54
+ return nil , conn .lastError ()
55
+ }
56
+
57
+ size := int (C .sqlite3_blob_bytes (blob ))
58
+ bb := & SQLiteBlob {conn : conn , blob : blob , size : size , offset : 0 }
59
+
60
+ runtime .SetFinalizer (bb , (* SQLiteBlob ).Close )
61
+
62
+ return bb , nil
63
+ }
64
+
65
+ // Read implements the io.Reader interface.
66
+ func (s * SQLiteBlob ) Read (b []byte ) (n int , err error ) {
67
+ if s .offset >= s .size {
68
+ return 0 , io .EOF
69
+ }
70
+
71
+ if len (b ) == 0 {
72
+ return 0 , nil
73
+ }
74
+
75
+ n = s .size - s .offset
76
+ if len (b ) < n {
77
+ n = len (b )
78
+ }
79
+
80
+ p := & b [0 ]
81
+ ret := C .sqlite3_blob_read (s .blob , unsafe .Pointer (p ), C .int (n ), C .int (s .offset ))
82
+ if ret != C .SQLITE_OK {
83
+ return 0 , s .conn .lastError ()
84
+ }
85
+
86
+ s .offset += n
87
+
88
+ return n , nil
89
+ }
90
+
91
+ // Write implements the io.Writer interface.
92
+ func (s * SQLiteBlob ) Write (b []byte ) (n int , err error ) {
93
+ if len (b ) == 0 {
94
+ return 0 , nil
95
+ }
96
+
97
+ if s .offset >= s .size {
98
+ return 0 , fmt .Errorf ("sqlite3.SQLiteBlob.Write: insufficient space in %d-byte blob" , s .size )
99
+ }
100
+
101
+ n = s .size - s .offset
102
+ if len (b ) < n {
103
+ n = len (b )
104
+ }
105
+
106
+ if n != len (b ) {
107
+ return 0 , fmt .Errorf ("sqlite3.SQLiteBlob.Write: insufficient space in %d-byte blob" , s .size )
108
+ }
109
+
110
+ p := & b [0 ]
111
+ ret := C .sqlite3_blob_write (s .blob , unsafe .Pointer (p ), C .int (n ), C .int (s .offset ))
112
+ if ret != C .SQLITE_OK {
113
+ return 0 , s .conn .lastError ()
114
+ }
115
+
116
+ s .offset += n
117
+
118
+ return n , nil
119
+ }
120
+
121
+ // Seek implements the io.Seeker interface.
122
+ func (s * SQLiteBlob ) Seek (offset int64 , whence int ) (int64 , error ) {
123
+ if offset > math .MaxInt32 {
124
+ return 0 , fmt .Errorf ("sqlite3.SQLiteBlob.Seek: invalid offset %d" , offset )
125
+ }
126
+
127
+ var abs int64
128
+ switch whence {
129
+ case io .SeekStart :
130
+ abs = offset
131
+ case io .SeekCurrent :
132
+ abs = int64 (s .offset ) + offset
133
+ case io .SeekEnd :
134
+ abs = int64 (s .size ) + offset
135
+ default :
136
+ return 0 , fmt .Errorf ("sqlite3.SQLiteBlob.Seek: invalid whence %d" , whence )
137
+ }
138
+
139
+ if abs < 0 {
140
+ return 0 , errors .New ("sqlite.SQLiteBlob.Seek: negative position" )
141
+ }
142
+
143
+ if abs > math .MaxInt32 || abs > int64 (s .size ) {
144
+ return 0 , errors .New ("sqlite3.SQLiteBlob.Seek: overflow position" )
145
+ }
146
+
147
+ s .offset = int (abs )
148
+
149
+ return abs , nil
150
+ }
151
+
152
+ // Size returns the size of the blob.
153
+ func (s * SQLiteBlob ) Size () int {
154
+ return s .size
155
+ }
156
+
157
+ // Close implements the io.Closer interface.
158
+ func (s * SQLiteBlob ) Close () error {
159
+ ret := C .sqlite3_blob_close (s .blob )
160
+
161
+ s .blob = nil
162
+ runtime .SetFinalizer (s , nil )
163
+
164
+ if ret != C .SQLITE_OK {
165
+ return s .conn .lastError ()
166
+ }
167
+
168
+ return nil
169
+ }
0 commit comments