diff --git a/build.zig b/build.zig index 6062b36..817eeb9 100644 --- a/build.zig +++ b/build.zig @@ -5,9 +5,6 @@ const mem = std.mem; const ResolvedTarget = std.Build.ResolvedTarget; const Query = std.Target.Query; const builtin = @import("builtin"); -const Io = std.Io; - -const Preprocessor = @import("build/Preprocessor.zig"); fn getTarget(original_target: ResolvedTarget) ResolvedTarget { var tmp = original_target; @@ -109,9 +106,21 @@ fn computeTestTargets(isNative: bool, ci: ?bool) ?[]const TestTarget { return null; } +fn translateSQLite(b: *std.Build, dep: *std.Build.Dependency, header: []const u8, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *std.Build.Module { + const translate_c = b.addTranslateC(.{ + .root_source_file = b.path(header), + .target = target, + .optimize = optimize, + }); + translate_c.addIncludePath(dep.path(".")); + translate_c.addIncludePath(b.path("c")); + + return translate_c.createModule(); +} + // This creates a SQLite static library from the SQLite dependency code. fn makeSQLiteLib(b: *std.Build, dep: *std.Build.Dependency, c_flags: []const []const u8, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, sqlite_c: enum { with, without }) *std.Build.Step.Compile { - const mod = b.addModule("lib-sqlite", .{ + const mod = b.createModule(.{ .target = target, .optimize = optimize, .link_libc = true, @@ -146,8 +155,6 @@ pub fn build(b: *std.Build) !void { const query = b.standardTargetOptionsQueryOnly(.{}); const target = b.resolveTargetQuery(query); const optimize = b.standardOptimizeOption(.{}); - var threaded = Io.Threaded.init_single_threaded; - const io = threaded.io(); // Upstream dependency const sqlite_dep = b.dependency("sqlite", .{ @@ -161,22 +168,23 @@ pub fn build(b: *std.Build) !void { defer flags.deinit(b.allocator); try flags.append(b.allocator, "-std=c99"); - inline for (std.meta.fields(EnableOptions)) |field| { - const opt = b.option(bool, field.name, "Enable " ++ field.name) orelse field.defaultValue().?; + const enable_info = @typeInfo(EnableOptions).@"struct"; + inline for (enable_info.field_names, enable_info.field_attrs) |field_name, field_attrs| { + const opt = b.option(bool, field_name, "Enable " ++ field_name) orelse field_attrs.defaultValue(bool).?; if (opt) { - var buf: [field.name.len]u8 = undefined; - const name = std.ascii.upperString(&buf, field.name); + var buf: [field_name.len]u8 = undefined; + const name = std.ascii.upperString(&buf, field_name); const flag = try std.fmt.allocPrint(b.allocator, "-DSQLITE_ENABLE_{s}", .{name}); try flags.append(b.allocator, flag); } } - inline for (std.meta.fields(BoolFeatureOptions)) |field| { - comptime var buf: [field.name.len]u8 = undefined; - const name = comptime std.ascii.upperString(&buf, field.name); - const opt = b.option(bool, field.name, "Set SQLITE_" ++ name); + inline for (@typeInfo(BoolFeatureOptions).@"enum".field_names) |field_name| { + comptime var buf: [field_name.len]u8 = undefined; + const name = comptime std.ascii.upperString(&buf, field_name); + const opt = b.option(bool, field_name, "Set SQLITE_" ++ name); if (opt) |v| { const flag_value = if (v) "1" else "0"; @@ -186,10 +194,10 @@ pub fn build(b: *std.Build) !void { } } - inline for (std.meta.fields(DefineFeatureOptions)) |field| { - comptime var buf: [field.name.len]u8 = undefined; - const name = comptime std.ascii.upperString(&buf, field.name); - const opt = b.option(bool, field.name, "Set SQLITE_" ++ name) orelse false; + inline for (@typeInfo(DefineFeatureOptions).@"enum".field_names) |field_name| { + comptime var buf: [field_name.len]u8 = undefined; + const name = comptime std.ascii.upperString(&buf, field_name); + const opt = b.option(bool, field_name, "Set SQLITE_" ++ name) orelse false; if (opt) { const flag = try std.fmt.allocPrint(b.allocator, "-DSQLITE_" ++ name, .{}); @@ -198,10 +206,11 @@ pub fn build(b: *std.Build) !void { } } - inline for (std.meta.fields(IntFeatureOptions)) |field| { - comptime var buf: [field.name.len]u8 = undefined; - const name = comptime std.ascii.upperString(&buf, field.name); - const opt = b.option(field.type, field.name, "Set SQLITE_" ++ name); + const int_info = @typeInfo(IntFeatureOptions).@"struct"; + inline for (int_info.field_names, int_info.field_types) |field_name, field_type| { + comptime var buf: [field_name.len]u8 = undefined; + const name = comptime std.ascii.upperString(&buf, field_name); + const opt = b.option(field_type, field_name, "Set SQLITE_" ++ name); if (opt) |v| { const flag = try std.fmt.allocPrint(b.allocator, "-DSQLITE_" ++ name ++ "={}", .{v}); @@ -226,13 +235,13 @@ pub fn build(b: *std.Build) !void { }); mod.addIncludePath(b.path("c")); mod.addIncludePath(sqlite_dep.path(".")); + mod.addImport("sqlite3_c", translateSQLite(b, sqlite_dep, "c/sqlite3_c.h", target, optimize)); mod.linkLibrary(lib); break :blk .{ lib, mod }; }; b.installArtifact(sqlite_lib); - // const sqliteext_mod = blk: { _ = blk: { const lib = makeSQLiteLib(b, sqlite_dep, c_flags, target, optimize, .without); @@ -241,6 +250,7 @@ pub fn build(b: *std.Build) !void { .link_libc = true, }); mod.addIncludePath(b.path("c")); + mod.addImport("sqlite3_ext_c", translateSQLite(b, sqlite_dep, "c/loadable_ext_c.h", target, optimize)); mod.linkLibrary(lib); break :blk mod; @@ -271,7 +281,7 @@ pub fn build(b: *std.Build) !void { const test_sqlite_lib = makeSQLiteLib(b, sqlite_dep, c_flags, cross_target, optimize, .with); - const mod = b.addModule(test_name, .{ + const mod = b.createModule(.{ .target = cross_target, .optimize = optimize, .root_source_file = b.path("sqlite.zig"), @@ -284,6 +294,7 @@ pub fn build(b: *std.Build) !void { }); tests.root_module.addIncludePath(b.path("c")); tests.root_module.addIncludePath(sqlite_dep.path(".")); + tests.root_module.addImport("sqlite3_c", translateSQLite(b, sqlite_dep, "c/sqlite3_c.h", cross_target, optimize)); tests.root_module.linkLibrary(test_sqlite_lib); const tests_options = b.addOptions(); @@ -308,31 +319,34 @@ pub fn build(b: *std.Build) !void { // Tools // - addPreprocessStep(b, io, sqlite_dep); + addPreprocessStep(b, sqlite_dep); } -fn addPreprocessStep(b: *std.Build, io: Io, sqlite_dep: *std.Build.Dependency) void { - var wf = b.addWriteFiles(); - - // Preprocessing step - const preprocess = PreprocessStep.create(b, .{ - .source = sqlite_dep.path("."), - .target = wf.getDirectory(), - .io = io, +fn addPreprocessStep(b: *std.Build, sqlite_dep: *std.Build.Dependency) void { + const exe = b.addExecutable(.{ + .name = "preprocess", + .root_module = b.createModule(.{ + .root_source_file = b.path("build/Preprocessor.zig"), + .target = b.graph.host, + }), }); - preprocess.step.dependOn(&wf.step); + + const run = b.addRunArtifact(exe); + run.addFileArg(sqlite_dep.path("sqlite3.h")); + run.addFileArg(sqlite_dep.path("sqlite3ext.h")); + const loadable_sqlite3_h = run.addOutputFileArg2("loadable-ext-sqlite3.h", .{}); + const loadable_sqlite3ext_h = run.addOutputFileArg2("loadable-ext-sqlite3ext.h", .{}); const w = b.addUpdateSourceFiles(); - w.addCopyFileToSource(preprocess.target.join(b.allocator, "loadable-ext-sqlite3.h") catch @panic("OOM"), "c/loadable-ext-sqlite3.h"); - w.addCopyFileToSource(preprocess.target.join(b.allocator, "loadable-ext-sqlite3ext.h") catch @panic("OOM"), "c/loadable-ext-sqlite3ext.h"); - w.step.dependOn(&preprocess.step); + w.addCopyFileToSource(loadable_sqlite3_h, "c/loadable-ext-sqlite3.h"); + w.addCopyFileToSource(loadable_sqlite3ext_h, "c/loadable-ext-sqlite3ext.h"); const preprocess_headers = b.step("preprocess-headers", "Preprocess the headers for the loadable extensions"); preprocess_headers.dependOn(&w.step); } fn addZigcrypto(b: *std.Build, sqlite_mod: *std.Build.Module, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *std.Build.Step.InstallArtifact { - const mod = b.addModule("zigcryto", .{ + const mod = b.createModule(.{ .root_source_file = b.path("examples/zigcrypto.zig"), .target = getTarget(target), .optimize = optimize, @@ -352,7 +366,7 @@ fn addZigcrypto(b: *std.Build, sqlite_mod: *std.Build.Module, target: std.Build. } fn addZigcryptoTestRun(b: *std.Build, sqlite_mod: *std.Build.Module, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *std.Build.Step.Run { - const mod = b.addModule("zigcryto-test", .{ + const mod = b.createModule(.{ .root_source_file = b.path("examples/zigcrypto_test.zig"), .target = getTarget(target), .optimize = optimize, @@ -436,48 +450,3 @@ const IntFeatureOptions = struct { default_wal_synchronous: std.math.IntFittingRange(0, 3), max_expr_depth: c_int, }; - -const PreprocessStep = struct { - const Config = struct { - source: std.Build.LazyPath, - target: std.Build.LazyPath, - io: Io, - }; - - step: std.Build.Step, - - source: std.Build.LazyPath, - target: std.Build.LazyPath, - io: Io, - - fn create(owner: *std.Build, config: Config) *PreprocessStep { - const step = owner.allocator.create(PreprocessStep) catch @panic("OOM"); - step.* = .{ - .step = std.Build.Step.init(.{ - .id = std.Build.Step.Id.custom, - .name = "preprocess", - .owner = owner, - .makeFn = make, - }), - .source = config.source, - .target = config.target, - .io = config.io, - }; - - return step; - } - - fn make(step: *std.Build.Step, _: std.Build.Step.MakeOptions) !void { - const ps: *PreprocessStep = @fieldParentPtr("step", step); - const owner = step.owner; - - const sqlite3_h = try ps.source.path(owner, "sqlite3.h").getPath3(owner, step).toString(owner.allocator); - const sqlite3ext_h = try ps.source.path(owner, "sqlite3ext.h").getPath3(owner, step).toString(owner.allocator); - - const loadable_sqlite3_h = try ps.target.path(owner, "loadable-ext-sqlite3.h").getPath3(owner, step).toString(owner.allocator); - const loadable_sqlite3ext_h = try ps.target.path(owner, "loadable-ext-sqlite3ext.h").getPath3(owner, step).toString(owner.allocator); - - try Preprocessor.sqlite3(owner.allocator, ps.io, sqlite3_h, loadable_sqlite3_h); - try Preprocessor.sqlite3ext(owner.allocator, ps.io, sqlite3ext_h, loadable_sqlite3ext_h); - } -}; diff --git a/build.zig.zon b/build.zig.zon index 06507f1..d13c596 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,7 +1,7 @@ .{ .name = .sqlite, .fingerprint = 0xb8bb86826b7f6417, - .minimum_zig_version = "0.14.0", + .minimum_zig_version = "0.17.0", .version = "3.48.0", .dependencies = .{ .sqlite = .{ diff --git a/build/Preprocessor.zig b/build/Preprocessor.zig index 47cb354..8dd7f88 100644 --- a/build/Preprocessor.zig +++ b/build/Preprocessor.zig @@ -19,7 +19,7 @@ const Io = std.Io; // And even if the sqlite3_api is defined before, the generated code fails to compile because the functions are defined as consts and // can only reference comptime stuff, however sqlite3_api is a runtime variable. // -// The only viable option is to completely reomve the original function definitions and redefine all functions in Zig which forward +// The only viable option is to completely remove the original function definitions and redefine all functions in Zig which forward // calls to the sqlite3_api object. // // This works but it requires fairly extensive modifications of both sqlite3.h and sqlite3ext.h which is time consuming to do manually; @@ -31,8 +31,7 @@ fn readOriginalData(allocator: mem.Allocator, io: Io, path: []const u8) ![]const var buf: [1024]u8 = undefined; var reader = file.reader(io, &buf); - const data = reader.interface.readAlloc(allocator, 1024 * 1024); - return data; + return reader.interface.allocRemaining(allocator, .limited(16 * 1024 * 1024)); } const Processor = struct { @@ -201,6 +200,8 @@ pub fn sqlite3(allocator: mem.Allocator, io: Io, input_path: []const u8, output_ var w = output_file.writer(io, &write_buff); try w.interface.writeAll("/* sqlite3.h edited by the zig-sqlite build script */\n"); + try processor.dump(&w); + try w.interface.flush(); } pub fn sqlite3ext(allocator: mem.Allocator, io: Io, input_path: []const u8, output_path: []const u8) !void { @@ -238,4 +239,19 @@ pub fn sqlite3ext(allocator: mem.Allocator, io: Io, input_path: []const u8, outp var write_buff: [1028]u8 = undefined; var w = output_file.writer(io, &write_buff); try w.interface.writeAll("/* sqlite3ext.h edited by the zig-sqlite build script */\n"); + try processor.dump(&w); + try w.interface.flush(); +} + +/// Usage: preprocess +pub fn main(init: std.process.Init) !void { + const arena = init.arena.allocator(); + const args = try init.minimal.args.toSlice(arena); + if (args.len != 5) { + std.log.err("usage: {s} ", .{args[0]}); + std.process.exit(1); + } + + try sqlite3(arena, init.io, args[1], args[3]); + try sqlite3ext(arena, init.io, args[2], args[4]); } diff --git a/c.zig b/c.zig index 3a43106..a68de05 100644 --- a/c.zig +++ b/c.zig @@ -3,10 +3,7 @@ const root = @import("root"); pub const c = if (@hasDecl(root, "loadable_extension")) @import("c/loadable_extension.zig") else - @cImport({ - @cInclude("sqlite3.h"); - @cInclude("workaround.h"); - }); + @import("sqlite3_c"); // versionGreaterThanOrEqualTo returns true if the SQLite version is >= to the major.minor.patch provided. pub fn versionGreaterThanOrEqualTo(major: u8, minor: u8, patch: u8) bool { diff --git a/c/loadable_ext_c.h b/c/loadable_ext_c.h new file mode 100644 index 0000000..acad757 --- /dev/null +++ b/c/loadable_ext_c.h @@ -0,0 +1,2 @@ +#include "loadable-ext-sqlite3ext.h" +#include "workaround.h" diff --git a/c/loadable_extension.zig b/c/loadable_extension.zig index dfce56c..bfea5ba 100644 --- a/c/loadable_extension.zig +++ b/c/loadable_extension.zig @@ -1,7 +1,4 @@ -pub const c = @cImport({ - @cInclude("loadable-ext-sqlite3ext.h"); - @cInclude("workaround.h"); -}); +pub const c = @import("sqlite3_ext_c"); pub var sqlite3_api: [*c]c.sqlite3_api_routines = null; diff --git a/c/sqlite3_c.h b/c/sqlite3_c.h new file mode 100644 index 0000000..9760436 --- /dev/null +++ b/c/sqlite3_c.h @@ -0,0 +1,2 @@ +#include "sqlite3.h" +#include "workaround.h" diff --git a/sqlite.zig b/sqlite.zig index 1e11e0d..f65f455 100644 --- a/sqlite.zig +++ b/sqlite.zig @@ -46,8 +46,8 @@ fn isZigString(comptime T: type) bool { if (info != .pointer) break :blk false; const ptr = &info.pointer; - // Check for CV qualifiers that would prevent coerction to []const u8 - if (ptr.is_volatile or ptr.is_allowzero) break :blk false; + // Check for CV qualifiers that would prevent coercion to []const u8 + if (ptr.attrs.@"volatile" or ptr.attrs.@"allowzero") break :blk false; // If it's already a slice, simple check. if (ptr.size == .slice) { @@ -656,25 +656,25 @@ pub const Db = struct { else => @compileError("cannot use func, expecting a function"), }; if (step_fn_info.is_generic) @compileError("step function can't be generic"); - if (step_fn_info.is_var_args) @compileError("step function can't be variadic"); + if (step_fn_info.attrs.varargs) @compileError("step function can't be variadic"); const finalize_fn_info = switch (@typeInfo(@TypeOf(finalize_func))) { .@"fn" => |fn_info| fn_info, else => @compileError("cannot use func, expecting a function"), }; - if (finalize_fn_info.params.len != 1) @compileError("finalize function must take exactly one argument"); + if (finalize_fn_info.param_types.len != 1) @compileError("finalize function must take exactly one argument"); if (finalize_fn_info.is_generic) @compileError("finalize function can't be generic"); - if (finalize_fn_info.is_var_args) @compileError("finalize function can't be variadic"); + if (finalize_fn_info.attrs.varargs) @compileError("finalize function can't be variadic"); - if (step_fn_info.params[0].type.? != finalize_fn_info.params[0].type.?) { + if (step_fn_info.param_types[0].? != finalize_fn_info.param_types[0].?) { @compileError("both step and finalize functions must have the same first argument and it must be a FunctionContext"); } - if (step_fn_info.params[0].type.? != FunctionContext) { + if (step_fn_info.param_types[0].? != FunctionContext) { @compileError("both step and finalize functions must have a first argument of type FunctionContext"); } // subtract the context argument - const real_args_len = step_fn_info.params.len - 1; + const real_args_len = step_fn_info.param_types.len - 1; // @@ -700,11 +700,10 @@ pub const Db = struct { comptime var i: usize = 0; inline while (i < real_args_len) : (i += 1) { - // Remember the firt argument is always the function context - const arg = step_fn_info.params[i + 1]; + // Remember the first argument is always the function context + const ArgType = step_fn_info.param_types[i + 1].?; const arg_ptr = &args[i + 1]; - const ArgType = arg.type.?; helpers.setTypeFromValue(ArgType, arg_ptr, sqlite_args[i].?); } @@ -749,7 +748,7 @@ pub const Db = struct { else => @compileError("expecting a function"), }; if (fn_info.is_generic) @compileError("function can't be generic"); - if (fn_info.is_var_args) @compileError("function can't be variadic"); + if (fn_info.attrs.varargs) @compileError("function can't be variadic"); const ArgTuple = std.meta.ArgsTuple(Type); @@ -760,18 +759,18 @@ pub const Db = struct { const result = c.sqlite3_create_function_v2( self.db, func_name, - fn_info.params.len, + fn_info.param_types.len, flags, null, struct { fn xFunc(ctx: ?*c.sqlite3_context, argc: c_int, argv: [*c]?*c.sqlite3_value) callconv(.c) void { - debug.assert(argc == fn_info.params.len); + debug.assert(argc == fn_info.param_types.len); - const sqlite_args = argv[0..fn_info.params.len]; + const sqlite_args = argv[0..fn_info.param_types.len]; var fn_args: ArgTuple = undefined; - inline for (fn_info.params, 0..) |arg, i| { - const ArgType = arg.type.?; + inline for (fn_info.param_types, 0..) |ArgType_, i| { + const ArgType = ArgType_.?; helpers.setTypeFromValue(ArgType, &fn_args[i], sqlite_args[i].?); } @@ -1080,13 +1079,13 @@ pub fn Iterator(comptime Type: type) type { if (@typeInfo(Type.BaseType) == .int) { const inner_value = try self.readField(Type.BaseType, options, 0); - return @enumFromInt(@as(TI.tag_type, @intCast(inner_value))); + return @fromBackingInt(@intCast(@as(TI.tag_type, @intCast(inner_value)))); } @compileError("enum column " ++ @typeName(Type) ++ " must have a BaseType of either string or int"); }, .@"struct" => { - std.debug.assert(columns == TypeInfo.@"struct".fields.len); + std.debug.assert(columns == TypeInfo.@"struct".field_names.len); return try self.readStruct(options); }, else => @compileError("cannot read into type " ++ @typeName(Type) ++ " ; if dynamic memory allocation is required use nextAlloc or oneAlloc"), @@ -1164,12 +1163,12 @@ pub fn Iterator(comptime Type: type) type { return std.meta.stringToEnum(Type, inner_value) orelse unreachable; } if (@typeInfo(Type.BaseType) == .int) { - return @enumFromInt(@as(TI.tag_type, @intCast(inner_value))); + return @fromBackingInt(@intCast(@as(TI.tag_type, @intCast(inner_value)))); } @compileError("enum column " ++ @typeName(Type) ++ " must have a BaseType of either string or int"); }, .@"struct" => { - std.debug.assert(columns == TypeInfo.@"struct".fields.len); + std.debug.assert(columns == TypeInfo.@"struct".field_names.len); return try self.readStruct(.{ .allocator = allocator, }); @@ -1399,12 +1398,13 @@ pub fn Iterator(comptime Type: type) type { var value: Type = undefined; - inline for (@typeInfo(Type).@"struct".fields, 0..) |field, _i| { + const struct_info = @typeInfo(Type).@"struct"; + inline for (struct_info.field_names, struct_info.field_types, 0..) |field_name, field_type, _i| { const i = @as(usize, _i); - const ret = try self.readField(field.type, options, i); + const ret = try self.readField(field_type, options, i); - @field(value, field.name) = ret; + @field(value, field_name) = ret; } return value; @@ -1448,7 +1448,7 @@ pub fn Iterator(comptime Type: type) type { return std.meta.stringToEnum(FieldType, inner_value) orelse FieldType.default; } if (@typeInfo(FieldType.BaseType) == .int) { - return @enumFromInt(@as(TI.tag_type, @intCast(inner_value))); + return @fromBackingInt(@intCast(@as(TI.tag_type, @intCast(inner_value)))); } @compileError("enum column " ++ @typeName(FieldType) ++ " must have a BaseType of either string or int"); }, @@ -1665,7 +1665,7 @@ pub const DynamicStatement = struct { if (comptime isZigString(FieldType.BaseType)) { try self.bindField(FieldType.BaseType, options, field_name, i, @tagName(field)); } else if (@typeInfo(FieldType.BaseType) == .int) { - try self.bindField(FieldType.BaseType, options, field_name, i, @intFromEnum(field)); + try self.bindField(FieldType.BaseType, options, field_name, i, @backingInt(field)); } else { @compileError("enum column " ++ @typeName(FieldType) ++ " must have a BaseType of either string or int to bind"); } @@ -1690,16 +1690,16 @@ pub const DynamicStatement = struct { return; } if (info.tag_type) |UnionTagType| { - inline for (info.fields) |u_field| { + inline for (info.field_names, info.field_types) |u_field_name, u_field_type| { // This wasn't entirely obvious when I saw code like this elsewhere, it works because of type coercion. // See https://ziglang.org/documentation/master/#Type-Coercion-unions-and-enums const field_tag: std.meta.Tag(FieldType) = field; - const this_tag: std.meta.Tag(FieldType) = @field(UnionTagType, u_field.name); + const this_tag: std.meta.Tag(FieldType) = @field(UnionTagType, u_field_name); if (field_tag == this_tag) { - const field_value = @field(field, u_field.name); + const field_value = @field(field, u_field_name); - try self.bindField(u_field.type, options, u_field.name, i, field_value); + try self.bindField(u_field_type, options, u_field_name, i, field_value); } } } else { @@ -1747,14 +1747,14 @@ pub const DynamicStatement = struct { switch (@typeInfo(Type)) { .@"struct" => |StructTypeInfo| { - inline for (StructTypeInfo.fields, 0..) |struct_field, struct_field_i| { - const field_value = @field(values, struct_field.name); + inline for (StructTypeInfo.field_names, StructTypeInfo.field_types, 0..) |field_name, field_type, struct_field_i| { + const field_value = @field(values, field_name); - const i = sqlite3BindParameterIndex(self.stmt, struct_field.name); + const i = sqlite3BindParameterIndex(self.stmt, field_name); if (i >= 0) { - try self.bindField(struct_field.type, options, struct_field.name, i, field_value); + try self.bindField(field_type, options, field_name, i, field_value); } else { - try self.bindField(struct_field.type, options, struct_field.name, struct_field_i, field_value); + try self.bindField(field_type, options, field_name, struct_field_i, field_value); } } }, @@ -2045,8 +2045,8 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: anytype) type const StructTypeInfo = @typeInfo(StructType).@"struct"; comptime marker_len_check: { - if (query.bind_markers.len != StructTypeInfo.fields.len) { - if (query.bind_markers.len > StructTypeInfo.fields.len) { + if (query.bind_markers.len != StructTypeInfo.field_names.len) { + if (query.bind_markers.len > StructTypeInfo.field_names.len) { var found_markers = 0; for (query.bind_markers) |bind_marker| { if (bind_marker.name) |name| { @@ -2061,21 +2061,21 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: anytype) type } @compileError(std.fmt.comptimePrint("expected {d} bind parameters but got {d}", .{ query.bind_markers.len, - StructTypeInfo.fields.len, + StructTypeInfo.field_names.len, })); } } - inline for (StructTypeInfo.fields, 0..) |struct_field, _i| { + inline for (StructTypeInfo.field_types, 0..) |field_type, _i| { const bind_marker = query.bind_markers[_i]; if (bind_marker.typed) |typ| { - const FieldTypeInfo = @typeInfo(struct_field.type); + const FieldTypeInfo = @typeInfo(field_type); switch (FieldTypeInfo) { .@"struct", .@"enum", .@"union" => comptime assertMarkerType( - if (@hasDecl(struct_field.type, "BaseType")) struct_field.type.BaseType else struct_field.type, + if (@hasDecl(field_type, "BaseType")) field_type.BaseType else field_type, typ, ), - else => comptime assertMarkerType(struct_field.type, typ), + else => comptime assertMarkerType(field_type, typ), } } } @@ -3109,7 +3109,7 @@ test "sqlite: blob open, reopen" { const data = try blob.read_from_db(&read_buff); - try testing.expectEqualSlices(u8, blob_data1 ** 2, data); + try testing.expectEqualSlices(u8, blob_data1 ++ blob_data1, data); } // Reopen the blob in the second row @@ -3126,7 +3126,7 @@ test "sqlite: blob open, reopen" { const data = try blob.read_from_db(&read_buff); - try testing.expectEqualSlices(u8, blob_data2 ** 2, data); + try testing.expectEqualSlices(u8, blob_data2 ++ blob_data2, data); } try blob.close(); @@ -3377,7 +3377,7 @@ const MyData = struct { pub fn readField(alloc: mem.Allocator, value: BaseType) !MyData { _ = alloc; - var result = [_]u8{0} ** 16; + var result: [16]u8 = @splat(0); var i: usize = 0; while (i < result.len) : (i += 1) { const j = i * 2; diff --git a/test.zig b/test.zig index fcc8aa7..987ceee 100644 --- a/test.zig +++ b/test.zig @@ -24,14 +24,14 @@ fn tmpDbPath(allocator: mem.Allocator) ![:0]const u8 { const tmp_dir = testing.tmpDir(.{}); const path = try std.fs.path.join(allocator, &[_][]const u8{ - "zig-cache", + ".zig-cache", "tmp", &tmp_dir.sub_path, "zig-sqlite.db", }); defer allocator.free(path); - return allocator.dupeZ(u8, path); + return allocator.dupeSentinel(u8, path, 0); } fn dbMode(allocator: mem.Allocator) Db.Mode { @@ -39,12 +39,12 @@ fn dbMode(allocator: mem.Allocator) Db.Mode { break :blk .{ .Memory = {} }; } else blk: { if (build_options.dbfile) |dbfile| { - return .{ .File = allocator.dupeZ(u8, dbfile) catch unreachable }; + return .{ .File = allocator.dupeSentinel(u8, dbfile, 0) catch unreachable }; } const path = tmpDbPath(allocator) catch unreachable; - std.fs.cwd().deleteFile(path) catch {}; + std.Io.Dir.cwd().deleteFile(testing.io, path) catch {}; break :blk .{ .File = path }; }; } diff --git a/vtab.zig b/vtab.zig index b804dc9..96a1787 100644 --- a/vtab.zig +++ b/vtab.zig @@ -324,9 +324,9 @@ fn validateCursorType(comptime Table: type) void { const info = @typeInfo(@TypeOf(Cursor.init)).@"fn"; - if (info.params.len != 2) @compileError(error_message); - if (info.params[0].type.? != mem.Allocator) @compileError(error_message); - if (info.params[1].type.? != *Table) @compileError(error_message); + if (info.param_types.len != 2) @compileError(error_message); + if (info.param_types[0].? != mem.Allocator) @compileError(error_message); + if (info.param_types[1].? != *Table) @compileError(error_message); if (info.return_type.? != Cursor.InitError!*Cursor) @compileError(error_message); } @@ -342,8 +342,8 @@ fn validateCursorType(comptime Table: type) void { const info = @typeInfo(@TypeOf(Cursor.deinit)).@"fn"; - if (info.params.len != 1) @compileError(error_message); - if (info.params[0].type.? != *Cursor) @compileError(error_message); + if (info.param_types.len != 1) @compileError(error_message); + if (info.param_types[0].? != *Cursor) @compileError(error_message); if (info.return_type.? != void) @compileError(error_message); } @@ -363,9 +363,9 @@ fn validateCursorType(comptime Table: type) void { const info = @typeInfo(@TypeOf(Cursor.next)).@"fn"; - if (info.params.len != 2) @compileError(error_message); - if (info.params[0].type.? != *Cursor) @compileError(error_message); - if (info.params[1].type.? != *VTabDiagnostics) @compileError(error_message); + if (info.param_types.len != 2) @compileError(error_message); + if (info.param_types[0].? != *Cursor) @compileError(error_message); + if (info.param_types[1].? != *VTabDiagnostics) @compileError(error_message); if (info.return_type.? != Cursor.NextError!void) @compileError(error_message); } @@ -385,9 +385,9 @@ fn validateCursorType(comptime Table: type) void { const info = @typeInfo(@TypeOf(Cursor.hasNext)).@"fn"; - if (info.params.len != 2) @compileError(error_message); - if (info.params[0].type.? != *Cursor) @compileError(error_message); - if (info.params[1].type.? != *VTabDiagnostics) @compileError(error_message); + if (info.param_types.len != 2) @compileError(error_message); + if (info.param_types[0].? != *Cursor) @compileError(error_message); + if (info.param_types[1].? != *VTabDiagnostics) @compileError(error_message); if (info.return_type.? != Cursor.HasNextError!bool) @compileError(error_message); } @@ -407,11 +407,11 @@ fn validateCursorType(comptime Table: type) void { const info = @typeInfo(@TypeOf(Cursor.filter)).@"fn"; - if (info.params.len != 4) @compileError(error_message); - if (info.params[0].type.? != *Cursor) @compileError(error_message); - if (info.params[1].type.? != *VTabDiagnostics) @compileError(error_message); - if (info.params[2].type.? != IndexIdentifier) @compileError(error_message); - if (info.params[3].type.? != []FilterArg) @compileError(error_message); + if (info.param_types.len != 4) @compileError(error_message); + if (info.param_types[0].? != *Cursor) @compileError(error_message); + if (info.param_types[1].? != *VTabDiagnostics) @compileError(error_message); + if (info.param_types[2].? != IndexIdentifier) @compileError(error_message); + if (info.param_types[3].? != []FilterArg) @compileError(error_message); if (info.return_type.? != Cursor.FilterError!void) @compileError(error_message); } @@ -434,10 +434,10 @@ fn validateCursorType(comptime Table: type) void { const info = @typeInfo(@TypeOf(Cursor.column)).@"fn"; - if (info.params.len != 3) @compileError(error_message); - if (info.params[0].type.? != *Cursor) @compileError(error_message); - if (info.params[1].type.? != *VTabDiagnostics) @compileError(error_message); - if (info.params[2].type.? != i32) @compileError(error_message); + if (info.param_types.len != 3) @compileError(error_message); + if (info.param_types[0].? != *Cursor) @compileError(error_message); + if (info.param_types[1].? != *VTabDiagnostics) @compileError(error_message); + if (info.param_types[2].? != i32) @compileError(error_message); if (info.return_type.? != Cursor.ColumnError!Cursor.Column) @compileError(error_message); } @@ -457,9 +457,9 @@ fn validateCursorType(comptime Table: type) void { const info = @typeInfo(@TypeOf(Cursor.rowId)).@"fn"; - if (info.params.len != 2) @compileError(error_message); - if (info.params[0].type.? != *Cursor) @compileError(error_message); - if (info.params[1].type.? != *VTabDiagnostics) @compileError(error_message); + if (info.param_types.len != 2) @compileError(error_message); + if (info.param_types[0].? != *Cursor) @compileError(error_message); + if (info.param_types[1].? != *VTabDiagnostics) @compileError(error_message); if (info.return_type.? != Cursor.RowIDError!i64) @compileError(error_message); } } @@ -482,11 +482,11 @@ fn validateTableType(comptime Table: type) void { const info = @typeInfo(@TypeOf(Table.init)).@"fn"; - if (info.params.len != 3) @compileError(error_message); - if (info.params[0].type.? != mem.Allocator) @compileError(error_message); - if (info.params[1].type.? != *VTabDiagnostics) @compileError(error_message); + if (info.param_types.len != 3) @compileError(error_message); + if (info.param_types[0].? != mem.Allocator) @compileError(error_message); + if (info.param_types[1].? != *VTabDiagnostics) @compileError(error_message); // TODO(vincent): maybe allow a signature without the params since a table can do withoout them - if (info.params[2].type.? != []const ModuleArgument) @compileError(error_message); + if (info.param_types[2].? != []const ModuleArgument) @compileError(error_message); if (info.return_type.? != Table.InitError!*Table) @compileError(error_message); } @@ -502,9 +502,9 @@ fn validateTableType(comptime Table: type) void { const info = @typeInfo(@TypeOf(Table.deinit)).@"fn"; - if (info.params.len != 2) @compileError(error_message); - if (info.params[0].type.? != *Table) @compileError(error_message); - if (info.params[1].type.? != mem.Allocator) @compileError(error_message); + if (info.param_types.len != 2) @compileError(error_message); + if (info.param_types[0].? != *Table) @compileError(error_message); + if (info.param_types[1].? != mem.Allocator) @compileError(error_message); if (info.return_type.? != void) @compileError(error_message); } @@ -524,10 +524,10 @@ fn validateTableType(comptime Table: type) void { const info = @typeInfo(@TypeOf(Table.buildBestIndex)).@"fn"; - if (info.params.len != 3) @compileError(error_message); - if (info.params[0].type.? != *Table) @compileError(error_message); - if (info.params[1].type.? != *VTabDiagnostics) @compileError(error_message); - if (info.params[2].type.? != *BestIndexBuilder) @compileError(error_message); + if (info.param_types.len != 3) @compileError(error_message); + if (info.param_types[0].? != *Table) @compileError(error_message); + if (info.param_types[1].? != *VTabDiagnostics) @compileError(error_message); + if (info.param_types[2].? != *BestIndexBuilder) @compileError(error_message); if (info.return_type.? != Table.BuildBestIndexError!void) @compileError(error_message); } @@ -931,15 +931,15 @@ pub fn VirtualTable( switch (@typeInfo(ColumnType)) { .@"union" => |info| { if (info.tag_type) |UnionTagType| { - inline for (info.fields) |u_field| { + inline for (info.field_names) |u_field_name| { // This wasn't entirely obvious when I saw code like this elsewhere, it works because of type coercion. // See https://ziglang.org/documentation/master/#Type-Coercion-unions-and-enums const column_tag: std.meta.Tag(ColumnType) = column; - const this_tag: std.meta.Tag(ColumnType) = @field(UnionTagType, u_field.name); + const this_tag: std.meta.Tag(ColumnType) = @field(UnionTagType, u_field_name); if (column_tag == this_tag) { - const column_value = @field(column, u_field.name); + const column_value = @field(column, u_field_name); helpers.setResult(ctx, column_value); } @@ -1048,9 +1048,9 @@ const TestVirtualTable = struct { res.rows = rows; // Build the schema - res.schema = try allocator.dupeZ(u8, + res.schema = try allocator.dupeSentinel(u8, \\CREATE TABLE foobar(foo TEXT, bar TEXT, baz INTEGER) - ); + , 0); res.arena_state = arena.state;