github.com/ncruces/go-sqlite3@v0.15.1-0.20240520133447-53eef1510ff0/tests/conn_test.go (about) 1 package tests 2 3 import ( 4 "context" 5 "errors" 6 "math" 7 "os" 8 "path/filepath" 9 "strings" 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 _ "github.com/ncruces/go-sqlite3/vfs/memdb" 16 ) 17 18 func TestConn_Open_dir(t *testing.T) { 19 t.Parallel() 20 21 _, err := sqlite3.OpenFlags(".", 0) 22 if err == nil { 23 t.Fatal("want error") 24 } 25 if !errors.Is(err, sqlite3.CANTOPEN) { 26 t.Errorf("got %v, want sqlite3.CANTOPEN", err) 27 } 28 } 29 30 func TestConn_Open_notfound(t *testing.T) { 31 t.Parallel() 32 33 _, err := sqlite3.OpenFlags("test.db", sqlite3.OPEN_READONLY) 34 if err == nil { 35 t.Fatal("want error") 36 } 37 if !errors.Is(err, sqlite3.CANTOPEN) { 38 t.Errorf("got %v, want sqlite3.CANTOPEN", err) 39 } 40 } 41 42 func TestConn_Open_modeof(t *testing.T) { 43 t.Parallel() 44 45 dir := t.TempDir() 46 file := filepath.Join(dir, "test.db") 47 mode := filepath.Join(dir, "modeof.txt") 48 49 fd, err := os.OpenFile(mode, os.O_CREATE, 0624) 50 if err != nil { 51 t.Fatal(err) 52 } 53 fi, err := fd.Stat() 54 if err != nil { 55 t.Fatal(err) 56 } 57 fd.Close() 58 59 db, err := sqlite3.Open("file:" + file + "?modeof=" + mode) 60 if err != nil { 61 t.Fatal(err) 62 } 63 di, err := os.Stat(file) 64 if err != nil { 65 t.Fatal(err) 66 } 67 db.Close() 68 69 if di.Mode() != fi.Mode() { 70 t.Errorf("got %v, want %v", di.Mode(), fi.Mode()) 71 } 72 73 _, err = sqlite3.Open("file:" + file + "?modeof=" + mode + "2") 74 if err == nil { 75 t.Fatal("want error") 76 } 77 } 78 79 func TestConn_Close(t *testing.T) { 80 var db *sqlite3.Conn 81 db.Close() 82 } 83 84 func TestConn_Close_BUSY(t *testing.T) { 85 t.Parallel() 86 87 db, err := sqlite3.Open(":memory:") 88 if err != nil { 89 t.Fatal(err) 90 } 91 defer db.Close() 92 93 stmt, _, err := db.Prepare(`BEGIN`) 94 if err != nil { 95 t.Fatal(err) 96 } 97 defer stmt.Close() 98 99 err = db.Close() 100 if err == nil { 101 t.Fatal("want error") 102 } 103 if !errors.Is(err, sqlite3.BUSY) { 104 t.Errorf("got %v, want sqlite3.BUSY", err) 105 } 106 var terr interface{ Temporary() bool } 107 if !errors.As(err, &terr) || !terr.Temporary() { 108 t.Error("not temporary", err) 109 } 110 if got := err.Error(); got != `sqlite3: database is locked: unable to close due to unfinalized statements or unfinished backups` { 111 t.Error("got message:", got) 112 } 113 } 114 115 func TestConn_SetInterrupt(t *testing.T) { 116 t.Parallel() 117 118 db, err := sqlite3.Open(":memory:") 119 if err != nil { 120 t.Fatal(err) 121 } 122 defer db.Close() 123 124 ctx, cancel := context.WithCancel(context.Background()) 125 db.SetInterrupt(ctx) 126 127 // Interrupt doesn't interrupt this. 128 err = db.Exec(`SELECT 1`) 129 if err != nil { 130 t.Fatal(err) 131 } 132 133 db.SetInterrupt(context.Background()) 134 135 stmt, _, err := db.Prepare(` 136 WITH RECURSIVE 137 fibonacci (curr, next) 138 AS ( 139 SELECT 0, 1 140 UNION ALL 141 SELECT next, curr + next FROM fibonacci 142 LIMIT 1e7 143 ) 144 SELECT min(curr) FROM fibonacci 145 `) 146 if err != nil { 147 t.Fatal(err) 148 } 149 defer stmt.Close() 150 151 db.SetInterrupt(ctx) 152 go cancel() 153 154 // Interrupting works. 155 err = stmt.Exec() 156 if !errors.Is(err, sqlite3.INTERRUPT) { 157 t.Errorf("got %v, want sqlite3.INTERRUPT", err) 158 } 159 160 // Interrupting sticks. 161 err = db.Exec(`SELECT 1`) 162 if !errors.Is(err, sqlite3.INTERRUPT) { 163 t.Errorf("got %v, want sqlite3.INTERRUPT", err) 164 } 165 166 ctx, cancel = context.WithCancel(context.Background()) 167 defer cancel() 168 db.SetInterrupt(ctx) 169 170 // Interrupting can be cleared. 171 err = db.Exec(`SELECT 1`) 172 if err != nil { 173 t.Fatal(err) 174 } 175 } 176 177 func TestConn_Prepare_empty(t *testing.T) { 178 t.Parallel() 179 180 db, err := sqlite3.Open(":memory:") 181 if err != nil { 182 t.Fatal(err) 183 } 184 defer db.Close() 185 186 stmt, _, err := db.Prepare(``) 187 if err != nil { 188 t.Fatal(err) 189 } 190 defer stmt.Close() 191 192 if stmt != nil { 193 t.Error("want nil") 194 } 195 } 196 197 func TestConn_Prepare_tail(t *testing.T) { 198 t.Parallel() 199 200 db, err := sqlite3.Open(":memory:") 201 if err != nil { 202 t.Fatal(err) 203 } 204 defer db.Close() 205 206 stmt, tail, err := db.Prepare(`SELECT 1; -- HERE`) 207 if err != nil { 208 t.Fatal(err) 209 } 210 defer stmt.Close() 211 212 if !strings.Contains(tail, "-- HERE") { 213 t.Errorf("got %q", tail) 214 } 215 } 216 217 func TestConn_Prepare_invalid(t *testing.T) { 218 t.Parallel() 219 220 db, err := sqlite3.Open(":memory:") 221 if err != nil { 222 t.Fatal(err) 223 } 224 defer db.Close() 225 226 var serr *sqlite3.Error 227 228 _, _, err = db.Prepare(`SELECT`) 229 if err == nil { 230 t.Fatal("want error") 231 } 232 if !errors.As(err, &serr) { 233 t.Fatalf("got %T, want sqlite3.Error", err) 234 } 235 if rc := serr.Code(); rc != sqlite3.ERROR { 236 t.Errorf("got %d, want sqlite3.ERROR", rc) 237 } 238 if got := err.Error(); got != `sqlite3: SQL logic error: incomplete input` { 239 t.Error("got message:", got) 240 } 241 242 _, _, err = db.Prepare(`SELECT * FRM sqlite_schema`) 243 if err == nil { 244 t.Fatal("want error") 245 } 246 if !errors.As(err, &serr) { 247 t.Fatalf("got %T, want sqlite3.ERROR", err) 248 } 249 if rc := serr.Code(); rc != sqlite3.ERROR { 250 t.Errorf("got %d, want sqlite3.ERROR", rc) 251 } 252 if got := serr.SQL(); got != `FRM sqlite_schema` { 253 t.Error("got SQL:", got) 254 } 255 if got := serr.Error(); got != `sqlite3: SQL logic error: near "FRM": syntax error` { 256 t.Error("got message:", got) 257 } 258 } 259 260 func TestConn_Config(t *testing.T) { 261 t.Parallel() 262 263 db, err := sqlite3.Open(":memory:") 264 if err != nil { 265 t.Fatal(err) 266 } 267 defer db.Close() 268 269 o, err := db.Config(sqlite3.DBCONFIG_DEFENSIVE) 270 if err != nil { 271 t.Fatal(err) 272 } 273 if o != false { 274 t.Error("want false") 275 } 276 277 o, err = db.Config(sqlite3.DBCONFIG_DEFENSIVE, true) 278 if err != nil { 279 t.Fatal(err) 280 } 281 if o != true { 282 t.Error("want true") 283 } 284 285 o, err = db.Config(sqlite3.DBCONFIG_DEFENSIVE) 286 if err != nil { 287 t.Fatal(err) 288 } 289 if o != true { 290 t.Error("want true") 291 } 292 293 o, err = db.Config(sqlite3.DBCONFIG_DEFENSIVE, false) 294 if err != nil { 295 t.Fatal(err) 296 } 297 if o != false { 298 t.Error("want false") 299 } 300 301 o, err = db.Config(sqlite3.DBCONFIG_DEFENSIVE) 302 if err != nil { 303 t.Fatal(err) 304 } 305 if o != false { 306 t.Error("want false") 307 } 308 } 309 310 func TestConn_ConfigLog(t *testing.T) { 311 t.Parallel() 312 313 db, err := sqlite3.Open(":memory:") 314 if err != nil { 315 t.Fatal(err) 316 } 317 defer db.Close() 318 319 var code sqlite3.ExtendedErrorCode 320 err = db.ConfigLog(func(c sqlite3.ExtendedErrorCode, msg string) { 321 t.Log(msg) 322 code = c 323 }) 324 if err != nil { 325 t.Fatal(err) 326 } 327 328 db.Prepare(`SELECT * FRM sqlite_schema`) 329 330 if code != sqlite3.ExtendedErrorCode(sqlite3.ERROR) { 331 t.Error("want sqlite3.ERROR") 332 } 333 } 334 335 func TestConn_Limit(t *testing.T) { 336 t.Parallel() 337 338 db, err := sqlite3.Open(":memory:") 339 if err != nil { 340 t.Fatal(err) 341 } 342 defer db.Close() 343 344 l := db.Limit(sqlite3.LIMIT_COLUMN, -1) 345 if l != 2000 { 346 t.Errorf("got %d, want 2000", l) 347 } 348 349 l = db.Limit(sqlite3.LIMIT_COLUMN, 100) 350 if l != 2000 { 351 t.Errorf("got %d, want 2000", l) 352 } 353 354 l = db.Limit(sqlite3.LIMIT_COLUMN, -1) 355 if l != 100 { 356 t.Errorf("got %d, want 100", l) 357 } 358 359 l = db.Limit(math.MaxUint32, -1) 360 if l != -1 { 361 t.Errorf("got %d, want -1", l) 362 } 363 } 364 365 func TestConn_SetAuthorizer(t *testing.T) { 366 t.Parallel() 367 368 db, err := sqlite3.Open(":memory:") 369 if err != nil { 370 t.Fatal(err) 371 } 372 defer db.Close() 373 374 err = db.SetAuthorizer(func(action sqlite3.AuthorizerActionCode, name3rd, name4th, schema, nameInner string) sqlite3.AuthorizerReturnCode { 375 return sqlite3.AUTH_DENY 376 }) 377 if err != nil { 378 t.Fatal(err) 379 } 380 381 err = db.Exec(`SELECT * FROM sqlite_schema`) 382 if !errors.Is(err, sqlite3.AUTH) { 383 t.Errorf("got %v, want sqlite3.AUTH", err) 384 } 385 } 386 387 func TestConn_ReleaseMemory(t *testing.T) { 388 t.Parallel() 389 390 db, err := sqlite3.Open(":memory:") 391 if err != nil { 392 t.Fatal(err) 393 } 394 defer db.Close() 395 396 err = db.ReleaseMemory() 397 if err != nil { 398 t.Fatal(err) 399 } 400 } 401 402 func TestConn_SetLastInsertRowID(t *testing.T) { 403 t.Parallel() 404 405 db, err := sqlite3.Open(":memory:") 406 if err != nil { 407 t.Fatal(err) 408 } 409 defer db.Close() 410 411 db.SetLastInsertRowID(42) 412 413 got := db.LastInsertRowID() 414 if got != 42 { 415 t.Errorf("got %d, want 42", got) 416 } 417 } 418 419 func TestConn_Filename(t *testing.T) { 420 t.Parallel() 421 422 file := filepath.Join(t.TempDir(), "test.db") 423 db, err := sqlite3.Open(file) 424 if err != nil { 425 t.Fatal(err) 426 } 427 defer db.Close() 428 429 n := db.Filename("") 430 if n.String() != file { 431 t.Errorf("got %v", n) 432 } 433 if n.Database() != file { 434 t.Errorf("got %v", n) 435 } 436 if n.DatabaseFile() == nil { 437 t.Errorf("got %v", n) 438 } 439 440 n = db.Filename("xpto") 441 if n != nil { 442 t.Errorf("got %v", n) 443 } 444 if n.String() != "" { 445 t.Errorf("got %v", n) 446 } 447 if n.Database() != "" { 448 t.Errorf("got %v", n) 449 } 450 if n.Journal() != "" { 451 t.Errorf("got %v", n) 452 } 453 if n.WAL() != "" { 454 t.Errorf("got %v", n) 455 } 456 if n.DatabaseFile() != nil { 457 t.Errorf("got %v", n) 458 } 459 } 460 461 func TestConn_ReadOnly(t *testing.T) { 462 t.Parallel() 463 464 db, err := sqlite3.Open(":memory:") 465 if err != nil { 466 t.Fatal(err) 467 } 468 defer db.Close() 469 470 if ro, ok := db.ReadOnly(""); ro != false || ok != false { 471 t.Errorf("got %v,%v", ro, ok) 472 } 473 474 if ro, ok := db.ReadOnly("xpto"); ro != false || ok != true { 475 t.Errorf("got %v,%v", ro, ok) 476 } 477 } 478 479 func TestConn_DBName(t *testing.T) { 480 t.Parallel() 481 482 db, err := sqlite3.Open(":memory:") 483 if err != nil { 484 t.Fatal(err) 485 } 486 defer db.Close() 487 488 if name := db.DBName(0); name != "main" { 489 t.Errorf("got %s", name) 490 } 491 492 if name := db.DBName(5); name != "" { 493 t.Errorf("got %s", name) 494 } 495 } 496 497 func TestConn_AutoVacuumPages(t *testing.T) { 498 t.Parallel() 499 500 db, err := sqlite3.Open("file:test.db?vfs=memdb&_pragma=auto_vacuum(full)") 501 if err != nil { 502 t.Fatal(err) 503 } 504 defer db.Close() 505 506 err = db.AutoVacuumPages(func(schema string, dbPages, freePages, bytesPerPage uint) uint { 507 return freePages 508 }) 509 if err != nil { 510 t.Fatal(err) 511 } 512 513 err = db.Exec(`CREATE TABLE test (col)`) 514 if err != nil { 515 t.Fatal(err) 516 } 517 518 err = db.Exec(`INSERT INTO test VALUES (zeroblob(1024*1024))`) 519 if err != nil { 520 t.Fatal(err) 521 } 522 523 err = db.Exec(`DROP TABLE test`) 524 if err != nil { 525 t.Fatal(err) 526 } 527 }