From ed9feaa803057d2aa2659bb979c329882b36a1c6 Mon Sep 17 00:00:00 2001
From: Garet Halliday <me@garet.holiday>
Date: Thu, 14 Sep 2023 15:55:34 -0500
Subject: [PATCH] copy in from prepared statement is broken

---
 lib/fed/packets/v3.0/copydata.go | 24 ++++++++++++++++++++
 test/inst/copydata.go            |  7 ++++++
 test/inst/copydone.go            |  7 ++++++
 test/runner.go                   |  5 ++++
 test/tester_test.go              |  2 ++
 test/tests/copy_in.go            | 39 ++++++++++++++++++++++++++++++++
 6 files changed, 84 insertions(+)
 create mode 100644 lib/fed/packets/v3.0/copydata.go
 create mode 100644 test/inst/copydata.go
 create mode 100644 test/inst/copydone.go
 create mode 100644 test/tests/copy_in.go

diff --git a/lib/fed/packets/v3.0/copydata.go b/lib/fed/packets/v3.0/copydata.go
new file mode 100644
index 00000000..9f407870
--- /dev/null
+++ b/lib/fed/packets/v3.0/copydata.go
@@ -0,0 +1,24 @@
+package packets
+
+import (
+	"pggat/lib/fed"
+	"pggat/lib/util/slices"
+)
+
+type CopyData []byte
+
+func (T *CopyData) ReadFromPacket(packet fed.Packet) bool {
+	if packet.Type() != TypeCopyData {
+		return false
+	}
+
+	*T = slices.Resize(*T, len(packet.Payload()))
+	packet.ReadBytes(*T)
+	return true
+}
+
+func (T *CopyData) IntoPacket() fed.Packet {
+	packet := fed.NewPacket(TypeCopyData, len(*T))
+	packet = packet.AppendBytes(*T)
+	return packet
+}
diff --git a/test/inst/copydata.go b/test/inst/copydata.go
new file mode 100644
index 00000000..3b719fb7
--- /dev/null
+++ b/test/inst/copydata.go
@@ -0,0 +1,7 @@
+package inst
+
+type CopyData []byte
+
+func (CopyData) instruction() {}
+
+var _ Instruction = CopyData{}
diff --git a/test/inst/copydone.go b/test/inst/copydone.go
new file mode 100644
index 00000000..bab72b7d
--- /dev/null
+++ b/test/inst/copydone.go
@@ -0,0 +1,7 @@
+package inst
+
+type CopyDone struct{}
+
+func (CopyDone) instruction() {}
+
+var _ Instruction = CopyDone{}
diff --git a/test/runner.go b/test/runner.go
index 8ed80068..4cd6ce0f 100644
--- a/test/runner.go
+++ b/test/runner.go
@@ -78,6 +78,11 @@ func (T *Runner) prepare(client *gsql.Client, until int) []Capturer {
 				Target: string(v),
 			}
 			client.Do(&results[i], p.IntoPacket())
+		case inst.CopyData:
+			p := packets.CopyData(v)
+			client.Do(&results[i], p.IntoPacket())
+		case inst.CopyDone:
+			client.Do(&results[i], fed.NewPacket(packets.TypeCopyDone))
 		}
 	}
 
diff --git a/test/tester_test.go b/test/tester_test.go
index 5c58b1f1..a1001767 100644
--- a/test/tester_test.go
+++ b/test/tester_test.go
@@ -174,6 +174,8 @@ func TestTester(t *testing.T) {
 		tests.EQP8,
 		tests.CopyOut0,
 		tests.CopyOut1,
+		tests.CopyIn0,
+		tests.CopyIn1,
 		tests.DiscardAll,
 	); err != nil {
 		fmt.Print(err.Error())
diff --git a/test/tests/copy_in.go b/test/tests/copy_in.go
new file mode 100644
index 00000000..18f85261
--- /dev/null
+++ b/test/tests/copy_in.go
@@ -0,0 +1,39 @@
+package tests
+
+import (
+	"pggat/test"
+	"pggat/test/inst"
+)
+
+var CopyIn0 = test.Test{
+	SideEffects: true,
+	Name:        "Copy In 0",
+	Instructions: []inst.Instruction{
+		inst.SimpleQuery("CREATE TABLE test ( x integer NOT NULL, y varchar(40) NOT NULL PRIMARY KEY )"),
+		inst.SimpleQuery("COPY test FROM STDIN"),
+		inst.CopyData{49, 50, 51, 9, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 10},
+		inst.CopyData{45, 51, 50, 52, 9, 103, 97, 114, 101, 116, 32, 119, 97, 115, 32, 104, 101, 114, 101, 10},
+		inst.CopyDone{},
+		inst.SimpleQuery("DROP TABLE test"),
+	},
+}
+
+var CopyIn1 = test.Test{
+	SideEffects: true,
+	Name:        "Copy In 1",
+	Instructions: []inst.Instruction{
+		inst.SimpleQuery("CREATE TABLE test ( x integer NOT NULL, y varchar(40) NOT NULL PRIMARY KEY )"),
+		inst.Parse{
+			Query: "COPY test FROM STDIN",
+		},
+		inst.DescribePreparedStatement(""),
+		inst.Bind{},
+		inst.DescribePortal(""),
+		inst.Execute(""),
+		inst.Sync{},
+		inst.CopyData{49, 50, 51, 9, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 10},
+		inst.CopyData{45, 51, 50, 52, 9, 103, 97, 114, 101, 116, 32, 119, 97, 115, 32, 104, 101, 114, 101, 10},
+		inst.CopyDone{},
+		inst.SimpleQuery("DROP TABLE test"),
+	},
+}
-- 
GitLab