aboutsummaryrefslogtreecommitdiff
path: root/src/proto/error_response.zig
diff options
context:
space:
mode:
authorMartin Ashby <martin@ashbysoft.com>2023-09-29 09:44:54 +0100
committerMartin Ashby <martin@ashbysoft.com>2023-09-29 09:44:54 +0100
commitfada72cd26ad31e1fc834788c1224ed05a78143b (patch)
treedb71f2cbc6cbf9c47148271682641c940eb75650 /src/proto/error_response.zig
parent6de632a41bdd127e92de68d61a18dfee91b8b188 (diff)
downloadpgz-fada72cd26ad31e1fc834788c1224ed05a78143b.tar.gz
pgz-fada72cd26ad31e1fc834788c1224ed05a78143b.tar.bz2
pgz-fada72cd26ad31e1fc834788c1224ed05a78143b.tar.xz
pgz-fada72cd26ad31e1fc834788c1224ed05a78143b.zip
Generify ErrorResponse to allow for NoticeResponse which shares it'sHEADmain
structure. Add a very basic test for running an actual query
Diffstat (limited to 'src/proto/error_response.zig')
-rw-r--r--src/proto/error_response.zig297
1 files changed, 151 insertions, 146 deletions
diff --git a/src/proto/error_response.zig b/src/proto/error_response.zig
index 58ca06e..f572f0a 100644
--- a/src/proto/error_response.zig
+++ b/src/proto/error_response.zig
@@ -3,160 +3,165 @@ const HMByteString = std.AutoHashMap(u8, []const u8);
const ByteArrayList = std.ArrayList(u8);
const ProtocolError = @import("../main.zig").ProtocolError;
-const ErrorResponse = @This();
-pub const Tag: u8 = 'E';
+pub fn ErrorNoticeResponse(comptime tag:u8) type {
+ return struct {
+ pub const Tag: u8 = tag;
+ buf: ?[]const u8 = null, // owned
+ severity: []const u8,
+ severity_unlocalized: ?[]const u8 = null,
+ code: []const u8,
+ message: []const u8,
+ detail: ?[]const u8 = null,
+ hint: ?[]const u8 = null,
+ position: ?u32 = null,
+ internal_position: ?u32 = null,
+ internal_query: ?[]const u8 = null,
+ where: ?[]const u8 = null,
+ schema_name: ?[]const u8 = null,
+ table_name: ?[]const u8 = null,
+ column_name: ?[]const u8 = null,
+ data_type_name: ?[]const u8 = null,
+ constraint_name: ?[]const u8 = null,
+ file_name: ?[]const u8 = null,
+ line: ?u32 = null,
+ routine: ?[]const u8 = null,
+ unknown_fields: HMByteString,
-buf: ?[]const u8 = null, // owned
-severity: []const u8,
-severity_unlocalized: ?[]const u8 = null,
-code: []const u8,
-message: []const u8,
-detail: ?[]const u8 = null,
-hint: ?[]const u8 = null,
-position: ?u32 = null,
-internal_position: ?u32 = null,
-internal_query: ?[]const u8 = null,
-where: ?[]const u8 = null,
-schema_name: ?[]const u8 = null,
-table_name: ?[]const u8 = null,
-column_name: ?[]const u8 = null,
-data_type_name: ?[]const u8 = null,
-constraint_name: ?[]const u8 = null,
-file_name: ?[]const u8 = null,
-line: ?u32 = null,
-routine: ?[]const u8 = null,
-unknown_fields: HMByteString,
-
-pub fn read(allocator: std.mem.Allocator, buf: []const u8) !ErrorResponse {
- var res = ErrorResponse{
- .severity = "",
- .code = "",
- .message = "",
- .unknown_fields = HMByteString.init(allocator),
- .buf = buf,
- };
- errdefer res.deinit(allocator);
- var it = std.mem.splitScalar(u8, res.buf.?, 0);
- var setSev = false;
- var setCode = false;
- var setMsg = false;
- while (it.next()) |next| {
- if (next.len < 1) break;
- switch (next[0]) {
- 0 => break,
- 'S' => {
- res.severity = next[1..];
- setSev = true;
- },
- 'V' => {
- res.severity_unlocalized = next[1..];
- },
- 'C' => {
- res.code = next[1..];
- setCode = true;
- },
- 'M' => {
- res.message = next[1..];
- setMsg = true;
- },
- 'D' => {
- res.detail = next[1..];
- },
- 'H' => {
- res.hint = next[1..];
- },
- 'P' => {
- res.position = try std.fmt.parseInt(u32, next[1..], 10);
- },
- 'p' => {
- res.internal_position = try std.fmt.parseInt(u32, next[1..], 10);
- },
- 'q' => {
- res.internal_query = next[1..];
- },
- 'W' => {
- res.where = next[1..];
- },
- 's' => {
- res.schema_name = next[1..];
- },
- 't' => {
- res.table_name = next[1..];
- },
- 'c' => {
- res.column_name = next[1..];
- },
- 'd' => {
- res.data_type_name = next[1..];
- },
- 'n' => {
- res.constraint_name = next[1..];
- },
- 'F' => {
- res.file_name = next[1..];
- },
- 'L' => {
- res.line = try std.fmt.parseInt(u32, next[1..], 10);
- },
- 'R' => {
- res.routine = next[1..];
- },
- else => {
- try res.unknown_fields.put(next[0], next[1..]);
- },
+ pub fn read(allocator: std.mem.Allocator, buf: []const u8) !@This() {
+ var res = @This(){
+ .severity = "",
+ .code = "",
+ .message = "",
+ .unknown_fields = HMByteString.init(allocator),
+ .buf = buf,
+ };
+ errdefer res.deinit(allocator);
+ var it = std.mem.splitScalar(u8, res.buf.?, 0);
+ var setSev = false;
+ var setCode = false;
+ var setMsg = false;
+ while (it.next()) |next| {
+ if (next.len < 1) break;
+ switch (next[0]) {
+ 0 => break,
+ 'S' => {
+ res.severity = next[1..];
+ setSev = true;
+ },
+ 'V' => {
+ res.severity_unlocalized = next[1..];
+ },
+ 'C' => {
+ res.code = next[1..];
+ setCode = true;
+ },
+ 'M' => {
+ res.message = next[1..];
+ setMsg = true;
+ },
+ 'D' => {
+ res.detail = next[1..];
+ },
+ 'H' => {
+ res.hint = next[1..];
+ },
+ 'P' => {
+ res.position = try std.fmt.parseInt(u32, next[1..], 10);
+ },
+ 'p' => {
+ res.internal_position = try std.fmt.parseInt(u32, next[1..], 10);
+ },
+ 'q' => {
+ res.internal_query = next[1..];
+ },
+ 'W' => {
+ res.where = next[1..];
+ },
+ 's' => {
+ res.schema_name = next[1..];
+ },
+ 't' => {
+ res.table_name = next[1..];
+ },
+ 'c' => {
+ res.column_name = next[1..];
+ },
+ 'd' => {
+ res.data_type_name = next[1..];
+ },
+ 'n' => {
+ res.constraint_name = next[1..];
+ },
+ 'F' => {
+ res.file_name = next[1..];
+ },
+ 'L' => {
+ res.line = try std.fmt.parseInt(u32, next[1..], 10);
+ },
+ 'R' => {
+ res.routine = next[1..];
+ },
+ else => {
+ try res.unknown_fields.put(next[0], next[1..]);
+ },
+ }
+ }
+ if (!(setSev and setCode and setMsg)) return ProtocolError.MissingField;
+ return res;
}
- }
- if (!(setSev and setCode and setMsg)) return ProtocolError.MissingField;
- return res;
-}
-pub fn write(self: ErrorResponse, allocator: std.mem.Allocator, stream_writer: anytype) !void {
- try stream_writer.writeByte(Tag);
- var al = ByteArrayList.init(allocator);
- defer al.deinit();
- var cw = std.io.countingWriter(al.writer());
- var writer = cw.writer();
- try writer.writeIntBig(u32, 0); // Length placeholder.
+ pub fn write(self: @This(), allocator: std.mem.Allocator, stream_writer: anytype) !void {
+ try stream_writer.writeByte(Tag);
+ var al = ByteArrayList.init(allocator);
+ defer al.deinit();
+ var cw = std.io.countingWriter(al.writer());
+ var writer = cw.writer();
+ try writer.writeIntBig(u32, 0); // Length placeholder.
- try write_field_nt('S', self, "severity", writer);
- if (self.severity_unlocalized) |severity_unlocalized| try write_nt('V', severity_unlocalized, writer);
- try write_field_nt('C', self, "code", writer);
- try write_field_nt('M', self, "message", writer);
- if (self.detail) |detail| try write_nt('D', detail, writer);
- // TODO rest of the fields
+ try write_field_nt('S', self, "severity", writer);
+ if (self.severity_unlocalized) |severity_unlocalized| try write_nt('V', severity_unlocalized, writer);
+ try write_field_nt('C', self, "code", writer);
+ try write_field_nt('M', self, "message", writer);
+ if (self.detail) |detail| try write_nt('D', detail, writer);
+ // TODO rest of the fields
- // replace the length and write it to the actual stream
- std.mem.writeIntBig(u32, al.items[0..4], @as(u32, @intCast(cw.bytes_written)));
- try stream_writer.writeAll(al.items);
-}
-fn write_field_nt(comptime tag: u8, self: ErrorResponse, comptime field: []const u8, writer: anytype) !void {
- try write_nt(tag, @field(self, field), writer);
-}
-fn write_nt(comptime tag: u8, value: []const u8, writer: anytype) !void {
- try writer.writeByte(tag);
- try writer.writeAll(value);
- try writer.writeByte(0);
-}
+ // replace the length and write it to the actual stream
+ std.mem.writeIntBig(u32, al.items[0..4], @as(u32, @intCast(cw.bytes_written)));
+ try stream_writer.writeAll(al.items);
+ }
+ fn write_field_nt(comptime label: u8, self: @This(), comptime field: []const u8, writer: anytype) !void {
+ try write_nt(label, @field(self, field), writer);
+ }
+ fn write_nt(comptime label: u8, value: []const u8, writer: anytype) !void {
+ try writer.writeByte(label);
+ try writer.writeAll(value);
+ try writer.writeByte(0);
+ }
-pub fn deinit(self: *ErrorResponse, allocator: std.mem.Allocator) void {
- self.unknown_fields.deinit();
- if (self.buf != null) allocator.free(self.buf.?);
-}
+ pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void {
+ self.unknown_fields.deinit();
+ if (self.buf != null) allocator.free(self.buf.?);
+ }
-pub fn format(self: ErrorResponse, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
- _ = options;
- _ = fmt;
- try writer.writeAll("ErrorResponse severity [");
- try writer.writeAll(self.severity);
- try writer.writeAll("] ");
- try writer.writeAll("code [");
- try writer.writeAll(self.code);
- try writer.writeAll("] ");
- try writer.writeAll("message [");
- try writer.writeAll(self.message);
- try writer.writeAll("]");
+ pub fn format(self: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
+ _ = options;
+ _ = fmt;
+ try writer.writeAll(@typeName(@TypeOf(@This())));
+ try writer.writeAll(" severity [");
+ try writer.writeAll(self.severity);
+ try writer.writeAll("] ");
+ try writer.writeAll("code [");
+ try writer.writeAll(self.code);
+ try writer.writeAll("] ");
+ try writer.writeAll("message [");
+ try writer.writeAll(self.message);
+ try writer.writeAll("]");
+ }
+ };
}
+
test "round trip" {
+ const ErrorResponse = ErrorNoticeResponse('E');
const allocator = std.testing.allocator;
var sm = ErrorResponse{
.severity = "foo",
@@ -175,7 +180,7 @@ test "round trip" {
var fbs = std.io.fixedBufferStream(bal.items);
var reader = fbs.reader();
const tag = try reader.readByte();
- try std.testing.expectEqual(Tag, tag);
+ try std.testing.expectEqual(ErrorResponse.Tag, tag);
const len = try reader.readIntBig(u32);
const buf = try allocator.alloc(u8, len - 4);
try reader.readNoEof(buf);