diff options
| author | Lucas Faria Mendes <lucas.oliveira1676@etec.sp.gov.br> | 2025-12-05 09:53:37 +0000 |
|---|---|---|
| committer | Lucas Faria Mendes <lucas.oliveira1676@etec.sp.gov.br> | 2025-12-05 09:53:37 +0000 |
| commit | 696362172c20e4e08a412f3412b711d0a78811db (patch) | |
| tree | eaf3dad97bf80e33b38f9336f0d67a37f45df642 | |
| parent | ec53ee2bda1a63b27025601b9b8e4710434207a2 (diff) | |
| download | sqlite-zig-696362172c20e4e08a412f3412b711d0a78811db.tar.gz sqlite-zig-696362172c20e4e08a412f3412b711d0a78811db.zip | |
codecrafters submit [skip ci]
| -rwxr-xr-x | src/main.zig | 54 | ||||
| -rw-r--r-- | src/schema.zig | 83 |
2 files changed, 120 insertions, 17 deletions
diff --git a/src/main.zig b/src/main.zig index c06bd66..4394d13 100755 --- a/src/main.zig +++ b/src/main.zig @@ -38,23 +38,22 @@ pub fn main() !void { } else if (std.mem.eql(u8, args[2], ".tables")) { try tables.showTables(allocator, &file, page_size, stdout); } else if (std.mem.startsWith(u8, args[2], "SELECT") or std.mem.startsWith(u8, args[2], "select")) { - // Parse SELECT query: "SELECT column FROM table" - var tokens = std.mem.tokenizeScalar(u8, args[2], ' '); - - // Skip "SELECT" - _ = tokens.next(); + // Parse SELECT query + // Find "FROM" or "from" keyword + const from_idx_upper = std.mem.indexOf(u8, args[2], "FROM"); + const from_idx_lower = std.mem.indexOf(u8, args[2], "from"); + const from_idx = from_idx_upper orelse from_idx_lower orelse return error.InvalidQuery; - // Get column name or aggregate function - const column_name = tokens.next() orelse return error.InvalidQuery; + // Extract column part (between SELECT and FROM) + const select_len: usize = 6; // length of "SELECT" or "select" + const column_part = std.mem.trim(u8, args[2][select_len..from_idx], " \t\n"); - // Skip "FROM" or "from" - _ = tokens.next(); - - // Get table name - const table_name = tokens.next() orelse return error.InvalidQuery; + // Extract table name (after FROM) + const from_end = from_idx + 4; // length of "FROM" + const table_name = std.mem.trim(u8, args[2][from_end..], " \t\n"); // Check if this is COUNT(*) - if (std.mem.indexOf(u8, column_name, "count(") != null or std.mem.indexOf(u8, column_name, "COUNT(") != null) { + if (std.mem.indexOf(u8, column_part, "count(") != null or std.mem.indexOf(u8, column_part, "COUNT(") != null) { const rootpage = try schema.getRootpage(allocator, &file, page_size, table_name); const row_count = try schema.countRows(allocator, &file, page_size, rootpage); try stdout.print("{}\n", .{row_count}); @@ -63,14 +62,35 @@ pub fn main() !void { const create_sql = try schema.getCreateTableSQL(allocator, &file, page_size, table_name); defer allocator.free(create_sql); - // Find the column index - const column_idx = try schema.parseColumnIndex(create_sql, column_name); + // Parse column names (split by comma) + var column_list = std.ArrayList([]const u8){}; + defer column_list.deinit(allocator); + + var col_tokens = std.mem.tokenizeScalar(u8, column_part, ','); + while (col_tokens.next()) |col| { + const trimmed = std.mem.trim(u8, col, " \t\n"); + try column_list.append(allocator, trimmed); + } // Get the table's root page const rootpage = try schema.getRootpage(allocator, &file, page_size, table_name); - // Read and print all rows - try schema.readTableRows(allocator, &file, page_size, rootpage, column_idx, stdout); + if (column_list.items.len == 1) { + // Single column query + const column_idx = try schema.parseColumnIndex(create_sql, column_list.items[0]); + try schema.readTableRows(allocator, &file, page_size, rootpage, column_idx, stdout); + } else { + // Multiple column query + var column_indices = std.ArrayList(usize){}; + defer column_indices.deinit(allocator); + + for (column_list.items) |col_name| { + const idx = try schema.parseColumnIndex(create_sql, col_name); + try column_indices.append(allocator, idx); + } + + try schema.readTableRowsMultiColumn(allocator, &file, page_size, rootpage, column_indices.items, stdout); + } } } else { var tokens = std.mem.tokenizeScalar(u8, args[2], ' '); diff --git a/src/schema.zig b/src/schema.zig index ccfc9e0..5a6d60b 100644 --- a/src/schema.zig +++ b/src/schema.zig @@ -290,3 +290,86 @@ pub fn readTableRows(allocator: std.mem.Allocator, file: *std.fs.File, page_size } } } + +pub fn readTableRowsMultiColumn(allocator: std.mem.Allocator, file: *std.fs.File, page_size: u16, rootpage: u32, column_indices: []const usize, stdout: anytype) !void { + if (rootpage == 0) return; + + const page_offset = (rootpage - 1) * @as(u64, page_size); + var page_data = try allocator.alloc(u8, page_size); + defer allocator.free(page_data); + + _ = try file.seekTo(page_offset); + _ = try file.read(page_data); + + const page_type = page_data[0]; + if (page_type != 0x0d) return; + + const num_cells = std.mem.readInt(u16, page_data[3..5], .big); + + var cell_pointers = try allocator.alloc(u16, num_cells); + defer allocator.free(cell_pointers); + + for (0..num_cells) |i| { + const offset = 8 + i * 2; + const cell_ptr_bytes = page_data[offset .. offset + 2]; + cell_pointers[i] = std.mem.readInt(u16, cell_ptr_bytes[0..2], .big); + } + + for (0..num_cells) |i| { + const cell_data = page_data[cell_pointers[i]..]; + + var parsed = varint.parse(cell_data); + var pos = parsed.len; + + parsed = varint.parse(cell_data[pos..]); + pos += parsed.len; + + const record_data = cell_data[pos..]; + parsed = varint.parse(record_data); + const header_size = parsed.value; + var header_pos = parsed.len; + + var serial_types = std.ArrayList(u64){}; + defer serial_types.deinit(allocator); + + while (header_pos < header_size) { + parsed = varint.parse(record_data[header_pos..]); + try serial_types.append(allocator, parsed.value); + header_pos += parsed.len; + } + + // For each requested column + for (column_indices, 0..) |column_idx, col_num| { + // Calculate position for this column + var body_pos: usize = header_size; + for (0..column_idx) |col| { + if (col >= serial_types.items.len) break; + const st = serial_types.items[col]; + if (st >= 13 and (st % 2) == 1) { + body_pos += (st - 13) / 2; + } else if (st >= 1 and st <= 6) { + const int_result = record.readInt(record_data[body_pos..], st); + body_pos += int_result.len; + } + } + + // Print separator if not first column + if (col_num > 0) { + try stdout.print("|", .{}); + } + + // Read and print the column value + if (column_idx < serial_types.items.len) { + const st = serial_types.items[column_idx]; + if (st >= 13 and (st % 2) == 1) { + const str_result = record.readString(record_data[body_pos..], st); + try stdout.print("{s}", .{str_result.value}); + } else if (st >= 1 and st <= 6) { + const int_result = record.readInt(record_data[body_pos..], st); + try stdout.print("{}", .{int_result.value}); + } + } + } + try stdout.print("\n", .{}); + } +} |