...

Source file src/github.com/jackc/pgx/v4/large_objects_test.go

Documentation: github.com/jackc/pgx/v4

     1  package pgx_test
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  	"os"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/jackc/pgconn"
    11  	"github.com/jackc/pgx/v4"
    12  )
    13  
    14  func TestLargeObjects(t *testing.T) {
    15  	t.Parallel()
    16  
    17  	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    18  	defer cancel()
    19  
    20  	conn, err := pgx.Connect(ctx, os.Getenv("PGX_TEST_DATABASE"))
    21  	if err != nil {
    22  		t.Fatal(err)
    23  	}
    24  
    25  	skipCockroachDB(t, conn, "Server does support large objects")
    26  
    27  	tx, err := conn.Begin(ctx)
    28  	if err != nil {
    29  		t.Fatal(err)
    30  	}
    31  
    32  	testLargeObjects(t, ctx, tx)
    33  }
    34  
    35  func TestLargeObjectsPreferSimpleProtocol(t *testing.T) {
    36  	t.Parallel()
    37  
    38  	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    39  	defer cancel()
    40  
    41  	config, err := pgx.ParseConfig(os.Getenv("PGX_TEST_DATABASE"))
    42  	if err != nil {
    43  		t.Fatal(err)
    44  	}
    45  
    46  	config.PreferSimpleProtocol = true
    47  
    48  	conn, err := pgx.ConnectConfig(ctx, config)
    49  	if err != nil {
    50  		t.Fatal(err)
    51  	}
    52  
    53  	skipCockroachDB(t, conn, "Server does support large objects")
    54  
    55  	tx, err := conn.Begin(ctx)
    56  	if err != nil {
    57  		t.Fatal(err)
    58  	}
    59  
    60  	testLargeObjects(t, ctx, tx)
    61  }
    62  
    63  func testLargeObjects(t *testing.T, ctx context.Context, tx pgx.Tx) {
    64  	lo := tx.LargeObjects()
    65  
    66  	id, err := lo.Create(ctx, 0)
    67  	if err != nil {
    68  		t.Fatal(err)
    69  	}
    70  
    71  	obj, err := lo.Open(ctx, id, pgx.LargeObjectModeRead|pgx.LargeObjectModeWrite)
    72  	if err != nil {
    73  		t.Fatal(err)
    74  	}
    75  
    76  	n, err := obj.Write([]byte("testing"))
    77  	if err != nil {
    78  		t.Fatal(err)
    79  	}
    80  	if n != 7 {
    81  		t.Errorf("Expected n to be 7, got %d", n)
    82  	}
    83  
    84  	pos, err := obj.Seek(1, 0)
    85  	if err != nil {
    86  		t.Fatal(err)
    87  	}
    88  	if pos != 1 {
    89  		t.Errorf("Expected pos to be 1, got %d", pos)
    90  	}
    91  
    92  	res := make([]byte, 6)
    93  	n, err = obj.Read(res)
    94  	if err != nil {
    95  		t.Fatal(err)
    96  	}
    97  	if string(res) != "esting" {
    98  		t.Errorf(`Expected res to be "esting", got %q`, res)
    99  	}
   100  	if n != 6 {
   101  		t.Errorf("Expected n to be 6, got %d", n)
   102  	}
   103  
   104  	n, err = obj.Read(res)
   105  	if err != io.EOF {
   106  		t.Error("Expected io.EOF, go nil")
   107  	}
   108  	if n != 0 {
   109  		t.Errorf("Expected n to be 0, got %d", n)
   110  	}
   111  
   112  	pos, err = obj.Tell()
   113  	if err != nil {
   114  		t.Fatal(err)
   115  	}
   116  	if pos != 7 {
   117  		t.Errorf("Expected pos to be 7, got %d", pos)
   118  	}
   119  
   120  	err = obj.Truncate(1)
   121  	if err != nil {
   122  		t.Fatal(err)
   123  	}
   124  
   125  	pos, err = obj.Seek(-1, 2)
   126  	if err != nil {
   127  		t.Fatal(err)
   128  	}
   129  	if pos != 0 {
   130  		t.Errorf("Expected pos to be 0, got %d", pos)
   131  	}
   132  
   133  	res = make([]byte, 2)
   134  	n, err = obj.Read(res)
   135  	if err != io.EOF {
   136  		t.Errorf("Expected err to be io.EOF, got %v", err)
   137  	}
   138  	if n != 1 {
   139  		t.Errorf("Expected n to be 1, got %d", n)
   140  	}
   141  	if res[0] != 't' {
   142  		t.Errorf("Expected res[0] to be 't', got %v", res[0])
   143  	}
   144  
   145  	err = obj.Close()
   146  	if err != nil {
   147  		t.Fatal(err)
   148  	}
   149  
   150  	err = lo.Unlink(ctx, id)
   151  	if err != nil {
   152  		t.Fatal(err)
   153  	}
   154  
   155  	_, err = lo.Open(ctx, id, pgx.LargeObjectModeRead)
   156  	if e, ok := err.(*pgconn.PgError); !ok || e.Code != "42704" {
   157  		t.Errorf("Expected undefined_object error (42704), got %#v", err)
   158  	}
   159  }
   160  
   161  func TestLargeObjectsMultipleTransactions(t *testing.T) {
   162  	t.Parallel()
   163  
   164  	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
   165  	defer cancel()
   166  
   167  	conn, err := pgx.Connect(ctx, os.Getenv("PGX_TEST_DATABASE"))
   168  	if err != nil {
   169  		t.Fatal(err)
   170  	}
   171  
   172  	skipCockroachDB(t, conn, "Server does support large objects")
   173  
   174  	tx, err := conn.Begin(ctx)
   175  	if err != nil {
   176  		t.Fatal(err)
   177  	}
   178  
   179  	lo := tx.LargeObjects()
   180  
   181  	id, err := lo.Create(ctx, 0)
   182  	if err != nil {
   183  		t.Fatal(err)
   184  	}
   185  
   186  	obj, err := lo.Open(ctx, id, pgx.LargeObjectModeWrite)
   187  	if err != nil {
   188  		t.Fatal(err)
   189  	}
   190  
   191  	n, err := obj.Write([]byte("testing"))
   192  	if err != nil {
   193  		t.Fatal(err)
   194  	}
   195  	if n != 7 {
   196  		t.Errorf("Expected n to be 7, got %d", n)
   197  	}
   198  
   199  	// Commit the first transaction
   200  	err = tx.Commit(ctx)
   201  	if err != nil {
   202  		t.Fatal(err)
   203  	}
   204  
   205  	// IMPORTANT: Use the same connection for another query
   206  	query := `select n from generate_series(1,10) n`
   207  	rows, err := conn.Query(ctx, query)
   208  	if err != nil {
   209  		t.Fatal(err)
   210  	}
   211  	rows.Close()
   212  
   213  	// Start a new transaction
   214  	tx2, err := conn.Begin(ctx)
   215  	if err != nil {
   216  		t.Fatal(err)
   217  	}
   218  
   219  	lo2 := tx2.LargeObjects()
   220  
   221  	// Reopen the large object in the new transaction
   222  	obj2, err := lo2.Open(ctx, id, pgx.LargeObjectModeRead|pgx.LargeObjectModeWrite)
   223  	if err != nil {
   224  		t.Fatal(err)
   225  	}
   226  
   227  	pos, err := obj2.Seek(1, 0)
   228  	if err != nil {
   229  		t.Fatal(err)
   230  	}
   231  	if pos != 1 {
   232  		t.Errorf("Expected pos to be 1, got %d", pos)
   233  	}
   234  
   235  	res := make([]byte, 6)
   236  	n, err = obj2.Read(res)
   237  	if err != nil {
   238  		t.Fatal(err)
   239  	}
   240  	if string(res) != "esting" {
   241  		t.Errorf(`Expected res to be "esting", got %q`, res)
   242  	}
   243  	if n != 6 {
   244  		t.Errorf("Expected n to be 6, got %d", n)
   245  	}
   246  
   247  	n, err = obj2.Read(res)
   248  	if err != io.EOF {
   249  		t.Error("Expected io.EOF, go nil")
   250  	}
   251  	if n != 0 {
   252  		t.Errorf("Expected n to be 0, got %d", n)
   253  	}
   254  
   255  	pos, err = obj2.Tell()
   256  	if err != nil {
   257  		t.Fatal(err)
   258  	}
   259  	if pos != 7 {
   260  		t.Errorf("Expected pos to be 7, got %d", pos)
   261  	}
   262  
   263  	err = obj2.Truncate(1)
   264  	if err != nil {
   265  		t.Fatal(err)
   266  	}
   267  
   268  	pos, err = obj2.Seek(-1, 2)
   269  	if err != nil {
   270  		t.Fatal(err)
   271  	}
   272  	if pos != 0 {
   273  		t.Errorf("Expected pos to be 0, got %d", pos)
   274  	}
   275  
   276  	res = make([]byte, 2)
   277  	n, err = obj2.Read(res)
   278  	if err != io.EOF {
   279  		t.Errorf("Expected err to be io.EOF, got %v", err)
   280  	}
   281  	if n != 1 {
   282  		t.Errorf("Expected n to be 1, got %d", n)
   283  	}
   284  	if res[0] != 't' {
   285  		t.Errorf("Expected res[0] to be 't', got %v", res[0])
   286  	}
   287  
   288  	err = obj2.Close()
   289  	if err != nil {
   290  		t.Fatal(err)
   291  	}
   292  
   293  	err = lo2.Unlink(ctx, id)
   294  	if err != nil {
   295  		t.Fatal(err)
   296  	}
   297  
   298  	_, err = lo2.Open(ctx, id, pgx.LargeObjectModeRead)
   299  	if e, ok := err.(*pgconn.PgError); !ok || e.Code != "42704" {
   300  		t.Errorf("Expected undefined_object error (42704), got %#v", err)
   301  	}
   302  }
   303  

View as plain text