Skip to documentation
SLOP

tiny.sql.PreparedStatement

Reference tiny.sql PreparedStatement

Defined in tiny.sql.

API (22)

Actions

Public operations.

Fields and members

Public fields and members.

No direct callersNo direct callstiny.sqlPreparedStatement
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Source: lib/sql/src/statement/execute.zig:141

zig
pub const Prepared = struct {    allocator: Allocator,    catalog: catalog_mod.Catalog,    source: []u8,    statement: ast_mod.Statement,    parameters: []ast_mod.Parameter,    bindings: []result_mod.Binding,    relation: ?plan.PreparedRelation,    execution: Execution,    validation: plan.Validation = .content,    pub fn deinit(self: *Prepared) void {        for (self.bindings) |*binding| binding.deinit(self.allocator);        self.allocator.free(self.bindings);        self.allocator.free(self.parameters);        self.execution.deinit(self.allocator);        if (self.relation) |*relation| relation.deinit();        self.statement.deinit(self.allocator);        self.allocator.free(self.source);        self.* = undefined;    }    pub fn execute(self: *Prepared, result_allocator: Allocator, options: ExecuteOptions) ast_mod.Error!result_mod.Result {        return self.executeResolved(result_allocator, options) catch |err| switch (err) {            error.RelationNotFound => error.TableNotFound,            else => err,        };    }    fn executeResolved(self: *Prepared, result_allocator: Allocator, options: ExecuteOptions) ast_mod.Error!result_mod.Result {        return self.executeOnce(result_allocator, options) catch |err| switch (err) {            error.PlanChanged => {                try self.reprepare();                return try self.executeOnce(result_allocator, options);            },            else => err,        };    }    /// Opens a cursor over the rows the select returns in `target`, which the    /// cursor fills in place. `target` is undefined after an error.    pub fn openCursor(        self: *Prepared,        target: *cursor_mod.Cursor,        result_allocator: Allocator,    ) ast_mod.Error!void {        self.openCursorResolved(target, result_allocator) catch |err| return switch (err) {            error.RelationNotFound => error.TableNotFound,            else => err,        };    }    fn openCursorResolved(        self: *Prepared,        target: *cursor_mod.Cursor,        result_allocator: Allocator,    ) ast_mod.Error!void {        self.openCursorOnce(target, result_allocator) catch |err| switch (err) {            error.PlanChanged => {                try self.reprepare();                try self.openCursorOnce(target, result_allocator);            },            else => return err,        };    }    pub fn parameterCount(self: *const Prepared) usize {        return self.parameters.len;    }    pub fn cacheKey(self: *const Prepared) plan.PlanKey {        return self.relation.?.cacheKey();    }    pub fn currentCacheKey(self: *Prepared) ast_mod.Error!plan.PlanKey {        const relation = try self.relationPtr();        return try relation.currentCacheKey();    }    pub fn parameterName(self: *const Prepared, index: usize) ast_mod.Error!?[]const u8 {        if (index == 0 or index > self.parameters.len) return error.ParameterIndexOutOfBounds;        return self.parameters[index - 1].name;    }    pub fn parameterIndex(self: *const Prepared, name: []const u8) ?usize {        for (self.parameters, 0..) |parameter, offset| {            if (parameter.name) |parameter_name| {                if (std.mem.eql(u8, parameter_name, name)) return offset + 1;            }        }        return null;    }    pub fn bind(self: *Prepared, index: usize, bound_value: row.Value) ast_mod.Error!void {        if (index == 0 or index > self.bindings.len) return error.ParameterIndexOutOfBounds;        try self.bindings[index - 1].set(self.allocator, bound_value);    }    pub fn bindName(self: *Prepared, name: []const u8, bound_value: row.Value) ast_mod.Error!void {        const index = self.parameterIndex(name) orelse return error.ParameterNotFound;        try self.bind(index, bound_value);    }    pub fn clearBinding(self: *Prepared, index: usize) ast_mod.Error!void {        if (index == 0 or index > self.bindings.len) return error.ParameterIndexOutOfBounds;        self.bindings[index - 1].clear();    }    pub fn clearBindings(self: *Prepared) void {        for (self.bindings) |*binding| binding.clear();    }    fn executeOnce(self: *Prepared, result_allocator: Allocator, options: ExecuteOptions) ast_mod.Error!result_mod.Result {        const phase = trace.scope("statement.execute");        defer phase.end();        return switch (self.statement) {            .insert => |insert| try self.executeInsert(insert, result_allocator, options),            .select => |select| .{                .rows = try self.executeSelect(select, result_allocator),            },            .update => |update| try self.executeUpdate(update, result_allocator, options),            .delete => |delete| try self.executeDelete(delete, result_allocator, options),            .create_table => |create_table| .{                .catalog = try self.executeCreateTable(create_table, result_allocator, options),            },            .create_index => |create_index| .{                .catalog = try self.executeCreateIndex(create_index, result_allocator, options),            },            .drop_table => |drop_table| .{                .catalog = try self.executeDropTable(drop_table, result_allocator, options),            },            .analyze => |analyze| .{                .catalog = try self.executeAnalyze(analyze, result_allocator, options),            },        };    }    fn executeInsert(self: *Prepared, insert: ast_mod.Insert, result_allocator: Allocator, options: ExecuteOptions) ast_mod.Error!result_mod.Result {        const insert_execution = switch (self.execution) {            .insert => |*execution| execution,            else => unreachable,        };        const relation = try self.relationPtr();        const rowid_slot = insert_execution.rowidSlot();        std.debug.assert(rowid_slot < insert.values.len);        const rowid = try self.rowidValue(insert.values[rowid_slot]);        const values = insert_execution.resolve(            insert,            relation.handle.definitions,            self,        );        return try applyEdits(relation, result_allocator, options, &.{.{ .put = .{            .rowid = rowid,            .values = values,        } }});    }    fn executeUpdate(self: *Prepared, update: ast_mod.Update, result_allocator: Allocator, options: ExecuteOptions) ast_mod.Error!result_mod.Result {        const update_execution = switch (self.execution) {            .update => |execution| execution,            else => unreachable,        };        const relation = try self.relationPtr();        const assignments = try result_allocator.alloc(relation_mod.Edit.Assignment, update.assignments.len);        defer result_allocator.free(assignments);        for (assignments, update.assignments, update_execution.assignment_fields) |*target, assignment, field| {            target.* = .{                .column = field,                .value = self.expressionValue(assignment.value),            };        }        if (predicate_mod.rowidEqualityOnly(update.predicates)) |expression| {            return try applyEdits(relation, result_allocator, options, &.{.{ .update = .{                .rowid = try self.rowidValue(expression),                .assignments = assignments,            } }});        }        const matched = try self.matchedRowids(relation, update.predicates, result_allocator, options);        defer result_allocator.free(matched);        const edits = try result_allocator.alloc(PendingEdit, matched.len);        defer result_allocator.free(edits);        for (edits, matched) |*edit, rowid| {            edit.* = .{ .update = .{                .rowid = rowid,                .assignments = assignments,            } };        }        return try applyEdits(relation, result_allocator, options, edits);    }    fn executeDelete(self: *Prepared, delete: ast_mod.Delete, result_allocator: Allocator, options: ExecuteOptions) ast_mod.Error!result_mod.Result {        const relation = try self.relationPtr();        if (predicate_mod.rowidEqualityOnly(delete.predicates)) |expression| {            return try applyEdits(relation, result_allocator, options, &.{.{                .delete = try self.rowidValue(expression),            }});        }        const matched = try self.matchedRowids(relation, delete.predicates, result_allocator, options);        defer result_allocator.free(matched);        const edits = try result_allocator.alloc(PendingEdit, matched.len);        defer result_allocator.free(edits);        for (edits, matched) |*edit, rowid| edit.* = .{ .delete = rowid };        return try applyEdits(relation, result_allocator, options, edits);    }    fn matchedRowids(self: *Prepared, relation: *plan.PreparedRelation, predicates: []const ast_mod.Predicate, result_allocator: Allocator, options: ExecuteOptions) ast_mod.Error![]i64 {        const phase = trace.scope("statement.matched_rowids");        defer phase.end();        var reader = try relation.execute();        defer reader.deinit();        var predicate_stack: [relation_mod.max_index_fields + 1]ast_mod.Predicate = undefined;        var value_stack: [relation_mod.max_index_fields + 1]row.Value = undefined;        const runtime = try predicate_mod.runtimePredicates(self, predicates, result_allocator, &predicate_stack, &value_stack);        defer runtime.deinit(result_allocator);        var overlay = try StagedOverlay.init(            result_allocator,            options,            relation,            reader.borrow(),        );        defer overlay.deinit();        var matched: std.ArrayList(i64) = .empty;        errdefer matched.deinit(result_allocator);        if (predicate_mod.firstRowidPredicate(predicates, .eq)) |offset| {            const rowid = try predicate_mod.rowidFromValue(runtime.values[offset]);            if (overlay.visible(rowid)) |staged| {                if (staged) |bytes| {                    if (try predicate_mod.rowBytesMatchPredicates(runtime.predicates, runtime.values, &relation.handle, rowid, bytes)) {                        try matched.append(result_allocator, rowid);                    }                }            } else if (try reader.get(result_allocator, rowid)) |bytes| {                defer result_allocator.free(bytes);                if (try predicate_mod.rowBytesMatchPredicates(runtime.predicates, runtime.values, &relation.handle, rowid, bytes)) {                    try matched.append(result_allocator, rowid);                }            }            return try matched.toOwnedSlice(result_allocator);        }        var start: ?i64 = null;        var end: ?i64 = null;        if (predicate_mod.firstRowidRangePredicate(predicates)) |offset| {            const rowid = try predicate_mod.rowidFromValue(runtime.values[offset]);            start = predicate_mod.rowidStart(predicates[offset].operator, rowid);            end = predicate_mod.rowidEnd(predicates[offset].operator, rowid);        }        var scan: sql.TableScan = undefined;        try reader.scan(&scan, result_allocator, start, end);        defer scan.deinit();        while (try scan.next()) |entry| {            if (overlay.shadows(entry.rowid)) continue;            if (!try predicate_mod.rowBytesMatchPredicates(runtime.predicates, runtime.values, &relation.handle, entry.rowid, entry.bytes)) continue;            try matched.append(result_allocator, entry.rowid);        }        var overlay_rows = overlay.rows.iterator();        while (overlay_rows.next()) |staged| {            const bytes = staged.value_ptr.* orelse continue;            if (!try predicate_mod.rowBytesMatchPredicates(runtime.predicates, runtime.values, &relation.handle, staged.key_ptr.*, bytes)) continue;            try matched.append(result_allocator, staged.key_ptr.*);        }        std.mem.sort(i64, matched.items, {}, std.sort.asc(i64));        return try matched.toOwnedSlice(result_allocator);    }    fn executeCreateTable(self: *Prepared, create_table: ast_mod.CreateTable, result_allocator: Allocator, options: ExecuteOptions) ast_mod.Error!session_mod.CatalogFlush {        const database_session = try options.databaseSession();        return try database_session.createRelation(result_allocator, &self.catalog, create_table.relationDefinition(), options.commit());    }    fn executeCreateIndex(self: *Prepared, create_index: ast_mod.CreateIndex, result_allocator: Allocator, options: ExecuteOptions) ast_mod.Error!session_mod.CatalogFlush {        const database_session = try options.databaseSession();        const create_index_execution = switch (self.execution) {            .create_index => |execution| execution,            else => unreachable,        };        return try database_session.createIndex(result_allocator, &self.catalog, create_index.table, .{            .name = create_index.name,            .fields = create_index_execution.fields,            .columns = create_index_execution.columns,        }, options.commit());    }    fn executeDropTable(self: *Prepared, drop_table: ast_mod.DropTable, result_allocator: Allocator, options: ExecuteOptions) ast_mod.Error!session_mod.CatalogFlush {        const database_session = try options.databaseSession();        return try database_session.dropRelation(result_allocator, &self.catalog, drop_table.table, options.commit());    }    fn executeAnalyze(self: *Prepared, analyze: ast_mod.Analyze, result_allocator: Allocator, options: ExecuteOptions) ast_mod.Error!session_mod.CatalogFlush {        const database_session = try options.databaseSession();        return try database_session.analyzeRelation(result_allocator, &self.catalog, analyze.table, options.commit());    }    fn executeSelect(self: *Prepared, select: ast_mod.Select, result_allocator: Allocator) ast_mod.Error!result_mod.Rows {        const select_execution = switch (self.execution) {            .select => |execution| execution,            else => unreachable,        };        if (select_execution.order_fields.len != 0 and !orderIsRowidAscending(select_execution.order_fields)) {            return try self.executeSortedSelect(select, result_allocator);        }        const relation = try self.relationPtr();        var reader = try relation.execute();        defer reader.deinit();        var predicate_stack: [relation_mod.max_index_fields + 1]ast_mod.Predicate = undefined;        var value_stack: [relation_mod.max_index_fields + 1]row.Value = undefined;        const predicates = try predicate_mod.runtimePredicates(self, select.predicates, result_allocator, &predicate_stack, &value_stack);        defer predicates.deinit(result_allocator);        const access = try access_mod.runtimeSelectAccess(select, relation, select_execution.fields, predicates.values);        if (select_execution.order_fields.len != 0 and            (access == .index or access == .covering))        {            return try self.executeSortedSelect(select, result_allocator);        }        var window = try self.selectWindow(select);        switch (access) {            .rowid => |rowid_access| if (rowid_access.operator == .eq) {                const rowid = try predicate_mod.rowidFromValue(predicates.values[rowid_access.predicate_index]);                const bytes = (try reader.get(result_allocator, rowid)) orelse return .{                    .allocator = result_allocator,                    .storage = .{ .single = null },                };                errdefer result_allocator.free(bytes);                if (!try predicate_mod.rowBytesMatchPredicates(predicates.predicates, predicates.values, &relation.handle, rowid, bytes)) {                    result_allocator.free(bytes);                    return .{                        .allocator = result_allocator,                        .storage = .{ .single = null },                    };                }                if (!window.admit()) {                    result_allocator.free(bytes);                    return .{                        .allocator = result_allocator,                        .storage = .{ .single = null },                    };                }                if (select_execution.fields.len == 0) {                    return .{                        .allocator = result_allocator,                        .storage = .{ .single = bytes },                    };                }                const projected = try result_mod.selectedRow(result_allocator, select_execution.fields, rowid, bytes);                result_allocator.free(bytes);                return .{                    .allocator = result_allocator,                    .storage = .{ .single = projected },                };            },            else => {},        }        var selected: std.ArrayList([]u8) = .empty;        errdefer result_mod.freeSelectedRows(result_allocator, selected.items);        switch (access) {            .rowid => |rowid_access| {                const rowid = try predicate_mod.rowidFromValue(predicates.values[rowid_access.predicate_index]);                var scan: sql.TableScan = undefined;                try reader.scan(                    &scan,                    result_allocator,                    predicate_mod.rowidStart(rowid_access.operator, rowid),                    predicate_mod.rowidEnd(rowid_access.operator, rowid),                );                defer scan.deinit();                while (try scan.next()) |entry| {                    if (window.full()) break;                    if (!predicate_mod.rowidMatches(entry.rowid, rowid_access.operator, rowid)) continue;                    if (!try predicate_mod.rowBytesMatchPredicates(predicates.predicates, predicates.values, &relation.handle, entry.rowid, entry.bytes)) continue;                    if (!window.admit()) continue;                    try result_mod.appendSelectedRow(result_allocator, &selected, select_execution.fields, entry.rowid, entry.bytes);                }            },            .index => |indexed| {                var bound_storage: [relation_mod.max_index_fields]row.Value = undefined;                const bound_values = predicate_mod.indexedPrefixValues(indexed, predicates.values, &bound_storage);                const covered = access_mod.indexCoversPredicates(&relation.handle, indexed.index_slot, select_execution.fields, predicates.predicates);                var index_scan: sql.IndexScan = undefined;                switch (indexed.operator) {                    .eq => try reader.lookup(                        &index_scan,                        result_allocator,                        indexed.index_slot,                        bound_values,                    ),                    .lt, .lte, .gt, .gte => try reader.indexRange(                        &index_scan,                        result_allocator,                        indexed.index_slot,                        predicate_mod.indexedRangeStart(indexed, bound_values),                        predicate_mod.indexedRangeEnd(indexed, bound_values),                    ),                }                defer index_scan.deinit();                while (try index_scan.next()) |entry| {                    if (window.full()) break;                    if (covered) {                        var index_values: [catalog_mod.max_columns]row.Value = undefined;                        var index_scratch: [page.size]u8 = undefined;                        const values = try predicate_mod.coveredIndexValues(                            predicates.predicates,                            predicates.values,                            &relation.handle,                            indexed.index_slot,                            entry,                            &index_values,                            &index_scratch,                        ) orelse continue;                        if (!window.admit()) continue;                        try result_mod.appendSelectedIndexRow(                            result_allocator,                            &selected,                            select_execution.fields,                            &relation.handle,                            indexed.index_slot,                            values,                            entry.rowid,                        );                        continue;                    }                    const bytes = (try reader.get(result_allocator, entry.rowid)) orelse continue;                    errdefer result_allocator.free(bytes);                    if (!try predicate_mod.rowBytesMatchPredicates(predicates.predicates, predicates.values, &relation.handle, entry.rowid, bytes)) {                        result_allocator.free(bytes);                        continue;                    }                    if (!window.admit()) {                        result_allocator.free(bytes);                        continue;                    }                    try result_mod.appendSelectedRow(result_allocator, &selected, select_execution.fields, entry.rowid, bytes);                    result_allocator.free(bytes);                }            },            .covering => unreachable,            .scan => {                var scan: sql.TableScan = undefined;                try reader.scan(&scan, result_allocator, null, null);                defer scan.deinit();                while (try scan.next()) |entry| {                    if (window.full()) break;                    if (!try predicate_mod.rowBytesMatchPredicates(predicates.predicates, predicates.values, &relation.handle, entry.rowid, entry.bytes)) continue;                    if (!window.admit()) continue;                    try result_mod.appendSelectedRow(result_allocator, &selected, select_execution.fields, entry.rowid, entry.bytes);                }            },        }        return .{            .allocator = result_allocator,            .storage = .{ .many = try selected.toOwnedSlice(result_allocator) },        };    }    fn executeSortedSelect(self: *Prepared, select: ast_mod.Select, result_allocator: Allocator) ast_mod.Error!result_mod.Rows {        const phase = trace.scope("statement.execute_sorted_select");        defer phase.end();        const relation = try self.relationPtr();        var reader = try relation.execute();        defer reader.deinit();        return .{            .allocator = result_allocator,            .storage = .{ .many = try self.sortedSelectedRows(select, result_allocator, &reader) },        };    }    fn sortedSelectedRows(        self: *Prepared,        select: ast_mod.Select,        result_allocator: Allocator,        reader: *const plan.RelationRead,    ) ast_mod.Error![][]u8 {        const select_execution = switch (self.execution) {            .select => |execution| execution,            else => unreachable,        };        const collected = try self.collectSortedRows(select, result_allocator, reader);        errdefer result_mod.freeSortedRows(result_allocator, collected);        std.mem.sort(result_mod.SortedRow, collected, result_mod.SortedRowContext{            .order_fields = select_execution.order_fields,        }, result_mod.sortedRowLessThan);        const window = try self.selectWindow(select);        const start = @min(window.skip, collected.len);        const end = if (window.remaining) |remaining| @min(start +| remaining, collected.len) else collected.len;        std.debug.assert(start <= end);        std.debug.assert(end <= collected.len);        const selected = try result_allocator.alloc([]u8, end - start);        for (selected, collected[start..end]) |*out, sorted_row| out.* = sorted_row.projected;        for (collected[0..start]) |sorted_row| result_allocator.free(sorted_row.projected);        for (collected[end..]) |sorted_row| result_allocator.free(sorted_row.projected);        for (collected) |sorted_row| result_mod.freeSortedKeys(result_allocator, sorted_row.keys);        result_allocator.free(collected);        return selected;    }    fn collectSortedRows(        self: *Prepared,        select: ast_mod.Select,        result_allocator: Allocator,        reader: *const plan.RelationRead,    ) ast_mod.Error![]result_mod.SortedRow {        const select_execution = switch (self.execution) {            .select => |execution| execution,            else => unreachable,        };        const relation = try self.relationPtr();        var predicate_stack: [relation_mod.max_index_fields + 1]ast_mod.Predicate = undefined;        var value_stack: [relation_mod.max_index_fields + 1]row.Value = undefined;        const predicates = try predicate_mod.runtimePredicates(self, select.predicates, result_allocator, &predicate_stack, &value_stack);        defer predicates.deinit(result_allocator);        const access = try access_mod.runtimeSelectAccess(select, relation, select_execution.fields, predicates.values);        var collected: std.ArrayList(result_mod.SortedRow) = .empty;        errdefer {            result_mod.freeSortedRowContents(result_allocator, collected.items);            collected.deinit(result_allocator);        }        switch (access) {            .rowid => |rowid_access| {                const rowid = try predicate_mod.rowidFromValue(predicates.values[rowid_access.predicate_index]);                if (rowid_access.operator == .eq) {                    const bytes = (try reader.get(result_allocator, rowid)) orelse return try collected.toOwnedSlice(result_allocator);                    defer result_allocator.free(bytes);                    if (!try predicate_mod.rowBytesMatchPredicates(predicates.predicates, predicates.values, &relation.handle, rowid, bytes)) {                        return try collected.toOwnedSlice(result_allocator);                    }                    try result_mod.appendSortedRow(result_allocator, &collected, select_execution.fields, select_execution.order_fields, rowid, bytes);                    return try collected.toOwnedSlice(result_allocator);                }                var scan: sql.TableScan = undefined;                try reader.scan(                    &scan,                    result_allocator,                    predicate_mod.rowidStart(rowid_access.operator, rowid),                    predicate_mod.rowidEnd(rowid_access.operator, rowid),                );                defer scan.deinit();                while (try scan.next()) |entry| {                    if (!predicate_mod.rowidMatches(entry.rowid, rowid_access.operator, rowid)) continue;                    if (!try predicate_mod.rowBytesMatchPredicates(predicates.predicates, predicates.values, &relation.handle, entry.rowid, entry.bytes)) continue;                    try result_mod.appendSortedRow(result_allocator, &collected, select_execution.fields, select_execution.order_fields, entry.rowid, entry.bytes);                }            },            .index => |indexed| {                var bound_storage: [relation_mod.max_index_fields]row.Value = undefined;                const bound_values = predicate_mod.indexedPrefixValues(indexed, predicates.values, &bound_storage);                var index_scan: sql.IndexScan = undefined;                switch (indexed.operator) {                    .eq => try reader.lookup(                        &index_scan,                        result_allocator,                        indexed.index_slot,                        bound_values,                    ),                    .lt, .lte, .gt, .gte => try reader.indexRange(                        &index_scan,                        result_allocator,                        indexed.index_slot,                        predicate_mod.indexedRangeStart(indexed, bound_values),                        predicate_mod.indexedRangeEnd(indexed, bound_values),                    ),                }                defer index_scan.deinit();                const covered = access_mod.indexCoversPredicates(                    &relation.handle,                    indexed.index_slot,                    select_execution.fields,                    predicates.predicates,                ) and access_mod.indexCoversOrder(                    &relation.handle,                    indexed.index_slot,                    select.order,                );                try collectIndexRows(                    result_allocator,                    &collected,                    reader,                    &index_scan,                    select_execution,                    &relation.handle,                    predicates,                    indexed.index_slot,                    covered,                );            },            .covering => |index_slot| {                var index_scan: sql.IndexScan = undefined;                try reader.indexScan(&index_scan, result_allocator, index_slot, null, null);                defer index_scan.deinit();                try collectIndexRows(                    result_allocator,                    &collected,                    reader,                    &index_scan,                    select_execution,                    &relation.handle,                    predicates,                    index_slot,                    true,                );            },            .scan => {                var scan: sql.TableScan = undefined;                try reader.scan(&scan, result_allocator, null, null);                defer scan.deinit();                while (try scan.next()) |entry| {                    if (!try predicate_mod.rowBytesMatchPredicates(predicates.predicates, predicates.values, &relation.handle, entry.rowid, entry.bytes)) continue;                    try result_mod.appendSortedRow(result_allocator, &collected, select_execution.fields, select_execution.order_fields, entry.rowid, entry.bytes);                }            },        }        return try collected.toOwnedSlice(result_allocator);    }    /// Appends a sorted row for each entry an open index scan yields. A covered scan builds the    /// row from the decoded key, and an uncovered scan reads the table row.    fn collectIndexRows(        result_allocator: Allocator,        collected: *std.ArrayList(result_mod.SortedRow),        reader: *const plan.RelationRead,        index_scan: *sql.IndexScan,        select_execution: SelectExecution,        handle: *const catalog_mod.RelationHandle,        predicates: predicate_mod.RuntimePredicates,        index_slot: usize,        covered: bool,    ) ast_mod.Error!void {        while (try index_scan.next()) |entry| {            if (covered) {                var index_values: [catalog_mod.max_columns]row.Value = undefined;                var index_scratch: [page.size]u8 = undefined;                const values = try predicate_mod.coveredIndexValues(                    predicates.predicates,                    predicates.values,                    handle,                    index_slot,                    entry,                    &index_values,                    &index_scratch,                ) orelse continue;                try result_mod.appendSortedIndexRow(                    result_allocator,                    collected,                    select_execution.fields,                    select_execution.order_fields,                    handle,                    index_slot,                    values,                    entry.rowid,                );                continue;            }            const bytes = (try reader.get(result_allocator, entry.rowid)) orelse continue;            defer result_allocator.free(bytes);            if (!try predicate_mod.rowBytesMatchPredicates(                predicates.predicates,                predicates.values,                handle,                entry.rowid,                bytes,            )) continue;            try result_mod.appendSortedRow(                result_allocator,                collected,                select_execution.fields,                select_execution.order_fields,                entry.rowid,                bytes,            );        }    }    fn openCursorOnce(        self: *Prepared,        target: *cursor_mod.Cursor,        result_allocator: Allocator,    ) ast_mod.Error!void {        const phase = trace.scope("statement.cursor.open");        defer phase.end();        const select = switch (self.statement) {            .select => |select_statement| select_statement,            else => return error.UnsupportedStatement,        };        const select_execution = switch (self.execution) {            .select => |execution| execution,            else => unreachable,        };        const relation = try self.relationPtr();        var reader = try relation.execute();        var reader_live = true;        errdefer if (reader_live) reader.deinit();        var owned_predicates = try predicate_mod.ownedPredicates(result_allocator, self, select.predicates);        var owned_predicates_live = true;        errdefer if (owned_predicates_live) owned_predicates.deinit(result_allocator);        const access = try access_mod.runtimeSelectAccess(select, relation, select_execution.fields, owned_predicates.values);        const sort_needed = select_execution.order_fields.len != 0 and            (!orderIsRowidAscending(select_execution.order_fields) or                access == .index or access == .covering);        target.* = .{            .allocator = result_allocator,            .relation = relation,            .reader = null,            .fields = select_execution.fields,            .access = access,            .predicates = owned_predicates.predicates,            .predicate_values = owned_predicates.values,            .state = .empty,            .window = if (sort_needed) .{} else try self.selectWindow(select),        };        owned_predicates_live = false;        errdefer target.deinit();        if (sort_needed) {            const rows = try self.sortedSelectedRows(select, result_allocator, &reader);            target.state = .{ .sorted = .{ .rows = rows } };            reader.deinit();            reader_live = false;            return;        }        target.reader = reader;        reader_live = false;        switch (access) {            .rowid => |rowid_access| {                const rowid = try predicate_mod.rowidFromValue(                    target.predicate_values[rowid_access.predicate_index],                );                if (rowid_access.operator == .eq) {                    const bytes = (try reader.get(result_allocator, rowid)) orelse {                        target.state = .empty;                        return;                    };                    errdefer result_allocator.free(bytes);                    if (!try predicate_mod.rowBytesMatchPredicates(                        target.predicates,                        target.predicate_values,                        &relation.handle,                        rowid,                        bytes,                    )) {                        result_allocator.free(bytes);                        target.state = .empty;                        return;                    }                    if (select_execution.fields.len == 0) {                        target.state = .{ .single = .{ .bytes = bytes } };                        return;                    }                    const projected = try result_mod.selectedRow(result_allocator, select_execution.fields, rowid, bytes);                    result_allocator.free(bytes);                    target.state = .{ .single = .{ .bytes = projected } };                    return;                }                target.state = .{ .rowid = undefined };                errdefer target.state = .empty;                try reader.scan(                    &target.state.rowid,                    result_allocator,                    predicate_mod.rowidStart(rowid_access.operator, rowid),                    predicate_mod.rowidEnd(rowid_access.operator, rowid),                );            },            .index => |indexed| {                var bound_storage: [relation_mod.max_index_fields]row.Value = undefined;                const bound_values = predicate_mod.indexedPrefixValues(                    indexed,                    target.predicate_values,                    &bound_storage,                );                const covered = access_mod.indexCoversPredicates(                    &relation.handle,                    indexed.index_slot,                    select_execution.fields,                    target.predicates,                );                target.state = .{ .index = .{ .scan = undefined, .covered = covered } };                errdefer target.state = .empty;                const index_scan = &target.state.index.scan;                switch (indexed.operator) {                    .eq => try reader.lookup(                        index_scan,                        result_allocator,                        indexed.index_slot,                        bound_values,                    ),                    .lt, .lte, .gt, .gte => try reader.indexRange(                        index_scan,                        result_allocator,                        indexed.index_slot,                        predicate_mod.indexedRangeStart(indexed, bound_values),                        predicate_mod.indexedRangeEnd(indexed, bound_values),                    ),                }            },            .covering => unreachable,            .scan => {                target.state = .{ .scan = undefined };                errdefer target.state = .empty;                try reader.scan(&target.state.scan, result_allocator, null, null);            },        }    }    fn selectWindow(self: *const Prepared, select: ast_mod.Select) ast_mod.Error!Window {        var window = Window{};        if (select.limit) |expression| window.remaining = try self.windowCount(expression);        if (select.offset) |expression| window.skip = try self.windowCount(expression);        return window;    }    fn windowCount(self: *const Prepared, expression: ast_mod.Expression) ast_mod.Error!usize {        return switch (self.expressionValue(expression)) {            .integer => |integer| if (integer < 0) error.InvalidLimit else @intCast(integer),            else => error.InvalidLimit,        };    }    fn rowidValue(self: *const Prepared, expression: ast_mod.Expression) ast_mod.Error!i64 {        return try predicate_mod.rowidFromValue(self.expressionValue(expression));    }    pub fn expressionValue(self: *const Prepared, expression: ast_mod.Expression) row.Value {        return switch (expression) {            .literal => |literal| literal,            .parameter => |index| self.bindings[index].value(),        };    }    fn reprepare(self: *Prepared) ast_mod.Error!void {        const phase = trace.scope("statement.reprepare");        defer phase.end();        if (self.relation == null) return;        var relation = try prepareStatementRelation(&self.catalog, self.allocator, self.statement, ast_mod.parameterShape(self.parameters), self.validation) orelse return;        errdefer relation.deinit();        var execution = try prepareExecution(self.allocator, self.statement, &relation);        errdefer execution.deinit(self.allocator);        self.execution.deinit(self.allocator);        self.relation.?.deinit();        self.relation = relation;        self.execution = execution;    }    fn relationPtr(self: *Prepared) ast_mod.Error!*plan.PreparedRelation {        if (self.relation) |*relation| return relation;        return error.UnsupportedStatement;    }};

Source: lib/sql/src/root.zig:175

zig
pub const PreparedStatement = statement.Prepared;
Called byCallsNo direct callsPreparedStatementbindNamePreparedStatementbind
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersPreparedStatementbindPreparedStatementparameterIndexPreparedStatementbindName
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.sql.src.statement.execute.PreparedrelationPtrPreparedStatementcurrentCacheKey
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callersprivate sourcelib.sql.src.statement.execute.ExecutiondeinitPreparedStatementdeinit
Static calls · unresolved targets: 1 · external targets: 3.
Called byCallsNo direct callersprivate sourcelib.sql.src.statement.execute.PreparedexecuteResolvedPreparedStatementexecute
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsprivate sourcelib.sql.src.statement.execute.PreparedexecuteUpdateprivate sourcelib.sql.src.statement.execute.PreparedrowidValueprivate sourcelib.sql.src.statement.execute.PreparedwindowCountPreparedStatementexpressionValue
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.sql.src.statement.execute.PreparedopenCursorResolvedPreparedStatementopenCursor
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsPreparedStatementbindNamePreparedStatementparameterIndex
Static calls · unresolved targets: 0 · external targets: 0.

Also reachable as

statement.Prepared.

Audit

Definitions14
Public names28
Members9
Version26.7.0
Revisiondaab053ee433