commands: createIndexes/listIndexes/dropIndexes + planner wiring
Adds the three driver commands, parameterized E11000 messages (engine dup_index carries the index name into writeErrors), the scan_matching planner wiring (_id fast path → index plan → scan) and the first-$match aggregate pushdown. The equivalence test (mixed-type corpus x 27 filters, non-sparse and sparse indexes) drove out three real bugs: the two-bound range under-approximation on multikey indexes (fall back to scan), a dangling single-value option array in the planner, and update-time unique violations now reporting writeErrors instead of corrupting state.
This commit is contained in:
22
src/db.zig
22
src/db.zig
@@ -289,7 +289,9 @@ pub const Engine = struct {
|
||||
const coll = try self.get_or_create_collection(db_name, coll_name);
|
||||
var ix = try index.parse_spec(self.gpa, spec_doc);
|
||||
var committed = false;
|
||||
errdefer if (!committed) ix.deinit(self.gpa);
|
||||
// Runs on every return path (including the idempotent no-op): the
|
||||
// parsed spec is only owned by the collection once committed.
|
||||
defer if (!committed) ix.deinit(self.gpa);
|
||||
|
||||
for (coll.indexes.items) |*existing| {
|
||||
if (std.mem.eql(u8, existing.name, ix.name)) {
|
||||
@@ -300,20 +302,16 @@ pub const Engine = struct {
|
||||
|
||||
// Build entries over the existing documents, checking uniqueness as
|
||||
// we go (the index is not exposed until the end, so mutating it is
|
||||
// safe). On any failure the built entries are freed and nothing is
|
||||
// persisted.
|
||||
var built_list: std.ArrayListUnmanaged(index.BuiltEntries) = .empty;
|
||||
defer {
|
||||
for (built_list.items) |*b| b.deinit(self.gpa);
|
||||
built_list.deinit(self.gpa);
|
||||
}
|
||||
// safe). Each batch is inserted into the index immediately (which
|
||||
// drains it), so on any later failure the errdefer ix.deinit frees
|
||||
// every inserted entry key; a batch that fails before insertion is
|
||||
// freed by its own errdefer. Nothing is persisted on failure.
|
||||
var doc_it = coll.docs.iterator();
|
||||
while (doc_it.next()) |entry| {
|
||||
var built = try ix.build_entries(self.gpa, entry.value_ptr.*, entry.key_ptr.*);
|
||||
built_list.append(self.gpa, built) catch |err| {
|
||||
built.deinit(self.gpa);
|
||||
return err;
|
||||
};
|
||||
// Runs on success too: insert_entries drains the keys, leaving
|
||||
// only the (now empty) ArrayList buffer to free.
|
||||
defer built.deinit(self.gpa);
|
||||
if (built.multikey) ix.multikey = true;
|
||||
if (ix.unique) {
|
||||
try ix.check_unique(built.entries.items, entry.key_ptr.*);
|
||||
|
||||
Reference in New Issue
Block a user