github.com/ncruces/go-sqlite3@v0.15.1-0.20240520133447-53eef1510ff0/tests/blob_test.go (about) 1 package tests 2 3 import ( 4 "bytes" 5 "crypto/rand" 6 "errors" 7 "fmt" 8 "hash/adler32" 9 "io" 10 "testing" 11 12 "github.com/ncruces/go-sqlite3" 13 _ "github.com/ncruces/go-sqlite3/embed" 14 _ "github.com/ncruces/go-sqlite3/tests/testcfg" 15 ) 16 17 func TestBlob(t *testing.T) { 18 t.Parallel() 19 20 db, err := sqlite3.Open(":memory:") 21 if err != nil { 22 t.Fatal(err) 23 } 24 defer db.Close() 25 26 err = db.Exec(`CREATE TABLE test (col)`) 27 if err != nil { 28 t.Fatal(err) 29 } 30 31 err = db.Exec(`INSERT INTO test VALUES (zeroblob(1024))`) 32 if err != nil { 33 t.Fatal(err) 34 } 35 36 blob, err := db.OpenBlob("main", "test", "col", db.LastInsertRowID(), true) 37 if err != nil { 38 t.Fatal(err) 39 } 40 defer blob.Close() 41 42 size := blob.Size() 43 if size != 1024 { 44 t.Errorf("got %d, want 1024", size) 45 } 46 47 var data [1280]byte 48 _, err = rand.Read(data[:]) 49 if err != nil { 50 t.Fatal(err) 51 } 52 53 _, err = blob.Write(data[:size/2]) 54 if err != nil { 55 t.Fatal(err) 56 } 57 58 n, err := blob.Write(data[:]) 59 if n != 0 || !errors.Is(err, sqlite3.ERROR) { 60 t.Fatalf("got (%d, %v), want (0, ERROR)", n, err) 61 } 62 63 _, err = blob.Write(data[size/2 : size]) 64 if err != nil { 65 t.Fatal(err) 66 } 67 68 _, err = blob.Seek(size/4, io.SeekStart) 69 if err != nil { 70 t.Fatal(err) 71 } 72 73 if got, err := io.ReadAll(blob); err != nil { 74 t.Fatal(err) 75 } else if !bytes.Equal(got, data[size/4:size]) { 76 t.Errorf("got %q, want %q", got, data[size/4:size]) 77 } 78 79 if n, err := blob.Read(make([]byte, 1)); n != 0 || err != io.EOF { 80 t.Errorf("got (%d, %v), want (0, EOF)", n, err) 81 } 82 83 if err := blob.Close(); err != nil { 84 t.Fatal(err) 85 } 86 87 if err := db.Close(); err != nil { 88 t.Fatal(err) 89 } 90 } 91 92 func TestBlob_large(t *testing.T) { 93 t.Parallel() 94 95 db, err := sqlite3.Open(":memory:") 96 if err != nil { 97 t.Fatal(err) 98 } 99 defer db.Close() 100 101 err = db.Exec(`CREATE TABLE test (col)`) 102 if err != nil { 103 t.Fatal(err) 104 } 105 106 err = db.Exec(`INSERT INTO test VALUES (zeroblob(1000000))`) 107 if err != nil { 108 t.Fatal(err) 109 } 110 111 blob, err := db.OpenBlob("main", "test", "col", db.LastInsertRowID(), true) 112 if err != nil { 113 t.Fatal(err) 114 } 115 defer blob.Close() 116 117 size := blob.Size() 118 if size != 1000000 { 119 t.Errorf("got %d, want 1000000", size) 120 } 121 122 hash := adler32.New() 123 _, err = io.CopyN(blob, io.TeeReader(rand.Reader, hash), 1000000) 124 if err != nil { 125 t.Fatal(err) 126 } 127 128 _, err = blob.Seek(0, io.SeekStart) 129 if err != nil { 130 t.Fatal(err) 131 } 132 133 want := hash.Sum32() 134 hash.Reset() 135 _, err = io.Copy(hash, blob) 136 if err != nil { 137 t.Fatal(err) 138 } 139 140 if got := hash.Sum32(); got != want { 141 t.Fatalf("got %d, want %d", got, want) 142 } 143 144 if err := blob.Close(); err != nil { 145 t.Fatal(err) 146 } 147 148 if err := db.Close(); err != nil { 149 t.Fatal(err) 150 } 151 } 152 153 func TestBlob_overflow(t *testing.T) { 154 t.Parallel() 155 156 db, err := sqlite3.Open(":memory:") 157 if err != nil { 158 t.Fatal(err) 159 } 160 defer db.Close() 161 162 err = db.Exec(`CREATE TABLE test (col)`) 163 if err != nil { 164 t.Fatal(err) 165 } 166 167 err = db.Exec(`INSERT INTO test VALUES (zeroblob(1024))`) 168 if err != nil { 169 t.Fatal(err) 170 } 171 172 blob, err := db.OpenBlob("main", "test", "col", db.LastInsertRowID(), true) 173 if err != nil { 174 t.Fatal(err) 175 } 176 defer blob.Close() 177 178 n, err := blob.ReadFrom(rand.Reader) 179 if n != 1024 || !errors.Is(err, sqlite3.ERROR) { 180 t.Fatalf("got (%d, %v), want (0, ERROR)", n, err) 181 } 182 183 n, err = blob.ReadFrom(rand.Reader) 184 if n != 0 || !errors.Is(err, sqlite3.ERROR) { 185 t.Fatalf("got (%d, %v), want (0, ERROR)", n, err) 186 } 187 188 _, err = blob.Seek(-128, io.SeekEnd) 189 if err != nil { 190 t.Fatal(err) 191 } 192 193 n, err = blob.WriteTo(io.Discard) 194 if n != 128 || err != nil { 195 t.Fatalf("got (%d, %v), want (128, nil)", n, err) 196 } 197 198 n, err = blob.WriteTo(io.Discard) 199 if n != 0 || err != nil { 200 t.Fatalf("got (%d, %v), want (0, nil)", n, err) 201 } 202 203 if err := blob.Close(); err != nil { 204 t.Fatal(err) 205 } 206 207 if err := db.Close(); err != nil { 208 t.Fatal(err) 209 } 210 } 211 212 func TestBlob_invalid(t *testing.T) { 213 t.Parallel() 214 215 db, err := sqlite3.Open(":memory:") 216 if err != nil { 217 t.Fatal(err) 218 } 219 defer db.Close() 220 221 err = db.Exec(`CREATE TABLE test (col)`) 222 if err != nil { 223 t.Fatal(err) 224 } 225 226 err = db.Exec(`INSERT INTO test VALUES (zeroblob(1024))`) 227 if err != nil { 228 t.Fatal(err) 229 } 230 231 _, err = db.OpenBlob("", "test", "col", db.LastInsertRowID(), false) 232 if !errors.Is(err, sqlite3.ERROR) { 233 t.Fatal("want error") 234 } 235 } 236 237 func TestBlob_Write_readonly(t *testing.T) { 238 t.Parallel() 239 240 db, err := sqlite3.Open(":memory:") 241 if err != nil { 242 t.Fatal(err) 243 } 244 defer db.Close() 245 246 err = db.Exec(`CREATE TABLE test (col)`) 247 if err != nil { 248 t.Fatal(err) 249 } 250 251 err = db.Exec(`INSERT INTO test VALUES (zeroblob(1024))`) 252 if err != nil { 253 t.Fatal(err) 254 } 255 256 blob, err := db.OpenBlob("main", "test", "col", db.LastInsertRowID(), false) 257 if err != nil { 258 t.Fatal(err) 259 } 260 defer blob.Close() 261 262 _, err = blob.Write([]byte("data")) 263 if !errors.Is(err, sqlite3.READONLY) { 264 t.Fatal("want error") 265 } 266 } 267 268 func TestBlob_Read_expired(t *testing.T) { 269 t.Parallel() 270 271 db, err := sqlite3.Open(":memory:") 272 if err != nil { 273 t.Fatal(err) 274 } 275 defer db.Close() 276 277 err = db.Exec(`CREATE TABLE test (col)`) 278 if err != nil { 279 t.Fatal(err) 280 } 281 282 err = db.Exec(`INSERT INTO test VALUES (zeroblob(1024))`) 283 if err != nil { 284 t.Fatal(err) 285 } 286 287 blob, err := db.OpenBlob("main", "test", "col", db.LastInsertRowID(), false) 288 if err != nil { 289 t.Fatal(err) 290 } 291 defer blob.Close() 292 293 err = db.Exec(`DELETE FROM test`) 294 if err != nil { 295 t.Fatal(err) 296 } 297 298 _, err = io.ReadAll(blob) 299 if !errors.Is(err, sqlite3.ABORT) { 300 t.Fatal("want error", err) 301 } 302 } 303 304 func TestBlob_Seek(t *testing.T) { 305 t.Parallel() 306 307 db, err := sqlite3.Open(":memory:") 308 if err != nil { 309 t.Fatal(err) 310 } 311 defer db.Close() 312 313 err = db.Exec(`CREATE TABLE test (col)`) 314 if err != nil { 315 t.Fatal(err) 316 } 317 318 err = db.Exec(`INSERT INTO test VALUES (zeroblob(1024))`) 319 if err != nil { 320 t.Fatal(err) 321 } 322 323 blob, err := db.OpenBlob("main", "test", "col", db.LastInsertRowID(), true) 324 if err != nil { 325 t.Fatal(err) 326 } 327 defer blob.Close() 328 329 _, err = blob.Seek(0, 10) 330 if err == nil { 331 t.Fatal("want error") 332 } 333 334 _, err = blob.Seek(-1, io.SeekCurrent) 335 if err == nil { 336 t.Fatal("want error") 337 } 338 339 n, err := blob.Seek(1, io.SeekEnd) 340 if err != nil { 341 t.Fatal(err) 342 } 343 if n != blob.Size()+1 { 344 t.Errorf("got %d, want %d", n, blob.Size()) 345 } 346 347 _, err = blob.Write([]byte("data")) 348 if !errors.Is(err, sqlite3.ERROR) { 349 t.Fatal("want error") 350 } 351 } 352 353 func TestBlob_Reopen(t *testing.T) { 354 t.Parallel() 355 356 db, err := sqlite3.Open(":memory:") 357 if err != nil { 358 t.Fatal(err) 359 } 360 defer db.Close() 361 362 err = db.Exec(`CREATE TABLE test (col)`) 363 if err != nil { 364 t.Fatal(err) 365 } 366 367 var rowids []int64 368 for i := 0; i < 100; i++ { 369 err = db.Exec(`INSERT INTO test VALUES (zeroblob(10))`) 370 if err != nil { 371 t.Fatal(err) 372 } 373 rowids = append(rowids, db.LastInsertRowID()) 374 } 375 if changes := db.Changes(); changes != 1 { 376 t.Errorf("got %d want 1", changes) 377 } 378 if changes := db.TotalChanges(); changes != 100 { 379 t.Errorf("got %d want 100", changes) 380 } 381 382 var blob *sqlite3.Blob 383 384 for i, rowid := range rowids { 385 if i > 0 { 386 err = blob.Reopen(rowid) 387 } else { 388 blob, err = db.OpenBlob("main", "test", "col", rowid, true) 389 } 390 if err != nil { 391 t.Fatal(err) 392 } 393 394 _, err = fmt.Fprintf(blob, "blob %d\n", i) 395 if err != nil { 396 t.Fatal(err) 397 } 398 } 399 if err := blob.Close(); err != nil { 400 t.Fatal(err) 401 } 402 403 for i, rowid := range rowids { 404 if i > 0 { 405 err = blob.Reopen(rowid) 406 } else { 407 blob, err = db.OpenBlob("main", "test", "col", rowid, false) 408 } 409 if err != nil { 410 t.Fatal(err) 411 } 412 413 var got int 414 _, err = fmt.Fscanf(blob, "blob %d\n", &got) 415 if err != nil { 416 t.Fatal(err) 417 } 418 if got != i { 419 t.Errorf("got %d, want %d", got, i) 420 } 421 } 422 if err := blob.Close(); err != nil { 423 t.Fatal(err) 424 } 425 }