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  }