const std = @import("std"); const heap = std.heap; const InputBuffer = struct { buffer: [*]u8, buffer_length: usize, input_length: usize }; var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); const MetaCommandError = error{UNRECOGNIZED_COMMAND}; const PrepareResultError = error{ UNRECOGNIZED_STATEMENT, SYNTAX_ERROR }; const COLUMN_USERNAME_SIZE = 32; const COLUMN_EMAIL_SIZE = 255; const Row = struct { id: i16, username: [COLUMN_USERNAME_SIZE]u8, email: [COLUMN_EMAIL_SIZE]u8 }; var Table: [8]Row = undefined; const StatementType = enum { INSERT, SELECT }; const Statement = struct { type: StatementType, data_to_insert: [*]anyopaque, data_inserted: usize = 0 }; pub fn new_input_buffer() !*InputBuffer { const input_buffers = try allocator.alloc(InputBuffer, 1); const input_buffer = &input_buffers[0]; input_buffer.buffer = undefined; input_buffer.buffer_length = 0; input_buffer.input_length = 0; return input_buffer; } pub fn main() !void { // DEBUG: Temporary data before insert is implemented Table[0] = Row{ .id = 1, .username = undefined, .email = undefined }; std.mem.copyForwards(u8, &Table[0].username, "example"); std.mem.copyForwards(u8, &Table[0].email, "example@gml.com"); // END DEBUG const input_buffer: *InputBuffer = try new_input_buffer(); // defer std.heap.page_allocator.free(input_buffer); const stdout_file = std.io.getStdOut().writer(); var bw = std.io.bufferedWriter(stdout_file); const stdout = bw.writer(); _ = stdout; // autofix while (true) { print_prompt(); try read_input(input_buffer); const command = input_buffer.buffer[0 .. input_buffer.buffer_length - 1]; if (input_buffer.buffer[0] == '.') { do_meta_command(command) catch |err| { switch (err) { MetaCommandError.UNRECOGNIZED_COMMAND => { std.debug.print("Unrecognized command {s}\n", .{input_buffer.buffer[0 .. input_buffer.buffer_length - 1]}); continue; }, } }; } var statement: Statement = (try allocator.alloc(Statement, 1))[0]; prepare_statement(input_buffer.*, &statement) catch |err| { switch (err) { PrepareResultError.UNRECOGNIZED_STATEMENT => { std.debug.print("Unrecognized keyword at start of {s}\n", .{command}); continue; }, PrepareResultError.SYNTAX_ERROR => { std.debug.print("Unrecognized syntax near {s}\n", .{command}); continue; }, } }; execute_statement(&statement); } } pub fn print_prompt() void { std.debug.print("db > ", .{}); } pub fn read_input(input_buffer: *InputBuffer) !void { const stdin = std.io.getStdIn().reader(); const tempInput = try allocator.alloc(u8, 256); if (stdin.read(tempInput)) |input_size| { input_buffer.buffer_length = input_size; input_buffer.buffer = tempInput.ptr; input_buffer.input_length = input_buffer.buffer_length - 1; input_buffer.buffer[input_buffer.buffer_length - 1] = 0; } else |err| { return err; } } pub fn close_input_buffer(input_buffer: *InputBuffer) void { allocator.free(input_buffer); } pub fn do_meta_command(command: []u8) MetaCommandError!void { if (std.mem.eql(u8, command, ".exit")) { std.os.exit(0); return; } else { return MetaCommandError.UNRECOGNIZED_COMMAND; } } pub fn prepare_statement(input_buffer: InputBuffer, statement: *Statement) PrepareResultError!void { if (std.mem.eql(u8, input_buffer.buffer[0..6], "insert")) { statement.type = StatementType.INSERT; var data = std.mem.split(u8, input_buffer.buffer[7 .. input_buffer.buffer_length - 1], " "); while (data.next()) |field| { statement.data_to_insert[statement.data_inserted] = &field; statement.data_inserted += 1; } return; } if (std.mem.eql(u8, input_buffer.buffer[0..6], "select")) { statement.type = StatementType.SELECT; return; } return PrepareResultError.UNRECOGNIZED_STATEMENT; } pub fn execute_statement(statement: *Statement) void { switch (statement.type) { StatementType.INSERT => {}, StatementType.SELECT => { select_all(); }, } } pub fn select_all() void { std.debug.print("id | username | email\n", .{}); for (Table) |rowItem| { if (rowItem.id == 0) return; std.debug.print("{} {s} {s}\n", .{ rowItem.id, rowItem.username[0..], rowItem.email[0..] }); } } pub fn insert() !void {}