tiny.sql.Relation
Defined in relation.
API (23)
Actions
Public operations.
applyEditsapplyEditsIndeletegetgetIntoindexRangeindexScanlastRowIdlookupopenputputEncodedreaderscanscanProjectedsummarizeupdatevalidateIndexesvalueLength
Fields and members
Public fields and members.
Source
Source: lib/sql/src/relation.zig:247
zig
pub const Relation = struct { space: space_mod.Space, table: table_mod.Table, indexes: [max_indexes]Indexed = undefined, index_count: usize, pub fn open(space: *const space_mod.Space, options: Options) Error!Relation { if (options.indexes.len > max_indexes) return error.TooManyIndexes; var relation = Relation{ .space = space.*, .table = try space.rowidTable(options.table_root), .index_count = options.indexes.len, }; for (options.indexes, 0..) |spec, offset| { if (spec.fields.len > max_index_fields) return error.TooManyIndexFields; relation.indexes[offset] = .{ .index = try space.index(spec.root_page, spec.columns), .fields = spec.fields, }; } return relation; } pub fn reader(self: *const Relation, snapshot: file.Snapshot) Error!Reader { const opened_space = try self.space.reader(snapshot); var opened = Reader{ .space = opened_space, .table = try opened_space.rowidTable(self.table.rows.root_page), .index_count = self.index_count, }; for (0..self.index_count) |offset| { opened.indexes[offset] = .{ .index = try opened_space.index( self.indexes[offset].index.entries.root_page, self.indexes[offset].index.columns, ), .fields = self.indexes[offset].fields, }; } return opened; } pub fn put(self: *Relation, allocator: Allocator, rowid: i64, values: []const row.Value, options: file.CommitOptions) Error!file.Commit { const phase = trace.scope("relation.put"); defer phase.end(); const bytes = try allocator.alloc(u8, try row.encodedSize(values)); defer allocator.free(bytes); const encoded = try row.encode(bytes, values); return try self.applyEdits(allocator, &.{.{ .put = .{ .rowid = rowid, .bytes = encoded, } }}, options); } pub fn putEncoded(self: *Relation, allocator: Allocator, rowid: i64, bytes: []const u8, options: file.CommitOptions) Error!file.Commit { const phase = trace.scope("relation.put_encoded"); defer phase.end(); return try self.applyEdits(allocator, &.{.{ .put = .{ .rowid = rowid, .bytes = bytes, } }}, options); } pub fn update(self: *Relation, allocator: Allocator, rowid: i64, assignments: []const Edit.Assignment, options: file.CommitOptions) Error!file.Commit { const phase = trace.scope("relation.update"); defer phase.end(); return try self.applyEdits(allocator, &.{.{ .update = .{ .rowid = rowid, .assignments = assignments, } }}, options); } pub fn delete(self: *Relation, allocator: Allocator, rowid: i64, options: file.CommitOptions) Error!file.Commit { const phase = trace.scope("relation.delete"); defer phase.end(); return try self.applyEdits(allocator, &.{.{ .delete = rowid }}, options); } pub fn applyEdits(self: *Relation, allocator: Allocator, edits: []const Edit, options: file.CommitOptions) Error!file.Commit { const phase = trace.scope("relation.apply_edits"); defer phase.end(); var write = try self.space.beginWrite(); defer write.deinit(); try self.applyEditsIn(allocator, &write, edits); return try write.commit(options); } pub fn applyEditsIn( self: *Relation, allocator: Allocator, write: *tree.Write, edits: []const Edit, ) Error!void { const phase = trace.scope("relation.apply_edits_in"); defer phase.end(); try write.claimBatch(self.table.rows.root_page); var states: std.AutoArrayHashMapUnmanaged(i64, AppliedEdit) = .empty; defer { for (states.values()) |*state| state.deinit(allocator); states.deinit(allocator); } const base_reader = try self.reader(write.snapshot); for (edits) |edit| { try accumulateEdit(allocator, &base_reader, &states, edit); } for (states.values()) |state| try self.applyEditStateIn(write, state); } pub fn lastRowId(self: *const Relation) Error!?i64 { var read = try self.space.database.beginRead(); defer read.deinit(); const opened = try self.reader(read.snapshot()); return try opened.lastRowId(); } pub fn get(self: *const Relation, allocator: Allocator, rowid: i64) Error!?[]u8 { var read = try self.space.database.beginRead(); defer read.deinit(); const opened = try self.reader(read.snapshot()); return try opened.get(allocator, rowid); } pub fn valueLength(self: *const Relation, rowid: i64) Error!?usize { var read = try self.space.database.beginRead(); defer read.deinit(); const opened = try self.reader(read.snapshot()); return try opened.valueLength(rowid); } pub fn getInto(self: *const Relation, rowid: i64, target: []u8) Error!?[]u8 { var read = try self.space.database.beginRead(); defer read.deinit(); const opened = try self.reader(read.snapshot()); return try opened.getInto(rowid, target); } pub fn scan( self: *const Relation, target: *Scan, allocator: Allocator, start: ?i64, end: ?i64, ) Error!void { var read = try self.space.database.beginRead(); defer read.deinit(); const opened = try self.reader(read.snapshot()); try opened.scan(target, allocator, start, end); } pub fn scanProjected( self: *const Relation, target: *Scan, allocator: Allocator, start: ?i64, end: ?i64, projection: table_mod.Projection, ) Error!void { var read = try self.space.database.beginRead(); defer read.deinit(); const opened = try self.reader(read.snapshot()); try opened.scanProjected(target, allocator, start, end, projection); } pub fn lookup( self: *const Relation, target: *index_mod.Scan, allocator: Allocator, index_slot: usize, prefix: []const row.Value, ) Error!void { var read = try self.space.database.beginRead(); defer read.deinit(); const opened = try self.reader(read.snapshot()); try opened.lookup(target, allocator, index_slot, prefix); } pub fn indexScan( self: *const Relation, target: *index_mod.Scan, allocator: Allocator, index_slot: usize, start: ?[]const row.Value, end: ?[]const row.Value, ) Error!void { var read = try self.space.database.beginRead(); defer read.deinit(); const opened = try self.reader(read.snapshot()); try opened.indexScan(target, allocator, index_slot, start, end); } pub fn indexRange( self: *const Relation, target: *index_mod.Scan, allocator: Allocator, index_slot: usize, start: ?index_mod.Bound, end: ?index_mod.Bound, ) Error!void { var read = try self.space.database.beginRead(); defer read.deinit(); const opened = try self.reader(read.snapshot()); try opened.indexRange(target, allocator, index_slot, start, end); } pub fn summarize(self: *const Relation) Error!Summary { var read = try self.space.database.beginRead(); defer read.deinit(); const opened = try self.reader(read.snapshot()); return try opened.summarize(); } pub fn validateIndexes(self: *const Relation, allocator: Allocator) Error!void { const phase = trace.scope("relation.validate_indexes"); defer phase.end(); var table_scan: Scan = undefined; try self.scan(&table_scan, allocator, null, null); defer table_scan.deinit(); while (try table_scan.next()) |entry| { const view = try entry.view(); var index_offset: usize = 0; while (index_offset < self.index_count) : (index_offset += 1) { const indexed = &self.indexes[index_offset]; var projected: [max_index_fields]row.Value = undefined; const values = try projectView(view, indexed.fields, &projected); if (!try indexContainsRowid(allocator, &indexed.index, values, entry.rowid)) return error.SecondaryIndexCorrupt; } } var index_offset: usize = 0; while (index_offset < self.index_count) : (index_offset += 1) { const indexed = &self.indexes[index_offset]; var index_scan: index_mod.Scan = undefined; try indexed.index.scan(&index_scan, allocator, null, null); defer index_scan.deinit(); while (try index_scan.next()) |entry| { const bytes = (try self.table.get(allocator, entry.rowid)) orelse return error.SecondaryIndexCorrupt; defer allocator.free(bytes); const view = try row.View.init(bytes); var projected: [max_index_fields]row.Value = undefined; const values = try projectView(view, indexed.fields, &projected); var decoded_values: [max_index_fields]row.Value = undefined; var scratch: [page.size]u8 = undefined; const decoded = try key.decodeIndex(decoded_values[0..], scratch[0..], entry.key); const valid = decoded.rowid == entry.rowid and valuesEqual(values, decoded.values, indexed.index.columns); if (!valid) return error.SecondaryIndexCorrupt; } } } fn putViewIndexesIn(self: *Relation, write: *tree.Write, rowid: i64, view: row.View) Error!void { var offset: usize = 0; while (offset < self.index_count) : (offset += 1) { var projected: [max_index_fields]row.Value = undefined; const indexed = try projectView(view, self.indexes[offset].fields, &projected); try self.indexes[offset].index.putIn(write, rowid, indexed); } } fn deleteIndexesIn(self: *Relation, write: *tree.Write, rowid: i64, view: row.View) Error!void { var offset: usize = 0; while (offset < self.index_count) : (offset += 1) { var projected: [max_index_fields]row.Value = undefined; const indexed = try projectView(view, self.indexes[offset].fields, &projected); try self.indexes[offset].index.deleteIn(write, rowid, indexed); } } fn accumulateEdit( allocator: Allocator, base_reader: *const Reader, states: *std.AutoArrayHashMapUnmanaged(i64, AppliedEdit), edit: Edit, ) Error!void { const state = try appliedEdit( allocator, base_reader, states, editRowid(edit), ); switch (edit) { .put => |put_edit| { _ = try row.View.init(put_edit.bytes); state.current = put_edit.bytes; }, .update => |update_edit| { const current = state.current orelse return error.KeyNotFound; state.adoptMerged(allocator, try applyUpdate(allocator, current, update_edit.assignments)); }, .delete => { if (state.current == null) return error.KeyNotFound; state.current = null; }, } } fn appliedEdit( allocator: Allocator, base_reader: *const Reader, states: *std.AutoArrayHashMapUnmanaged(i64, AppliedEdit), rowid: i64, ) Error!*AppliedEdit { if (states.getPtr(rowid)) |state| return state; const base = try base_reader.get(allocator, rowid); errdefer if (base) |bytes| allocator.free(bytes); try states.putNoClobber(allocator, rowid, .{ .rowid = rowid, .base = base, .current = if (base) |bytes| bytes else null, }); return states.getPtr(rowid).?; } fn applyEditStateIn(self: *Relation, write: *tree.Write, state: AppliedEdit) Error!void { if (state.base) |base| { if (state.current) |current| { if (std.mem.eql(u8, base, current)) return; try self.deleteIndexesIn(write, state.rowid, try row.View.init(base)); try self.table.putEncodedIn(write, state.rowid, current); try self.putViewIndexesIn(write, state.rowid, try row.View.init(current)); } else { try self.deleteIndexesIn(write, state.rowid, try row.View.init(base)); try self.table.deleteIn(write, state.rowid); } } else if (state.current) |current| { try self.table.putEncodedIn(write, state.rowid, current); try self.putViewIndexesIn(write, state.rowid, try row.View.init(current)); } }};Source: lib/sql/src/root.zig:237
zig
pub const Relation = relation.Relation;Complete caller list for Relation.open
13 direct callers.
lib.sql.src.catalog.openPlannedRelation[function] — private source atlib/sql/src/catalog.zig:1593in nearest public ownertiny.sql.cataloglib.sql.src.relation.test_relation_applies_edit_batches_to_table_and_secondary_indexes[function] — test source atlib/sql/src/relation.zig:759in nearest public ownertiny.sql.relationlib.sql.src.relation.test_relation_applies_update_edits_within_batches[function] — test source atlib/sql/src/relation.zig:904in nearest public ownertiny.sql.relationlib.sql.src.relation.test_relation_delete_removes_table_row_and_secondary_index_entry[function] — test source atlib/sql/src/relation.zig:731in nearest public ownertiny.sql.relationlib.sql.src.relation.test_relation_maintains_secondary_index_through_replace_and_reopen[function] — test source atlib/sql/src/relation.zig:682in nearest public ownertiny.sql.relationlib.sql.src.relation.test_relation_put_accepts_rows_larger_than_a_page[function] — test source atlib/sql/src/relation.zig:1073in nearest public ownertiny.sql.relationlib.sql.src.relation.test_relation_reader_scans_and_looks_up_one_fixed_snapshot[function] — test source atlib/sql/src/relation.zig:618in nearest public ownertiny.sql.relationlib.sql.src.relation.test_relation_rejects_an_index_key_larger_than_a_page_and_stays_writable[function] — test source atlib/sql/src/relation.zig:1028in nearest public ownertiny.sql.relationlib.sql.src.relation.test_relation_rejects_mismatched_secondary_index_entries[function] — test source atlib/sql/src/relation.zig:988in nearest public ownertiny.sql.relationlib.sql.src.relation.test_relation_rejects_orphaned_secondary_index_entries[function] — test source atlib/sql/src/relation.zig:968in nearest public ownertiny.sql.relationlib.sql.src.relation.test_relation_update_merges_assigned_columns_and_maintains_secondary_index[function] — test source atlib/sql/src/relation.zig:843in nearest public ownertiny.sql.relationlib.sql.src.relation.test_relation_update_requires_an_existing_row_and_known_columns[function] — test source atlib/sql/src/relation.zig:879in nearest public ownertiny.sql.relationlib.sql.src.relation.test_relation_validates_secondary_indexes_against_table_rows[function] — test source atlib/sql/src/relation.zig:946in nearest public ownertiny.sql.relation
Complete caller list for Relation.reader
11 direct callers.
tiny.sql.Relation.applyEditsIn[method] atlib/sql/src/relation.zig:339tiny.sql.Relation.get[method] atlib/sql/src/relation.zig:369tiny.sql.Relation.getInto[method] atlib/sql/src/relation.zig:383tiny.sql.Relation.indexRange[method] atlib/sql/src/relation.zig:444tiny.sql.Relation.indexScan[method] atlib/sql/src/relation.zig:430tiny.sql.Relation.lastRowId[method] atlib/sql/src/relation.zig:362tiny.sql.Relation.lookup[method] atlib/sql/src/relation.zig:417tiny.sql.Relation.scan[method] atlib/sql/src/relation.zig:390tiny.sql.Relation.scanProjected[method] atlib/sql/src/relation.zig:403tiny.sql.Relation.summarize[method] atlib/sql/src/relation.zig:458tiny.sql.Relation.valueLength[method] atlib/sql/src/relation.zig:376
Audit
| Definitions | 20 |
|---|---|
| Public names | 40 |
| Members | 4 |
| Version | 26.7.0 |
| Revision | daab053ee433 |