From 579b6cd612600fb7a72d93cbe917dee794f3a2c7 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Fri, 3 Mar 2017 15:33:34 -0600 Subject: [PATCH 1/9] Initial proof-of-concept for pgtype Squashed commit of the following: commit c19454582b335ce5bdda6320f7e4e8c76cfeaf44 Author: Jack Christensen Date: Fri Mar 3 15:24:47 2017 -0600 Add AssignTo to pgtype.Timestamptz Also handle infinity for pgtype.Date commit 7329933610b38f4bc15731b1f7c55c520b49e300 Author: Jack Christensen Date: Fri Mar 3 15:12:18 2017 -0600 Implement AssignTo for most pgtypes commit cc3d1e4af896d34ec98c3bf2e982d0367451f21c Author: Jack Christensen Date: Thu Mar 2 21:19:07 2017 -0600 Use pgtype.Int2Array in pgx commit 36da5cc2178d1a31a56dc6e6f128843bd80dea0b Author: Jack Christensen Date: Tue Feb 28 21:45:33 2017 -0600 Add text array transcoding commit 1b0f18d99f38b69f8c2db26388815e67b2b03d59 Author: Jack Christensen Date: Mon Feb 27 19:28:55 2017 -0600 Add ParseUntypedTextArray commit 0f50ce3e833fc38495d333228daf04f5142be676 Author: Jack Christensen Date: Mon Feb 27 18:54:20 2017 -0600 wip commit d934f273627d79997035c282416db922f2fbe87a Author: Jack Christensen Date: Sun Feb 26 17:14:32 2017 -0600 WIP - beginning text format array parsing commit 7276ad33ce7fa9c250745a3ed909998f3dae4a32 Author: Jack Christensen Date: Sat Feb 25 22:50:11 2017 -0600 Beginning binary arrays commit 917faa5a3175d376222423c10aca297a20f96448 Author: Jack Christensen Date: Sat Feb 25 19:36:35 2017 -0600 Fix incomplete tests commit de8c140cfb98b7b047d53c5718ccbf12eaf813a1 Author: Jack Christensen Date: Sat Feb 25 19:32:22 2017 -0600 Add timestamptz null and infinity commit 7d9f954de4e071a1eccac762248079b90dbeb53f Author: Jack Christensen Date: Sat Feb 25 18:19:38 2017 -0600 Add infinity to pgtype.Date commit 7bf783ae20ba05571c2fb9f661183233c95eab41 Author: Jack Christensen Date: Sat Feb 25 17:19:55 2017 -0600 Add Status to pgtype.Date commit 984500455c9b9a4b6221758540d248e6410d93a4 Author: Jack Christensen Date: Sat Feb 25 16:54:01 2017 -0600 Add status to Int4 and Int8 commit 6fe76fcfc2de31552790db3b093480a9d5b2a742 Author: Jack Christensen Date: Sat Feb 25 16:40:27 2017 -0600 Extract testSuccessfulTranscode commit 001647c1da03f796014cf21f41c9a7fd2cfadfde Author: Jack Christensen Date: Sat Feb 25 16:15:51 2017 -0600 Add Status to pgtype.Int2 commit 720451f06d13d9c9fa2a0482e010f24bf4627c2a Author: Jack Christensen Date: Sat Feb 25 15:56:44 2017 -0600 Add status to pgtype.Bool commit 325f700b6edff215a692b10bc5b94cdfe1100769 Author: Jack Christensen Date: Fri Feb 24 17:28:15 2017 -0600 Add date to conversion system commit 4a9343e45d3897f59eab98a0009d2ddbe07e02d7 Author: Jack Christensen Date: Fri Feb 24 16:28:35 2017 -0600 Add bool to oid based encoding commit d984fcafab1476cf84852485b6711f4b2069eb6d Author: Jack Christensen Date: Fri Feb 24 16:15:38 2017 -0600 Add pgtype interfaces commit 0f93bfc2de4023b069b966c0988bf7f0469d1809 Author: Jack Christensen Date: Fri Feb 24 14:48:34 2017 -0600 Begin introduction of Convert commit e5707023cac7c07342b8c910e480d09a1caaf6ee Author: Jack Christensen Date: Fri Feb 24 14:10:56 2017 -0600 Move bool to pgtype commit bb764d2129efe7fb21e841dbb35e6d0dc7586d37 Author: Jack Christensen Date: Fri Feb 24 13:45:05 2017 -0600 Add Int2 test commit 08c49437f455a32f7c3f0a524cd21a895d440301 Author: Jack Christensen Date: Fri Feb 24 13:44:09 2017 -0600 Add Int4 test commit 16722952222fd15c53c8fa84974645504a6d0dc0 Author: Jack Christensen Date: Fri Feb 24 08:56:59 2017 -0600 Add int8 tests commit 83a5447cd2c46b58d0880023cc4e9af0c84988a2 Author: Jack Christensen Date: Wed Feb 22 18:08:05 2017 -0600 wip commit 0ca0ee72068a72b016729b01fccef22474595285 Author: Jack Christensen Date: Mon Feb 20 18:56:52 2017 -0600 wip commit d2c2baf4ea2cd0793d68c7094c425217df952bec Author: Jack Christensen Date: Mon Feb 20 18:46:10 2017 -0600 wip commit f78371da0098356527b193fd496a338da5fe414b Author: Jack Christensen Date: Mon Feb 20 17:43:39 2017 -0600 wip commit 3366699bea62ec0110db05f3cb2998d58ac9ce5d Author: Jack Christensen Date: Mon Feb 20 14:07:47 2017 -0600 wip commit 66b79e940870fd0133ebb10ac1547e1d4d7d0b51 Author: Jack Christensen Date: Mon Feb 20 13:35:37 2017 -0600 Extract pgio commit 8b07d97d1305ed98fd76db6e306a289c0af92d56 Author: Jack Christensen Date: Mon Feb 20 13:20:00 2017 -0600 wip commit 62f1adb3427f4317b708da075dce50c4d4daff7b Author: Jack Christensen Date: Mon Feb 20 12:08:46 2017 -0600 wip commit a712d2546933a5a8433c65eef0ff2ee135077c87 Author: Jack Christensen Date: Mon Feb 20 09:30:52 2017 -0600 wip commit 4faf97cc588126dda160fc360680719572a23105 Author: Jack Christensen Date: Fri Feb 17 22:20:18 2017 -0600 wip --- doc.go | 8 +++++ read.go | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ write.go | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 209 insertions(+) create mode 100644 doc.go create mode 100644 read.go create mode 100644 write.go diff --git a/doc.go b/doc.go new file mode 100644 index 00000000..36233a47 --- /dev/null +++ b/doc.go @@ -0,0 +1,8 @@ +// Package pgio a extremely low-level IO toolkit for the PostgreSQL wire protocol. +/* +pgio provides functions for reading and writing integers from io.Reader and +io.Writer while doing byte order conversion. It publishes interfaces which +readers and writers may implement to decode and encode messages with the minimum +of memory allocations. +*/ +package pgio diff --git a/read.go b/read.go new file mode 100644 index 00000000..7c39162c --- /dev/null +++ b/read.go @@ -0,0 +1,104 @@ +package pgio + +import ( + "encoding/binary" + "io" +) + +type Uint16Reader interface { + ReadUint16() (n uint16, err error) +} + +type Uint32Reader interface { + ReadUint32() (n uint32, err error) +} + +type Uint64Reader interface { + ReadUint64() (n uint64, err error) +} + +// ReadByte reads a byte from r. +func ReadByte(r io.Reader) (byte, error) { + if r, ok := r.(io.ByteReader); ok { + return r.ReadByte() + } + + buf := make([]byte, 1) + _, err := r.Read(buf) + return buf[0], err +} + +// ReadUint16 reads an uint16 from r in PostgreSQL wire format (network byte order). This +// may be more efficient than directly using Read if r provides a ReadUint16 +// method. +func ReadUint16(r io.Reader) (uint16, error) { + if r, ok := r.(Uint16Reader); ok { + return r.ReadUint16() + } + + buf := make([]byte, 2) + _, err := io.ReadFull(r, buf) + if err != nil { + return 0, err + } + + return binary.BigEndian.Uint16(buf), nil +} + +// ReadInt16 reads an int16 r in PostgreSQL wire format (network byte order). This +// may be more efficient than directly using Read if r provides a ReadUint16 +// method. +func ReadInt16(r io.Reader) (int16, error) { + n, err := ReadUint16(r) + return int16(n), err +} + +// ReadUint32 reads an uint32 r in PostgreSQL wire format (network byte order). This +// may be more efficient than directly using Read if r provides a ReadUint32 +// method. +func ReadUint32(r io.Reader) (uint32, error) { + if r, ok := r.(Uint32Reader); ok { + return r.ReadUint32() + } + + buf := make([]byte, 4) + _, err := io.ReadFull(r, buf) + if err != nil { + return 0, err + } + + return binary.BigEndian.Uint32(buf), nil +} + +// ReadInt32 reads an int32 r in PostgreSQL wire format (network byte order). This +// may be more efficient than directly using Read if r provides a ReadUint32 +// method. +func ReadInt32(r io.Reader) (int32, error) { + n, err := ReadUint32(r) + return int32(n), err +} + +// ReadUint64 reads an uint64 r in PostgreSQL wire format (network byte order). This +// may be more efficient than directly using Read if r provides a ReadUint64 +// method. +func ReadUint64(r io.Reader) (uint64, error) { + if r, ok := r.(Uint64Reader); ok { + return r.ReadUint64() + } + + buf := make([]byte, 8) + _, err := io.ReadFull(r, buf) + if err != nil { + return 0, err + } + + return binary.BigEndian.Uint64(buf), nil +} + +// ReadInt64 reads an int64 r in PostgreSQL wire format (network byte order). This +// may be more efficient than directly using Read if r provides a ReadUint64 +// method. +func ReadInt64(r io.Reader) (int64, error) { + n, err := ReadUint64(r) + return int64(n), err +} diff --git a/write.go b/write.go new file mode 100644 index 00000000..823fbd00 --- /dev/null +++ b/write.go @@ -0,0 +1,97 @@ +package pgio + +import ( + "encoding/binary" + "io" +) + +type Uint16Writer interface { + WriteUint16(uint16) (n int, err error) +} + +type Uint32Writer interface { + WriteUint32(uint32) (n int, err error) +} + +type Uint64Writer interface { + WriteUint64(uint64) (n int, err error) +} + +// WriteByte writes b to w. +func WriteByte(w io.Writer, b byte) error { + if w, ok := w.(io.ByteWriter); ok { + return w.WriteByte(b) + } + _, err := w.Write([]byte{b}) + return err +} + +// WriteUint16 writes n to w in PostgreSQL wire format (network byte order). This +// may be more efficient than directly using Write if w provides a WriteUint16 +// method. +func WriteUint16(w io.Writer, n uint16) (int, error) { + if w, ok := w.(Uint16Writer); ok { + return w.WriteUint16(n) + } + b := make([]byte, 2) + binary.BigEndian.PutUint16(b, n) + return w.Write(b) +} + +// WriteInt16 writes n to w in PostgreSQL wire format (network byte order). This +// may be more efficient than directly using Write if w provides a WriteUint16 +// method. +func WriteInt16(w io.Writer, n int16) (int, error) { + return WriteUint16(w, uint16(n)) +} + +// WriteUint32 writes n to w in PostgreSQL wire format (network byte order). This +// may be more efficient than directly using Write if w provides a WriteUint32 +// method. +func WriteUint32(w io.Writer, n uint32) (int, error) { + if w, ok := w.(Uint32Writer); ok { + return w.WriteUint32(n) + } + b := make([]byte, 4) + binary.BigEndian.PutUint32(b, n) + return w.Write(b) +} + +// WriteInt32 writes n to w in PostgreSQL wire format (network byte order). This +// may be more efficient than directly using Write if w provides a WriteUint32 +// method. +func WriteInt32(w io.Writer, n int32) (int, error) { + return WriteUint32(w, uint32(n)) +} + +// WriteUint64 writes n to w in PostgreSQL wire format (network byte order). This +// may be more efficient than directly using Write if w provides a WriteUint64 +// method. +func WriteUint64(w io.Writer, n uint64) (int, error) { + if w, ok := w.(Uint64Writer); ok { + return w.WriteUint64(n) + } + b := make([]byte, 8) + binary.BigEndian.PutUint64(b, n) + return w.Write(b) +} + +// WriteInt64 writes n to w in PostgreSQL wire format (network byte order). This +// may be more efficient than directly using Write if w provides a WriteUint64 +// method. +func WriteInt64(w io.Writer, n int64) (int, error) { + return WriteUint64(w, uint64(n)) +} + +// WriteCString writes s to w followed by a null byte. +func WriteCString(w io.Writer, s string) (int, error) { + n, err := io.WriteString(w, s) + if err != nil { + return n, err + } + err = WriteByte(w, 0) + if err != nil { + return n, err + } + return n + 1, nil +} From d4fe3edf84071a0dee5e60bf356f5c97eb3f87fd Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Tue, 2 May 2017 20:38:26 -0500 Subject: [PATCH 2/9] Refactor pgio and types to append buffers --- read.go | 106 ++++++++++---------------------------------------- read_test.go | 57 +++++++++++++++++++++++++++ write.go | 105 ++++++++++++------------------------------------- write_test.go | 78 +++++++++++++++++++++++++++++++++++++ 4 files changed, 180 insertions(+), 166 deletions(-) create mode 100644 read_test.go create mode 100644 write_test.go diff --git a/read.go b/read.go index 7c39162c..7ddad508 100644 --- a/read.go +++ b/read.go @@ -2,103 +2,39 @@ package pgio import ( "encoding/binary" - "io" ) -type Uint16Reader interface { - ReadUint16() (n uint16, err error) +func NextByte(buf []byte) ([]byte, byte) { + b := buf[0] + return buf[1:], b } -type Uint32Reader interface { - ReadUint32() (n uint32, err error) +func NextUint16(buf []byte) ([]byte, uint16) { + n := binary.BigEndian.Uint16(buf) + return buf[2:], n } -type Uint64Reader interface { - ReadUint64() (n uint64, err error) +func NextUint32(buf []byte) ([]byte, uint32) { + n := binary.BigEndian.Uint32(buf) + return buf[4:], n } -// ReadByte reads a byte from r. -func ReadByte(r io.Reader) (byte, error) { - if r, ok := r.(io.ByteReader); ok { - return r.ReadByte() - } - - buf := make([]byte, 1) - _, err := r.Read(buf) - return buf[0], err +func NextUint64(buf []byte) ([]byte, uint64) { + n := binary.BigEndian.Uint64(buf) + return buf[8:], n } -// ReadUint16 reads an uint16 from r in PostgreSQL wire format (network byte order). This -// may be more efficient than directly using Read if r provides a ReadUint16 -// method. -func ReadUint16(r io.Reader) (uint16, error) { - if r, ok := r.(Uint16Reader); ok { - return r.ReadUint16() - } - - buf := make([]byte, 2) - _, err := io.ReadFull(r, buf) - if err != nil { - return 0, err - } - - return binary.BigEndian.Uint16(buf), nil +func NextInt16(buf []byte) ([]byte, int16) { + buf, n := NextUint16(buf) + return buf, int16(n) } -// ReadInt16 reads an int16 r in PostgreSQL wire format (network byte order). This -// may be more efficient than directly using Read if r provides a ReadUint16 -// method. -func ReadInt16(r io.Reader) (int16, error) { - n, err := ReadUint16(r) - return int16(n), err +func NextInt32(buf []byte) ([]byte, int32) { + buf, n := NextUint32(buf) + return buf, int32(n) } -// ReadUint32 reads an uint32 r in PostgreSQL wire format (network byte order). This -// may be more efficient than directly using Read if r provides a ReadUint32 -// method. -func ReadUint32(r io.Reader) (uint32, error) { - if r, ok := r.(Uint32Reader); ok { - return r.ReadUint32() - } - - buf := make([]byte, 4) - _, err := io.ReadFull(r, buf) - if err != nil { - return 0, err - } - - return binary.BigEndian.Uint32(buf), nil -} - -// ReadInt32 reads an int32 r in PostgreSQL wire format (network byte order). This -// may be more efficient than directly using Read if r provides a ReadUint32 -// method. -func ReadInt32(r io.Reader) (int32, error) { - n, err := ReadUint32(r) - return int32(n), err -} - -// ReadUint64 reads an uint64 r in PostgreSQL wire format (network byte order). This -// may be more efficient than directly using Read if r provides a ReadUint64 -// method. -func ReadUint64(r io.Reader) (uint64, error) { - if r, ok := r.(Uint64Reader); ok { - return r.ReadUint64() - } - - buf := make([]byte, 8) - _, err := io.ReadFull(r, buf) - if err != nil { - return 0, err - } - - return binary.BigEndian.Uint64(buf), nil -} - -// ReadInt64 reads an int64 r in PostgreSQL wire format (network byte order). This -// may be more efficient than directly using Read if r provides a ReadUint64 -// method. -func ReadInt64(r io.Reader) (int64, error) { - n, err := ReadUint64(r) - return int64(n), err +func NextInt64(buf []byte) ([]byte, int64) { + buf, n := NextUint64(buf) + return buf, int64(n) } diff --git a/read_test.go b/read_test.go new file mode 100644 index 00000000..fbe29ae4 --- /dev/null +++ b/read_test.go @@ -0,0 +1,57 @@ +package pgio + +import ( + "testing" +) + +func TestNextByte(t *testing.T) { + buf := []byte{42, 1} + var b byte + buf, b = NextByte(buf) + if b != 42 { + t.Errorf("NextByte(buf) => %v, want %v", b, 42) + } + buf, b = NextByte(buf) + if b != 1 { + t.Errorf("NextByte(buf) => %v, want %v", b, 1) + } +} + +func TestNextUint16(t *testing.T) { + buf := []byte{0, 42, 0, 1} + var n uint16 + buf, n = NextUint16(buf) + if n != 42 { + t.Errorf("NextUint16(buf) => %v, want %v", n, 42) + } + buf, n = NextUint16(buf) + if n != 1 { + t.Errorf("NextUint16(buf) => %v, want %v", n, 1) + } +} + +func TestNextUint32(t *testing.T) { + buf := []byte{0, 0, 0, 42, 0, 0, 0, 1} + var n uint32 + buf, n = NextUint32(buf) + if n != 42 { + t.Errorf("NextUint32(buf) => %v, want %v", n, 42) + } + buf, n = NextUint32(buf) + if n != 1 { + t.Errorf("NextUint32(buf) => %v, want %v", n, 1) + } +} + +func TestNextUint64(t *testing.T) { + buf := []byte{0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 1} + var n uint64 + buf, n = NextUint64(buf) + if n != 42 { + t.Errorf("NextUint64(buf) => %v, want %v", n, 42) + } + buf, n = NextUint64(buf) + if n != 1 { + t.Errorf("NextUint64(buf) => %v, want %v", n, 1) + } +} diff --git a/write.go b/write.go index 823fbd00..96aedf9d 100644 --- a/write.go +++ b/write.go @@ -1,97 +1,40 @@ package pgio -import ( - "encoding/binary" - "io" -) +import "encoding/binary" -type Uint16Writer interface { - WriteUint16(uint16) (n int, err error) +func AppendUint16(buf []byte, n uint16) []byte { + wp := len(buf) + buf = append(buf, 0, 0) + binary.BigEndian.PutUint16(buf[wp:], n) + return buf } -type Uint32Writer interface { - WriteUint32(uint32) (n int, err error) +func AppendUint32(buf []byte, n uint32) []byte { + wp := len(buf) + buf = append(buf, 0, 0, 0, 0) + binary.BigEndian.PutUint32(buf[wp:], n) + return buf } -type Uint64Writer interface { - WriteUint64(uint64) (n int, err error) +func AppendUint64(buf []byte, n uint64) []byte { + wp := len(buf) + buf = append(buf, 0, 0, 0, 0, 0, 0, 0, 0) + binary.BigEndian.PutUint64(buf[wp:], n) + return buf } -// WriteByte writes b to w. -func WriteByte(w io.Writer, b byte) error { - if w, ok := w.(io.ByteWriter); ok { - return w.WriteByte(b) - } - _, err := w.Write([]byte{b}) - return err +func AppendInt16(buf []byte, n int16) []byte { + return AppendUint16(buf, uint16(n)) } -// WriteUint16 writes n to w in PostgreSQL wire format (network byte order). This -// may be more efficient than directly using Write if w provides a WriteUint16 -// method. -func WriteUint16(w io.Writer, n uint16) (int, error) { - if w, ok := w.(Uint16Writer); ok { - return w.WriteUint16(n) - } - b := make([]byte, 2) - binary.BigEndian.PutUint16(b, n) - return w.Write(b) +func AppendInt32(buf []byte, n int32) []byte { + return AppendUint32(buf, uint32(n)) } -// WriteInt16 writes n to w in PostgreSQL wire format (network byte order). This -// may be more efficient than directly using Write if w provides a WriteUint16 -// method. -func WriteInt16(w io.Writer, n int16) (int, error) { - return WriteUint16(w, uint16(n)) +func AppendInt64(buf []byte, n int64) []byte { + return AppendUint64(buf, uint64(n)) } -// WriteUint32 writes n to w in PostgreSQL wire format (network byte order). This -// may be more efficient than directly using Write if w provides a WriteUint32 -// method. -func WriteUint32(w io.Writer, n uint32) (int, error) { - if w, ok := w.(Uint32Writer); ok { - return w.WriteUint32(n) - } - b := make([]byte, 4) - binary.BigEndian.PutUint32(b, n) - return w.Write(b) -} - -// WriteInt32 writes n to w in PostgreSQL wire format (network byte order). This -// may be more efficient than directly using Write if w provides a WriteUint32 -// method. -func WriteInt32(w io.Writer, n int32) (int, error) { - return WriteUint32(w, uint32(n)) -} - -// WriteUint64 writes n to w in PostgreSQL wire format (network byte order). This -// may be more efficient than directly using Write if w provides a WriteUint64 -// method. -func WriteUint64(w io.Writer, n uint64) (int, error) { - if w, ok := w.(Uint64Writer); ok { - return w.WriteUint64(n) - } - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, n) - return w.Write(b) -} - -// WriteInt64 writes n to w in PostgreSQL wire format (network byte order). This -// may be more efficient than directly using Write if w provides a WriteUint64 -// method. -func WriteInt64(w io.Writer, n int64) (int, error) { - return WriteUint64(w, uint64(n)) -} - -// WriteCString writes s to w followed by a null byte. -func WriteCString(w io.Writer, s string) (int, error) { - n, err := io.WriteString(w, s) - if err != nil { - return n, err - } - err = WriteByte(w, 0) - if err != nil { - return n, err - } - return n + 1, nil +func SetInt32(buf []byte, n int32) { + binary.BigEndian.PutUint32(buf, uint32(n)) } diff --git a/write_test.go b/write_test.go new file mode 100644 index 00000000..bd50e71c --- /dev/null +++ b/write_test.go @@ -0,0 +1,78 @@ +package pgio + +import ( + "reflect" + "testing" +) + +func TestAppendUint16NilBuf(t *testing.T) { + buf := AppendUint16(nil, 1) + if !reflect.DeepEqual(buf, []byte{0, 1}) { + t.Errorf("AppendUint16(nil, 1) => %v, want %v", buf, []byte{0, 1}) + } +} + +func TestAppendUint16EmptyBuf(t *testing.T) { + buf := []byte{} + buf = AppendUint16(buf, 1) + if !reflect.DeepEqual(buf, []byte{0, 1}) { + t.Errorf("AppendUint16(nil, 1) => %v, want %v", buf, []byte{0, 1}) + } +} + +func TestAppendUint16BufWithCapacityDoesNotAllocate(t *testing.T) { + buf := make([]byte, 0, 4) + AppendUint16(buf, 1) + buf = buf[0:2] + if !reflect.DeepEqual(buf, []byte{0, 1}) { + t.Errorf("AppendUint16(nil, 1) => %v, want %v", buf, []byte{0, 1}) + } +} + +func TestAppendUint32NilBuf(t *testing.T) { + buf := AppendUint32(nil, 1) + if !reflect.DeepEqual(buf, []byte{0, 0, 0, 1}) { + t.Errorf("AppendUint32(nil, 1) => %v, want %v", buf, []byte{0, 0, 0, 1}) + } +} + +func TestAppendUint32EmptyBuf(t *testing.T) { + buf := []byte{} + buf = AppendUint32(buf, 1) + if !reflect.DeepEqual(buf, []byte{0, 0, 0, 1}) { + t.Errorf("AppendUint32(nil, 1) => %v, want %v", buf, []byte{0, 0, 0, 1}) + } +} + +func TestAppendUint32BufWithCapacityDoesNotAllocate(t *testing.T) { + buf := make([]byte, 0, 4) + AppendUint32(buf, 1) + buf = buf[0:4] + if !reflect.DeepEqual(buf, []byte{0, 0, 0, 1}) { + t.Errorf("AppendUint32(nil, 1) => %v, want %v", buf, []byte{0, 0, 0, 1}) + } +} + +func TestAppendUint64NilBuf(t *testing.T) { + buf := AppendUint64(nil, 1) + if !reflect.DeepEqual(buf, []byte{0, 0, 0, 0, 0, 0, 0, 1}) { + t.Errorf("AppendUint64(nil, 1) => %v, want %v", buf, []byte{0, 0, 0, 0, 0, 0, 0, 1}) + } +} + +func TestAppendUint64EmptyBuf(t *testing.T) { + buf := []byte{} + buf = AppendUint64(buf, 1) + if !reflect.DeepEqual(buf, []byte{0, 0, 0, 0, 0, 0, 0, 1}) { + t.Errorf("AppendUint64(nil, 1) => %v, want %v", buf, []byte{0, 0, 0, 0, 0, 0, 0, 1}) + } +} + +func TestAppendUint64BufWithCapacityDoesNotAllocate(t *testing.T) { + buf := make([]byte, 0, 8) + AppendUint64(buf, 1) + buf = buf[0:8] + if !reflect.DeepEqual(buf, []byte{0, 0, 0, 0, 0, 0, 0, 1}) { + t.Errorf("AppendUint64(nil, 1) => %v, want %v", buf, []byte{0, 0, 0, 0, 0, 0, 0, 1}) + } +} From 6f398d8bb59696901d4fe3a9c88e158f54b9b395 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Sat, 6 May 2017 08:48:40 -0500 Subject: [PATCH 3/9] Update pgproto3 to enable pgmock --- read.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/read.go b/read.go index 7ddad508..033bada4 100644 --- a/read.go +++ b/read.go @@ -1,6 +1,7 @@ package pgio import ( + "bytes" "encoding/binary" ) @@ -38,3 +39,13 @@ func NextInt64(buf []byte) ([]byte, int64) { buf, n := NextUint64(buf) return buf, int64(n) } + +func NextCString(buf []byte) ([]byte, string, bool) { + idx := bytes.IndexByte(buf, 0) + if idx < 0 { + return buf, "", false + } + cstring := string(buf[:idx]) + buf = buf[:idx+1] + return buf, cstring, true +} From 2d209bd579c721e74cdc7614b1e643958fbae0e3 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Sat, 6 May 2017 08:53:37 -0500 Subject: [PATCH 4/9] Remove read functions from pgio and update docs --- doc.go | 8 +++----- read.go | 51 ---------------------------------------------- read_test.go | 57 ---------------------------------------------------- 3 files changed, 3 insertions(+), 113 deletions(-) delete mode 100644 read.go delete mode 100644 read_test.go diff --git a/doc.go b/doc.go index 36233a47..ef2dcc7f 100644 --- a/doc.go +++ b/doc.go @@ -1,8 +1,6 @@ -// Package pgio a extremely low-level IO toolkit for the PostgreSQL wire protocol. +// Package pgio is a low-level toolkit building messages in the PostgreSQL wire protocol. /* -pgio provides functions for reading and writing integers from io.Reader and -io.Writer while doing byte order conversion. It publishes interfaces which -readers and writers may implement to decode and encode messages with the minimum -of memory allocations. +pgio provides functions for appending integers to a []byte while doing byte +order conversion. */ package pgio diff --git a/read.go b/read.go deleted file mode 100644 index 033bada4..00000000 --- a/read.go +++ /dev/null @@ -1,51 +0,0 @@ -package pgio - -import ( - "bytes" - "encoding/binary" -) - -func NextByte(buf []byte) ([]byte, byte) { - b := buf[0] - return buf[1:], b -} - -func NextUint16(buf []byte) ([]byte, uint16) { - n := binary.BigEndian.Uint16(buf) - return buf[2:], n -} - -func NextUint32(buf []byte) ([]byte, uint32) { - n := binary.BigEndian.Uint32(buf) - return buf[4:], n -} - -func NextUint64(buf []byte) ([]byte, uint64) { - n := binary.BigEndian.Uint64(buf) - return buf[8:], n -} - -func NextInt16(buf []byte) ([]byte, int16) { - buf, n := NextUint16(buf) - return buf, int16(n) -} - -func NextInt32(buf []byte) ([]byte, int32) { - buf, n := NextUint32(buf) - return buf, int32(n) -} - -func NextInt64(buf []byte) ([]byte, int64) { - buf, n := NextUint64(buf) - return buf, int64(n) -} - -func NextCString(buf []byte) ([]byte, string, bool) { - idx := bytes.IndexByte(buf, 0) - if idx < 0 { - return buf, "", false - } - cstring := string(buf[:idx]) - buf = buf[:idx+1] - return buf, cstring, true -} diff --git a/read_test.go b/read_test.go deleted file mode 100644 index fbe29ae4..00000000 --- a/read_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package pgio - -import ( - "testing" -) - -func TestNextByte(t *testing.T) { - buf := []byte{42, 1} - var b byte - buf, b = NextByte(buf) - if b != 42 { - t.Errorf("NextByte(buf) => %v, want %v", b, 42) - } - buf, b = NextByte(buf) - if b != 1 { - t.Errorf("NextByte(buf) => %v, want %v", b, 1) - } -} - -func TestNextUint16(t *testing.T) { - buf := []byte{0, 42, 0, 1} - var n uint16 - buf, n = NextUint16(buf) - if n != 42 { - t.Errorf("NextUint16(buf) => %v, want %v", n, 42) - } - buf, n = NextUint16(buf) - if n != 1 { - t.Errorf("NextUint16(buf) => %v, want %v", n, 1) - } -} - -func TestNextUint32(t *testing.T) { - buf := []byte{0, 0, 0, 42, 0, 0, 0, 1} - var n uint32 - buf, n = NextUint32(buf) - if n != 42 { - t.Errorf("NextUint32(buf) => %v, want %v", n, 42) - } - buf, n = NextUint32(buf) - if n != 1 { - t.Errorf("NextUint32(buf) => %v, want %v", n, 1) - } -} - -func TestNextUint64(t *testing.T) { - buf := []byte{0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 1} - var n uint64 - buf, n = NextUint64(buf) - if n != 42 { - t.Errorf("NextUint64(buf) => %v, want %v", n, 42) - } - buf, n = NextUint64(buf) - if n != 1 { - t.Errorf("NextUint64(buf) => %v, want %v", n, 1) - } -} From 2a112595551c4551e0c6064224b95e6035a16092 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Sat, 30 Mar 2019 12:03:04 -0500 Subject: [PATCH 5/9] Add readme and license --- LICENSE | 22 ++++++++++++++++++++++ README.md | 11 +++++++++++ 2 files changed, 33 insertions(+) create mode 100644 LICENSE create mode 100644 README.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..c1c4f50f --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2019 Jack Christensen + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..81139c3e --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +[![](https://godoc.org/github.com/jackc/pgpassfile?status.svg)](https://godoc.org/github.com/jackc/pgpassfile) +[![Build Status](https://travis-ci.org/jackc/pgpassfile.svg)](https://travis-ci.org/jackc/pgpassfile) + +# pgio + +Package pgio is a low-level toolkit building messages in the PostgreSQL wire protocol. + +pgio provides functions for appending integers to a []byte while doing byte +order conversion. + +Extracted from original implementation in https://github.com/jackc/pgx. From 715eaaf2ed8a28a35a85d331f3b1ef08a177a5af Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Sat, 30 Mar 2019 12:03:34 -0500 Subject: [PATCH 6/9] Add go module support --- go.mod | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 go.mod diff --git a/go.mod b/go.mod new file mode 100644 index 00000000..c1efdddb --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/jackc/pgio + +go 1.12 From 8abf4a9eaab90a7470c06fdd6c048f748da0d168 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Sat, 30 Mar 2019 12:04:23 -0500 Subject: [PATCH 7/9] Fix links in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 81139c3e..1952ed86 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![](https://godoc.org/github.com/jackc/pgpassfile?status.svg)](https://godoc.org/github.com/jackc/pgpassfile) -[![Build Status](https://travis-ci.org/jackc/pgpassfile.svg)](https://travis-ci.org/jackc/pgpassfile) +[![](https://godoc.org/github.com/jackc/pgio?status.svg)](https://godoc.org/github.com/jackc/pgio) +[![Build Status](https://travis-ci.org/jackc/pgio.svg)](https://travis-ci.org/jackc/pgio) # pgio From 8d9c2a3dafd92d070bd758a165022fd1059e3195 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Sat, 30 Mar 2019 12:04:38 -0500 Subject: [PATCH 8/9] Add travis ci --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..e176228e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: go + +go: + - 1.x + - tip + +matrix: + allow_failures: + - go: tip From d35500e3979fc75bfe76d8e727223ea039edef76 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Mon, 21 Feb 2022 14:32:55 -0600 Subject: [PATCH 9/9] Move pgio --- .travis.yml | 9 --------- LICENSE | 22 ---------------------- README.md | 11 ----------- go.mod | 3 --- pgio/README.md | 6 ++++++ doc.go => pgio/doc.go | 0 write.go => pgio/write.go | 0 write_test.go => pgio/write_test.go | 0 8 files changed, 6 insertions(+), 45 deletions(-) delete mode 100644 .travis.yml delete mode 100644 LICENSE delete mode 100644 README.md delete mode 100644 go.mod create mode 100644 pgio/README.md rename doc.go => pgio/doc.go (100%) rename write.go => pgio/write.go (100%) rename write_test.go => pgio/write_test.go (100%) diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index e176228e..00000000 --- a/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go - -go: - - 1.x - - tip - -matrix: - allow_failures: - - go: tip diff --git a/LICENSE b/LICENSE deleted file mode 100644 index c1c4f50f..00000000 --- a/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2019 Jack Christensen - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md deleted file mode 100644 index 1952ed86..00000000 --- a/README.md +++ /dev/null @@ -1,11 +0,0 @@ -[![](https://godoc.org/github.com/jackc/pgio?status.svg)](https://godoc.org/github.com/jackc/pgio) -[![Build Status](https://travis-ci.org/jackc/pgio.svg)](https://travis-ci.org/jackc/pgio) - -# pgio - -Package pgio is a low-level toolkit building messages in the PostgreSQL wire protocol. - -pgio provides functions for appending integers to a []byte while doing byte -order conversion. - -Extracted from original implementation in https://github.com/jackc/pgx. diff --git a/go.mod b/go.mod deleted file mode 100644 index c1efdddb..00000000 --- a/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/jackc/pgio - -go 1.12 diff --git a/pgio/README.md b/pgio/README.md new file mode 100644 index 00000000..b2fc5801 --- /dev/null +++ b/pgio/README.md @@ -0,0 +1,6 @@ +# pgio + +Package pgio is a low-level toolkit building messages in the PostgreSQL wire protocol. + +pgio provides functions for appending integers to a []byte while doing byte +order conversion. diff --git a/doc.go b/pgio/doc.go similarity index 100% rename from doc.go rename to pgio/doc.go diff --git a/write.go b/pgio/write.go similarity index 100% rename from write.go rename to pgio/write.go diff --git a/write_test.go b/pgio/write_test.go similarity index 100% rename from write_test.go rename to pgio/write_test.go