From 339e1d1e2509375a93e7dd3dedc7e4245229b48d Mon Sep 17 00:00:00 2001 From: Lucas Faria Mendes Date: Fri, 5 Dec 2025 06:09:50 -0300 Subject: codecrafters submit [skip ci] --- src/main.zig | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) (limited to 'src/main.zig') diff --git a/src/main.zig b/src/main.zig index 6dbb671..cccdf44 100755 --- a/src/main.zig +++ b/src/main.zig @@ -3,6 +3,30 @@ var stdout_buffer: [1024]u8 = undefined; var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer); const stdout = &stdout_writer.interface; +fn parseVarint(data: []const u8) struct { value: u64, len: usize } { + var result: u64 = 0; + var i: usize = 0; + + while (i < data.len and i < 9) : (i += 1) { + const byte = data[i]; + result |= @as(u64, byte & 0x7f) << @as(u6, @intCast(i * 7)); + + if ((byte & 0x80) == 0) { + return .{ .value = result, .len = i + 1 }; + } + } + + return .{ .value = result, .len = i }; +} + +fn readStringFromRecord(data: []const u8, serial_type: u64) struct { value: []const u8, len: usize } { + if (serial_type >= 13 and (serial_type % 2) == 1) { + const size = (serial_type - 13) / 2; + return .{ .value = data[0..size], .len = size }; + } + return .{ .value = "", .len = 0 }; +} + pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); @@ -34,5 +58,91 @@ pub fn main() !void { const num_tables = std.mem.readInt(u16, &buf, .big); try stdout.print("number of tables: {}\n", .{num_tables}); try stdout.flush(); + } else if (std.mem.eql(u8, command, ".tables")) { + var file = try std.fs.cwd().openFile(database_file_path, .{}); + defer file.close(); + + var buf: [2]u8 = undefined; + _ = try file.seekTo(16); + _ = try file.read(&buf); + const page_size = std.mem.readInt(u16, &buf, .big); + + _ = try file.seekTo(103); + _ = try file.read(&buf); + const num_cells = std.mem.readInt(u16, &buf, .big); + + var cell_pointers = try allocator.alloc(u16, num_cells); + defer allocator.free(cell_pointers); + + for (0..num_cells) |i| { + _ = try file.seekTo(108 + i * 2); + _ = try file.read(&buf); + cell_pointers[i] = std.mem.readInt(u16, &buf, .big); + } + + var page_data = try allocator.alloc(u8, page_size); + defer allocator.free(page_data); + + _ = try file.seekTo(0); + _ = try file.read(page_data); + + var first_table = true; + + for (0..num_cells) |i| { + const cell_offset = cell_pointers[i]; + const cell_data = page_data[cell_offset..]; + + var parsed = parseVarint(cell_data); + var pos = parsed.len; + + parsed = parseVarint(cell_data[pos..]); + pos += parsed.len; + + const record_start = pos; + const record_data = cell_data[record_start..]; + + parsed = parseVarint(record_data); + const header_size = parsed.value; + var header_pos = parsed.len; + + var serial_types: [5]u64 = undefined; + for (0..5) |col| { + parsed = parseVarint(record_data[header_pos..]); + serial_types[col] = parsed.value; + header_pos += parsed.len; + } + + var body_pos: usize = header_size; + + for (0..2) |col| { + const serial_type = serial_types[col]; + if (serial_type >= 13 and (serial_type % 2) == 1) { + const size = (serial_type - 13) / 2; + body_pos += size; + } + } + + const tbl_name_type = serial_types[2]; + const tbl_name = readStringFromRecord(record_data[body_pos..], tbl_name_type); + + const body_pos_type: usize = header_size; + const type_serial = serial_types[0]; + const type_str = readStringFromRecord(record_data[body_pos_type..], type_serial); + + if (std.mem.eql(u8, type_str.value, "table")) { + if (!std.mem.eql(u8, tbl_name.value, "sqlite_sequence")) { + if (!first_table) { + try stdout.print(" ", .{}); + } + try stdout.print("{s}", .{tbl_name.value}); + first_table = false; + } + } + } + + if (!first_table) { + try stdout.print("\n", .{}); + } + try stdout.flush(); } } -- cgit v1.2.3