large_objects.go (3363B)
1 package pgx 2 3 import ( 4 "context" 5 "errors" 6 "io" 7 ) 8 9 // LargeObjects is a structure used to access the large objects API. It is only valid within the transaction where it 10 // was created. 11 // 12 // For more details see: http://www.postgresql.org/docs/current/static/largeobjects.html 13 type LargeObjects struct { 14 tx Tx 15 } 16 17 type LargeObjectMode int32 18 19 const ( 20 LargeObjectModeWrite LargeObjectMode = 0x20000 21 LargeObjectModeRead LargeObjectMode = 0x40000 22 ) 23 24 // Create creates a new large object. If oid is zero, the server assigns an unused OID. 25 func (o *LargeObjects) Create(ctx context.Context, oid uint32) (uint32, error) { 26 err := o.tx.QueryRow(ctx, "select lo_create($1)", oid).Scan(&oid) 27 return oid, err 28 } 29 30 // Open opens an existing large object with the given mode. ctx will also be used for all operations on the opened large 31 // object. 32 func (o *LargeObjects) Open(ctx context.Context, oid uint32, mode LargeObjectMode) (*LargeObject, error) { 33 var fd int32 34 err := o.tx.QueryRow(ctx, "select lo_open($1, $2)", oid, mode).Scan(&fd) 35 if err != nil { 36 return nil, err 37 } 38 return &LargeObject{fd: fd, tx: o.tx, ctx: ctx}, nil 39 } 40 41 // Unlink removes a large object from the database. 42 func (o *LargeObjects) Unlink(ctx context.Context, oid uint32) error { 43 var result int32 44 err := o.tx.QueryRow(ctx, "select lo_unlink($1)", oid).Scan(&result) 45 if err != nil { 46 return err 47 } 48 49 if result != 1 { 50 return errors.New("failed to remove large object") 51 } 52 53 return nil 54 } 55 56 // A LargeObject is a large object stored on the server. It is only valid within the transaction that it was initialized 57 // in. It uses the context it was initialized with for all operations. It implements these interfaces: 58 // 59 // io.Writer 60 // io.Reader 61 // io.Seeker 62 // io.Closer 63 type LargeObject struct { 64 ctx context.Context 65 tx Tx 66 fd int32 67 } 68 69 // Write writes p to the large object and returns the number of bytes written and an error if not all of p was written. 70 func (o *LargeObject) Write(p []byte) (int, error) { 71 var n int 72 err := o.tx.QueryRow(o.ctx, "select lowrite($1, $2)", o.fd, p).Scan(&n) 73 if err != nil { 74 return n, err 75 } 76 77 if n < 0 { 78 return 0, errors.New("failed to write to large object") 79 } 80 81 return n, nil 82 } 83 84 // Read reads up to len(p) bytes into p returning the number of bytes read. 85 func (o *LargeObject) Read(p []byte) (int, error) { 86 var res []byte 87 err := o.tx.QueryRow(o.ctx, "select loread($1, $2)", o.fd, len(p)).Scan(&res) 88 copy(p, res) 89 if err != nil { 90 return len(res), err 91 } 92 93 if len(res) < len(p) { 94 err = io.EOF 95 } 96 return len(res), err 97 } 98 99 // Seek moves the current location pointer to the new location specified by offset. 100 func (o *LargeObject) Seek(offset int64, whence int) (n int64, err error) { 101 err = o.tx.QueryRow(o.ctx, "select lo_lseek64($1, $2, $3)", o.fd, offset, whence).Scan(&n) 102 return n, err 103 } 104 105 // Tell returns the current read or write location of the large object descriptor. 106 func (o *LargeObject) Tell() (n int64, err error) { 107 err = o.tx.QueryRow(o.ctx, "select lo_tell64($1)", o.fd).Scan(&n) 108 return n, err 109 } 110 111 // Truncate the large object to size. 112 func (o *LargeObject) Truncate(size int64) (err error) { 113 _, err = o.tx.Exec(o.ctx, "select lo_truncate64($1, $2)", o.fd, size) 114 return err 115 } 116 117 // Close the large object descriptor. 118 func (o *LargeObject) Close() error { 119 _, err := o.tx.Exec(o.ctx, "select lo_close($1)", o.fd) 120 return err 121 }