Skip to documentation
SLOP

tiny.sql.Catalog

Reference tiny.sql Catalog

Defined in catalog.

API (17)

Actions

Public operations.

Fields and members

Public fields and members.

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

Source

Source: lib/sql/src/catalog.zig:701

zig
pub const Catalog = struct {    database: *file.Database,    meta_page: u32,    root_page: u32,    schema: table.Table,    pub fn open(database: *file.Database, options: Options) Error!Catalog {        try validateOptions(options);        return .{            .database = database,            .meta_page = options.meta_page,            .root_page = options.root_page,            .schema = try table.Table.open(database, .{                .tree = catalogTreeOptions(options),            }),        };    }    pub fn schemaState(self: *const Catalog, allocator: Allocator) Error!Schema {        return try readSchemaState(&self.schema, allocator);    }    pub fn beginMaterialization(self: *const Catalog, allocator: Allocator) Error!Materialization {        var roots: [space_mod.max_roots]space_mod.RootSpec = undefined;        var root_count: usize = 0;        try addRoot(&roots, &root_count, .{ .root_page = self.root_page });        var state = CatalogState{};        var scan: table.Scan = undefined;        try self.schema.scan(&scan, allocator, null, null);        defer scan.deinit();        while (try scan.next()) |entry| {            var scratch = CatalogScratch{};            switch (try state.record(entry, &scratch)) {                .schema, .stats => {},                .object => |object| try addRoot(&roots, &root_count, .{                    .root_page = object.root_page,                    .identity_page = object.identity_page,                }),            }        }        const current_schema = try state.schemaOrDefault();        if (state.max_rowid == std.math.maxInt(i64)) return error.CatalogCorrupt;        const space = try space_mod.Space.open(self.database, .{            .meta_page = self.meta_page,            .roots = roots[0..root_count],        });        var write = try space.beginWrite();        errdefer write.deinit();        return .{            .allocator = allocator,            .catalog = self,            .roots = roots,            .root_count = root_count,            .schema = try space.rowidTable(self.root_page),            .write = write,            .current_schema = current_schema,            .next_rowid = @max(state.max_rowid + 1, first_object_rowid),        };    }    pub fn prepareRelationStats(        _: *const Catalog,        allocator: Allocator,        definition: RelationDefinition,        puts: []const relation_mod.Edit.Put,        table_summary: tree.Summary,        index_summaries: []const tree.Summary,    ) Error!PreparedRelationStats {        try validateDefinition(definition);        if (definition.indexes.len != index_summaries.len) return error.CatalogCorrupt;        var previous_rowid: ?i64 = null;        for (puts) |put| {            _ = try row.View.init(put.bytes);            if (previous_rowid) |previous| {                if (put.rowid <= previous) return error.CatalogCorrupt;            }            previous_rowid = put.rowid;        }        const indexes = try allocator.alloc(IndexStats, definition.indexes.len);        var index_count: usize = 0;        errdefer {            for (indexes[0..index_count]) |*index_stats| {                allocator.free(index_stats.name);                freeIndexDistribution(allocator, index_stats.distribution);            }            allocator.free(indexes);        }        const distribution_blobs = try allocator.alloc([]u8, definition.indexes.len);        var blob_count: usize = 0;        errdefer {            for (distribution_blobs[0..blob_count]) |bytes| {                if (bytes.len != 0) allocator.free(bytes);            }            allocator.free(distribution_blobs);        }        for (            definition.indexes,            index_summaries,            indexes,            distribution_blobs,            0..,        ) |index_definition, summary, *index_stats, *distribution_blob, index_offset| {            const prepared = try prepareIndexStats(                allocator,                index_definition,                puts,                summary,                index_offset,            );            index_stats.* = prepared.stats;            distribution_blob.* = prepared.distribution_blob;            index_count += 1;            blob_count += 1;        }        return .{            .allocator = allocator,            .stats = .{                .allocator = allocator,                .table_root_page = 0,                .table = table_summary,                .indexes = indexes,            },            .distribution_blobs = distribution_blobs,        };    }    pub fn createRelation(self: *const Catalog, allocator: Allocator, definition: RelationDefinition, options: file.CommitOptions) Error!Commit {        const phase = trace.scope("catalog.create_relation");        defer phase.end();        try validateDefinition(definition);        var roots: [space_mod.max_roots]space_mod.RootSpec = undefined;        var root_count: usize = 0;        try addRoot(&roots, &root_count, .{ .root_page = self.root_page });        var state = CatalogState{};        {            var scan: table.Scan = undefined;            try self.schema.scan(&scan, allocator, null, null);            defer scan.deinit();            while (try scan.next()) |entry| {                var scratch = CatalogScratch{};                switch (try state.record(entry, &scratch)) {                    .schema => {},                    .object => |object| {                        if (std.mem.eql(u8, object.name, definition.name)) return error.ObjectExists;                        for (definition.indexes) |index_definition| {                            if (std.mem.eql(u8, object.name, index_definition.name)) return error.ObjectExists;                        }                        try addRoot(&roots, &root_count, .{ .root_page = object.root_page, .identity_page = object.identity_page });                    },                    .stats => {},                }            }        }        const next_schema = try bumpSchemaVersion(try state.schemaOrDefault());        const space = try space_mod.Space.open(self.database, .{            .meta_page = self.meta_page,            .roots = roots[0..root_count],        });        var schema = try space.rowidTable(self.root_page);        var write = try space.beginWrite();        defer write.deinit();        const table_root = try allocateCatalogRoot(&write, &roots, &root_count);        var index_roots: [relation_mod.max_indexes]space_mod.RootSpec = undefined;        for (definition.indexes, 0..) |_, index_offset| {            index_roots[index_offset] = try allocateCatalogRoot(&write, &roots, &root_count);        }        try putSchemaRow(&schema, &write, next_schema);        var definitions_buffer: [page.size]u8 = undefined;        const definitions = try encodeDefinitions(&definitions_buffer, definition.columns);        var next_rowid = @max(state.max_rowid + 1, first_object_rowid);        try putCatalogRow(&schema, &write, next_rowid, relation_kind, definition.name, definition.name, table_root.root_page, table_root.identity_page, definitions, "");        next_rowid += 1;        for (definition.indexes, 0..) |index_definition, index_offset| {            var fields_buffer: [relation_mod.max_index_fields * field_bytes]u8 = undefined;            var collations_buffer: [relation_mod.max_index_fields]u8 = undefined;            const fields = try encodeFields(&fields_buffer, index_definition.fields);            const collations = try encodeCollations(&collations_buffer, index_definition.fields.len, index_definition.columns);            try putCatalogRow(                &schema,                &write,                next_rowid,                index_kind,                index_definition.name,                definition.name,                index_roots[index_offset].root_page,                index_roots[index_offset].identity_page,                fields,                collations,            );            next_rowid += 1;        }        return .{            .storage = try write.commit(options),            .schema = next_schema,        };    }    pub fn createIndex(self: *const Catalog, allocator: Allocator, table_name: []const u8, definition: IndexDefinition, options: file.CommitOptions) Error!Commit {        const phase = trace.scope("catalog.create_index");        defer phase.end();        if (definition.name.len == 0) return error.CatalogCorrupt;        if (definition.fields.len == 0 or definition.fields.len > relation_mod.max_index_fields) return error.TooManyIndexFields;        if (definition.columns.len > definition.fields.len) return error.CatalogCorrupt;        var roots: [space_mod.max_roots]space_mod.RootSpec = undefined;        var root_count: usize = 0;        try addRoot(&roots, &root_count, .{ .root_page = self.root_page });        var table_root: ?u32 = null;        var table_definitions: [max_columns]ColumnDefinition = undefined;        var table_names: [max_column_name_bytes]u8 = undefined;        var table_defaults: [max_column_default_bytes]u8 = undefined;        var table_definition_count: usize = 0;        var table_index_count: usize = 0;        var old_stats: std.ArrayList(i64) = .empty;        defer old_stats.deinit(allocator);        var state = CatalogState{};        var scan: table.Scan = undefined;        try self.schema.scan(&scan, allocator, null, null);        defer scan.deinit();        while (try scan.next()) |entry| {            var scratch = CatalogScratch{};            switch (try state.record(entry, &scratch)) {                .schema => {},                .object => |object| switch (object.kind) {                    .relation => {                        if (std.mem.eql(u8, object.name, definition.name)) return error.ObjectExists;                        try addRoot(&roots, &root_count, .{ .root_page = object.root_page, .identity_page = object.identity_page });                        if (std.mem.eql(u8, object.name, table_name)) {                            if (table_root != null) return error.CatalogCorrupt;                            table_root = object.root_page;                            table_definition_count = object.definitions.len;                            _ = try copyDefinitions(&table_definitions, &table_names, &table_defaults, object.definitions);                        }                    },                    .index => {                        if (std.mem.eql(u8, object.name, definition.name)) return error.ObjectExists;                        try addRoot(&roots, &root_count, .{ .root_page = object.root_page, .identity_page = object.identity_page });                        if (std.mem.eql(u8, object.table_name, table_name)) table_index_count += 1;                    },                    .schema => unreachable,                    .stats => unreachable,                },                .stats => |stats| {                    if (std.mem.eql(u8, stats.table_name, table_name)) try old_stats.append(allocator, entry.rowid);                },            }        }        const next_schema = try bumpSchemaVersion(try state.schemaOrDefault());        const root_page = table_root orelse return error.RelationNotFound;        if (table_index_count >= relation_mod.max_indexes) return error.TooManyIndexes;        for (definition.fields) |field| {            if (field >= table_definition_count) return error.ColumnOutOfBounds;        }        const space = try space_mod.Space.open(self.database, .{            .meta_page = self.meta_page,            .roots = roots[0..root_count],        });        var table_rows = try space.rowidTable(root_page);        var schema = try space.rowidTable(self.root_page);        var write = try space.beginWrite();        defer write.deinit();        const index_root = try allocateCatalogRoot(&write, &roots, &root_count);        const index_space = try space_mod.Space.open(self.database, .{            .meta_page = self.meta_page,            .roots = roots[0..root_count],        });        var relation_index = try index_space.index(index_root.root_page, definition.columns);        var table_scan: table.Scan = undefined;        try table_rows.scan(&table_scan, allocator, null, null);        defer table_scan.deinit();        while (try table_scan.next()) |entry| {            const view = try entry.view();            var projected: [relation_mod.max_index_fields]row.Value = undefined;            try relation_index.putIn(&write, entry.rowid, try view.project(definition.fields, &projected));        }        for (old_stats.items) |rowid| try schema.deleteIn(&write, rowid);        try putSchemaRow(&schema, &write, next_schema);        var fields_buffer: [relation_mod.max_index_fields * field_bytes]u8 = undefined;        var collations_buffer: [relation_mod.max_index_fields]u8 = undefined;        const fields = try encodeFields(&fields_buffer, definition.fields);        const collations = try encodeCollations(&collations_buffer, definition.fields.len, definition.columns);        try putCatalogRow(            &schema,            &write,            @max(state.max_rowid + 1, first_object_rowid),            index_kind,            definition.name,            table_name,            index_root.root_page,            index_root.identity_page,            fields,            collations,        );        return .{            .storage = try write.commit(options),            .schema = next_schema,        };    }    pub fn dropRelation(self: *const Catalog, allocator: Allocator, name: []const u8, options: file.CommitOptions) Error!Commit {        const phase = trace.scope("catalog.drop_relation");        defer phase.end();        var roots: [space_mod.max_roots]space_mod.RootSpec = undefined;        var root_count: usize = 0;        try addRoot(&roots, &root_count, .{ .root_page = self.root_page });        var rowids: std.ArrayList(i64) = .empty;        defer rowids.deinit(allocator);        var found_relation = false;        var state = CatalogState{};        var scan: table.Scan = undefined;        try self.schema.scan(&scan, allocator, null, null);        defer scan.deinit();        while (try scan.next()) |entry| {            var scratch = CatalogScratch{};            switch (try state.record(entry, &scratch)) {                .schema => {},                .object => |object| switch (object.kind) {                    .relation => {                        try addRoot(&roots, &root_count, .{ .root_page = object.root_page, .identity_page = object.identity_page });                        if (std.mem.eql(u8, object.name, name)) {                            if (found_relation) return error.CatalogCorrupt;                            found_relation = true;                            try rowids.append(allocator, entry.rowid);                        }                    },                    .index => {                        try addRoot(&roots, &root_count, .{ .root_page = object.root_page, .identity_page = object.identity_page });                        if (std.mem.eql(u8, object.table_name, name)) try rowids.append(allocator, entry.rowid);                    },                    .schema => unreachable,                    .stats => unreachable,                },                .stats => |stats| {                    if (std.mem.eql(u8, stats.table_name, name)) try rowids.append(allocator, entry.rowid);                },            }        }        const next_schema = try bumpSchemaVersion(try state.schemaOrDefault());        if (!found_relation) return error.RelationNotFound;        const space = try space_mod.Space.open(self.database, .{            .meta_page = self.meta_page,            .roots = roots[0..root_count],        });        var schema = try space.rowidTable(self.root_page);        var write = try space.beginWrite();        defer write.deinit();        for (rowids.items) |rowid| try schema.deleteIn(&write, rowid);        try putSchemaRow(&schema, &write, next_schema);        return .{            .storage = try write.commit(options),            .schema = next_schema,        };    }    pub fn openRelation(        self: *const Catalog,        allocator: Allocator,        name: []const u8,    ) Error!RelationHandle {        return try openRelationFrom(            RelationHandle,            space_mod.Space,            relation_mod.Relation,            self.database,            &self.schema,            self.meta_page,            self.root_page,            allocator,            name,        );    }    pub fn relationNames(self: *const Catalog, allocator: Allocator) Error!RelationNames {        return try readRelationNames(&self.schema, allocator);    }    pub fn analyzeRelation(self: *const Catalog, allocator: Allocator, name: []const u8, options: file.CommitOptions) Error!Commit {        const phase = trace.scope("catalog.analyze_relation");        defer phase.end();        var roots: [space_mod.max_roots]space_mod.RootSpec = undefined;        var root_count: usize = 0;        try addRoot(&roots, &root_count, .{ .root_page = self.root_page });        var table_root: ?u32 = null;        var indexes: std.ArrayList(AnalyzeIndex) = .empty;        defer indexes.deinit(allocator);        defer freeAnalyzeIndexes(allocator, indexes.items);        var old_stats: std.ArrayList(i64) = .empty;        defer old_stats.deinit(allocator);        var state = CatalogState{};        var scan: table.Scan = undefined;        try self.schema.scan(&scan, allocator, null, null);        defer scan.deinit();        while (try scan.next()) |entry| {            var scratch = CatalogScratch{};            switch (try state.record(entry, &scratch)) {                .schema => {},                .object => |object| switch (object.kind) {                    .relation => {                        try addRoot(&roots, &root_count, .{ .root_page = object.root_page, .identity_page = object.identity_page });                        if (std.mem.eql(u8, object.name, name)) table_root = object.root_page;                    },                    .index => {                        try addRoot(&roots, &root_count, .{ .root_page = object.root_page, .identity_page = object.identity_page });                        if (std.mem.eql(u8, object.table_name, name)) {                            if (indexes.items.len >= relation_mod.max_indexes) return error.TooManyIndexes;                            const owned_name = try allocator.dupe(u8, object.name);                            var analyzed_index = AnalyzeIndex{                                .name = owned_name,                                .root_page = object.root_page,                                .field_count = object.fields.len,                            };                            @memcpy(analyzed_index.fields[0..object.fields.len], object.fields);                            @memcpy(analyzed_index.columns[0..object.columns.len], object.columns);                            indexes.append(allocator, analyzed_index) catch |err| {                                allocator.free(owned_name);                                return err;                            };                        }                    },                    .schema => unreachable,                    .stats => unreachable,                },                .stats => |stats| {                    if (std.mem.eql(u8, stats.table_name, name)) try old_stats.append(allocator, entry.rowid);                },            }        }        const current_schema = try state.schemaOrDefault();        const root_page = table_root orelse return error.RelationNotFound;        const space = try space_mod.Space.open(self.database, .{            .meta_page = self.meta_page,            .roots = roots[0..root_count],        });        var schema = try space.rowidTable(self.root_page);        var relation_table = try space.rowidTable(root_page);        const table_summary = try relation_table.summarize();        var index_summaries: [relation_mod.max_indexes]tree.Summary = undefined;        for (indexes.items, 0..) |index_object, index_offset| {            var relation_index = try space.index(index_object.root_page, index_object.indexColumns());            index_summaries[index_offset] = try relation_index.summarize();            indexes.items[index_offset].distribution_blob = try analyzeIndexDistribution(allocator, &relation_index);        }        var write = try space.beginWrite();        defer write.deinit();        for (old_stats.items) |rowid| try schema.deleteIn(&write, rowid);        var summary_buffer: [summary_blob_bytes]u8 = undefined;        var next_rowid = @max(state.max_rowid + 1, first_object_rowid);        try putCatalogRow(            &schema,            &write,            next_rowid,            stats_kind,            name,            name,            root_page,            0,            try encodeSummary(&summary_buffer, table_summary),            "",        );        next_rowid += 1;        for (indexes.items, 0..) |index_object, index_offset| {            try putCatalogRow(                &schema,                &write,                next_rowid,                stats_kind,                index_object.name,                name,                index_object.root_page,                0,                try encodeSummary(&summary_buffer, index_summaries[index_offset]),                index_object.distribution_blob,            );            next_rowid += 1;        }        return .{            .storage = try write.commit(options),            .schema = current_schema,        };    }    pub fn clearRelationStats(self: *const Catalog, allocator: Allocator, name: []const u8, options: file.CommitOptions) Error!?Commit {        const phase = trace.scope("catalog.clear_relation_stats");        defer phase.end();        var roots: [space_mod.max_roots]space_mod.RootSpec = undefined;        var root_count: usize = 0;        try addRoot(&roots, &root_count, .{ .root_page = self.root_page });        var old_stats: std.ArrayList(i64) = .empty;        defer old_stats.deinit(allocator);        var found_relation = false;        var state = CatalogState{};        var scan: table.Scan = undefined;        try self.schema.scan(&scan, allocator, null, null);        defer scan.deinit();        while (try scan.next()) |entry| {            var scratch = CatalogScratch{};            switch (try state.record(entry, &scratch)) {                .schema => {},                .object => |object| switch (object.kind) {                    .relation => {                        try addRoot(&roots, &root_count, .{ .root_page = object.root_page, .identity_page = object.identity_page });                        if (std.mem.eql(u8, object.name, name)) {                            if (found_relation) return error.CatalogCorrupt;                            found_relation = true;                        }                    },                    .index => try addRoot(&roots, &root_count, .{ .root_page = object.root_page, .identity_page = object.identity_page }),                    .schema => unreachable,                    .stats => unreachable,                },                .stats => |stats| {                    if (std.mem.eql(u8, stats.table_name, name)) try old_stats.append(allocator, entry.rowid);                },            }        }        const current_schema = try state.schemaOrDefault();        if (!found_relation) return error.RelationNotFound;        if (old_stats.items.len == 0) return null;        const space = try space_mod.Space.open(self.database, .{            .meta_page = self.meta_page,            .roots = roots[0..root_count],        });        var schema = try space.rowidTable(self.root_page);        var write = try space.beginWrite();        defer write.deinit();        for (old_stats.items) |rowid| try schema.deleteIn(&write, rowid);        return .{            .storage = try write.commit(options),            .schema = current_schema,        };    }    pub fn relationStats(self: *const Catalog, allocator: Allocator, name: []const u8) Error!?RelationStats {        return try readRelationStats(&self.schema, allocator, name);    }    /// Returns what `schemaState`, `openRelation` and `relationStats` return    /// for `name`, read in one catalog pass over one snapshot.    pub fn readRelation(        self: *const Catalog,        allocator: Allocator,        name: []const u8,    ) Error!RelationState {        return try readRelationFrom(            RelationHandle,            space_mod.Space,            relation_mod.Relation,            self.database,            &self.schema,            self.meta_page,            self.root_page,            allocator,            name,        );    }};

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

zig
pub const Catalog = catalog.Catalog;
Called byCallsNo direct callersprivate sourcelib.sql.src.catalogaddRootprivate sourcelib.sql.src.cataloganalyzeIndexDistributionprivate sourcelib.sql.src.catalogencodeSummaryprivate sourcelib.sql.src.catalogfreeAnalyzeIndexesprivate sourcelib.sql.src.catalogputCatalogRow+3 moreCataloganalyzeRelation
Static calls · unresolved targets: 3 · external targets: 17.
Called byCallsNo direct callersprivate sourcelib.sql.src.catalogaddRootTableScandeinitTableScannextRowIdTablescanCatalogbeginMaterialization
Static calls · unresolved targets: 0 · external targets: 6.
Called byCallsNo direct callersprivate sourcelib.sql.src.catalogaddRootTableScandeinitTableScannextRowIdTablescanCatalogclearRelationStats
Static calls · unresolved targets: 1 · external targets: 11.
Called byCallsNo direct callersprivate sourcelib.sql.src.catalogaddRootprivate sourcelib.sql.src.catalogallocateCatalogRootprivate sourcelib.sql.src.catalogbumpSchemaVersionprivate sourcelib.sql.src.catalogcopyDefinitionsprivate sourcelib.sql.src.catalogencodeCollations+6 moreCatalogcreateIndex
Static calls · unresolved targets: 1 · external targets: 16.
Called byCallsNo direct callersprivate sourcelib.sql.src.catalogaddRootprivate sourcelib.sql.src.catalogallocateCatalogRootprivate sourcelib.sql.src.catalogbumpSchemaVersionprivate sourcelib.sql.src.catalogencodeCollationsprivate sourcelib.sql.src.catalogencodeDefinitions+7 moreCatalogcreateRelation
Static calls · unresolved targets: 0 · external targets: 9.
Called byCallsNo direct callersprivate sourcelib.sql.src.catalogaddRootprivate sourcelib.sql.src.catalogbumpSchemaVersionprivate sourcelib.sql.src.catalogputSchemaRowTableScandeinitTableScannextRowIdTablescanCatalogdropRelation
Static calls · unresolved targets: 1 · external targets: 11.
Called byCallstest sourcelib.sql.src.catalogtest: catalog allocates distinct root...test sourcelib.sql.src.catalogtest: catalog analyzes composite inde...test sourcelib.sql.src.catalogtest: catalog analyzes relation stats...test sourcelib.sql.src.catalogtest: catalog clears relation stats w...test sourcelib.sql.src.catalogtest: catalog diagnoses pre identity ...+10 moreprivate sourcelib.sql.src.catalogcatalogTreeOptionsprivate sourcelib.sql.src.catalogvalidateOptionsRowIdTableopenCatalogopen
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.sql.src.catalogopenRelationFromCatalogopenRelation
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.sql.src.catalogfreeIndexDistributionprivate sourcelib.sql.src.catalogprepareIndexStatscatalogvalidateDefinitionRowViewinitCatalogprepareRelationStats
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsNo direct callersprivate sourcelib.sql.src.catalogreadRelationFromCatalogreadRelation
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.sql.src.catalogreadRelationNamesCatalogrelationNames
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.sql.src.catalogreadRelationStatsCatalogrelationStats
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.sql.src.catalogreadSchemaStateCatalogschemaState
Static calls · unresolved targets: 0 · external targets: 0.

Complete call list for Catalog.analyzeRelation

8 direct calls.

Complete call list for Catalog.createIndex

11 direct calls.

Complete call list for Catalog.createRelation

12 direct calls.

Complete caller list for Catalog.open

15 direct callers.

Audit

Definitions14
Public names28
Members4
Version26.7.0
Revisiondaab053ee433