summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Vincent Rischmann2024-04-14 20:50:44 +0200
committerGravatar GitHub2024-04-14 20:50:44 +0200
commit19dd52b7b7e9fa5ec029c4ac3bd53fb41e5be12c (patch)
tree453f927a6926b4f778a4be2a14164896734a60f0
parentMerge pull request #157 from vrischmann/update-latest-zig (diff)
parentci: run with -fqemu and -frosetta (diff)
downloadzig-sqlite-19dd52b7b7e9fa5ec029c4ac3bd53fb41e5be12c.tar.gz
zig-sqlite-19dd52b7b7e9fa5ec029c4ac3bd53fb41e5be12c.tar.xz
zig-sqlite-19dd52b7b7e9fa5ec029c4ac3bd53fb41e5be12c.zip
Merge pull request #158 from vrischmann/workaround-sqlite-transient
Workaround SQLITE_TRANSIENT
-rw-r--r--.github/workflows/main.yml26
-rw-r--r--build.zig140
-rw-r--r--c.zig1
-rw-r--r--c/loadable_extension.zig1
-rw-r--r--c/workaround.c5
-rw-r--r--c/workaround.h3
-rw-r--r--helpers.zig8
-rw-r--r--sqlite.zig2
8 files changed, 75 insertions, 111 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index adc7db1..6a6093c 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -29,18 +29,26 @@ jobs:
29 strategy: 29 strategy:
30 fail-fast: false 30 fail-fast: false
31 matrix: 31 matrix:
32 os: [ubuntu-latest, macos-latest, macos-12] 32 os: [ubuntu-latest, windows-latest, macos-latest]
33 runs-on: ${{ matrix.os }} 33 runs-on: ${{ matrix.os }}
34 steps: 34 steps:
35 - uses: actions/checkout@v4 35 - name: Checkout repository
36 uses: actions/checkout@v4
36 with: 37 with:
37 submodules: true 38 submodules: true
38 - uses: goto-bus-stop/setup-zig@v2 39
40 - name: Setup zig
41 uses: goto-bus-stop/setup-zig@v2
39 with: 42 with:
40 version: master 43 version: master
41 44
42 - uses: actions/cache@v4 45 - name: Install qemu
43 if: ${{ matrix.os != 'windows-latest' }} 46 if: ${{ matrix.os == 'ubuntu-latest' }}
47 run: |
48 sudo apt-get update -y && sudo apt-get install -y qemu-user-binfmt
49
50 - name: Restore cache
51 uses: actions/cache@v4
44 with: 52 with:
45 path: | 53 path: |
46 zig-cache 54 zig-cache
@@ -49,9 +57,17 @@ jobs:
49 restore-keys: ${{ runner.os }}-${{ matrix.os }}-zig- 57 restore-keys: ${{ runner.os }}-${{ matrix.os }}-zig-
50 58
51 - name: Run Tests in memory 59 - name: Run Tests in memory
60 if: ${{ matrix.os == 'ubuntu-latest' }}
61 run: zig build test -Dci=true -Din_memory=true --summary all -fqemu -fwine
62 - name: Run Tests in memory
63 if: ${{ matrix.os == 'macos-latest' }}
64 run: zig build test -Dci=true -Din_memory=true --summary all -frosetta
65 - name: Run Tests in memory
66 if: ${{ matrix.os == 'windows-latest' }}
52 run: zig build test -Dci=true -Din_memory=true --summary all 67 run: zig build test -Dci=true -Din_memory=true --summary all
53 68
54 - name: Build the example zigcrypto loadable extension 69 - name: Build the example zigcrypto loadable extension
55 run: zig build zigcrypto 70 run: zig build zigcrypto
56 - name: Test the zigcrypto loadable extension 71 - name: Test the zigcrypto loadable extension
72 if: ${{ matrix.os != 'windows-latest' }}
57 run: ./zig-out/bin/zigcrypto-test 73 run: ./zig-out/bin/zigcrypto-test
diff --git a/build.zig b/build.zig
index cd617f7..af6ece1 100644
--- a/build.zig
+++ b/build.zig
@@ -4,17 +4,6 @@ const Step = std.Build.Step;
4const ResolvedTarget = std.Build.ResolvedTarget; 4const ResolvedTarget = std.Build.ResolvedTarget;
5const Query = std.Target.Query; 5const Query = std.Target.Query;
6 6
7var sqlite3: ?*Step.Compile = null;
8
9fn linkSqlite(b: *Step.Compile) void {
10 if (sqlite3) |lib| {
11 b.linkLibrary(lib);
12 } else {
13 b.linkLibC();
14 b.linkSystemLibrary("sqlite3");
15 }
16}
17
18fn getTarget(original_target: ResolvedTarget, bundled: bool) ResolvedTarget { 7fn getTarget(original_target: ResolvedTarget, bundled: bool) ResolvedTarget {
19 if (bundled) { 8 if (bundled) {
20 var tmp = original_target; 9 var tmp = original_target;
@@ -46,70 +35,21 @@ const TestTarget = struct {
46const ci_targets = switch (builtin.target.cpu.arch) { 35const ci_targets = switch (builtin.target.cpu.arch) {
47 .x86_64 => switch (builtin.target.os.tag) { 36 .x86_64 => switch (builtin.target.os.tag) {
48 .linux => [_]TestTarget{ 37 .linux => [_]TestTarget{
49 // Targets linux but other CPU archs. 38 TestTarget{ .query = .{ .cpu_arch = .x86_64, .abi = .musl }, .bundled = true },
50 TestTarget{ 39 TestTarget{ .query = .{ .cpu_arch = .x86, .abi = .musl }, .bundled = true },
51 .query = .{}, 40 TestTarget{ .query = .{ .cpu_arch = .aarch64, .abi = .musl }, .bundled = true },
52 .bundled = false,
53 },
54 TestTarget{
55 .query = .{
56 .cpu_arch = .x86_64,
57 .abi = .musl,
58 },
59 .bundled = true,
60 },
61 TestTarget{
62 .query = .{
63 .cpu_arch = .x86,
64 .abi = .musl,
65 },
66 .bundled = true,
67 },
68 }, 41 },
69 .windows => [_]TestTarget{ 42 .windows => [_]TestTarget{
70 TestTarget{ 43 TestTarget{ .query = .{ .cpu_arch = .x86_64, .abi = .gnu }, .bundled = true },
71 .query = .{ 44 TestTarget{ .query = .{ .cpu_arch = .x86, .abi = .gnu }, .bundled = true },
72 .cpu_arch = .x86_64,
73 .abi = .gnu,
74 },
75 .bundled = true,
76 },
77 TestTarget{
78 .query = .{
79 .cpu_arch = .x86,
80 .abi = .gnu,
81 },
82 .bundled = true,
83 },
84 }, 45 },
85 .macos => [_]TestTarget{ 46 .macos => [_]TestTarget{
86 TestTarget{ 47 TestTarget{ .query = .{ .cpu_arch = .x86_64 }, .bundled = true },
87 .query = .{ 48 TestTarget{ .query = .{ .cpu_arch = .aarch64 }, .bundled = true },
88 .cpu_arch = .x86_64,
89 },
90 .bundled = true,
91 },
92 // TODO(vincent): this fails for some reason
93 // TestTarget{
94 // .query =.{
95 // .cpu_arch = .aarch64,
96 // },
97 // .bundled = true,
98 // },
99 },
100 else => [_]TestTarget{
101 TestTarget{
102 .query = .{},
103 .bundled = false,
104 },
105 },
106 },
107 else => [_]TestTarget{
108 TestTarget{
109 .query = .{},
110 .bundled = false,
111 }, 49 },
50 else => unreachable,
112 }, 51 },
52 else => unreachable,
113}; 53};
114 54
115const all_test_targets = switch (builtin.target.cpu.arch) { 55const all_test_targets = switch (builtin.target.cpu.arch) {
@@ -267,6 +207,8 @@ pub fn build(b: *std.Build) !void {
267 const target = b.resolveTargetQuery(query); 207 const target = b.resolveTargetQuery(query);
268 const optimize = b.standardOptimizeOption(.{}); 208 const optimize = b.standardOptimizeOption(.{});
269 209
210 const c_flags = &[_][]const u8{"-std=c99"};
211
270 const sqlite_lib = b.addStaticLibrary(.{ 212 const sqlite_lib = b.addStaticLibrary(.{
271 .name = "sqlite", 213 .name = "sqlite",
272 .target = target, 214 .target = target,
@@ -274,9 +216,12 @@ pub fn build(b: *std.Build) !void {
274 }); 216 });
275 217
276 sqlite_lib.addIncludePath(.{ .path = "c/" }); 218 sqlite_lib.addIncludePath(.{ .path = "c/" });
277 sqlite_lib.addCSourceFile(.{ 219 sqlite_lib.addCSourceFiles(.{
278 .file = .{ .path = "c/sqlite3.c" }, 220 .files = &[_][]const u8{
279 .flags = &[_][]const u8{"-std=c99"}, 221 "c/sqlite3.c",
222 "c/workaround.c",
223 },
224 .flags = c_flags,
280 }); 225 });
281 sqlite_lib.linkLibC(); 226 sqlite_lib.linkLibC();
282 sqlite_lib.installHeader(.{ .path = "c/sqlite3.h" }, "sqlite3.h"); 227 sqlite_lib.installHeader(.{ .path = "c/sqlite3.h" }, "sqlite3.h");
@@ -330,6 +275,20 @@ pub fn build(b: *std.Build) !void {
330 single_threaded_txt, 275 single_threaded_txt,
331 }); 276 });
332 277
278 const test_sqlite_lib = b.addStaticLibrary(.{
279 .name = "sqlite",
280 .target = cross_target,
281 .optimize = optimize,
282 });
283 test_sqlite_lib.addCSourceFiles(.{
284 .files = &[_][]const u8{
285 "c/sqlite3.c",
286 "c/workaround.c",
287 },
288 .flags = c_flags,
289 });
290 test_sqlite_lib.linkLibC();
291
333 const tests = b.addTest(.{ 292 const tests = b.addTest(.{
334 .name = test_name, 293 .name = test_name,
335 .target = cross_target, 294 .target = cross_target,
@@ -337,40 +296,22 @@ pub fn build(b: *std.Build) !void {
337 .root_source_file = .{ .path = "sqlite.zig" }, 296 .root_source_file = .{ .path = "sqlite.zig" },
338 .single_threaded = test_target.single_threaded, 297 .single_threaded = test_target.single_threaded,
339 }); 298 });
340 const run_tests = b.addRunArtifact(tests); 299 tests.addIncludePath(.{ .path = "c" });
341
342 if (bundled) { 300 if (bundled) {
343 const lib = b.addStaticLibrary(.{ 301 tests.linkLibrary(test_sqlite_lib);
344 .name = "sqlite", 302 } else {
345 .target = cross_target, 303 tests.linkLibC();
346 .optimize = optimize, 304 tests.addCSourceFile(.{ .file = .{ .path = "c/workaround.c" }, .flags = c_flags });
347 }); 305 tests.linkSystemLibrary("sqlite3");
348 lib.addCSourceFile(.{
349 .file = .{ .path = "c/sqlite3.c" },
350 .flags = &[_][]const u8{"-std=c99"},
351 });
352 lib.linkLibC();
353 sqlite3 = lib;
354 } 306 }
355 307
356 if (bundled) tests.addIncludePath(.{ .path = "c" });
357 linkSqlite(tests);
358
359 const lib = b.addStaticLibrary(.{
360 .name = "zig-sqlite",
361 .root_source_file = .{ .path = "sqlite.zig" },
362 .target = cross_target,
363 .optimize = optimize,
364 });
365 if (bundled) lib.addIncludePath(.{ .path = "c" });
366 linkSqlite(lib);
367
368 const tests_options = b.addOptions(); 308 const tests_options = b.addOptions();
369 tests.root_module.addImport("build_options", tests_options.createModule()); 309 tests.root_module.addImport("build_options", tests_options.createModule());
370 310
371 tests_options.addOption(bool, "in_memory", in_memory); 311 tests_options.addOption(bool, "in_memory", in_memory);
372 tests_options.addOption(?[]const u8, "dbfile", dbfile); 312 tests_options.addOption(?[]const u8, "dbfile", dbfile);
373 313
314 const run_tests = b.addRunArtifact(tests);
374 test_step.dependOn(&run_tests.step); 315 test_step.dependOn(&run_tests.step);
375 } 316 }
376 317
@@ -381,10 +322,7 @@ pub fn build(b: *std.Build) !void {
381 .target = getTarget(target, true), 322 .target = getTarget(target, true),
382 .optimize = optimize, 323 .optimize = optimize,
383 }); 324 });
384 lib.addCSourceFile(.{ 325 lib.addCSourceFile(.{ .file = .{ .path = "c/sqlite3.c" }, .flags = c_flags });
385 .file = .{ .path = "c/sqlite3.c" },
386 .flags = &[_][]const u8{"-std=c99"},
387 });
388 lib.addIncludePath(.{ .path = "c" }); 326 lib.addIncludePath(.{ .path = "c" });
389 lib.linkLibC(); 327 lib.linkLibC();
390 328
diff --git a/c.zig b/c.zig
index 4589aef..3a43106 100644
--- a/c.zig
+++ b/c.zig
@@ -5,6 +5,7 @@ pub const c = if (@hasDecl(root, "loadable_extension"))
5else 5else
6 @cImport({ 6 @cImport({
7 @cInclude("sqlite3.h"); 7 @cInclude("sqlite3.h");
8 @cInclude("workaround.h");
8 }); 9 });
9 10
10// versionGreaterThanOrEqualTo returns true if the SQLite version is >= to the major.minor.patch provided. 11// versionGreaterThanOrEqualTo returns true if the SQLite version is >= to the major.minor.patch provided.
diff --git a/c/loadable_extension.zig b/c/loadable_extension.zig
index 4b27534..fdfe15e 100644
--- a/c/loadable_extension.zig
+++ b/c/loadable_extension.zig
@@ -1,5 +1,6 @@
1const c = @cImport({ 1const c = @cImport({
2 @cInclude("loadable-ext-sqlite3ext.h"); 2 @cInclude("loadable-ext-sqlite3ext.h");
3 @cInclude("workaround.h");
3}); 4});
4 5
5pub usingnamespace c; 6pub usingnamespace c;
diff --git a/c/workaround.c b/c/workaround.c
new file mode 100644
index 0000000..592d33d
--- /dev/null
+++ b/c/workaround.c
@@ -0,0 +1,5 @@
1#include "workaround.h"
2
3my_sqlite3_destructor_type sqliteTransientAsDestructor() {
4 return (my_sqlite3_destructor_type)-1;
5}
diff --git a/c/workaround.h b/c/workaround.h
new file mode 100644
index 0000000..ae243b8
--- /dev/null
+++ b/c/workaround.h
@@ -0,0 +1,3 @@
1typedef void (*my_sqlite3_destructor_type)(void *);
2
3my_sqlite3_destructor_type sqliteTransientAsDestructor();
diff --git a/helpers.zig b/helpers.zig
index 7bb695e..b9a6131 100644
--- a/helpers.zig
+++ b/helpers.zig
@@ -13,8 +13,8 @@ pub fn setResult(ctx: ?*c.sqlite3_context, result: anytype) void {
13 const ResultType = @TypeOf(result); 13 const ResultType = @TypeOf(result);
14 14
15 switch (ResultType) { 15 switch (ResultType) {
16 Text => c.sqlite3_result_text(ctx, result.data.ptr, @intCast(result.data.len), c.SQLITE_TRANSIENT), 16 Text => c.sqlite3_result_text(ctx, result.data.ptr, @intCast(result.data.len), c.sqliteTransientAsDestructor()),
17 Blob => c.sqlite3_result_blob(ctx, result.data.ptr, @intCast(result.data.len), c.SQLITE_TRANSIENT), 17 Blob => c.sqlite3_result_blob(ctx, result.data.ptr, @intCast(result.data.len), c.sqliteTransientAsDestructor()),
18 else => switch (@typeInfo(ResultType)) { 18 else => switch (@typeInfo(ResultType)) {
19 .Int => |info| if ((info.bits + if (info.signedness == .unsigned) 1 else 0) <= 32) { 19 .Int => |info| if ((info.bits + if (info.signedness == .unsigned) 1 else 0) <= 32) {
20 c.sqlite3_result_int(ctx, result); 20 c.sqlite3_result_int(ctx, result);
@@ -26,12 +26,12 @@ pub fn setResult(ctx: ?*c.sqlite3_context, result: anytype) void {
26 .Float => c.sqlite3_result_double(ctx, result), 26 .Float => c.sqlite3_result_double(ctx, result),
27 .Bool => c.sqlite3_result_int(ctx, if (result) 1 else 0), 27 .Bool => c.sqlite3_result_int(ctx, if (result) 1 else 0),
28 .Array => |arr| switch (arr.child) { 28 .Array => |arr| switch (arr.child) {
29 u8 => c.sqlite3_result_blob(ctx, &result, arr.len, c.SQLITE_TRANSIENT), 29 u8 => c.sqlite3_result_blob(ctx, &result, arr.len, c.sqliteTransientAsDestructor()),
30 else => @compileError("cannot use a result of type " ++ @typeName(ResultType)), 30 else => @compileError("cannot use a result of type " ++ @typeName(ResultType)),
31 }, 31 },
32 .Pointer => |ptr| switch (ptr.size) { 32 .Pointer => |ptr| switch (ptr.size) {
33 .Slice => switch (ptr.child) { 33 .Slice => switch (ptr.child) {
34 u8 => c.sqlite3_result_text(ctx, result.ptr, @intCast(result.len), c.SQLITE_TRANSIENT), 34 u8 => c.sqlite3_result_text(ctx, result.ptr, @intCast(result.len), c.sqliteTransientAsDestructor()),
35 else => @compileError("cannot use a result of type " ++ @typeName(ResultType)), 35 else => @compileError("cannot use a result of type " ++ @typeName(ResultType)),
36 }, 36 },
37 else => @compileError("cannot use a result of type " ++ @typeName(ResultType)), 37 else => @compileError("cannot use a result of type " ++ @typeName(ResultType)),
diff --git a/sqlite.zig b/sqlite.zig
index be46dea..bd11dea 100644
--- a/sqlite.zig
+++ b/sqlite.zig
@@ -1676,7 +1676,7 @@ pub const DynamicStatement = struct {
1676 const data: []const u8 = field[0..field.len]; 1676 const data: []const u8 = field[0..field.len];
1677 1677
1678 // NOTE(vincent): The array is temporary and must be copied, therefore we use SQLITE_TRANSIENT 1678 // NOTE(vincent): The array is temporary and must be copied, therefore we use SQLITE_TRANSIENT
1679 const result = c.sqlite3_bind_text(self.stmt, column, data.ptr, @intCast(data.len), c.SQLITE_TRANSIENT); 1679 const result = c.sqlite3_bind_text(self.stmt, column, data.ptr, @intCast(data.len), c.sqliteTransientAsDestructor());
1680 return convertResultToError(result); 1680 return convertResultToError(result);
1681 }, 1681 },
1682 else => @compileError("cannot bind field " ++ field_name ++ " of type array of " ++ @typeName(arr.child)), 1682 else => @compileError("cannot bind field " ++ field_name ++ " of type array of " ++ @typeName(arr.child)),