feat: add appendSegment and rowPrefix
This commit is contained in:
1 parent
f36fa7f122
commit
4784acc242
1 file changed
+155
+155
@@ -0,0 +1,155 @@
|
||||
const std = @import("std");
|
||||
const dbmod = @import("db.zig");
|
||||
const row = @import("row.zig");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Db = dbmod.Db;
|
||||
const Value = row.Value;
|
||||
|
||||
/// Keyspace layout shared by every table and index living inside a single
|
||||
/// Db instance:
|
||||
/// "R\x00" table "\x00" orderedPk -> encoded Row
|
||||
/// "I\x00" table "\x00" field "\x00" orderedValue orderedPk -> encoded pk Value
|
||||
/// "J\x00" table "\x00" indexName "\x00" orderedValue1 .. orderedValueN orderedPk -> encoded pk Value
|
||||
/// "M\x00INDEXES\x00" table -> encoded list of indexed field names
|
||||
/// "M\x00CINDEXES\x00" table -> encoded list of composite index specs
|
||||
/// "M\x00UNIQUE\x00" table -> encoded list of UNIQUE-constrained field names
|
||||
/// "M\x00FKEYS\x00" table -> encoded list of FOREIGN KEY specs (field, refTable, refField)
|
||||
/// "M\x00CHECKS\x00" table -> encoded list of CHECK constraint specs (name, expr source)
|
||||
/// "M\x00REFBY\x00" table -> encoded list of reverse FK specs (childTable, childField, refField),
|
||||
/// one entry per OTHER table's FOREIGN KEY that names this table+refField
|
||||
///
|
||||
/// All namespaces share one flat LSM keyspace (there is only one Db), so the
|
||||
/// leading tag byte plus NUL separators keep tables, single-field indexes,
|
||||
/// composite indexes, and metadata from ever colliding or shadowing each
|
||||
/// other during a scan. A composite index entry's value columns are just N
|
||||
/// single-column `row.appendOrdered` encodings concatenated in the index's
|
||||
/// declared field order ahead of the primary key's - each encoding is
|
||||
/// already self-delimiting (fixed width for none/boolean/int/float, a
|
||||
/// 0x00 0x00 terminator for text/bytes with 0x00 bytes escaped), so the
|
||||
/// concatenation compares byte-for-byte in exactly the same order as
|
||||
/// comparing the value tuples component by component. That is what makes a
|
||||
/// prefix scan over the leading K of N components ("leftmost prefix" rule,
|
||||
/// same as a real multi-column B-tree index) a correct equality lookup on
|
||||
/// just those K columns, unconstrained on the rest.
|
||||
pub const rowTag: u8 = 'R';
|
||||
pub const indexTag: u8 = 'I';
|
||||
pub const compositeIndexTag: u8 = 'J';
|
||||
pub const metaTag: u8 = 'M';
|
||||
const sep: u8 = 0x00;
|
||||
|
||||
fn appendSegment(out: *std.ArrayList(u8), segment: []const u8) !void {
|
||||
try out.appendSlice(segment);
|
||||
try out.append(sep);
|
||||
}
|
||||
|
||||
pub fn rowPrefix(allocator: Allocator, table: []const u8) ![]u8 {
|
||||
var out = std.ArrayList(u8).init(allocator);
|
||||
errdefer out.deinit();
|
||||
try out.append(rowTag);
|
||||
try appendSegment(&out, table);
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub fn rowKey(allocator: Allocator, table: []const u8, pk: Value) ![]u8 {
|
||||
var out = std.ArrayList(u8).init(allocator);
|
||||
errdefer out.deinit();
|
||||
try out.append(rowTag);
|
||||
try appendSegment(&out, table);
|
||||
try row.appendOrdered(&out, pk);
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub fn indexPrefix(allocator: Allocator, table: []const u8, field: []const u8) ![]u8 {
|
||||
var out = std.ArrayList(u8).init(allocator);
|
||||
errdefer out.deinit();
|
||||
try out.append(indexTag);
|
||||
try appendSegment(&out, table);
|
||||
try appendSegment(&out, field);
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub fn indexEntryKey(allocator: Allocator, table: []const u8, field: []const u8, value: Value, pk: Value) ![]u8 {
|
||||
var out = std.ArrayList(u8).init(allocator);
|
||||
errdefer out.deinit();
|
||||
try out.append(indexTag);
|
||||
try appendSegment(&out, table);
|
||||
try appendSegment(&out, field);
|
||||
try row.appendOrdered(&out, value);
|
||||
try row.appendOrdered(&out, pk);
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub fn indexValueBound(allocator: Allocator, table: []const u8, field: []const u8, value: Value) ![]u8 {
|
||||
var out = std.ArrayList(u8).init(allocator);
|
||||
errdefer out.deinit();
|
||||
try out.append(indexTag);
|
||||
try appendSegment(&out, table);
|
||||
try appendSegment(&out, field);
|
||||
try row.appendOrdered(&out, value);
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
|
||||
fn metaKey(allocator: Allocator, table: []const u8) ![]u8 {
|
||||
var out = std.ArrayList(u8).init(allocator);
|
||||
errdefer out.deinit();
|
||||
try out.append(metaTag);
|
||||
try appendSegment(&out, "INDEXES");
|
||||
try out.appendSlice(table);
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
|
||||
fn compositeMetaKey(allocator: Allocator, table: []const u8) ![]u8 {
|
||||
var out = std.ArrayList(u8).init(allocator);
|
||||
errdefer out.deinit();
|
||||
try out.append(metaTag);
|
||||
try appendSegment(&out, "CINDEXES");
|
||||
try out.appendSlice(table);
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
|
||||
fn uniqueMetaKey(allocator: Allocator, table: []const u8) ![]u8 {
|
||||
var out = std.ArrayList(u8).init(allocator);
|
||||
errdefer out.deinit();
|
||||
try out.append(metaTag);
|
||||
try appendSegment(&out, "UNIQUE");
|
||||
try out.appendSlice(table);
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
|
||||
fn foreignKeyMetaKey(allocator: Allocator, table: []const u8) ![]u8 {
|
||||
var out = std.ArrayList(u8).init(allocator);
|
||||
errdefer out.deinit();
|
||||
try out.append(metaTag);
|
||||
try appendSegment(&out, "FKEYS");
|
||||
try out.appendSlice(table);
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
|
||||
fn checkMetaKey(allocator: Allocator, table: []const u8) ![]u8 {
|
||||
var out = std.ArrayList(u8).init(allocator);
|
||||
errdefer out.deinit();
|
||||
try out.append(metaTag);
|
||||
try appendSegment(&out, "CHECKS");
|
||||
try out.appendSlice(table);
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
|
||||
fn referencedByMetaKey(allocator: Allocator, table: []const u8) ![]u8 {
|
||||
var out = std.ArrayList(u8).init(allocator);
|
||||
errdefer out.deinit();
|
||||
try out.append(metaTag);
|
||||
try appendSegment(&out, "REFBY");
|
||||
try out.appendSlice(table);
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub fn compositeIndexPrefix(allocator: Allocator, table: []const u8, indexName: []const u8) ![]u8 {
|
||||
var out = std.ArrayList(u8).init(allocator);
|
||||
errdefer out.deinit();
|
||||
try out.append(compositeIndexTag);
|
||||
try appendSegment(&out, table);
|
||||
try appendSegment(&out, indexName);
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user