From 16c99331a9e2bf5df465f7236bee9975b5396900 Mon Sep 17 00:00:00 2001
From: Garet Halliday <me@garet.holiday>
Date: Fri, 25 Aug 2023 12:34:57 -0500
Subject: [PATCH] unmarshal

---
 lib/psql/query.go                      | 12 ++++-
 lib/psql/query_test.go                 |  2 +-
 lib/zap/packets/v3.0/datarow.go        | 52 +++++++++++++++++++++
 lib/zap/packets/v3.0/rowdescription.go | 63 ++++++++++++++++++++++++++
 4 files changed, 126 insertions(+), 3 deletions(-)
 create mode 100644 lib/zap/packets/v3.0/datarow.go
 create mode 100644 lib/zap/packets/v3.0/rowdescription.go

diff --git a/lib/psql/query.go b/lib/psql/query.go
index c7614236..1abc8595 100644
--- a/lib/psql/query.go
+++ b/lib/psql/query.go
@@ -36,9 +36,17 @@ func (T *resultReader) WriteByte(_ byte) error {
 func (T *resultReader) WritePacket(packet zap.Packet) error {
 	switch packet.Type() {
 	case packets.TypeRowDescription:
-		log.Println("row description", packet)
+		var rd packets.RowDescription
+		if !rd.ReadFromPacket(packet) {
+			return errors.New("invalid format")
+		}
+		log.Printf("row description: %#v", rd)
 	case packets.TypeDataRow:
-		log.Println("data row", packet)
+		var dr packets.DataRow
+		if !dr.ReadFromPacket(packet) {
+			return errors.New("invalid format")
+		}
+		log.Printf("data row: %#v", dr)
 	}
 	return nil
 }
diff --git a/lib/psql/query_test.go b/lib/psql/query_test.go
index 2f3449ee..4a573c25 100644
--- a/lib/psql/query_test.go
+++ b/lib/psql/query_test.go
@@ -29,7 +29,7 @@ func TestQuery(t *testing.T) {
 		return
 	}
 
-	err = Query(server, "SELECT * FROM pg_shadow")
+	err = Query(server, "SELECT usename, passwd FROM pg_shadow WHERE usename='postgres'")
 	if err != nil {
 		t.Error(err)
 		return
diff --git a/lib/zap/packets/v3.0/datarow.go b/lib/zap/packets/v3.0/datarow.go
new file mode 100644
index 00000000..689d350e
--- /dev/null
+++ b/lib/zap/packets/v3.0/datarow.go
@@ -0,0 +1,52 @@
+package packets
+
+import (
+	"pggat2/lib/util/slices"
+	"pggat2/lib/zap"
+)
+
+type DataRow struct {
+	Columns [][]byte
+}
+
+func (T *DataRow) ReadFromPacket(packet zap.Packet) bool {
+	if packet.Type() != TypeDataRow {
+		return false
+	}
+
+	var columnCount uint16
+	p := packet.ReadUint16(&columnCount)
+	T.Columns = slices.Resize(T.Columns, int(columnCount))
+	for i := 0; i < int(columnCount); i++ {
+		var valueLength int32
+		p = p.ReadInt32(&valueLength)
+		if valueLength == -1 {
+			continue
+		}
+		T.Columns[i] = slices.Resize(T.Columns[i], int(valueLength))
+		p = p.ReadBytes(T.Columns[i])
+	}
+
+	return true
+}
+
+func (T *DataRow) IntoPacket() zap.Packet {
+	size := 2
+	for _, v := range T.Columns {
+		size += len(v) + 4
+	}
+
+	packet := zap.NewPacket(TypeDataRow, size)
+	packet = packet.AppendUint16(uint16(len(T.Columns)))
+	for _, v := range T.Columns {
+		if v == nil {
+			packet = packet.AppendInt32(-1)
+			continue
+		}
+
+		packet = packet.AppendInt32(int32(len(v)))
+		packet = packet.AppendBytes(v)
+	}
+
+	return packet
+}
diff --git a/lib/zap/packets/v3.0/rowdescription.go b/lib/zap/packets/v3.0/rowdescription.go
new file mode 100644
index 00000000..3febb34c
--- /dev/null
+++ b/lib/zap/packets/v3.0/rowdescription.go
@@ -0,0 +1,63 @@
+package packets
+
+import (
+	"pggat2/lib/util/slices"
+	"pggat2/lib/zap"
+)
+
+type RowDescriptionField struct {
+	Name         string
+	TableID      int32
+	ColumnID     int16
+	Type         int32
+	TypeLength   int16
+	TypeModifier int32
+	FormatCode   int16
+}
+
+type RowDescription struct {
+	Fields []RowDescriptionField
+}
+
+func (T *RowDescription) ReadFromPacket(packet zap.Packet) bool {
+	if packet.Type() != TypeRowDescription {
+		return false
+	}
+
+	var fieldsPerRow uint16
+	p := packet.ReadUint16(&fieldsPerRow)
+	T.Fields = slices.Resize(T.Fields, int(fieldsPerRow))
+	for i := 0; i < int(fieldsPerRow); i++ {
+		p = p.ReadString(&T.Fields[i].Name)
+		p = p.ReadInt32(&T.Fields[i].TableID)
+		p = p.ReadInt16(&T.Fields[i].ColumnID)
+		p = p.ReadInt32(&T.Fields[i].Type)
+		p = p.ReadInt16(&T.Fields[i].TypeLength)
+		p = p.ReadInt32(&T.Fields[i].TypeModifier)
+		p = p.ReadInt16(&T.Fields[i].FormatCode)
+	}
+
+	return true
+}
+
+func (T *RowDescription) IntoPacket() zap.Packet {
+	size := 2
+	for _, v := range T.Fields {
+		size += len(v.Name) + 1
+		size += 4 + 2 + 4 + 2 + 4 + 2
+	}
+
+	packet := zap.NewPacket(TypeRowDescription, size)
+	packet = packet.AppendUint16(uint16(len(T.Fields)))
+	for _, v := range T.Fields {
+		packet = packet.AppendString(v.Name)
+		packet = packet.AppendInt32(v.TableID)
+		packet = packet.AppendInt16(v.ColumnID)
+		packet = packet.AppendInt32(v.Type)
+		packet = packet.AppendInt16(v.TypeLength)
+		packet = packet.AppendInt32(v.TypeModifier)
+		packet = packet.AppendInt16(v.FormatCode)
+	}
+
+	return packet
+}
-- 
GitLab