aboutsummaryrefslogtreecommitdiff
path: root/src/main.zig
diff options
context:
space:
mode:
authorMartin Ashby <martin@ashbysoft.com>2023-09-23 21:26:06 +0100
committerMartin Ashby <martin@ashbysoft.com>2023-09-23 21:26:06 +0100
commitddc6bee3757d3e68a14fafdc47eb5d0a0ba923bb (patch)
tree309ffbc89c42a3adf41a655025fe20e4014878c9 /src/main.zig
parent5a91b37ee7dd36db52dfde1727b780ec3fa4c67d (diff)
downloadpgz-ddc6bee3757d3e68a14fafdc47eb5d0a0ba923bb.tar.gz
pgz-ddc6bee3757d3e68a14fafdc47eb5d0a0ba923bb.tar.bz2
pgz-ddc6bee3757d3e68a14fafdc47eb5d0a0ba923bb.tar.xz
pgz-ddc6bee3757d3e68a14fafdc47eb5d0a0ba923bb.zip
Got a working test connecting to postgres server and reading data.
Added a couple more message types to facilitate this.
Diffstat (limited to 'src/main.zig')
-rw-r--r--src/main.zig85
1 files changed, 78 insertions, 7 deletions
diff --git a/src/main.zig b/src/main.zig
index e540256..e539f2f 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -1,10 +1,13 @@
const std = @import("std");
const testing = std.testing;
const StartupMessage = @import("startup_message.zig");
-const AuthenticationOk = @import("authentication_ok.zig");
-const AuthenticationCleartextPassword = @import("authentication_cleartext_password.zig");
+const AuthenticationRequest = @import("authentication_request.zig");
const PasswordMessage = @import("password_message.zig");
const ErrorResponse = @import("error_response.zig");
+const ReadyForQuery = @import("ready_for_query.zig");
+const ParameterStatus = @import("parameter_status.zig");
+const BackendKeyData = @import("backend_key_data.zig");
+const Conn = @import("conn.zig");
pub const ProtocolError = error{
InvalidProtocolVersion,
@@ -12,15 +15,16 @@ pub const ProtocolError = error{
InvalidMessageLength,
InvalidAuthType,
MissingField,
+ WrongMessageType,
+ InvalidTransactionStatus,
};
pub const ClientError = error{
UnsupportedAuthType,
};
-pub const AuthType = enum(u32) {
- AuthTypeOk = 0,
- AuthTypeCleartextPassword = 3,
+pub const ServerError = error{
+ ErrorResponse,
};
// Fallible version of enumFromInt
@@ -38,10 +42,77 @@ pub fn enum_from_int(comptime e: type, i: anytype) ?e {
}
}
+// Tag should already have been read in order to determine msg_type!
+pub fn read_message(comptime msg_type: type, allocator: std.mem.Allocator, stream_reader: anytype) !msg_type {
+ if (!@hasDecl(msg_type, "Tag")) @compileError("msg_type must have a Tag declaration!");
+ if (!@hasDecl(msg_type, "read")) @compileError("msg_type must have a read() function!");
+ const len = try stream_reader.readIntBig(u32);
+ const buf = try allocator.alloc(u8, @as(u32, @intCast(len-4)));
+ defer allocator.free(buf);
+ try stream_reader.readNoEof(buf);
+ return try msg_type.read(allocator, buf);
+}
+
+
+pub fn diagnosticReader(comptime n: usize, base_reader: anytype) DiagnosticReader(n, @TypeOf(base_reader)) {
+ return .{.child_reader = base_reader};
+}
+
+// keeps a buffer of the last n bytes read
+pub fn DiagnosticReader(comptime n: usize, comptime ReaderType: anytype) type {
+ return struct {
+ child_reader: ReaderType,
+ ring: [n]u8 = [_]u8{0}**n,
+ pos: usize = 0,
+
+ pub const Error = ReaderType.Error;
+ pub const Reader = std.io.Reader(*@This(), Error, read);
+
+ pub fn read(self: *@This(), buf: []u8) Error!usize {
+ const amt = try self.child_reader.read(buf);
+ for (0..amt) |i| {
+ self.ring[self.pos] = buf[i];
+ self.pos += 1;
+ self.pos %= n;
+ }
+ return amt;
+ }
+
+ pub fn reader(self: *@This()) Reader {
+ return .{ .context = self };
+ }
+
+ // Caller frees
+ pub fn get(self: @This(), allocator: std.mem.Allocator) ![]const u8 {
+ var buf = try allocator.alloc(u8, n);
+ errdefer allocator.free(buf);
+ @memcpy(buf[0..(n-self.pos)], self.ring[self.pos..n]);
+ @memcpy(buf[(n-self.pos)..n], self.ring[0..self.pos]);
+ return buf;
+ }
+ };
+}
+
+test "diagnostc reader" {
+ const a = std.testing.allocator;
+ const string = "The quick brown fox jumped over the lazy dog";
+ var fbs = std.io.fixedBufferStream(string);
+ var dr = diagnosticReader(15, fbs.reader());
+ var reader = dr.reader();
+ var buf = [_]u8{0}**20;
+ try reader.readNoEof(&buf);
+ const diag = try dr.get(a);
+ defer a.free(diag);
+ try std.testing.expectEqualStrings("uick brown fox ", diag);
+}
+
test {
_ = StartupMessage;
- _ = AuthenticationOk;
- _ = AuthenticationCleartextPassword;
+ _ = AuthenticationRequest;
_ = PasswordMessage;
_ = ErrorResponse;
+ _ = Conn;
+ _ = ReadyForQuery;
+ _ = ParameterStatus;
+ _ = BackendKeyData;
}