Skip to content
This repository was archived by the owner on Jan 5, 2025. It is now read-only.

Commit 68c81ce

Browse files
committed
check for sqlite version at runtime
Runtime check for sqlite version is needed for loading the extension at runtime. Bump the minimum version of sqlite to 3.26.0 to simplify module initialization
1 parent fd4aa73 commit 68c81ce

File tree

5 files changed

+62
-94
lines changed

5 files changed

+62
-94
lines changed

.github/workflows/ci.yaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,18 @@ jobs:
1818
matrix:
1919
os: [ "ubuntu-latest", "macos-latest", "windows-latest" ]
2020
sqlite:
21-
- version: 3.23.1
21+
- version: 3.26.0
2222
year: 2018
23-
- version: 3.29.0
23+
- version: 3.30.1
2424
year: 2019
25-
- version: 3.35.5
25+
- version: 3.34.1
2626
year: 2021
2727
- version: 3.38.5
2828
year: 2022
29-
- version: 3.41.2
30-
year: 2023
31-
- version: 3.44.2
29+
- version: 3.42.0
3230
year: 2023
31+
- version: 3.45.0
32+
year: 2024
3333
runs-on: ${{ matrix.os }}
3434
env:
3535
SQLITE_VERSION: ${{ matrix.sqlite.version }}

src/main.zig

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ const std = @import("std");
22
const Allocator = std.mem.Allocator;
33
const GeneralPurposeAllocator = std.heap.GeneralPurposeAllocator;
44

5-
const c = @import("sqlite3/c.zig").c;
5+
const c_mod = @import("sqlite3/c.zig");
6+
const c = c_mod.c;
7+
const encodeSqliteVersion = c_mod.encodeVersionNumber;
8+
const sqliteVersion = c_mod.versionNumber;
69
const sqlite = @import("sqlite3.zig");
710
const sqlite_errors = sqlite.errors;
811
const vtab = sqlite.vtab;
@@ -18,13 +21,20 @@ const SegmentInfoTabValFn = vtab.VirtualTable(SegmentInfoFn);
1821

1922
var allocator: GeneralPurposeAllocator(.{}) = undefined;
2023

24+
const min_sqlite_version = encodeSqliteVersion(3, 26, 0);
25+
2126
pub export fn sqlite3_stanchion_init(
2227
db: *c.sqlite3,
2328
err_msg: [*c][*c]u8,
2429
api: *c.sqlite3_api_routines,
2530
) callconv(.C) c_int {
2631
c.sqlite3_api = api;
2732

33+
if (sqliteVersion() < min_sqlite_version) {
34+
err_msg.* = @constCast(@ptrCast("stanchion requires sqlite version >= 3.26.0"));
35+
return c.SQLITE_ERROR;
36+
}
37+
2838
// To store data common to all table instances (global to the module), replace this allocator
2939
// with a struct containing the common data (see `ModuleContext` in `zig-sqlite`)
3040
allocator = GeneralPurposeAllocator(.{}){};

src/sqlite3/c.zig

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,12 @@ else
1010
@cInclude("result-transient.h");
1111
});
1212

13-
/// versionGreaterThanOrEqualTo returns true if the SQLite version is >= to the
14-
/// major.minor.patch provided.
15-
pub fn versionGreaterThanOrEqualTo(major: u8, minor: u8, patch: u8) bool {
16-
return c.SQLITE_VERSION_NUMBER >=
17-
@as(u32, major) * 1000000 + @as(u32, minor) * 1000 + @as(u32, patch);
13+
/// Returns the sqlite version encoded as a number
14+
pub fn versionNumber() u32 {
15+
return @intCast(c.sqlite3_libversion_number());
1816
}
1917

20-
comptime {
21-
if (!versionGreaterThanOrEqualTo(3, 23, 1)) {
22-
@compileError("must use SQLite >= 3.23.1");
23-
}
18+
/// Generates a sqlite encoded version number as an integer from major.minor.patch
19+
pub fn encodeVersionNumber(major: u8, minor: u8, patch: u8) u32 {
20+
return @as(u32, major) * 1000000 + @as(u32, minor) * 1000 + @as(u32, patch);
2421
}

src/sqlite3/errors.zig

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
const std = @import("std");
55
const mem = std.mem;
66

7-
const c = @import("c.zig").c;
8-
const versionGreaterThanOrEqualTo = @import("c.zig").versionGreaterThanOrEqualTo;
7+
const c_wrapper = @import("c.zig");
8+
const c = c_wrapper.c;
9+
const encodeVersionNumber = c_wrapper.encodeVersionNumber;
10+
const versionNumber = c_wrapper.versionNumber;
911

1012
pub const SQLiteExtendedIOError = error{
1113
SQLiteIOErrRead,
@@ -132,46 +134,32 @@ pub const Error = SQLiteError ||
132134
SQLiteExtendedConstraintError;
133135

134136
pub fn errorFromResultCode(code: c_int) Error {
135-
// These errors are only available since 3.22.0.
136-
if (comptime versionGreaterThanOrEqualTo(3, 22, 0)) {
137-
switch (code) {
138-
c.SQLITE_ERROR_MISSING_COLLSEQ => return error.SQLiteErrorMissingCollSeq,
139-
c.SQLITE_ERROR_RETRY => return error.SQLiteErrorRetry,
140-
c.SQLITE_READONLY_CANTINIT => return error.SQLiteReadOnlyCantInit,
141-
c.SQLITE_READONLY_DIRECTORY => return error.SQLiteReadOnlyDirectory,
142-
else => {},
143-
}
144-
}
137+
const sqlite_version = versionNumber();
145138

146-
// These errors are only available since 3.25.0.
147-
if (comptime versionGreaterThanOrEqualTo(3, 25, 0)) {
148-
switch (code) {
149-
c.SQLITE_ERROR_SNAPSHOT => return error.SQLiteErrorSnapshot,
150-
c.SQLITE_LOCKED_VTAB => return error.SQLiteLockedVTab,
151-
c.SQLITE_CANTOPEN_DIRTYWAL => return error.SQLiteCantOpenDirtyWAL,
152-
c.SQLITE_CORRUPT_SEQUENCE => return error.SQLiteCorruptSequence,
153-
else => {},
154-
}
155-
}
156139
// These errors are only available since 3.31.0.
157-
if (comptime versionGreaterThanOrEqualTo(3, 31, 0)) {
140+
const version_3_31_0 = encodeVersionNumber(3, 31, 0);
141+
if (sqlite_version >= version_3_31_0) {
158142
switch (code) {
159143
c.SQLITE_CANTOPEN_SYMLINK => return error.SQLiteCantOpenSymlink,
160144
c.SQLITE_CONSTRAINT_PINNED => return error.SQLiteConstraintPinned,
161145
else => {},
162146
}
163147
}
148+
164149
// These errors are only available since 3.32.0.
165-
if (comptime versionGreaterThanOrEqualTo(3, 32, 0)) {
150+
const version_3_32_0 = encodeVersionNumber(3, 32, 0);
151+
if (sqlite_version >= version_3_32_0) {
166152
switch (code) {
167153
c.SQLITE_IOERR_DATA => return error.SQLiteIOErrData, // See https://sqlite.org/cksumvfs.html
168154
c.SQLITE_BUSY_TIMEOUT => return error.SQLiteBusyTimeout,
169155
c.SQLITE_CORRUPT_INDEX => return error.SQLiteCorruptIndex,
170156
else => {},
171157
}
172158
}
159+
173160
// These errors are only available since 3.34.0.
174-
if (comptime versionGreaterThanOrEqualTo(3, 34, 0)) {
161+
const version_3_34_0 = encodeVersionNumber(3, 34, 0);
162+
if (sqlite_version >= version_3_34_0) {
175163
switch (code) {
176164
c.SQLITE_IOERR_CORRUPTFS => return error.SQLiteIOErrCorruptFS,
177165
else => {},

src/sqlite3/vtab.zig

Lines changed: 26 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -482,59 +482,32 @@ pub fn VirtualTable(comptime Table: type) type {
482482
return struct {
483483
const Self = @This();
484484

485-
pub const module = if (versionGreaterThanOrEqualTo(3, 26, 0))
486-
c.sqlite3_module{
487-
.iVersion = 3,
488-
.xCreate = if (tableHasDecl("create")) Creatable.xCreate else null,
489-
.xConnect = xConnect,
490-
.xBestIndex = xBestIndex,
491-
.xDisconnect = xDisconnect,
492-
.xDestroy = if (tableHasDecl("destroy")) Creatable.xDestroy else xDisconnect,
493-
.xOpen = xOpen,
494-
.xClose = xClose,
495-
.xFilter = xFilter,
496-
.xNext = xNext,
497-
.xEof = xEof,
498-
.xColumn = xColumn,
499-
.xRowid = xRowid,
500-
.xUpdate = if (tableHasDecl("update")) Writeable.xUpdate else null,
501-
.xBegin = if (tableHasDecl("begin")) Transactable.xBegin else null,
502-
.xSync = if (tableHasDecl("sync")) Transactable.xSync else null,
503-
.xCommit = if (tableHasDecl("commit")) Transactable.xCommit else null,
504-
.xRollback = if (tableHasDecl("rollback")) Transactable.xRollback else null,
505-
.xFindFunction = null,
506-
.xRename = null,
507-
.xSavepoint = if (tableHasDecl("savepoint")) Transactable.xSavepoint else null,
508-
.xRelease = if (tableHasDecl("release")) Transactable.xRelease else null,
509-
.xRollbackTo = if (tableHasDecl("rollbackTo")) Transactable.xRollbackTo else null,
510-
.xShadowName = if (tableHasDecl("isShadowName")) HasShadowTables.xShadowName else null,
511-
}
512-
else
513-
c.sqlite3_module{
514-
.iVersion = 2,
515-
.xCreate = if (tableHasDecl("create")) Creatable.xCreate else null,
516-
.xConnect = xConnect,
517-
.xBestIndex = xBestIndex,
518-
.xDisconnect = xDisconnect,
519-
.xDestroy = if (tableHasDecl("destroy")) Creatable.xDestroy else xDisconnect,
520-
.xOpen = xOpen,
521-
.xClose = xClose,
522-
.xFilter = xFilter,
523-
.xNext = xNext,
524-
.xEof = xEof,
525-
.xColumn = xColumn,
526-
.xRowid = xRowid,
527-
.xUpdate = if (tableHasDecl("update")) Writeable.xUpdate else null,
528-
.xBegin = if (tableHasDecl("begin")) Transactable.xBegin else null,
529-
.xSync = if (tableHasDecl("sync")) Transactable.xSync else null,
530-
.xCommit = if (tableHasDecl("commit")) Transactable.xCommit else null,
531-
.xRollback = if (tableHasDecl("rollback")) Transactable.xRollback else null,
532-
.xFindFunction = null,
533-
.xRename = null,
534-
.xSavepoint = if (tableHasDecl("savepoint")) Transactable.xSavepoint else null,
535-
.xRelease = if (tableHasDecl("release")) Transactable.xRelease else null,
536-
.xRollbackTo = if (tableHasDecl("rollbackTo")) Transactable.xRollbackTo else null,
537-
};
485+
pub const module = c.sqlite3_module{
486+
.iVersion = 3,
487+
.xCreate = if (tableHasDecl("create")) Creatable.xCreate else null,
488+
.xConnect = xConnect,
489+
.xBestIndex = xBestIndex,
490+
.xDisconnect = xDisconnect,
491+
.xDestroy = if (tableHasDecl("destroy")) Creatable.xDestroy else xDisconnect,
492+
.xOpen = xOpen,
493+
.xClose = xClose,
494+
.xFilter = xFilter,
495+
.xNext = xNext,
496+
.xEof = xEof,
497+
.xColumn = xColumn,
498+
.xRowid = xRowid,
499+
.xUpdate = if (tableHasDecl("update")) Writeable.xUpdate else null,
500+
.xBegin = if (tableHasDecl("begin")) Transactable.xBegin else null,
501+
.xSync = if (tableHasDecl("sync")) Transactable.xSync else null,
502+
.xCommit = if (tableHasDecl("commit")) Transactable.xCommit else null,
503+
.xRollback = if (tableHasDecl("rollback")) Transactable.xRollback else null,
504+
.xFindFunction = null,
505+
.xRename = null,
506+
.xSavepoint = if (tableHasDecl("savepoint")) Transactable.xSavepoint else null,
507+
.xRelease = if (tableHasDecl("release")) Transactable.xRelease else null,
508+
.xRollbackTo = if (tableHasDecl("rollbackTo")) Transactable.xRollbackTo else null,
509+
.xShadowName = if (tableHasDecl("isShadowName")) HasShadowTables.xShadowName else null,
510+
};
538511

539512
const table_decls = switch (@typeInfo(Table)) {
540513
.Struct => |table_struct| table_struct.decls,

0 commit comments

Comments
 (0)