├── .gitattributes ├── .gitignore ├── README.md ├── lib ├── sqlite3.dll ├── sqlite3.jai └── sqlite3.lib ├── module.jai └── src ├── Meta.jai ├── Migrator.jai ├── Model_Cache.jai ├── Result.jai ├── SQLite.jai └── Verbose.jai /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/.build 2 | *.exe 3 | *.pdb 4 | *.dot 5 | *.exp 6 | *.db 7 | *.db-shm 8 | *.db-wal 9 | *.dll 10 | !lib/**/*.dll 11 | *.lib 12 | !lib/**/*.lib 13 | .vs 14 | *.rdbg 15 | examples/**/bin 16 | examples/**/migrations 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SQLite for Jai 2 | ============== 3 | This is a Jai SQLite module that has some additional experimental ORM-like features. 4 | 5 | 6 | 7 | 8 | C API bindings 9 | -------------- 10 | By `#import`ing `SQLite`, you get access to [bindings for the SQLite C API](src/sqlite3.jai). These 11 | work exactly as you'd expect. 12 | 13 | 14 | 15 | 16 | Jai wrapper 17 | ----------- 18 | Unless you `#import "SQLite"(ONLY_C_BINDINGS=true)`, you also get [a more Jai-friendly set of wrapper functions](src/SQLite.jai). 19 | 20 | *(note that the latter is not an exhaustive port of all SQLite functions, at least, yet)* 21 | 22 | The database handle parameter is omitted from every wrapping procedure signature, as it is stored in 23 | the `context` instead. 24 | 25 | Instead of wrapping `sqlite3_exec()` as `exec()`, a more Jai-friendly `exec()` is provided: 26 | 27 | ```jai 28 | exec :: ( 29 | sql: string, // the SQL statement 30 | params: ..Any, // parameters to bind 31 | $code: Code = #code,null, // run this code for each returned row 32 | $ignore_returned_rows := false // ignore returned rows 33 | ) -> Result 34 | ``` 35 | 36 | This allows the user to provide a `Code` that should be run for each row returned from the database, 37 | instead of a callback function. Additionally, it `bind()`s each of `params`, so your `sql` 38 | statement can include [parameter notation](https://www.sqlite.org/lang_expr.html#varparam). 39 | 40 | In addition, several procedures that wrap `exec()` are provided to make common tasks easy: 41 | - `exec_row(T, sql, ..params) -> result, T, success` returns a single row of type `T` 42 | - `exec_rows(T, sql, ..params, allocator=temp) -> result, [..] T` returns an array of rows of type `T` 43 | - `exec_column(T, sql, ..params, allocator=temp) -> result, [..] T)` returns an array of values of type `T` from a single column 44 | - `exec_value(T, sql, ..params) -> result, T, success` returns a single value of type `T` 45 | 46 | To execute a query that doesn't return any rows, you can just write: 47 | 48 | ```jai 49 | some_id := 4; 50 | result := SQLite.exec("DELETE FROM User WHERE id = ?", some_id); 51 | assert(result == .OK); 52 | ``` 53 | 54 | `exec_row()` and `exec_rows()` work with Jai's anonymous structs, too: 55 | 56 | ```jai 57 | min_author_id := 2; 58 | result, rows := SQLite.exec_rows( 59 | struct { author_name: string; count: int; total_score: int; }, 60 | #string __SQL__ 61 | SELECT 62 | User.name AS author_name, 63 | COUNT(*) AS count, 64 | SUM(Post.score) AS total_score 65 | FROM Post 66 | LEFT JOIN User ON User.id = Post.author_id 67 | WHERE 68 | author_id >= ? AND 69 | parent_id IS NULL 70 | GROUP BY author_id 71 | __SQL__, 72 | min_author_id 73 | ); 74 | assert(result == .OK); 75 | for rows log("%1\n posts: %2\n total score: %3", it.author_name, it.count, it.total_score); 76 | ``` 77 | 78 | In the above example, all of the column names in the SQL statement match the member names of the 79 | struct. This seems like a pretty good idea, so by default we check this at runtime (unless a given 80 | column is unnamed). Thus, `exec_row()` and `exec_rows()` have an additional optional 81 | `check_column_names` parameter, which is `true` by default, but can be set to `false`, if, for 82 | whatever reason, you don't want this behavior. 83 | 84 | 85 | 86 | 87 | Model cache 88 | ----------- 89 | You can also `#import "SQLite"(USE_MODEL_CACHE=true);`, which, if you've set up your metaprogram 90 | correctly ~~(see [the “overview” example](examples/overview))~~, allows you to more easily create 91 | Jai structs that can automatically interface with SQLite, like this: 92 | 93 | ```jai 94 | using SQLite; 95 | 96 | My_Struct :: struct { using #as model: Model; 97 | name: string; 98 | boolean: bool; 99 | number: int; 100 | big_num: s64; 101 | real: float; 102 | big_real: float64; 103 | other: Cached(My_Other_Struct); 104 | private: int; @do_not_serialize; 105 | } 106 | ``` 107 | 108 | All of the members in the above struct--except for the last one--will be automatically de/serialized 109 | to/from your SQLite database, when using [the model cache](src/Model_Cache.jai). 110 | 111 | `Cached(My_Other_Struct)` is used for foreign-key references. in the example above, `other` will 112 | serialize to SQL as `other_id`, which will contain the ID of the `My_Other_Struct` that `other` 113 | points to. 114 | 115 | There's no need to include your own ID member, as that's included for you in `Model`, along with 116 | `created` and `modified` timestamps. (The timestamps are all handled in SQLite, and, for now, 117 | returned to you in Jai as UNIX timestamps.) 118 | 119 | ~~See [the “overview” example](examples/overview) for a sample use of this module. note that [overview.jai](examples/overview/overview.jai) 120 | contains the metaprogram, and [src/Main.jai](examples/overview/src/Main.jai) contains the actual 121 | program.~~ 122 | 123 | 124 | ### Model member notes 125 | There are various notes (`@xxx`) you can annotate the members of your model structs with, that make 126 | things easy for you: 127 | 128 | #### `@do_not_serialize` 129 | Indicates that this member should *not* be stored as a field in the SQLite table 130 | 131 | #### `@autofetch` 132 | Indicates that this member should be automatically fetched when an instance of this model struct is 133 | retrieved from the database. 134 | 135 | If a model `Model_Name` has a member `member_name` that is *both* `@autofetch` *and* 136 | `@do_not_serialize`, then you must provide a procedure called `fetch_member_name` ***within the body 137 | of the model struct***, that takes in a `*Cached(Model_Name)` and returns nothing. This procedure 138 | will be automatically executed when the instance is retrieved from the database. 139 | 140 | If the member is *not* `@do_not_serialize`, then the member type *must* be a `Cached(T)`, and it 141 | will be fetched automatically *every time* an instance of this model type is retrieved from the 142 | database. 143 | 144 | Here's an example: 145 | 146 | ```jai 147 | Foo :: struct { using #as model: Model; 148 | // bar will be fetched automatically (if not NULL) 149 | bar: Cached(Bar); @autofetch 150 | // baz will be "fetched" automatically, using the procedure below 151 | baz: int; @autofetch @do_not_serialize 152 | fetch_baz :: (using foo: *Cached(Foo)) { baz = 42; } 153 | } 154 | Bar :: struct { using #as model: Model; name: string; } 155 | 156 | // ... 157 | 158 | bar := insert(Bar.{name="BAR"}); 159 | insert(Foo.{bar=bar}); 160 | 161 | reset_model_cache(); // reset the cache so we can prove autofetching does in fact work 162 | 163 | foo := select_by_id(Foo, 1); 164 | assert(foo.bar.name == "BAR"); // proving bar was autofetched 165 | assert(foo.baz == 42 ); // proving baz was autofetched 166 | ``` 167 | 168 | **Caution should be exercised** when using `@autofetch`! Only `@autofetch` if you're *absoutely 169 | certain* that: 170 | - you will in fact use that member *every time* you retrieve a model instance from the database 171 | - your models' `@autofetch` members do not have *any* circular dependencies 172 | 173 | 174 | 175 | 176 | Context 177 | ------- 178 | The basic SQLite wrapper will add a `sqlite: SQLIte_Info` to the `context`, which contains the 179 | current database connection and other such bookkeeping. 180 | 181 | Using the model cache will add an additional `sqlite_model_cache` struct to the `context`, which is a cache of rows 182 | retrieved from the database. You can flush this cache at any time using `reset_model_cache();`. 183 | 184 | 185 | 186 | 187 | TODO 188 | ==== 189 | 190 | General 191 | ------- 192 | - fix the `overview` example 193 | - massively cull the `assert_ok()`s, with something like an `automatically_assert_ok` field in `SQLite_Info` 194 | - delete ~~a ton of~~ ~~even more~~ *yet even more* code from `Model_Cache` now that we have a better `exec()` and such 195 | - more compile-time checking of things to make usage more pleasant, e.g. help the user if they forget to `#as` the `using #as model: Model;` in their models 196 | - actually try this out with slightly non-trivial things like threading and such and see if it actually is good at all lmao 197 | - finish wrapping the rest of the SQLite API 198 | - test the code, like, at all 199 | - write documentation 200 | 201 | Possible model cache extensions 202 | ------------------------------- 203 | - `set(T, field_name, value, where, ..params)` 204 | - `delete_from(T, where, ..params)` 205 | - `insert(objs)` 206 | 207 | Big ideas 208 | --------- 209 | - work on the automatic migration system -- we can do SQLite stuff at compile time, so why not store it in a SQLite database? 210 | - eventually -- in the *distant* future -- we could resolve conflicts between migration dbs, creating a new, "merged" migration db 211 | 212 | Notes 213 | ----- 214 | - `@default=value` for model fields 215 | - figure out what to do about `NULL` values. consider something like `@null_if_default`/`@null_if=value`/`@not_null`/...? `Nullable(T)`...? ...? 216 | 217 | Things to explore 218 | ----------------- 219 | - maybe just huck the SQLite error message into the `context`? 220 | - maybe have the wrapper functions return enums that are subsets of `Result`? (`#must`...?) 221 | - more generally, figure out if there's a more ergonomic way to handle SQLite result and/or error passing 222 | -------------------------------------------------------------------------------- /lib/sqlite3.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rezich/SQLite/28311b802c20d6e811bfb4d50af6898010f2704b/lib/sqlite3.dll -------------------------------------------------------------------------------- /lib/sqlite3.jai: -------------------------------------------------------------------------------- 1 | // This is an automatically generated set of SQLite bindings. 2 | // See SQLite.jai for a more jai-friendly "fancy wrapper" around this. 3 | sqlite3_version: *s8; 4 | 5 | sqlite3_libversion :: () -> *s8 #foreign sqlite; 6 | 7 | sqlite3_sourceid :: () -> *s8 #foreign sqlite; 8 | 9 | sqlite3_libversion_number :: () -> s32 #foreign sqlite; 10 | 11 | sqlite3_compileoption_used :: (zOptName: *s8) -> s32 #foreign sqlite; 12 | 13 | sqlite3_compileoption_get :: (N: s32) -> *s8 #foreign sqlite; 14 | 15 | sqlite3_threadsafe :: () -> s32 #foreign sqlite; 16 | 17 | sqlite3 :: struct { 18 | } 19 | 20 | 21 | 22 | sqlite_int64 :: s64; 23 | 24 | sqlite_uint64 :: u64; 25 | 26 | sqlite3_int64 :: sqlite_int64; 27 | 28 | sqlite3_uint64 :: sqlite_uint64; 29 | 30 | sqlite3_close :: (unk0: *sqlite3) -> s32 #foreign sqlite; 31 | 32 | sqlite3_close_v2 :: (unk0: *sqlite3) -> s32 #foreign sqlite; 33 | 34 | sqlite3_callback :: #type (a0: *void, a1: s32, a2: **s8, a3: **s8) -> s32 #c_call; 35 | 36 | sqlite3_exec :: (unk0: *sqlite3, sql: *s8, callback: #type (a0: *void, a1: s32, a2: **s8, a3: **s8) -> s32 #c_call, unk1: *void, errmsg: **s8) -> s32 #foreign sqlite; 37 | 38 | 39 | 40 | sqlite3_file :: struct { 41 | pMethods: *sqlite3_io_methods; 42 | } 43 | 44 | 45 | 46 | sqlite3_io_methods :: struct { 47 | iVersion: s32; 48 | xClose: #type (a0: *sqlite3_file) -> s32 #c_call; 49 | xRead: #type (a0: *sqlite3_file, a1: *void, a2: s32, a3: sqlite3_int64) -> s32 #c_call; 50 | xWrite: #type (a0: *sqlite3_file, a1: *void, a2: s32, a3: sqlite3_int64) -> s32 #c_call; 51 | xTruncate: #type (a0: *sqlite3_file, a1: sqlite3_int64) -> s32 #c_call; 52 | xSync: #type (a0: *sqlite3_file, a1: s32) -> s32 #c_call; 53 | xFileSize: #type (a0: *sqlite3_file, a1: *sqlite3_int64) -> s32 #c_call; 54 | xLock: #type (a0: *sqlite3_file, a1: s32) -> s32 #c_call; 55 | xUnlock: #type (a0: *sqlite3_file, a1: s32) -> s32 #c_call; 56 | xCheckReservedLock: #type (a0: *sqlite3_file, a1: *s32) -> s32 #c_call; 57 | xFileControl: #type (a0: *sqlite3_file, a1: s32, a2: *void) -> s32 #c_call; 58 | xSectorSize: #type (a0: *sqlite3_file) -> s32 #c_call; 59 | xDeviceCharacteristics: #type (a0: *sqlite3_file) -> s32 #c_call; 60 | xShmMap: #type (a0: *sqlite3_file, a1: s32, a2: s32, a3: s32, a4: **void) -> s32 #c_call; 61 | xShmLock: #type (a0: *sqlite3_file, a1: s32, a2: s32, a3: s32) -> s32 #c_call; 62 | xShmBarrier: #type (a0: *sqlite3_file) -> void #c_call; 63 | xShmUnmap: #type (a0: *sqlite3_file, a1: s32) -> s32 #c_call; 64 | xFetch: #type (a0: *sqlite3_file, a1: sqlite3_int64, a2: s32, a3: **void) -> s32 #c_call; 65 | xUnfetch: #type (a0: *sqlite3_file, a1: sqlite3_int64, a2: *void) -> s32 #c_call; 66 | } 67 | 68 | sqlite3_mutex :: struct { 69 | } 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | sqlite3_syscall_ptr :: #type () -> void #c_call; 78 | 79 | sqlite3_vfs :: struct { 80 | iVersion: s32; 81 | szOsFile: s32; 82 | mxPathname: s32; 83 | pNext: *sqlite3_vfs; 84 | zName: *s8; 85 | pAppData: *void; 86 | xOpen: #type (a0: *sqlite3_vfs, a1: *s8, a2: *sqlite3_file, a3: s32, a4: *s32) -> s32 #c_call; 87 | xDelete: #type (a0: *sqlite3_vfs, a1: *s8, a2: s32) -> s32 #c_call; 88 | xAccess: #type (a0: *sqlite3_vfs, a1: *s8, a2: s32, a3: *s32) -> s32 #c_call; 89 | xFullPathname: #type (a0: *sqlite3_vfs, a1: *s8, a2: s32, a3: *s8) -> s32 #c_call; 90 | xDlOpen: #type (a0: *sqlite3_vfs, a1: *s8) -> *void #c_call; 91 | xDlError: #type (a0: *sqlite3_vfs, a1: s32, a2: *s8) -> void #c_call; 92 | xDlSym: #type (a0: *sqlite3_vfs, a1: *void, a2: *s8) -> (() -> void #c_call) #c_call; 93 | xDlClose: #type (a0: *sqlite3_vfs, a1: *void) -> void #c_call; 94 | xRandomness: #type (a0: *sqlite3_vfs, a1: s32, a2: *s8) -> s32 #c_call; 95 | xSleep: #type (a0: *sqlite3_vfs, a1: s32) -> s32 #c_call; 96 | xCurrentTime: #type (a0: *sqlite3_vfs, a1: *float64) -> s32 #c_call; 97 | xGetLastError: #type (a0: *sqlite3_vfs, a1: s32, a2: *s8) -> s32 #c_call; 98 | xCurrentTimeInt64: #type (a0: *sqlite3_vfs, a1: *sqlite3_int64) -> s32 #c_call; 99 | xSetSystemCall: #type (a0: *sqlite3_vfs, a1: *s8, a2: sqlite3_syscall_ptr) -> s32 #c_call; 100 | xGetSystemCall: #type (a0: *sqlite3_vfs, a1: *s8) -> sqlite3_syscall_ptr #c_call; 101 | xNextSystemCall: #type (a0: *sqlite3_vfs, a1: *s8) -> *s8 #c_call; 102 | } 103 | 104 | sqlite3_initialize :: () -> s32 #foreign sqlite; 105 | 106 | sqlite3_shutdown :: () -> s32 #foreign sqlite; 107 | 108 | sqlite3_os_init :: () -> s32 #foreign sqlite; 109 | 110 | sqlite3_os_end :: () -> s32 #foreign sqlite; 111 | 112 | sqlite3_config :: (unk0: s32, __args: ..Any) -> s32 #foreign sqlite; 113 | 114 | sqlite3_db_config :: (unk0: *sqlite3, op: s32, __args: ..Any) -> s32 #foreign sqlite; 115 | 116 | 117 | 118 | sqlite3_mem_methods :: struct { 119 | xMalloc: #type (a0: s32) -> *void #c_call; 120 | xFree: #type (a0: *void) -> void #c_call; 121 | xRealloc: #type (a0: *void, a1: s32) -> *void #c_call; 122 | xSize: #type (a0: *void) -> s32 #c_call; 123 | xRoundup: #type (a0: s32) -> s32 #c_call; 124 | xInit: #type (a0: *void) -> s32 #c_call; 125 | xShutdown: #type (a0: *void) -> void #c_call; 126 | pAppData: *void; 127 | } 128 | 129 | sqlite3_extended_result_codes :: (unk0: *sqlite3, onoff: s32) -> s32 #foreign sqlite; 130 | 131 | sqlite3_last_insert_rowid :: (unk0: *sqlite3) -> sqlite3_int64 #foreign sqlite; 132 | 133 | sqlite3_set_last_insert_rowid :: (unk0: *sqlite3, unk1: sqlite3_int64) -> void #foreign sqlite; 134 | 135 | sqlite3_changes :: (unk0: *sqlite3) -> s32 #foreign sqlite; 136 | 137 | sqlite3_changes64 :: (unk0: *sqlite3) -> sqlite3_int64 #foreign sqlite; 138 | 139 | sqlite3_total_changes :: (unk0: *sqlite3) -> s32 #foreign sqlite; 140 | 141 | sqlite3_total_changes64 :: (unk0: *sqlite3) -> sqlite3_int64 #foreign sqlite; 142 | 143 | sqlite3_interrupt :: (unk0: *sqlite3) -> void #foreign sqlite; 144 | 145 | sqlite3_complete :: (sql: *s8) -> s32 #foreign sqlite; 146 | 147 | sqlite3_complete16 :: (sql: *void) -> s32 #foreign sqlite; 148 | 149 | sqlite3_busy_handler :: (unk0: *sqlite3, unk1: #type (a0: *void, a1: s32) -> s32 #c_call, unk2: *void) -> s32 #foreign sqlite; 150 | 151 | sqlite3_busy_timeout :: (unk0: *sqlite3, ms: s32) -> s32 #foreign sqlite; 152 | 153 | sqlite3_get_table :: (db: *sqlite3, zSql: *s8, pazResult: ***s8, pnRow: *s32, pnColumn: *s32, pzErrmsg: **s8) -> s32 #foreign sqlite; 154 | 155 | sqlite3_free_table :: (result: **s8) -> void #foreign sqlite; 156 | 157 | sqlite3_mprintf :: (unk0: *s8, __args: ..Any) -> *s8 #foreign sqlite; 158 | 159 | //sqlite3_vmprintf :: (unk0: *s8, unk1: va_list) -> *s8 #foreign sqlite; 160 | 161 | sqlite3_snprintf :: (unk0: s32, unk1: *s8, unk2: *s8, __args: ..Any) -> *s8 #foreign sqlite; 162 | 163 | //sqlite3_vsnprintf :: (unk0: s32, unk1: *s8, unk2: *s8, unk3: va_list) -> *s8 #foreign sqlite; 164 | 165 | sqlite3_malloc :: (unk0: s32) -> *void #foreign sqlite; 166 | 167 | sqlite3_malloc64 :: (unk0: sqlite3_uint64) -> *void #foreign sqlite; 168 | 169 | sqlite3_realloc :: (unk0: *void, unk1: s32) -> *void #foreign sqlite; 170 | 171 | sqlite3_realloc64 :: (unk0: *void, unk1: sqlite3_uint64) -> *void #foreign sqlite; 172 | 173 | sqlite3_free :: (unk0: *void) -> void #foreign sqlite; 174 | 175 | sqlite3_msize :: (unk0: *void) -> sqlite3_uint64 #foreign sqlite; 176 | 177 | sqlite3_memory_used :: () -> sqlite3_int64 #foreign sqlite; 178 | 179 | sqlite3_memory_highwater :: (resetFlag: s32) -> sqlite3_int64 #foreign sqlite; 180 | 181 | sqlite3_randomness :: (N: s32, P: *void) -> void #foreign sqlite; 182 | 183 | sqlite3_set_authorizer :: (unk0: *sqlite3, xAuth: #type (a0: *void, a1: s32, a2: *s8, a3: *s8, a4: *s8, a5: *s8) -> s32 #c_call, pUserData: *void) -> s32 #foreign sqlite; 184 | 185 | sqlite3_trace :: (unk0: *sqlite3, xTrace: #type (a0: *void, a1: *s8) -> void #c_call, unk1: *void) -> *void #foreign sqlite; 186 | 187 | sqlite3_profile :: (unk0: *sqlite3, xProfile: #type (a0: *void, a1: *s8, a2: sqlite3_uint64) -> void #c_call, unk1: *void) -> *void #foreign sqlite; 188 | 189 | sqlite3_trace_v2 :: (unk0: *sqlite3, uMask: u32, xCallback: #type (a0: u32, a1: *void, a2: *void, a3: *void) -> s32 #c_call, pCtx: *void) -> s32 #foreign sqlite; 190 | 191 | sqlite3_progress_handler :: (unk0: *sqlite3, unk1: s32, unk2: #type (a0: *void) -> s32 #c_call, unk3: *void) -> void #foreign sqlite; 192 | 193 | sqlite3_open :: (filename: *s8, ppDb: **sqlite3) -> s32 #foreign sqlite; 194 | 195 | sqlite3_open16 :: (filename: *void, ppDb: **sqlite3) -> s32 #foreign sqlite; 196 | 197 | sqlite3_open_v2 :: (filename: *s8, ppDb: **sqlite3, flags: s32, zVfs: *s8) -> s32 #foreign sqlite; 198 | 199 | sqlite3_uri_parameter :: (zFilename: *s8, zParam: *s8) -> *s8 #foreign sqlite; 200 | 201 | sqlite3_uri_boolean :: (zFile: *s8, zParam: *s8, bDefault: s32) -> s32 #foreign sqlite; 202 | 203 | sqlite3_uri_int64 :: (unk0: *s8, unk1: *s8, unk2: sqlite3_int64) -> sqlite3_int64 #foreign sqlite; 204 | 205 | sqlite3_uri_key :: (zFilename: *s8, N: s32) -> *s8 #foreign sqlite; 206 | 207 | sqlite3_filename_database :: (unk0: *s8) -> *s8 #foreign sqlite; 208 | 209 | sqlite3_filename_journal :: (unk0: *s8) -> *s8 #foreign sqlite; 210 | 211 | sqlite3_filename_wal :: (unk0: *s8) -> *s8 #foreign sqlite; 212 | 213 | sqlite3_database_file_object :: (unk0: *s8) -> *sqlite3_file #foreign sqlite; 214 | 215 | sqlite3_create_filename :: (zDatabase: *s8, zJournal: *s8, zWal: *s8, nParam: s32, azParam: **s8) -> *s8 #foreign sqlite; 216 | 217 | sqlite3_free_filename :: (unk0: *s8) -> void #foreign sqlite; 218 | 219 | sqlite3_errcode :: (db: *sqlite3) -> s32 #foreign sqlite; 220 | 221 | sqlite3_extended_errcode :: (db: *sqlite3) -> s32 #foreign sqlite; 222 | 223 | sqlite3_errmsg :: (unk0: *sqlite3) -> *s8 #foreign sqlite; 224 | 225 | sqlite3_errmsg16 :: (unk0: *sqlite3) -> *void #foreign sqlite; 226 | 227 | sqlite3_errstr :: (unk0: s32) -> *s8 #foreign sqlite; 228 | 229 | sqlite3_stmt :: struct { 230 | } 231 | 232 | 233 | 234 | sqlite3_limit :: (unk0: *sqlite3, id: s32, newVal: s32) -> s32 #foreign sqlite; 235 | 236 | sqlite3_prepare :: (db: *sqlite3, zSql: *s8, nByte: s32, ppStmt: **sqlite3_stmt, pzTail: **s8) -> s32 #foreign sqlite; 237 | 238 | sqlite3_prepare_v2 :: (db: *sqlite3, zSql: *s8, nByte: s32, ppStmt: **sqlite3_stmt, pzTail: **s8) -> s32 #foreign sqlite; 239 | 240 | sqlite3_prepare_v3 :: (db: *sqlite3, zSql: *s8, nByte: s32, prepFlags: u32, ppStmt: **sqlite3_stmt, pzTail: **s8) -> s32 #foreign sqlite; 241 | 242 | sqlite3_prepare16 :: (db: *sqlite3, zSql: *void, nByte: s32, ppStmt: **sqlite3_stmt, pzTail: **void) -> s32 #foreign sqlite; 243 | 244 | sqlite3_prepare16_v2 :: (db: *sqlite3, zSql: *void, nByte: s32, ppStmt: **sqlite3_stmt, pzTail: **void) -> s32 #foreign sqlite; 245 | 246 | sqlite3_prepare16_v3 :: (db: *sqlite3, zSql: *void, nByte: s32, prepFlags: u32, ppStmt: **sqlite3_stmt, pzTail: **void) -> s32 #foreign sqlite; 247 | 248 | sqlite3_sql :: (pStmt: *sqlite3_stmt) -> *s8 #foreign sqlite; 249 | 250 | sqlite3_expanded_sql :: (pStmt: *sqlite3_stmt) -> *s8 #foreign sqlite; 251 | 252 | sqlite3_stmt_readonly :: (pStmt: *sqlite3_stmt) -> s32 #foreign sqlite; 253 | 254 | sqlite3_stmt_isexplain :: (pStmt: *sqlite3_stmt) -> s32 #foreign sqlite; 255 | 256 | sqlite3_stmt_busy :: (unk0: *sqlite3_stmt) -> s32 #foreign sqlite; 257 | 258 | sqlite3_value :: struct { 259 | } 260 | 261 | 262 | 263 | sqlite3_context :: struct { 264 | } 265 | 266 | 267 | 268 | sqlite3_bind_blob :: (unk0: *sqlite3_stmt, unk1: s32, unk2: *void, n: s32, unk3: #type (a0: *void) -> void #c_call) -> s32 #foreign sqlite; 269 | 270 | sqlite3_bind_blob64 :: (unk0: *sqlite3_stmt, unk1: s32, unk2: *void, unk3: sqlite3_uint64, unk4: #type (a0: *void) -> void #c_call) -> s32 #foreign sqlite; 271 | 272 | sqlite3_bind_double :: (unk0: *sqlite3_stmt, unk1: s32, unk2: float64) -> s32 #foreign sqlite; 273 | 274 | sqlite3_bind_int :: (unk0: *sqlite3_stmt, unk1: s32, unk2: s32) -> s32 #foreign sqlite; 275 | 276 | sqlite3_bind_int64 :: (unk0: *sqlite3_stmt, unk1: s32, unk2: sqlite3_int64) -> s32 #foreign sqlite; 277 | 278 | sqlite3_bind_null :: (unk0: *sqlite3_stmt, unk1: s32) -> s32 #foreign sqlite; 279 | 280 | sqlite3_bind_text :: (unk0: *sqlite3_stmt, unk1: s32, unk2: *s8, unk3: s32, unk4: #type (a0: *void) -> void #c_call) -> s32 #foreign sqlite; 281 | 282 | sqlite3_bind_text16 :: (unk0: *sqlite3_stmt, unk1: s32, unk2: *void, unk3: s32, unk4: #type (a0: *void) -> void #c_call) -> s32 #foreign sqlite; 283 | 284 | sqlite3_bind_text64 :: (unk0: *sqlite3_stmt, unk1: s32, unk2: *s8, unk3: sqlite3_uint64, unk4: #type (a0: *void) -> void #c_call, encoding: u8) -> s32 #foreign sqlite; 285 | 286 | sqlite3_bind_value :: (unk0: *sqlite3_stmt, unk1: s32, unk2: *sqlite3_value) -> s32 #foreign sqlite; 287 | 288 | sqlite3_bind_pointer :: (unk0: *sqlite3_stmt, unk1: s32, unk2: *void, unk3: *s8, unk4: #type (a0: *void) -> void #c_call) -> s32 #foreign sqlite; 289 | 290 | sqlite3_bind_zeroblob :: (unk0: *sqlite3_stmt, unk1: s32, n: s32) -> s32 #foreign sqlite; 291 | 292 | sqlite3_bind_zeroblob64 :: (unk0: *sqlite3_stmt, unk1: s32, unk2: sqlite3_uint64) -> s32 #foreign sqlite; 293 | 294 | sqlite3_bind_parameter_count :: (unk0: *sqlite3_stmt) -> s32 #foreign sqlite; 295 | 296 | sqlite3_bind_parameter_name :: (unk0: *sqlite3_stmt, unk1: s32) -> *s8 #foreign sqlite; 297 | 298 | sqlite3_bind_parameter_index :: (unk0: *sqlite3_stmt, zName: *s8) -> s32 #foreign sqlite; 299 | 300 | sqlite3_clear_bindings :: (unk0: *sqlite3_stmt) -> s32 #foreign sqlite; 301 | 302 | sqlite3_column_count :: (pStmt: *sqlite3_stmt) -> s32 #foreign sqlite; 303 | 304 | sqlite3_column_name :: (unk0: *sqlite3_stmt, N: s32) -> *s8 #foreign sqlite; 305 | 306 | sqlite3_column_name16 :: (unk0: *sqlite3_stmt, N: s32) -> *void #foreign sqlite; 307 | 308 | sqlite3_column_database_name :: (unk0: *sqlite3_stmt, unk1: s32) -> *s8 #foreign sqlite; 309 | 310 | sqlite3_column_database_name16 :: (unk0: *sqlite3_stmt, unk1: s32) -> *void #foreign sqlite; 311 | 312 | sqlite3_column_table_name :: (unk0: *sqlite3_stmt, unk1: s32) -> *s8 #foreign sqlite; 313 | 314 | sqlite3_column_table_name16 :: (unk0: *sqlite3_stmt, unk1: s32) -> *void #foreign sqlite; 315 | 316 | sqlite3_column_origin_name :: (unk0: *sqlite3_stmt, unk1: s32) -> *s8 #foreign sqlite; 317 | 318 | sqlite3_column_origin_name16 :: (unk0: *sqlite3_stmt, unk1: s32) -> *void #foreign sqlite; 319 | 320 | sqlite3_column_decltype :: (unk0: *sqlite3_stmt, unk1: s32) -> *s8 #foreign sqlite; 321 | 322 | sqlite3_column_decltype16 :: (unk0: *sqlite3_stmt, unk1: s32) -> *void #foreign sqlite; 323 | 324 | sqlite3_step :: (unk0: *sqlite3_stmt) -> s32 #foreign sqlite; 325 | 326 | sqlite3_data_count :: (pStmt: *sqlite3_stmt) -> s32 #foreign sqlite; 327 | 328 | sqlite3_column_blob :: (unk0: *sqlite3_stmt, iCol: s32) -> *void #foreign sqlite; 329 | 330 | sqlite3_column_double :: (unk0: *sqlite3_stmt, iCol: s32) -> float64 #foreign sqlite; 331 | 332 | sqlite3_column_int :: (unk0: *sqlite3_stmt, iCol: s32) -> s32 #foreign sqlite; 333 | 334 | sqlite3_column_int64 :: (unk0: *sqlite3_stmt, iCol: s32) -> sqlite3_int64 #foreign sqlite; 335 | 336 | sqlite3_column_text :: (unk0: *sqlite3_stmt, iCol: s32) -> *u8 #foreign sqlite; 337 | 338 | sqlite3_column_text16 :: (unk0: *sqlite3_stmt, iCol: s32) -> *void #foreign sqlite; 339 | 340 | sqlite3_column_value :: (unk0: *sqlite3_stmt, iCol: s32) -> *sqlite3_value #foreign sqlite; 341 | 342 | sqlite3_column_bytes :: (unk0: *sqlite3_stmt, iCol: s32) -> s32 #foreign sqlite; 343 | 344 | sqlite3_column_bytes16 :: (unk0: *sqlite3_stmt, iCol: s32) -> s32 #foreign sqlite; 345 | 346 | sqlite3_column_type :: (unk0: *sqlite3_stmt, iCol: s32) -> s32 #foreign sqlite; 347 | 348 | sqlite3_finalize :: (pStmt: *sqlite3_stmt) -> s32 #foreign sqlite; 349 | 350 | sqlite3_reset :: (pStmt: *sqlite3_stmt) -> s32 #foreign sqlite; 351 | 352 | sqlite3_create_function :: (db: *sqlite3, zFunctionName: *s8, nArg: s32, eTextRep: s32, pApp: *void, xFunc: #type (a0: *sqlite3_context, a1: s32, a2: **sqlite3_value) -> void #c_call, xStep: #type (a0: *sqlite3_context, a1: s32, a2: **sqlite3_value) -> void #c_call, xFinal: #type (a0: *sqlite3_context) -> void #c_call) -> s32 #foreign sqlite; 353 | 354 | sqlite3_create_function16 :: (db: *sqlite3, zFunctionName: *void, nArg: s32, eTextRep: s32, pApp: *void, xFunc: #type (a0: *sqlite3_context, a1: s32, a2: **sqlite3_value) -> void #c_call, xStep: #type (a0: *sqlite3_context, a1: s32, a2: **sqlite3_value) -> void #c_call, xFinal: #type (a0: *sqlite3_context) -> void #c_call) -> s32 #foreign sqlite; 355 | 356 | sqlite3_create_function_v2 :: (db: *sqlite3, zFunctionName: *s8, nArg: s32, eTextRep: s32, pApp: *void, xFunc: #type (a0: *sqlite3_context, a1: s32, a2: **sqlite3_value) -> void #c_call, xStep: #type (a0: *sqlite3_context, a1: s32, a2: **sqlite3_value) -> void #c_call, xFinal: #type (a0: *sqlite3_context) -> void #c_call, xDestroy: #type (a0: *void) -> void #c_call) -> s32 #foreign sqlite; 357 | 358 | sqlite3_create_window_function :: (db: *sqlite3, zFunctionName: *s8, nArg: s32, eTextRep: s32, pApp: *void, xStep: #type (a0: *sqlite3_context, a1: s32, a2: **sqlite3_value) -> void #c_call, xFinal: #type (a0: *sqlite3_context) -> void #c_call, xValue: #type (a0: *sqlite3_context) -> void #c_call, xInverse: #type (a0: *sqlite3_context, a1: s32, a2: **sqlite3_value) -> void #c_call, xDestroy: #type (a0: *void) -> void #c_call) -> s32 #foreign sqlite; 359 | 360 | sqlite3_aggregate_count :: (unk0: *sqlite3_context) -> s32 #foreign sqlite; 361 | 362 | sqlite3_expired :: (unk0: *sqlite3_stmt) -> s32 #foreign sqlite; 363 | 364 | sqlite3_transfer_bindings :: (unk0: *sqlite3_stmt, unk1: *sqlite3_stmt) -> s32 #foreign sqlite; 365 | 366 | sqlite3_global_recover :: () -> s32 #foreign sqlite; 367 | 368 | sqlite3_thread_cleanup :: () -> void #foreign sqlite; 369 | 370 | sqlite3_memory_alarm :: (unk0: #type (a0: *void, a1: sqlite3_int64, a2: s32) -> void #c_call, unk1: *void, unk2: sqlite3_int64) -> s32 #foreign sqlite; 371 | 372 | sqlite3_value_blob :: (unk0: *sqlite3_value) -> *void #foreign sqlite; 373 | 374 | sqlite3_value_double :: (unk0: *sqlite3_value) -> float64 #foreign sqlite; 375 | 376 | sqlite3_value_int :: (unk0: *sqlite3_value) -> s32 #foreign sqlite; 377 | 378 | sqlite3_value_int64 :: (unk0: *sqlite3_value) -> sqlite3_int64 #foreign sqlite; 379 | 380 | sqlite3_value_pointer :: (unk0: *sqlite3_value, unk1: *s8) -> *void #foreign sqlite; 381 | 382 | sqlite3_value_text :: (unk0: *sqlite3_value) -> *u8 #foreign sqlite; 383 | 384 | sqlite3_value_text16 :: (unk0: *sqlite3_value) -> *void #foreign sqlite; 385 | 386 | sqlite3_value_text16le :: (unk0: *sqlite3_value) -> *void #foreign sqlite; 387 | 388 | sqlite3_value_text16be :: (unk0: *sqlite3_value) -> *void #foreign sqlite; 389 | 390 | sqlite3_value_bytes :: (unk0: *sqlite3_value) -> s32 #foreign sqlite; 391 | 392 | sqlite3_value_bytes16 :: (unk0: *sqlite3_value) -> s32 #foreign sqlite; 393 | 394 | sqlite3_value_type :: (unk0: *sqlite3_value) -> s32 #foreign sqlite; 395 | 396 | sqlite3_value_numeric_type :: (unk0: *sqlite3_value) -> s32 #foreign sqlite; 397 | 398 | sqlite3_value_nochange :: (unk0: *sqlite3_value) -> s32 #foreign sqlite; 399 | 400 | sqlite3_value_frombind :: (unk0: *sqlite3_value) -> s32 #foreign sqlite; 401 | 402 | sqlite3_value_subtype :: (unk0: *sqlite3_value) -> u32 #foreign sqlite; 403 | 404 | sqlite3_value_dup :: (unk0: *sqlite3_value) -> *sqlite3_value #foreign sqlite; 405 | 406 | sqlite3_value_free :: (unk0: *sqlite3_value) -> void #foreign sqlite; 407 | 408 | sqlite3_aggregate_context :: (unk0: *sqlite3_context, nBytes: s32) -> *void #foreign sqlite; 409 | 410 | sqlite3_user_data :: (unk0: *sqlite3_context) -> *void #foreign sqlite; 411 | 412 | sqlite3_context_db_handle :: (unk0: *sqlite3_context) -> *sqlite3 #foreign sqlite; 413 | 414 | sqlite3_get_auxdata :: (unk0: *sqlite3_context, N: s32) -> *void #foreign sqlite; 415 | 416 | sqlite3_set_auxdata :: (unk0: *sqlite3_context, N: s32, unk1: *void, unk2: #type (a0: *void) -> void #c_call) -> void #foreign sqlite; 417 | 418 | sqlite3_destructor_type :: #type (a0: *void) -> void #c_call; 419 | 420 | sqlite3_result_blob :: (unk0: *sqlite3_context, unk1: *void, unk2: s32, unk3: #type (a0: *void) -> void #c_call) -> void #foreign sqlite; 421 | 422 | sqlite3_result_blob64 :: (unk0: *sqlite3_context, unk1: *void, unk2: sqlite3_uint64, unk3: #type (a0: *void) -> void #c_call) -> void #foreign sqlite; 423 | 424 | sqlite3_result_double :: (unk0: *sqlite3_context, unk1: float64) -> void #foreign sqlite; 425 | 426 | sqlite3_result_error :: (unk0: *sqlite3_context, unk1: *s8, unk2: s32) -> void #foreign sqlite; 427 | 428 | sqlite3_result_error16 :: (unk0: *sqlite3_context, unk1: *void, unk2: s32) -> void #foreign sqlite; 429 | 430 | sqlite3_result_error_toobig :: (unk0: *sqlite3_context) -> void #foreign sqlite; 431 | 432 | sqlite3_result_error_nomem :: (unk0: *sqlite3_context) -> void #foreign sqlite; 433 | 434 | sqlite3_result_error_code :: (unk0: *sqlite3_context, unk1: s32) -> void #foreign sqlite; 435 | 436 | sqlite3_result_int :: (unk0: *sqlite3_context, unk1: s32) -> void #foreign sqlite; 437 | 438 | sqlite3_result_int64 :: (unk0: *sqlite3_context, unk1: sqlite3_int64) -> void #foreign sqlite; 439 | 440 | sqlite3_result_null :: (unk0: *sqlite3_context) -> void #foreign sqlite; 441 | 442 | sqlite3_result_text :: (unk0: *sqlite3_context, unk1: *s8, unk2: s32, unk3: #type (a0: *void) -> void #c_call) -> void #foreign sqlite; 443 | 444 | sqlite3_result_text64 :: (unk0: *sqlite3_context, unk1: *s8, unk2: sqlite3_uint64, unk3: #type (a0: *void) -> void #c_call, encoding: u8) -> void #foreign sqlite; 445 | 446 | sqlite3_result_text16 :: (unk0: *sqlite3_context, unk1: *void, unk2: s32, unk3: #type (a0: *void) -> void #c_call) -> void #foreign sqlite; 447 | 448 | sqlite3_result_text16le :: (unk0: *sqlite3_context, unk1: *void, unk2: s32, unk3: #type (a0: *void) -> void #c_call) -> void #foreign sqlite; 449 | 450 | sqlite3_result_text16be :: (unk0: *sqlite3_context, unk1: *void, unk2: s32, unk3: #type (a0: *void) -> void #c_call) -> void #foreign sqlite; 451 | 452 | sqlite3_result_value :: (unk0: *sqlite3_context, unk1: *sqlite3_value) -> void #foreign sqlite; 453 | 454 | sqlite3_result_pointer :: (unk0: *sqlite3_context, unk1: *void, unk2: *s8, unk3: #type (a0: *void) -> void #c_call) -> void #foreign sqlite; 455 | 456 | sqlite3_result_zeroblob :: (unk0: *sqlite3_context, n: s32) -> void #foreign sqlite; 457 | 458 | sqlite3_result_zeroblob64 :: (unk0: *sqlite3_context, n: sqlite3_uint64) -> s32 #foreign sqlite; 459 | 460 | sqlite3_result_subtype :: (unk0: *sqlite3_context, unk1: u32) -> void #foreign sqlite; 461 | 462 | sqlite3_create_collation :: (unk0: *sqlite3, zName: *s8, eTextRep: s32, pArg: *void, xCompare: #type (a0: *void, a1: s32, a2: *void, a3: s32, a4: *void) -> s32 #c_call) -> s32 #foreign sqlite; 463 | 464 | sqlite3_create_collation_v2 :: (unk0: *sqlite3, zName: *s8, eTextRep: s32, pArg: *void, xCompare: #type (a0: *void, a1: s32, a2: *void, a3: s32, a4: *void) -> s32 #c_call, xDestroy: #type (a0: *void) -> void #c_call) -> s32 #foreign sqlite; 465 | 466 | sqlite3_create_collation16 :: (unk0: *sqlite3, zName: *void, eTextRep: s32, pArg: *void, xCompare: #type (a0: *void, a1: s32, a2: *void, a3: s32, a4: *void) -> s32 #c_call) -> s32 #foreign sqlite; 467 | 468 | sqlite3_collation_needed :: (unk0: *sqlite3, unk1: *void, unk2: #type (a0: *void, a1: *sqlite3, a2: s32, a3: *s8) -> void #c_call) -> s32 #foreign sqlite; 469 | 470 | sqlite3_collation_needed16 :: (unk0: *sqlite3, unk1: *void, unk2: #type (a0: *void, a1: *sqlite3, a2: s32, a3: *void) -> void #c_call) -> s32 #foreign sqlite; 471 | 472 | sqlite3_sleep :: (unk0: s32) -> s32 #foreign sqlite; 473 | 474 | sqlite3_temp_directory: *s8; 475 | 476 | sqlite3_data_directory: *s8; 477 | 478 | sqlite3_win32_set_directory :: (type: u32, zValue: *void) -> s32 #foreign sqlite; 479 | 480 | sqlite3_win32_set_directory8 :: (type: u32, zValue: *s8) -> s32 #foreign sqlite; 481 | 482 | sqlite3_win32_set_directory16 :: (type: u32, zValue: *void) -> s32 #foreign sqlite; 483 | 484 | sqlite3_get_autocommit :: (unk0: *sqlite3) -> s32 #foreign sqlite; 485 | 486 | sqlite3_db_handle :: (unk0: *sqlite3_stmt) -> *sqlite3 #foreign sqlite; 487 | 488 | sqlite3_db_filename :: (db: *sqlite3, zDbName: *s8) -> *s8 #foreign sqlite; 489 | 490 | sqlite3_db_readonly :: (db: *sqlite3, zDbName: *s8) -> s32 #foreign sqlite; 491 | 492 | sqlite3_txn_state :: (unk0: *sqlite3, zSchema: *s8) -> s32 #foreign sqlite; 493 | 494 | sqlite3_next_stmt :: (pDb: *sqlite3, pStmt: *sqlite3_stmt) -> *sqlite3_stmt #foreign sqlite; 495 | 496 | sqlite3_commit_hook :: (unk0: *sqlite3, unk1: #type (a0: *void) -> s32 #c_call, unk2: *void) -> *void #foreign sqlite; 497 | 498 | sqlite3_rollback_hook :: (unk0: *sqlite3, unk1: #type (a0: *void) -> void #c_call, unk2: *void) -> *void #foreign sqlite; 499 | 500 | sqlite3_autovacuum_pages :: (db: *sqlite3, unk0: #type (a0: *void, a1: *s8, a2: u32, a3: u32, a4: u32) -> u32 #c_call, unk1: *void, unk2: #type (a0: *void) -> void #c_call) -> s32 #foreign sqlite; 501 | 502 | sqlite3_update_hook :: (unk0: *sqlite3, unk1: #type (a0: *void, a1: s32, a2: *s8, a3: *s8, a4: sqlite3_int64) -> void #c_call, unk2: *void) -> *void #foreign sqlite; 503 | 504 | sqlite3_enable_shared_cache :: (unk0: s32) -> s32 #foreign sqlite; 505 | 506 | sqlite3_release_memory :: (unk0: s32) -> s32 #foreign sqlite; 507 | 508 | sqlite3_db_release_memory :: (unk0: *sqlite3) -> s32 #foreign sqlite; 509 | 510 | sqlite3_soft_heap_limit64 :: (N: sqlite3_int64) -> sqlite3_int64 #foreign sqlite; 511 | 512 | sqlite3_hard_heap_limit64 :: (N: sqlite3_int64) -> sqlite3_int64 #foreign sqlite; 513 | 514 | sqlite3_soft_heap_limit :: (N: s32) -> void #foreign sqlite; 515 | 516 | sqlite3_table_column_metadata :: (db: *sqlite3, zDbName: *s8, zTableName: *s8, zColumnName: *s8, pzDataType: **s8, pzCollSeq: **s8, pNotNull: *s32, pPrimaryKey: *s32, pAutoinc: *s32) -> s32 #foreign sqlite; 517 | 518 | sqlite3_load_extension :: (db: *sqlite3, zFile: *s8, zProc: *s8, pzErrMsg: **s8) -> s32 #foreign sqlite; 519 | 520 | sqlite3_enable_load_extension :: (db: *sqlite3, onoff: s32) -> s32 #foreign sqlite; 521 | 522 | sqlite3_auto_extension :: (xEntryPoint: #type () -> void #c_call) -> s32 #foreign sqlite; 523 | 524 | sqlite3_cancel_auto_extension :: (xEntryPoint: #type () -> void #c_call) -> s32 #foreign sqlite; 525 | 526 | sqlite3_reset_auto_extension :: () -> void #foreign sqlite; 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | sqlite3_module :: struct { 537 | iVersion: s32; 538 | xCreate: #type (a0: *sqlite3, a1: *void, a2: s32, a3: **s8, a4: **sqlite3_vtab, a5: **s8) -> s32 #c_call; 539 | xConnect: #type (a0: *sqlite3, a1: *void, a2: s32, a3: **s8, a4: **sqlite3_vtab, a5: **s8) -> s32 #c_call; 540 | xBestIndex: #type (a0: *sqlite3_vtab, a1: *sqlite3_index_info) -> s32 #c_call; 541 | xDisconnect: #type (a0: *sqlite3_vtab) -> s32 #c_call; 542 | xDestroy: #type (a0: *sqlite3_vtab) -> s32 #c_call; 543 | xOpen: #type (a0: *sqlite3_vtab, a1: **sqlite3_vtab_cursor) -> s32 #c_call; 544 | xClose: #type (a0: *sqlite3_vtab_cursor) -> s32 #c_call; 545 | xFilter: #type (a0: *sqlite3_vtab_cursor, a1: s32, a2: *s8, a3: s32, a4: **sqlite3_value) -> s32 #c_call; 546 | xNext: #type (a0: *sqlite3_vtab_cursor) -> s32 #c_call; 547 | xEof: #type (a0: *sqlite3_vtab_cursor) -> s32 #c_call; 548 | xColumn: #type (a0: *sqlite3_vtab_cursor, a1: *sqlite3_context, a2: s32) -> s32 #c_call; 549 | xRowid: #type (a0: *sqlite3_vtab_cursor, a1: *sqlite3_int64) -> s32 #c_call; 550 | xUpdate: #type (a0: *sqlite3_vtab, a1: s32, a2: **sqlite3_value, a3: *sqlite3_int64) -> s32 #c_call; 551 | xBegin: #type (a0: *sqlite3_vtab) -> s32 #c_call; 552 | xSync: #type (a0: *sqlite3_vtab) -> s32 #c_call; 553 | xCommit: #type (a0: *sqlite3_vtab) -> s32 #c_call; 554 | xRollback: #type (a0: *sqlite3_vtab) -> s32 #c_call; 555 | xFindFunction: #type (a0: *sqlite3_vtab, a1: s32, a2: *s8, a3: *#type (a0: *sqlite3_context, a1: s32, a2: **sqlite3_value) -> void #c_call, a4: **void) -> s32 #c_call; 556 | xRename: #type (a0: *sqlite3_vtab, a1: *s8) -> s32 #c_call; 557 | xSavepoint: #type (a0: *sqlite3_vtab, a1: s32) -> s32 #c_call; 558 | xRelease: #type (a0: *sqlite3_vtab, a1: s32) -> s32 #c_call; 559 | xRollbackTo: #type (a0: *sqlite3_vtab, a1: s32) -> s32 #c_call; 560 | xShadowName: #type (a0: *s8) -> s32 #c_call; 561 | } 562 | 563 | sqlite3_index_info :: struct { 564 | nConstraint: s32; 565 | sqlite3_index_constraint :: struct { 566 | iColumn: s32; 567 | op: u8; 568 | usable: u8; 569 | iTermOffset: s32; 570 | } 571 | aConstraint: *sqlite3_index_constraint; 572 | nOrderBy: s32; 573 | sqlite3_index_orderby :: struct { 574 | iColumn: s32; 575 | desc: u8; 576 | } 577 | aOrderBy: *sqlite3_index_orderby; 578 | sqlite3_index_constraint_usage :: struct { 579 | argvIndex: s32; 580 | omit: u8; 581 | } 582 | aConstraintUsage: *sqlite3_index_constraint_usage; 583 | idxNum: s32; 584 | idxStr: *s8; 585 | needToFreeIdxStr: s32; 586 | orderByConsumed: s32; 587 | estimatedCost: float64; 588 | estimatedRows: sqlite3_int64; 589 | idxFlags: s32; 590 | colUsed: sqlite3_uint64; 591 | } 592 | 593 | sqlite3_create_module :: (db: *sqlite3, zName: *s8, p: *sqlite3_module, pClientData: *void) -> s32 #foreign sqlite; 594 | 595 | sqlite3_create_module_v2 :: (db: *sqlite3, zName: *s8, p: *sqlite3_module, pClientData: *void, xDestroy: #type (a0: *void) -> void #c_call) -> s32 #foreign sqlite; 596 | 597 | sqlite3_drop_modules :: (db: *sqlite3, azKeep: **s8) -> s32 #foreign sqlite; 598 | 599 | sqlite3_vtab :: struct { 600 | pModule: *sqlite3_module; 601 | nRef: s32; 602 | zErrMsg: *s8; 603 | } 604 | 605 | sqlite3_vtab_cursor :: struct { 606 | pVtab: *sqlite3_vtab; 607 | } 608 | 609 | sqlite3_declare_vtab :: (unk0: *sqlite3, zSQL: *s8) -> s32 #foreign sqlite; 610 | 611 | sqlite3_overload_function :: (unk0: *sqlite3, zFuncName: *s8, nArg: s32) -> s32 #foreign sqlite; 612 | 613 | sqlite3_blob :: struct { 614 | } 615 | 616 | 617 | 618 | sqlite3_blob_open :: (unk0: *sqlite3, zDb: *s8, zTable: *s8, zColumn: *s8, iRow: sqlite3_int64, flags: s32, ppBlob: **sqlite3_blob) -> s32 #foreign sqlite; 619 | 620 | sqlite3_blob_reopen :: (unk0: *sqlite3_blob, unk1: sqlite3_int64) -> s32 #foreign sqlite; 621 | 622 | sqlite3_blob_close :: (unk0: *sqlite3_blob) -> s32 #foreign sqlite; 623 | 624 | sqlite3_blob_bytes :: (unk0: *sqlite3_blob) -> s32 #foreign sqlite; 625 | 626 | sqlite3_blob_read :: (unk0: *sqlite3_blob, Z: *void, N: s32, iOffset: s32) -> s32 #foreign sqlite; 627 | 628 | sqlite3_blob_write :: (unk0: *sqlite3_blob, z: *void, n: s32, iOffset: s32) -> s32 #foreign sqlite; 629 | 630 | sqlite3_vfs_find :: (zVfsName: *s8) -> *sqlite3_vfs #foreign sqlite; 631 | 632 | sqlite3_vfs_register :: (unk0: *sqlite3_vfs, makeDflt: s32) -> s32 #foreign sqlite; 633 | 634 | sqlite3_vfs_unregister :: (unk0: *sqlite3_vfs) -> s32 #foreign sqlite; 635 | 636 | sqlite3_mutex_alloc :: (unk0: s32) -> *sqlite3_mutex #foreign sqlite; 637 | 638 | sqlite3_mutex_free :: (unk0: *sqlite3_mutex) -> void #foreign sqlite; 639 | 640 | sqlite3_mutex_enter :: (unk0: *sqlite3_mutex) -> void #foreign sqlite; 641 | 642 | sqlite3_mutex_try :: (unk0: *sqlite3_mutex) -> s32 #foreign sqlite; 643 | 644 | sqlite3_mutex_leave :: (unk0: *sqlite3_mutex) -> void #foreign sqlite; 645 | 646 | 647 | 648 | sqlite3_mutex_methods :: struct { 649 | xMutexInit: #type () -> s32 #c_call; 650 | xMutexEnd: #type () -> s32 #c_call; 651 | xMutexAlloc: #type (a0: s32) -> *sqlite3_mutex #c_call; 652 | xMutexFree: #type (a0: *sqlite3_mutex) -> void #c_call; 653 | xMutexEnter: #type (a0: *sqlite3_mutex) -> void #c_call; 654 | xMutexTry: #type (a0: *sqlite3_mutex) -> s32 #c_call; 655 | xMutexLeave: #type (a0: *sqlite3_mutex) -> void #c_call; 656 | xMutexHeld: #type (a0: *sqlite3_mutex) -> s32 #c_call; 657 | xMutexNotheld: #type (a0: *sqlite3_mutex) -> s32 #c_call; 658 | } 659 | 660 | //sqlite3_mutex_held :: (unk0: *sqlite3_mutex) -> s32 #foreign sqlite; 661 | 662 | //sqlite3_mutex_notheld :: (unk0: *sqlite3_mutex) -> s32 #foreign sqlite; 663 | 664 | sqlite3_db_mutex :: (unk0: *sqlite3) -> *sqlite3_mutex #foreign sqlite; 665 | 666 | sqlite3_file_control :: (unk0: *sqlite3, zDbName: *s8, op: s32, unk1: *void) -> s32 #foreign sqlite; 667 | 668 | sqlite3_test_control :: (op: s32, __args: ..Any) -> s32 #foreign sqlite; 669 | 670 | sqlite3_keyword_count :: () -> s32 #foreign sqlite; 671 | 672 | sqlite3_keyword_name :: (unk0: s32, unk1: **s8, unk2: *s32) -> s32 #foreign sqlite; 673 | 674 | sqlite3_keyword_check :: (unk0: *s8, unk1: s32) -> s32 #foreign sqlite; 675 | 676 | sqlite3_str :: struct { 677 | } 678 | 679 | 680 | 681 | sqlite3_str_new :: (unk0: *sqlite3) -> *sqlite3_str #foreign sqlite; 682 | 683 | sqlite3_str_finish :: (unk0: *sqlite3_str) -> *s8 #foreign sqlite; 684 | 685 | sqlite3_str_appendf :: (unk0: *sqlite3_str, zFormat: *s8, __args: ..Any) -> void #foreign sqlite; 686 | 687 | //sqlite3_str_vappendf :: (unk0: *sqlite3_str, zFormat: *s8, unk1: va_list) -> void #foreign sqlite; 688 | 689 | sqlite3_str_append :: (unk0: *sqlite3_str, zIn: *s8, N: s32) -> void #foreign sqlite; 690 | 691 | sqlite3_str_appendall :: (unk0: *sqlite3_str, zIn: *s8) -> void #foreign sqlite; 692 | 693 | sqlite3_str_appendchar :: (unk0: *sqlite3_str, N: s32, C: s8) -> void #foreign sqlite; 694 | 695 | sqlite3_str_reset :: (unk0: *sqlite3_str) -> void #foreign sqlite; 696 | 697 | sqlite3_str_errcode :: (unk0: *sqlite3_str) -> s32 #foreign sqlite; 698 | 699 | sqlite3_str_length :: (unk0: *sqlite3_str) -> s32 #foreign sqlite; 700 | 701 | sqlite3_str_value :: (unk0: *sqlite3_str) -> *s8 #foreign sqlite; 702 | 703 | sqlite3_status :: (op: s32, pCurrent: *s32, pHighwater: *s32, resetFlag: s32) -> s32 #foreign sqlite; 704 | 705 | sqlite3_status64 :: (op: s32, pCurrent: *sqlite3_int64, pHighwater: *sqlite3_int64, resetFlag: s32) -> s32 #foreign sqlite; 706 | 707 | sqlite3_db_status :: (unk0: *sqlite3, op: s32, pCur: *s32, pHiwtr: *s32, resetFlg: s32) -> s32 #foreign sqlite; 708 | 709 | sqlite3_stmt_status :: (unk0: *sqlite3_stmt, op: s32, resetFlg: s32) -> s32 #foreign sqlite; 710 | 711 | sqlite3_pcache :: struct { 712 | } 713 | 714 | 715 | 716 | 717 | 718 | sqlite3_pcache_page :: struct { 719 | pBuf: *void; 720 | pExtra: *void; 721 | } 722 | 723 | 724 | 725 | sqlite3_pcache_methods2 :: struct { 726 | iVersion: s32; 727 | pArg: *void; 728 | xInit: #type (a0: *void) -> s32 #c_call; 729 | xShutdown: #type (a0: *void) -> void #c_call; 730 | xCreate: #type (a0: s32, a1: s32, a2: s32) -> *sqlite3_pcache #c_call; 731 | xCachesize: #type (a0: *sqlite3_pcache, a1: s32) -> void #c_call; 732 | xPagecount: #type (a0: *sqlite3_pcache) -> s32 #c_call; 733 | xFetch: #type (a0: *sqlite3_pcache, a1: u32, a2: s32) -> *sqlite3_pcache_page #c_call; 734 | xUnpin: #type (a0: *sqlite3_pcache, a1: *sqlite3_pcache_page, a2: s32) -> void #c_call; 735 | xRekey: #type (a0: *sqlite3_pcache, a1: *sqlite3_pcache_page, a2: u32, a3: u32) -> void #c_call; 736 | xTruncate: #type (a0: *sqlite3_pcache, a1: u32) -> void #c_call; 737 | xDestroy: #type (a0: *sqlite3_pcache) -> void #c_call; 738 | xShrink: #type (a0: *sqlite3_pcache) -> void #c_call; 739 | } 740 | 741 | 742 | 743 | sqlite3_pcache_methods :: struct { 744 | pArg: *void; 745 | xInit: #type (a0: *void) -> s32 #c_call; 746 | xShutdown: #type (a0: *void) -> void #c_call; 747 | xCreate: #type (a0: s32, a1: s32) -> *sqlite3_pcache #c_call; 748 | xCachesize: #type (a0: *sqlite3_pcache, a1: s32) -> void #c_call; 749 | xPagecount: #type (a0: *sqlite3_pcache) -> s32 #c_call; 750 | xFetch: #type (a0: *sqlite3_pcache, a1: u32, a2: s32) -> *void #c_call; 751 | xUnpin: #type (a0: *sqlite3_pcache, a1: *void, a2: s32) -> void #c_call; 752 | xRekey: #type (a0: *sqlite3_pcache, a1: *void, a2: u32, a3: u32) -> void #c_call; 753 | xTruncate: #type (a0: *sqlite3_pcache, a1: u32) -> void #c_call; 754 | xDestroy: #type (a0: *sqlite3_pcache) -> void #c_call; 755 | } 756 | 757 | sqlite3_backup :: struct { 758 | } 759 | 760 | 761 | 762 | sqlite3_backup_init :: (pDest: *sqlite3, zDestName: *s8, pSource: *sqlite3, zSourceName: *s8) -> *sqlite3_backup #foreign sqlite; 763 | 764 | sqlite3_backup_step :: (p: *sqlite3_backup, nPage: s32) -> s32 #foreign sqlite; 765 | 766 | sqlite3_backup_finish :: (p: *sqlite3_backup) -> s32 #foreign sqlite; 767 | 768 | sqlite3_backup_remaining :: (p: *sqlite3_backup) -> s32 #foreign sqlite; 769 | 770 | sqlite3_backup_pagecount :: (p: *sqlite3_backup) -> s32 #foreign sqlite; 771 | 772 | //sqlite3_unlock_notify :: (pBlocked: *sqlite3, xNotify: #type (a0: **void, a1: s32) -> void #c_call, pNotifyArg: *void) -> s32 #foreign sqlite; 773 | 774 | sqlite3_stricmp :: (unk0: *s8, unk1: *s8) -> s32 #foreign sqlite; 775 | 776 | sqlite3_strnicmp :: (unk0: *s8, unk1: *s8, unk2: s32) -> s32 #foreign sqlite; 777 | 778 | sqlite3_strglob :: (zGlob: *s8, zStr: *s8) -> s32 #foreign sqlite; 779 | 780 | sqlite3_strlike :: (zGlob: *s8, zStr: *s8, cEsc: u32) -> s32 #foreign sqlite; 781 | 782 | sqlite3_log :: (iErrCode: s32, zFormat: *s8, __args: ..Any) -> void #foreign sqlite; 783 | 784 | sqlite3_wal_hook :: (unk0: *sqlite3, unk1: #type (a0: *void, a1: *sqlite3, a2: *s8, a3: s32) -> s32 #c_call, unk2: *void) -> *void #foreign sqlite; 785 | 786 | sqlite3_wal_autocheckpoint :: (db: *sqlite3, N: s32) -> s32 #foreign sqlite; 787 | 788 | sqlite3_wal_checkpoint :: (db: *sqlite3, zDb: *s8) -> s32 #foreign sqlite; 789 | 790 | sqlite3_wal_checkpoint_v2 :: (db: *sqlite3, zDb: *s8, eMode: s32, pnLog: *s32, pnCkpt: *s32) -> s32 #foreign sqlite; 791 | 792 | sqlite3_vtab_config :: (unk0: *sqlite3, op: s32, __args: ..Any) -> s32 #foreign sqlite; 793 | 794 | sqlite3_vtab_on_conflict :: (unk0: *sqlite3) -> s32 #foreign sqlite; 795 | 796 | sqlite3_vtab_nochange :: (unk0: *sqlite3_context) -> s32 #foreign sqlite; 797 | 798 | sqlite3_vtab_collation :: (unk0: *sqlite3_index_info, unk1: s32) -> *s8 #foreign sqlite; 799 | 800 | //sqlite3_stmt_scanstatus :: (pStmt: *sqlite3_stmt, idx: s32, iScanStatusOp: s32, pOut: *void) -> s32 #foreign sqlite; 801 | 802 | //sqlite3_stmt_scanstatus_reset :: (unk0: *sqlite3_stmt) -> void #foreign sqlite; 803 | 804 | sqlite3_db_cacheflush :: (unk0: *sqlite3) -> s32 #foreign sqlite; 805 | 806 | sqlite3_system_errno :: (unk0: *sqlite3) -> s32 #foreign sqlite; 807 | 808 | sqlite3_snapshot :: struct { 809 | hidden: [48] u8; 810 | } 811 | 812 | 813 | 814 | //sqlite3_snapshot_get :: (db: *sqlite3, zSchema: *s8, ppSnapshot: **sqlite3_snapshot) -> s32 #foreign sqlite; 815 | 816 | //sqlite3_snapshot_open :: (db: *sqlite3, zSchema: *s8, pSnapshot: *sqlite3_snapshot) -> s32 #foreign sqlite; 817 | 818 | //sqlite3_snapshot_free :: (unk0: *sqlite3_snapshot) -> void #foreign sqlite; 819 | 820 | //sqlite3_snapshot_cmp :: (p1: *sqlite3_snapshot, p2: *sqlite3_snapshot) -> s32 #foreign sqlite; 821 | 822 | //sqlite3_snapshot_recover :: (db: *sqlite3, zDb: *s8) -> s32 #foreign sqlite; 823 | 824 | sqlite3_serialize :: (db: *sqlite3, zSchema: *s8, piSize: *sqlite3_int64, mFlags: u32) -> *u8 #foreign sqlite; 825 | 826 | sqlite3_deserialize :: (db: *sqlite3, zSchema: *s8, pData: *u8, szDb: sqlite3_int64, szBuf: sqlite3_int64, mFlags: u32) -> s32 #foreign sqlite; 827 | 828 | 829 | 830 | 831 | 832 | sqlite3_rtree_dbl :: float64; 833 | 834 | sqlite3_rtree_geometry_callback :: (db: *sqlite3, zGeom: *s8, xGeom: #type (a0: *sqlite3_rtree_geometry, a1: s32, a2: *sqlite3_rtree_dbl, a3: *s32) -> s32 #c_call, pContext: *void) -> s32 #foreign sqlite; 835 | 836 | sqlite3_rtree_geometry :: struct { 837 | pContext: *void; 838 | nParam: s32; 839 | aParam: *sqlite3_rtree_dbl; 840 | pUser: *void; 841 | xDelUser: #type (a0: *void) -> void #c_call; 842 | } 843 | 844 | sqlite3_rtree_query_callback :: (db: *sqlite3, zQueryFunc: *s8, xQueryFunc: #type (a0: *sqlite3_rtree_query_info) -> s32 #c_call, pContext: *void, xDestructor: #type (a0: *void) -> void #c_call) -> s32 #foreign sqlite; 845 | 846 | sqlite3_rtree_query_info :: struct { 847 | pContext: *void; 848 | nParam: s32; 849 | aParam: *sqlite3_rtree_dbl; 850 | pUser: *void; 851 | xDelUser: #type (a0: *void) -> void #c_call; 852 | aCoord: *sqlite3_rtree_dbl; 853 | anQueue: *u32; 854 | nCoord: s32; 855 | iLevel: s32; 856 | mxLevel: s32; 857 | iRowid: sqlite3_int64; 858 | rParentScore: sqlite3_rtree_dbl; 859 | eParentWithin: s32; 860 | eWithin: s32; 861 | rScore: sqlite3_rtree_dbl; 862 | apSqlParam: **sqlite3_value; 863 | } 864 | 865 | 866 | 867 | Fts5Context :: struct { 868 | } 869 | 870 | 871 | 872 | 873 | 874 | fts5_extension_function :: #type (a0: *Fts5ExtensionApi, a1: *Fts5Context, a2: *sqlite3_context, a3: s32, a4: **sqlite3_value) -> void #c_call; 875 | 876 | Fts5PhraseIter :: struct { 877 | a: *u8; 878 | b: *u8; 879 | } 880 | 881 | Fts5ExtensionApi :: struct { 882 | iVersion: s32; 883 | xUserData: #type (a0: *Fts5Context) -> *void #c_call; 884 | xColumnCount: #type (a0: *Fts5Context) -> s32 #c_call; 885 | xRowCount: #type (a0: *Fts5Context, a1: *sqlite3_int64) -> s32 #c_call; 886 | xColumnTotalSize: #type (a0: *Fts5Context, a1: s32, a2: *sqlite3_int64) -> s32 #c_call; 887 | xTokenize: #type (a0: *Fts5Context, a1: *s8, a2: s32, a3: *void, a4: #type (a0: *void, a1: s32, a2: *s8, a3: s32, a4: s32, a5: s32) -> s32 #c_call) -> s32 #c_call; 888 | xPhraseCount: #type (a0: *Fts5Context) -> s32 #c_call; 889 | xPhraseSize: #type (a0: *Fts5Context, a1: s32) -> s32 #c_call; 890 | xInstCount: #type (a0: *Fts5Context, a1: *s32) -> s32 #c_call; 891 | xInst: #type (a0: *Fts5Context, a1: s32, a2: *s32, a3: *s32, a4: *s32) -> s32 #c_call; 892 | xRowid: #type (a0: *Fts5Context) -> sqlite3_int64 #c_call; 893 | xColumnText: #type (a0: *Fts5Context, a1: s32, a2: **s8, a3: *s32) -> s32 #c_call; 894 | xColumnSize: #type (a0: *Fts5Context, a1: s32, a2: *s32) -> s32 #c_call; 895 | xQueryPhrase: #type (a0: *Fts5Context, a1: s32, a2: *void, a3: #type (a0: *Fts5ExtensionApi, a1: *Fts5Context, a2: *void) -> s32 #c_call) -> s32 #c_call; 896 | xSetAuxdata: #type (a0: *Fts5Context, a1: *void, a2: #type (a0: *void) -> void #c_call) -> s32 #c_call; 897 | xGetAuxdata: #type (a0: *Fts5Context, a1: s32) -> *void #c_call; 898 | xPhraseFirst: #type (a0: *Fts5Context, a1: s32, a2: *Fts5PhraseIter, a3: *s32, a4: *s32) -> s32 #c_call; 899 | xPhraseNext: #type (a0: *Fts5Context, a1: *Fts5PhraseIter, a2: *s32, a3: *s32) -> void #c_call; 900 | xPhraseFirstColumn: #type (a0: *Fts5Context, a1: s32, a2: *Fts5PhraseIter, a3: *s32) -> s32 #c_call; 901 | xPhraseNextColumn: #type (a0: *Fts5Context, a1: *Fts5PhraseIter, a2: *s32) -> void #c_call; 902 | } 903 | 904 | Fts5Tokenizer :: struct { 905 | } 906 | 907 | 908 | 909 | 910 | 911 | fts5_tokenizer :: struct { 912 | xCreate: #type (a0: *void, a1: **s8, a2: s32, a3: **Fts5Tokenizer) -> s32 #c_call; 913 | xDelete: #type (a0: *Fts5Tokenizer) -> void #c_call; 914 | xTokenize: #type (a0: *Fts5Tokenizer, a1: *void, a2: s32, a3: *s8, a4: s32, a5: #type (a0: *void, a1: s32, a2: *s8, a3: s32, a4: s32, a5: s32) -> s32 #c_call) -> s32 #c_call; 915 | } 916 | 917 | 918 | 919 | fts5_api :: struct { 920 | iVersion: s32; 921 | xCreateTokenizer: #type (a0: *fts5_api, a1: *s8, a2: *void, a3: *fts5_tokenizer, a4: #type (a0: *void) -> void #c_call) -> s32 #c_call; 922 | xFindTokenizer: #type (a0: *fts5_api, a1: *s8, a2: **void, a3: *fts5_tokenizer) -> s32 #c_call; 923 | xCreateFunction: #type (a0: *fts5_api, a1: *s8, a2: *void, a3: fts5_extension_function, a4: #type (a0: *void) -> void #c_call) -> s32 #c_call; 924 | } 925 | 926 | sqlite3_api_routines :: struct #type_info_none { 927 | aggregate_context: #type (a0: *sqlite3_context, a1: s32) -> *void #c_call; 928 | aggregate_count: #type (a0: *sqlite3_context) -> s32 #c_call; 929 | bind_blob: #type (a0: *sqlite3_stmt, a1: s32, a2: *void, a3: s32, a4: #type (a0: *void) -> void #c_call) -> s32 #c_call; 930 | bind_double: #type (a0: *sqlite3_stmt, a1: s32, a2: float64) -> s32 #c_call; 931 | bind_int: #type (a0: *sqlite3_stmt, a1: s32, a2: s32) -> s32 #c_call; 932 | bind_int64: #type (a0: *sqlite3_stmt, a1: s32, a2: sqlite_int64) -> s32 #c_call; 933 | bind_null: #type (a0: *sqlite3_stmt, a1: s32) -> s32 #c_call; 934 | bind_parameter_count: #type (a0: *sqlite3_stmt) -> s32 #c_call; 935 | bind_parameter_index: #type (a0: *sqlite3_stmt, a1: *s8) -> s32 #c_call; 936 | bind_parameter_name: #type (a0: *sqlite3_stmt, a1: s32) -> *s8 #c_call; 937 | bind_text: #type (a0: *sqlite3_stmt, a1: s32, a2: *s8, a3: s32, a4: #type (a0: *void) -> void #c_call) -> s32 #c_call; 938 | bind_text16: #type (a0: *sqlite3_stmt, a1: s32, a2: *void, a3: s32, a4: #type (a0: *void) -> void #c_call) -> s32 #c_call; 939 | bind_value: #type (a0: *sqlite3_stmt, a1: s32, a2: *sqlite3_value) -> s32 #c_call; 940 | busy_handler: #type (a0: *sqlite3, a1: #type (a0: *void, a1: s32) -> s32 #c_call, a2: *void) -> s32 #c_call; 941 | busy_timeout: #type (a0: *sqlite3, a1: s32) -> s32 #c_call; 942 | changes: #type (a0: *sqlite3) -> s32 #c_call; 943 | close: #type (a0: *sqlite3) -> s32 #c_call; 944 | collation_needed: #type (a0: *sqlite3, a1: *void, a2: #type (a0: *void, a1: *sqlite3, a2: s32, a3: *s8) -> void #c_call) -> s32 #c_call; 945 | collation_needed16: #type (a0: *sqlite3, a1: *void, a2: #type (a0: *void, a1: *sqlite3, a2: s32, a3: *void) -> void #c_call) -> s32 #c_call; 946 | column_blob: #type (a0: *sqlite3_stmt, a1: s32) -> *void #c_call; 947 | column_bytes: #type (a0: *sqlite3_stmt, a1: s32) -> s32 #c_call; 948 | column_bytes16: #type (a0: *sqlite3_stmt, a1: s32) -> s32 #c_call; 949 | column_count: #type (a0: *sqlite3_stmt) -> s32 #c_call; 950 | column_database_name: #type (a0: *sqlite3_stmt, a1: s32) -> *s8 #c_call; 951 | column_database_name16: #type (a0: *sqlite3_stmt, a1: s32) -> *void #c_call; 952 | column_decltype: #type (a0: *sqlite3_stmt, a1: s32) -> *s8 #c_call; 953 | column_decltype16: #type (a0: *sqlite3_stmt, a1: s32) -> *void #c_call; 954 | column_double: #type (a0: *sqlite3_stmt, a1: s32) -> float64 #c_call; 955 | column_int: #type (a0: *sqlite3_stmt, a1: s32) -> s32 #c_call; 956 | column_int64: #type (a0: *sqlite3_stmt, a1: s32) -> sqlite_int64 #c_call; 957 | column_name: #type (a0: *sqlite3_stmt, a1: s32) -> *s8 #c_call; 958 | column_name16: #type (a0: *sqlite3_stmt, a1: s32) -> *void #c_call; 959 | column_origin_name: #type (a0: *sqlite3_stmt, a1: s32) -> *s8 #c_call; 960 | column_origin_name16: #type (a0: *sqlite3_stmt, a1: s32) -> *void #c_call; 961 | column_table_name: #type (a0: *sqlite3_stmt, a1: s32) -> *s8 #c_call; 962 | column_table_name16: #type (a0: *sqlite3_stmt, a1: s32) -> *void #c_call; 963 | column_text: #type (a0: *sqlite3_stmt, a1: s32) -> *u8 #c_call; 964 | column_text16: #type (a0: *sqlite3_stmt, a1: s32) -> *void #c_call; 965 | column_type: #type (a0: *sqlite3_stmt, a1: s32) -> s32 #c_call; 966 | column_value: #type (a0: *sqlite3_stmt, a1: s32) -> *sqlite3_value #c_call; 967 | commit_hook: #type (a0: *sqlite3, a1: #type (a0: *void) -> s32 #c_call, a2: *void) -> *void #c_call; 968 | complete: #type (a0: *s8) -> s32 #c_call; 969 | complete16: #type (a0: *void) -> s32 #c_call; 970 | create_collation: #type (a0: *sqlite3, a1: *s8, a2: s32, a3: *void, a4: #type (a0: *void, a1: s32, a2: *void, a3: s32, a4: *void) -> s32 #c_call) -> s32 #c_call; 971 | create_collation16: #type (a0: *sqlite3, a1: *void, a2: s32, a3: *void, a4: #type (a0: *void, a1: s32, a2: *void, a3: s32, a4: *void) -> s32 #c_call) -> s32 #c_call; 972 | create_function: #type (a0: *sqlite3, a1: *s8, a2: s32, a3: s32, a4: *void, a5: #type (a0: *sqlite3_context, a1: s32, a2: **sqlite3_value) -> void #c_call, a6: #type (a0: *sqlite3_context, a1: s32, a2: **sqlite3_value) -> void #c_call, a7: #type (a0: *sqlite3_context) -> void #c_call) -> s32 #c_call; 973 | create_function16: #type (a0: *sqlite3, a1: *void, a2: s32, a3: s32, a4: *void, a5: #type (a0: *sqlite3_context, a1: s32, a2: **sqlite3_value) -> void #c_call, a6: #type (a0: *sqlite3_context, a1: s32, a2: **sqlite3_value) -> void #c_call, a7: #type (a0: *sqlite3_context) -> void #c_call) -> s32 #c_call; 974 | create_module: #type (a0: *sqlite3, a1: *s8, a2: *sqlite3_module, a3: *void) -> s32 #c_call; 975 | data_count: #type (a0: *sqlite3_stmt) -> s32 #c_call; 976 | db_handle: #type (a0: *sqlite3_stmt) -> *sqlite3 #c_call; 977 | declare_vtab: #type (a0: *sqlite3, a1: *s8) -> s32 #c_call; 978 | enable_shared_cache: #type (a0: s32) -> s32 #c_call; 979 | errcode: #type (a0: *sqlite3) -> s32 #c_call; 980 | errmsg: #type (a0: *sqlite3) -> *s8 #c_call; 981 | errmsg16: #type (a0: *sqlite3) -> *void #c_call; 982 | exec: #type (a0: *sqlite3, a1: *s8, a2: sqlite3_callback, a3: *void, a4: **s8) -> s32 #c_call; 983 | expired: #type (a0: *sqlite3_stmt) -> s32 #c_call; 984 | finalize: #type (a0: *sqlite3_stmt) -> s32 #c_call; 985 | free: #type (a0: *void) -> void #c_call; 986 | free_table: #type (a0: **s8) -> void #c_call; 987 | get_autocommit: #type (a0: *sqlite3) -> s32 #c_call; 988 | get_auxdata: #type (a0: *sqlite3_context, a1: s32) -> *void #c_call; 989 | get_table: #type (a0: *sqlite3, a1: *s8, a2: ***s8, a3: *s32, a4: *s32, a5: **s8) -> s32 #c_call; 990 | global_recover: #type () -> s32 #c_call; 991 | interruptx: #type (a0: *sqlite3) -> void #c_call; 992 | last_insert_rowid: #type (a0: *sqlite3) -> sqlite_int64 #c_call; 993 | libversion: #type () -> *s8 #c_call; 994 | libversion_number: #type () -> s32 #c_call; 995 | malloc: #type (a0: s32) -> *void #c_call; 996 | mprintf: #type (a0: *s8) -> *s8 #c_call; 997 | open: #type (a0: *s8, a1: **sqlite3) -> s32 #c_call; 998 | open16: #type (a0: *void, a1: **sqlite3) -> s32 #c_call; 999 | prepare: #type (a0: *sqlite3, a1: *s8, a2: s32, a3: **sqlite3_stmt, a4: **s8) -> s32 #c_call; 1000 | prepare16: #type (a0: *sqlite3, a1: *void, a2: s32, a3: **sqlite3_stmt, a4: **void) -> s32 #c_call; 1001 | profile: #type (a0: *sqlite3, a1: #type (a0: *void, a1: *s8, a2: sqlite_uint64) -> void #c_call, a2: *void) -> *void #c_call; 1002 | progress_handler: #type (a0: *sqlite3, a1: s32, a2: #type (a0: *void) -> s32 #c_call, a3: *void) -> void #c_call; 1003 | realloc: #type (a0: *void, a1: s32) -> *void #c_call; 1004 | reset: #type (a0: *sqlite3_stmt) -> s32 #c_call; 1005 | result_blob: #type (a0: *sqlite3_context, a1: *void, a2: s32, a3: #type (a0: *void) -> void #c_call) -> void #c_call; 1006 | result_double: #type (a0: *sqlite3_context, a1: float64) -> void #c_call; 1007 | result_error: #type (a0: *sqlite3_context, a1: *s8, a2: s32) -> void #c_call; 1008 | result_error16: #type (a0: *sqlite3_context, a1: *void, a2: s32) -> void #c_call; 1009 | result_int: #type (a0: *sqlite3_context, a1: s32) -> void #c_call; 1010 | result_int64: #type (a0: *sqlite3_context, a1: sqlite_int64) -> void #c_call; 1011 | result_null: #type (a0: *sqlite3_context) -> void #c_call; 1012 | result_text: #type (a0: *sqlite3_context, a1: *s8, a2: s32, a3: #type (a0: *void) -> void #c_call) -> void #c_call; 1013 | result_text16: #type (a0: *sqlite3_context, a1: *void, a2: s32, a3: #type (a0: *void) -> void #c_call) -> void #c_call; 1014 | result_text16be: #type (a0: *sqlite3_context, a1: *void, a2: s32, a3: #type (a0: *void) -> void #c_call) -> void #c_call; 1015 | result_text16le: #type (a0: *sqlite3_context, a1: *void, a2: s32, a3: #type (a0: *void) -> void #c_call) -> void #c_call; 1016 | result_value: #type (a0: *sqlite3_context, a1: *sqlite3_value) -> void #c_call; 1017 | rollback_hook: #type (a0: *sqlite3, a1: #type (a0: *void) -> void #c_call, a2: *void) -> *void #c_call; 1018 | set_authorizer: #type (a0: *sqlite3, a1: #type (a0: *void, a1: s32, a2: *s8, a3: *s8, a4: *s8, a5: *s8) -> s32 #c_call, a2: *void) -> s32 #c_call; 1019 | set_auxdata: #type (a0: *sqlite3_context, a1: s32, a2: *void, a3: #type (a0: *void) -> void #c_call) -> void #c_call; 1020 | xsnprintf: #type (a0: s32, a1: *s8, a2: *s8) -> *s8 #c_call; 1021 | step: #type (a0: *sqlite3_stmt) -> s32 #c_call; 1022 | table_column_metadata: #type (a0: *sqlite3, a1: *s8, a2: *s8, a3: *s8, a4: **s8, a5: **s8, a6: *s32, a7: *s32, a8: *s32) -> s32 #c_call; 1023 | thread_cleanup: #type () -> void #c_call; 1024 | total_changes: #type (a0: *sqlite3) -> s32 #c_call; 1025 | trace: #type (a0: *sqlite3, a1: #type (a0: *void, a1: *s8) -> void #c_call, a2: *void) -> *void #c_call; 1026 | transfer_bindings: #type (a0: *sqlite3_stmt, a1: *sqlite3_stmt) -> s32 #c_call; 1027 | update_hook: #type (a0: *sqlite3, a1: #type (a0: *void, a1: s32, a2: *s8, a3: *s8, a4: sqlite_int64) -> void #c_call, a2: *void) -> *void #c_call; 1028 | user_data: #type (a0: *sqlite3_context) -> *void #c_call; 1029 | value_blob: #type (a0: *sqlite3_value) -> *void #c_call; 1030 | value_bytes: #type (a0: *sqlite3_value) -> s32 #c_call; 1031 | value_bytes16: #type (a0: *sqlite3_value) -> s32 #c_call; 1032 | value_double: #type (a0: *sqlite3_value) -> float64 #c_call; 1033 | value_int: #type (a0: *sqlite3_value) -> s32 #c_call; 1034 | value_int64: #type (a0: *sqlite3_value) -> sqlite_int64 #c_call; 1035 | value_numeric_type: #type (a0: *sqlite3_value) -> s32 #c_call; 1036 | value_text: #type (a0: *sqlite3_value) -> *u8 #c_call; 1037 | value_text16: #type (a0: *sqlite3_value) -> *void #c_call; 1038 | value_text16be: #type (a0: *sqlite3_value) -> *void #c_call; 1039 | value_text16le: #type (a0: *sqlite3_value) -> *void #c_call; 1040 | value_type: #type (a0: *sqlite3_value) -> s32 #c_call; 1041 | // vmprintf: #type (a0: *s8, a1: va_list) -> *s8 #c_call; 1042 | overload_function: #type (a0: *sqlite3, a1: *s8, a2: s32) -> s32 #c_call; 1043 | prepare_v2: #type (a0: *sqlite3, a1: *s8, a2: s32, a3: **sqlite3_stmt, a4: **s8) -> s32 #c_call; 1044 | prepare16_v2: #type (a0: *sqlite3, a1: *void, a2: s32, a3: **sqlite3_stmt, a4: **void) -> s32 #c_call; 1045 | clear_bindings: #type (a0: *sqlite3_stmt) -> s32 #c_call; 1046 | create_module_v2: #type (a0: *sqlite3, a1: *s8, a2: *sqlite3_module, a3: *void, a4: #type (a0: *void) -> void #c_call) -> s32 #c_call; 1047 | bind_zeroblob: #type (a0: *sqlite3_stmt, a1: s32, a2: s32) -> s32 #c_call; 1048 | blob_bytes: #type (a0: *sqlite3_blob) -> s32 #c_call; 1049 | blob_close: #type (a0: *sqlite3_blob) -> s32 #c_call; 1050 | blob_open: #type (a0: *sqlite3, a1: *s8, a2: *s8, a3: *s8, a4: sqlite3_int64, a5: s32, a6: **sqlite3_blob) -> s32 #c_call; 1051 | blob_read: #type (a0: *sqlite3_blob, a1: *void, a2: s32, a3: s32) -> s32 #c_call; 1052 | blob_write: #type (a0: *sqlite3_blob, a1: *void, a2: s32, a3: s32) -> s32 #c_call; 1053 | create_collation_v2: #type (a0: *sqlite3, a1: *s8, a2: s32, a3: *void, a4: #type (a0: *void, a1: s32, a2: *void, a3: s32, a4: *void) -> s32 #c_call, a5: #type (a0: *void) -> void #c_call) -> s32 #c_call; 1054 | file_control: #type (a0: *sqlite3, a1: *s8, a2: s32, a3: *void) -> s32 #c_call; 1055 | memory_highwater: #type (a0: s32) -> sqlite3_int64 #c_call; 1056 | memory_used: #type () -> sqlite3_int64 #c_call; 1057 | mutex_alloc: #type (a0: s32) -> *sqlite3_mutex #c_call; 1058 | mutex_enter: #type (a0: *sqlite3_mutex) -> void #c_call; 1059 | mutex_free: #type (a0: *sqlite3_mutex) -> void #c_call; 1060 | mutex_leave: #type (a0: *sqlite3_mutex) -> void #c_call; 1061 | mutex_try: #type (a0: *sqlite3_mutex) -> s32 #c_call; 1062 | open_v2: #type (a0: *s8, a1: **sqlite3, a2: s32, a3: *s8) -> s32 #c_call; 1063 | release_memory: #type (a0: s32) -> s32 #c_call; 1064 | result_error_nomem: #type (a0: *sqlite3_context) -> void #c_call; 1065 | result_error_toobig: #type (a0: *sqlite3_context) -> void #c_call; 1066 | sleep: #type (a0: s32) -> s32 #c_call; 1067 | soft_heap_limit: #type (a0: s32) -> void #c_call; 1068 | vfs_find: #type (a0: *s8) -> *sqlite3_vfs #c_call; 1069 | vfs_register: #type (a0: *sqlite3_vfs, a1: s32) -> s32 #c_call; 1070 | vfs_unregister: #type (a0: *sqlite3_vfs) -> s32 #c_call; 1071 | xthreadsafe: #type () -> s32 #c_call; 1072 | result_zeroblob: #type (a0: *sqlite3_context, a1: s32) -> void #c_call; 1073 | result_error_code: #type (a0: *sqlite3_context, a1: s32) -> void #c_call; 1074 | test_control: #type (a0: s32) -> s32 #c_call; 1075 | randomness: #type (a0: s32, a1: *void) -> void #c_call; 1076 | context_db_handle: #type (a0: *sqlite3_context) -> *sqlite3 #c_call; 1077 | extended_result_codes: #type (a0: *sqlite3, a1: s32) -> s32 #c_call; 1078 | limit: #type (a0: *sqlite3, a1: s32, a2: s32) -> s32 #c_call; 1079 | next_stmt: #type (a0: *sqlite3, a1: *sqlite3_stmt) -> *sqlite3_stmt #c_call; 1080 | sql: #type (a0: *sqlite3_stmt) -> *s8 #c_call; 1081 | status: #type (a0: s32, a1: *s32, a2: *s32, a3: s32) -> s32 #c_call; 1082 | backup_finish: #type (a0: *sqlite3_backup) -> s32 #c_call; 1083 | backup_init: #type (a0: *sqlite3, a1: *s8, a2: *sqlite3, a3: *s8) -> *sqlite3_backup #c_call; 1084 | backup_pagecount: #type (a0: *sqlite3_backup) -> s32 #c_call; 1085 | backup_remaining: #type (a0: *sqlite3_backup) -> s32 #c_call; 1086 | backup_step: #type (a0: *sqlite3_backup, a1: s32) -> s32 #c_call; 1087 | compileoption_get: #type (a0: s32) -> *s8 #c_call; 1088 | compileoption_used: #type (a0: *s8) -> s32 #c_call; 1089 | create_function_v2: #type (a0: *sqlite3, a1: *s8, a2: s32, a3: s32, a4: *void, a5: #type (a0: *sqlite3_context, a1: s32, a2: **sqlite3_value) -> void #c_call, a6: #type (a0: *sqlite3_context, a1: s32, a2: **sqlite3_value) -> void #c_call, a7: #type (a0: *sqlite3_context) -> void #c_call, a8: #type (a0: *void) -> void #c_call) -> s32 #c_call; 1090 | db_config: #type (a0: *sqlite3, a1: s32) -> s32 #c_call; 1091 | db_mutex: #type (a0: *sqlite3) -> *sqlite3_mutex #c_call; 1092 | db_status: #type (a0: *sqlite3, a1: s32, a2: *s32, a3: *s32, a4: s32) -> s32 #c_call; 1093 | extended_errcode: #type (a0: *sqlite3) -> s32 #c_call; 1094 | log: #type (a0: s32, a1: *s8) -> void #c_call; 1095 | soft_heap_limit64: #type (a0: sqlite3_int64) -> sqlite3_int64 #c_call; 1096 | sourceid: #type () -> *s8 #c_call; 1097 | stmt_status: #type (a0: *sqlite3_stmt, a1: s32, a2: s32) -> s32 #c_call; 1098 | strnicmp: #type (a0: *s8, a1: *s8, a2: s32) -> s32 #c_call; 1099 | unlock_notify: #type (a0: *sqlite3, a1: #type (a0: **void, a1: s32) -> void #c_call, a2: *void) -> s32 #c_call; 1100 | wal_autocheckpoint: #type (a0: *sqlite3, a1: s32) -> s32 #c_call; 1101 | wal_checkpoint: #type (a0: *sqlite3, a1: *s8) -> s32 #c_call; 1102 | wal_hook: #type (a0: *sqlite3, a1: #type (a0: *void, a1: *sqlite3, a2: *s8, a3: s32) -> s32 #c_call, a2: *void) -> *void #c_call; 1103 | blob_reopen: #type (a0: *sqlite3_blob, a1: sqlite3_int64) -> s32 #c_call; 1104 | vtab_config: #type (a0: *sqlite3, a1: s32) -> s32 #c_call; 1105 | vtab_on_conflict: #type (a0: *sqlite3) -> s32 #c_call; 1106 | close_v2: #type (a0: *sqlite3) -> s32 #c_call; 1107 | db_filename: #type (a0: *sqlite3, a1: *s8) -> *s8 #c_call; 1108 | db_readonly: #type (a0: *sqlite3, a1: *s8) -> s32 #c_call; 1109 | db_release_memory: #type (a0: *sqlite3) -> s32 #c_call; 1110 | errstr: #type (a0: s32) -> *s8 #c_call; 1111 | stmt_busy: #type (a0: *sqlite3_stmt) -> s32 #c_call; 1112 | stmt_readonly: #type (a0: *sqlite3_stmt) -> s32 #c_call; 1113 | stricmp: #type (a0: *s8, a1: *s8) -> s32 #c_call; 1114 | uri_boolean: #type (a0: *s8, a1: *s8, a2: s32) -> s32 #c_call; 1115 | uri_int64: #type (a0: *s8, a1: *s8, a2: sqlite3_int64) -> sqlite3_int64 #c_call; 1116 | uri_parameter: #type (a0: *s8, a1: *s8) -> *s8 #c_call; 1117 | // xvsnprintf: #type (a0: s32, a1: *s8, a2: *s8, a3: va_list) -> *s8 #c_call; 1118 | wal_checkpoint_v2: #type (a0: *sqlite3, a1: *s8, a2: s32, a3: *s32, a4: *s32) -> s32 #c_call; 1119 | auto_extension: #type (a0: #type () -> void #c_call) -> s32 #c_call; 1120 | bind_blob64: #type (a0: *sqlite3_stmt, a1: s32, a2: *void, a3: sqlite3_uint64, a4: #type (a0: *void) -> void #c_call) -> s32 #c_call; 1121 | bind_text64: #type (a0: *sqlite3_stmt, a1: s32, a2: *s8, a3: sqlite3_uint64, a4: #type (a0: *void) -> void #c_call, a5: u8) -> s32 #c_call; 1122 | cancel_auto_extension: #type (a0: #type () -> void #c_call) -> s32 #c_call; 1123 | load_extension: #type (a0: *sqlite3, a1: *s8, a2: *s8, a3: **s8) -> s32 #c_call; 1124 | malloc64: #type (a0: sqlite3_uint64) -> *void #c_call; 1125 | msize: #type (a0: *void) -> sqlite3_uint64 #c_call; 1126 | realloc64: #type (a0: *void, a1: sqlite3_uint64) -> *void #c_call; 1127 | reset_auto_extension: #type () -> void #c_call; 1128 | result_blob64: #type (a0: *sqlite3_context, a1: *void, a2: sqlite3_uint64, a3: #type (a0: *void) -> void #c_call) -> void #c_call; 1129 | result_text64: #type (a0: *sqlite3_context, a1: *s8, a2: sqlite3_uint64, a3: #type (a0: *void) -> void #c_call, a4: u8) -> void #c_call; 1130 | strglob: #type (a0: *s8, a1: *s8) -> s32 #c_call; 1131 | value_dup: #type (a0: *sqlite3_value) -> *sqlite3_value #c_call; 1132 | value_free: #type (a0: *sqlite3_value) -> void #c_call; 1133 | result_zeroblob64: #type (a0: *sqlite3_context, a1: sqlite3_uint64) -> s32 #c_call; 1134 | bind_zeroblob64: #type (a0: *sqlite3_stmt, a1: s32, a2: sqlite3_uint64) -> s32 #c_call; 1135 | value_subtype: #type (a0: *sqlite3_value) -> u32 #c_call; 1136 | result_subtype: #type (a0: *sqlite3_context, a1: u32) -> void #c_call; 1137 | status64: #type (a0: s32, a1: *sqlite3_int64, a2: *sqlite3_int64, a3: s32) -> s32 #c_call; 1138 | strlike: #type (a0: *s8, a1: *s8, a2: u32) -> s32 #c_call; 1139 | db_cacheflush: #type (a0: *sqlite3) -> s32 #c_call; 1140 | system_errno: #type (a0: *sqlite3) -> s32 #c_call; 1141 | trace_v2: #type (a0: *sqlite3, a1: u32, a2: #type (a0: u32, a1: *void, a2: *void, a3: *void) -> s32 #c_call, a3: *void) -> s32 #c_call; 1142 | expanded_sql: #type (a0: *sqlite3_stmt) -> *s8 #c_call; 1143 | set_last_insert_rowid: #type (a0: *sqlite3, a1: sqlite3_int64) -> void #c_call; 1144 | prepare_v3: #type (a0: *sqlite3, a1: *s8, a2: s32, a3: u32, a4: **sqlite3_stmt, a5: **s8) -> s32 #c_call; 1145 | prepare16_v3: #type (a0: *sqlite3, a1: *void, a2: s32, a3: u32, a4: **sqlite3_stmt, a5: **void) -> s32 #c_call; 1146 | bind_pointer: #type (a0: *sqlite3_stmt, a1: s32, a2: *void, a3: *s8, a4: #type (a0: *void) -> void #c_call) -> s32 #c_call; 1147 | result_pointer: #type (a0: *sqlite3_context, a1: *void, a2: *s8, a3: #type (a0: *void) -> void #c_call) -> void #c_call; 1148 | value_pointer: #type (a0: *sqlite3_value, a1: *s8) -> *void #c_call; 1149 | vtab_nochange: #type (a0: *sqlite3_context) -> s32 #c_call; 1150 | value_nochange: #type (a0: *sqlite3_value) -> s32 #c_call; 1151 | vtab_collation: #type (a0: *sqlite3_index_info, a1: s32) -> *s8 #c_call; 1152 | keyword_count: #type () -> s32 #c_call; 1153 | keyword_name: #type (a0: s32, a1: **s8, a2: *s32) -> s32 #c_call; 1154 | keyword_check: #type (a0: *s8, a1: s32) -> s32 #c_call; 1155 | str_new: #type (a0: *sqlite3) -> *sqlite3_str #c_call; 1156 | str_finish: #type (a0: *sqlite3_str) -> *s8 #c_call; 1157 | str_appendf: #type (a0: *sqlite3_str, a1: *s8) -> void #c_call; 1158 | // str_vappendf: #type (a0: *sqlite3_str, a1: *s8, a2: va_list) -> void #c_call; 1159 | str_append: #type (a0: *sqlite3_str, a1: *s8, a2: s32) -> void #c_call; 1160 | str_appendall: #type (a0: *sqlite3_str, a1: *s8) -> void #c_call; 1161 | str_appendchar: #type (a0: *sqlite3_str, a1: s32, a2: s8) -> void #c_call; 1162 | str_reset: #type (a0: *sqlite3_str) -> void #c_call; 1163 | str_errcode: #type (a0: *sqlite3_str) -> s32 #c_call; 1164 | str_length: #type (a0: *sqlite3_str) -> s32 #c_call; 1165 | str_value: #type (a0: *sqlite3_str) -> *s8 #c_call; 1166 | create_window_function: #type (a0: *sqlite3, a1: *s8, a2: s32, a3: s32, a4: *void, a5: #type (a0: *sqlite3_context, a1: s32, a2: **sqlite3_value) -> void #c_call, a6: #type (a0: *sqlite3_context) -> void #c_call, a7: #type (a0: *sqlite3_context) -> void #c_call, a8: #type (a0: *sqlite3_context, a1: s32, a2: **sqlite3_value) -> void #c_call, a9: #type (a0: *void) -> void #c_call) -> s32 #c_call; 1167 | normalized_sql: #type (a0: *sqlite3_stmt) -> *s8 #c_call; 1168 | stmt_isexplain: #type (a0: *sqlite3_stmt) -> s32 #c_call; 1169 | value_frombind: #type (a0: *sqlite3_value) -> s32 #c_call; 1170 | drop_modules: #type (a0: *sqlite3, a1: **s8) -> s32 #c_call; 1171 | hard_heap_limit64: #type (a0: sqlite3_int64) -> sqlite3_int64 #c_call; 1172 | uri_key: #type (a0: *s8, a1: s32) -> *s8 #c_call; 1173 | filename_database: #type (a0: *s8) -> *s8 #c_call; 1174 | filename_journal: #type (a0: *s8) -> *s8 #c_call; 1175 | filename_wal: #type (a0: *s8) -> *s8 #c_call; 1176 | create_filename: #type (a0: *s8, a1: *s8, a2: *s8, a3: s32, a4: **s8) -> *s8 #c_call; 1177 | free_filename: #type (a0: *s8) -> void #c_call; 1178 | database_file_object: #type (a0: *s8) -> *sqlite3_file #c_call; 1179 | txn_state: #type (a0: *sqlite3, a1: *s8) -> s32 #c_call; 1180 | changes64: #type (a0: *sqlite3) -> sqlite3_int64 #c_call; 1181 | total_changes64: #type (a0: *sqlite3) -> sqlite3_int64 #c_call; 1182 | autovacuum_pages: #type (a0: *sqlite3, a1: #type (a0: *void, a1: *s8, a2: u32, a3: u32, a4: u32) -> u32 #c_call, a2: *void, a3: #type (a0: *void) -> void #c_call) -> s32 #c_call; 1183 | } 1184 | 1185 | sqlite3_loadext_entry :: #type (a0: *sqlite3, a1: **s8, a2: *sqlite3_api_routines) -> s32 #c_call; 1186 | 1187 | SQLITE_OK :: 0; /* Successful result */ 1188 | SQLITE_ERROR :: 1; /* Generic error */ 1189 | SQLITE_INTERNAL :: 2; /* Internal logic error in SQLite */ 1190 | SQLITE_PERM :: 3; /* Access permission denied */ 1191 | SQLITE_ABORT :: 4; /* Callback routine requested an abort */ 1192 | SQLITE_BUSY :: 5; /* The database file is locked */ 1193 | SQLITE_LOCKED :: 6; /* A table in the database is locked */ 1194 | SQLITE_NOMEM :: 7; /* A malloc() failed */ 1195 | SQLITE_READONLY :: 8; /* Attempt to write a readonly database */ 1196 | SQLITE_INTERRUPT :: 9; /* Operation terminated by sqlite3_interrupt()*/ 1197 | SQLITE_IOERR :: 10; /* Some kind of disk I/O error occurred */ 1198 | SQLITE_CORRUPT :: 11; /* The database disk image is malformed */ 1199 | SQLITE_NOTFOUND :: 12; /* Unknown opcode in sqlite3_file_control() */ 1200 | SQLITE_FULL :: 13; /* Insertion failed because database is full */ 1201 | SQLITE_CANTOPEN :: 14; /* Unable to open the database file */ 1202 | SQLITE_PROTOCOL :: 15; /* Database lock protocol error */ 1203 | SQLITE_EMPTY :: 16; /* Internal use only */ 1204 | SQLITE_SCHEMA :: 17; /* The database schema changed */ 1205 | SQLITE_TOOBIG :: 18; /* String or BLOB exceeds size limit */ 1206 | SQLITE_CONSTRAINT :: 19; /* Abort due to constraint violation */ 1207 | SQLITE_MISMATCH :: 20; /* Data type mismatch */ 1208 | SQLITE_MISUSE :: 21; /* Library used incorrectly */ 1209 | SQLITE_NOLFS :: 22; /* Uses OS features not supported on host */ 1210 | SQLITE_AUTH :: 23; /* Authorization denied */ 1211 | SQLITE_FORMAT :: 24; /* Not used */ 1212 | SQLITE_RANGE :: 25; /* 2nd parameter to sqlite3_bind out of range */ 1213 | SQLITE_NOTADB :: 26; /* File opened that is not a database file */ 1214 | SQLITE_NOTICE :: 27; /* Notifications from sqlite3_log() */ 1215 | SQLITE_WARNING :: 28; /* Warnings from sqlite3_log() */ 1216 | SQLITE_ROW :: 100; /* sqlite3_step() has another row ready */ 1217 | SQLITE_DONE :: 101; /* sqlite3_step() has finished executing */ 1218 | 1219 | 1220 | sqlite :: #library "../lib/sqlite3"; -------------------------------------------------------------------------------- /lib/sqlite3.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rezich/SQLite/28311b802c20d6e811bfb4d50af6898010f2704b/lib/sqlite3.lib -------------------------------------------------------------------------------- /module.jai: -------------------------------------------------------------------------------- 1 | #module_parameters( 2 | ONLY_C_BINDINGS := false, // don't even include the wrapper 3 | VERBOSE := false, // log wrapper-invoked SQL statements to console 4 | USE_MODEL_CACHE := false, // set true in your main program to enable ORM-like features 5 | FROM_METAPROGRAM := false, // set true in your meta program to enable ORM features 6 | STRICT_TABLES := false, // (ORM) use strict tables 7 | MAKE_MIGRATIONS := false // (ORM) work in progress 8 | ); 9 | 10 | #if MAKE_MIGRATIONS && !FROM_METAPROGRAM then #assert false "MAKE_MIGRATIONS only works from the metaprogram."; 11 | 12 | #if !ONLY_C_BINDINGS { #load "src/SQLite.jai"; 13 | #if FROM_METAPROGRAM then #load "src/Meta.jai"; 14 | #if FROM_METAPROGRAM && MAKE_MIGRATIONS then #load "src/Migrator.jai"; 15 | #if FROM_METAPROGRAM || USE_MODEL_CACHE then #load "src/Model_Cache.jai"; 16 | } 17 | #load "lib/sqlite3.jai"; 18 | -------------------------------------------------------------------------------- /src/Meta.jai: -------------------------------------------------------------------------------- 1 | prebuild_step :: (w: Workspace) { 2 | options := get_build_options(w); 3 | DLL_NAME :: "sqlite3.dll"; 4 | dll_\ source := sprint("%1../lib/%2", #filepath, DLL_NAME); 5 | dll_destination := sprint("%1/%2", options.output_path, DLL_NAME); 6 | (#import "File").make_directory_if_it_does_not_exist("bin"); 7 | if !file_exists(dll_destination) then copy_file(dll_source, dll_destination); 8 | array_reset(*model_names); 9 | } 10 | 11 | build_step :: inline (message: *Message) { 12 | if message.kind == { 13 | case .TYPECHECKED; 14 | typechecked := cast(*Message_Typechecked) message; 15 | for typechecked_struct: typechecked.structs { 16 | code_struct := typechecked_struct.expression; 17 | name := code_struct.defined_type.name; 18 | if is_a_model(code_struct.defined_type) { 19 | array_add_if_unique(*model_names, name); 20 | sb_table: String_Builder; 21 | sb_fk: String_Builder; 22 | print_to_builder(*sb_table, #string SQL 23 | CREATE TABLE %1(id INTEGER PRIMARY KEY 24 | SQL, /* 1 */ name); 25 | append(*sb_table, #string SQL 26 | ,created TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP 27 | ,modified TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP 28 | SQL ); 29 | for serializable_members_of(code_struct.defined_type) { 30 | if member_is_foreign_key(it) { 31 | print_to_builder(*sb_table, #string SQL 32 | ,%1_id INTEGER 33 | SQL, /* 1 */ it.name); 34 | fk_name := get_foreign_key_name_from(it, name); 35 | on_update, on_delete: string; 36 | for it.notes { 37 | found, key, value := split_from_left(it, #char "="); 38 | if !found continue; 39 | is_valid_fk_action :: (value: string) -> bool { for enum_names(Foreign_Key_Action) if it == value then return true; assert(false, "Invalid Foreign_Key_Action in Cached(T) note."); return false; } 40 | if key == "on_update" && is_valid_fk_action(value) then on_update = replace(value, "_", " "); 41 | if key == "on_delete" && is_valid_fk_action(value) then on_delete = replace(value, "_", " "); 42 | } 43 | print_to_builder(*sb_fk, #string SQL 44 | ,FOREIGN KEY(%1_id) REFERENCES %2(id)%3%4 45 | SQL, /* 1 */ it.name, 46 | /* 2 */ fk_name, 47 | /* 3 */ ifx on_update != "" then sprint(" ON UPDATE %", on_update), 48 | /* 4 */ ifx on_delete != "" then sprint(" ON DELETE %", on_delete) 49 | ); 50 | } 51 | else { 52 | sql_type: string; 53 | default_value: string; 54 | if it.type.type == { 55 | case .BOOL; #through; 56 | case .ENUM; #through; 57 | case .INTEGER; sql_type="INTEGER"; default_value="0"; 58 | case .FLOAT; sql_type="REAL"; default_value="0"; 59 | case .STRING; sql_type="TEXT"; 60 | } 61 | print_to_builder(*sb_table, #string SQL 62 | ,%1 %2%3%4 63 | SQL, /* 1 */ it.name, 64 | /* 2 */ sql_type, 65 | /* 3 */ " NOT NULL", //TODO: optional nullability 66 | /* 4 */ ifx default_value then sprint(" DEFAULT %", default_value) 67 | ); 68 | } 69 | } 70 | strict_table := STRICT_TABLES; 71 | for code_struct.defined_type.notes { 72 | if it == "strict" { strict_table = true; break; } 73 | found, key, value := split_from_left(it, #char "="); 74 | if !found continue; 75 | if key == "strict" && value != "true" && value != "" { strict_table = true; break; } 76 | } 77 | append(*sb_table, builder_to_string(*sb_fk)); 78 | print_to_builder(*sb_table, #string SQL 79 | )%1; 80 | SQL, /* 1 */ ifx strict_table then " STRICT"); 81 | array_add(*table_schemas, trim(builder_to_string(*sb_table), " \t\n")); 82 | } 83 | } 84 | 85 | case .PHASE; 86 | phase := cast(*Message_Phase) message; 87 | if phase.phase == .TYPECHECKED_ALL_WE_CAN { 88 | if !generated_code { 89 | iterate_model_names :: (str: string) -> string #expand { 90 | sb: String_Builder; 91 | for `model_names print_to_builder(*sb, str, it); 92 | return builder_to_string(*sb); 93 | } 94 | iterate_table_schemas :: (str: string) -> string #expand { 95 | sb: String_Builder; 96 | for `table_schemas print_to_builder(*sb, str, it); 97 | return builder_to_string(*sb); 98 | } 99 | add_to_build :: (w: Workspace, args: ..Any) { 100 | sb: String_Builder; 101 | for args print_to_builder(*sb, "%", it); 102 | add_build_string(builder_to_string(*sb), w); 103 | } 104 | quick_sort(model_names, compare_strings); 105 | add_to_build(message.workspace, #string XX 106 | SQLite_Model_Cache :: struct { 107 | #import "Hash_Table"; 108 | XX, iterate_model_names(#string XX 109 | _%1: Table(s64, %1); 110 | XX), #string XX 111 | } 112 | __reset_model_cache :: (reinit := true) { 113 | using context.sqlite_model_cache; 114 | XX, iterate_model_names(#string XX 115 | table_reset(*_%1); //TODO: fix this dumb stopgap measure 116 | if _%1.allocated > 0 { deinit(*_%1); if reinit then init(*_%1); } 117 | XX), #string XX 118 | } 119 | TABLE_SCHEMAS :: string.[ 120 | XX, iterate_table_schemas(#string XX 121 | #string XX_TABLE_SCHEMA_XX 122 | %1 123 | XX_TABLE_SCHEMA_XX, 124 | XX), #string XX 125 | ]; 126 | XX ); 127 | #if MAKE_MIGRATIONS then make_migrations(model_names, table_schemas); 128 | generated_code = true; 129 | } 130 | } 131 | } 132 | } 133 | 134 | reset_build :: () { 135 | array_reset(*model_names); 136 | array_reset(*table_schemas); 137 | generated_code = false; 138 | } 139 | 140 | #scope_file 141 | 142 | model_names: [..] string; 143 | table_schemas: [..] string; 144 | generated_code := false; 145 | 146 | #import "Basic"; 147 | #import "Compiler"; 148 | #import "String"; 149 | #import "Sort"; 150 | #import "File"; 151 | #import "File_Utilities"; 152 | -------------------------------------------------------------------------------- /src/Migrator.jai: -------------------------------------------------------------------------------- 1 | // This is a work in progress! 2 | 3 | Migration :: struct { 4 | index: int; 5 | table_schemas: Table(string, Table_Schema); 6 | } 7 | 8 | Table_Schema :: struct { 9 | create: string; 10 | columns: Table(string, Column); 11 | foreign_keys: Table(string, Foreign_Key); 12 | strict: bool; 13 | 14 | Column :: struct { 15 | name: string; 16 | type: string; 17 | not_null: bool; 18 | default: string; 19 | } 20 | Foreign_Key :: struct { 21 | parent_table: string; 22 | child_table: string; 23 | parent_key: string; 24 | child_key: string; 25 | on_update: string; 26 | on_delete: string; 27 | } 28 | } 29 | 30 | migrations: [..] Migration; 31 | 32 | parse_table_schema :: (using table_schema: *Table_Schema) { 33 | for split(create, "\n") { 34 | if begins_with(it, "CREATE TABLE") then continue; 35 | if begins_with(it, ",created TEXT") then continue; 36 | if begins_with(it, ",modified TEXT") then continue; 37 | if begins_with(it, ",FOREIGN KEY") { 38 | fk: Foreign_Key; 39 | right := it; 40 | left: string; 41 | found: bool; 42 | found, left, right = split_from_left(right, ",FOREIGN KEY("); 43 | found, left, right = split_from_left(right, ") REFERENCES "); 44 | fk.child_key = copy_string(left); 45 | found, left, right = split_from_left(right, "("); 46 | fk.parent_table = copy_string(left); 47 | found, left, right = split_from_left(right, ")"); 48 | fk.parent_key = copy_string(left); 49 | if contains(it, "ON UPDATE") { 50 | on: string; 51 | found, left, right = split_from_left(right, "ON UPDATE "); 52 | found, left, on = split_from_left(right, " ON DELETE "); 53 | fk.on_update = copy_string(on); 54 | } 55 | if contains(it, "ON DELETE") { 56 | on: string; 57 | found, left, on = split_from_left(right, "ON DELETE "); 58 | fk.on_delete = copy_string(on); 59 | } 60 | table_set(*foreign_keys, fk.child_key, fk); 61 | continue; 62 | } 63 | if begins_with(it, ",") { 64 | column: Column; 65 | right := it; 66 | left: string; 67 | found: bool; 68 | found, left, right = split_from_left(right, ","); 69 | found, left, right = split_from_left(right, " "); 70 | column.name = copy_string(left); 71 | column.not_null = contains(it, "NOT NULL"); 72 | if contains(it, " DEFAULT ") { 73 | found, left, right = split_from_left(right, " DEFAULT "); 74 | column.default = copy_string(right); 75 | } 76 | table_set(*columns, column.name, column); 77 | continue; 78 | } 79 | if begins_with(it, ")") { 80 | strict = contains(it, "STRICT"); 81 | continue; 82 | } 83 | } 84 | } 85 | 86 | load_migration :: (index: int) -> Migration { 87 | migration: Migration; 88 | migration.index = index; 89 | for files_in_migration(index) { 90 | table_schema := table_set( 91 | *migration.table_schemas, 92 | path_strip_extension(it), 93 | .{create=read_entire_file(sprint("migrations/%/%", index, it))} 94 | ); 95 | parse_table_schema(table_schema); 96 | } 97 | return migration; 98 | } 99 | 100 | compare_migrations :: (old: Migration, new: Migration) { 101 | tables_compared: [..] string; 102 | for table_schema, table_name: old.table_schemas { 103 | defer array_add(*tables_compared, table_name); 104 | new_table_schema := table_find_pointer(*new.table_schemas, table_name); 105 | if !new_table_schema { 106 | log("table % was removed", table_name); 107 | continue; 108 | } 109 | if compare_table_schemas(table_schema, new_table_schema) { 110 | log("table % was altered", table_name); 111 | } 112 | } 113 | for table_schema, table_name: new.table_schemas { 114 | for tables_compared if it == table_name then continue table_schema; 115 | defer array_add(*tables_compared, table_name); 116 | log("table % was added", table_name); 117 | } 118 | 119 | } 120 | 121 | compare_table_schemas :: (old: Table_Schema, new: Table_Schema) -> bool { 122 | return compare(old.create, new.create) != 0; 123 | } 124 | 125 | make_migrations :: (model_names: [] string, table_schemas: [] string) { 126 | current_migration_in_filesystem, current_migration_on_disk: Migration; 127 | 128 | for table_schemas { 129 | table_schema := table_set( 130 | *current_migration_in_filesystem.table_schemas, 131 | model_names[it_index], 132 | .{create=it} 133 | ); 134 | parse_table_schema(table_schema); 135 | } 136 | 137 | make_directory_if_it_does_not_exist("migrations"); 138 | migration_already_existed := file_exists("migrations/0"); 139 | if migration_already_existed { 140 | current_migration_on_disk = load_migration(0); 141 | compare_migrations( 142 | current_migration_in_filesystem, 143 | current_migration_on_disk 144 | ); 145 | } 146 | save_current_migration_to_disk(); 147 | /*existing_migrations := migrations_list(); 148 | if existing_migrations.count == 0 { 149 | make_directory_if_it_does_not_exist("migrations/1"); 150 | for `model_names write_entire_file( 151 | sprint("migrations/1/%.sql", it), 152 | `table_schemas[it_index] 153 | ); 154 | }*/ 155 | } 156 | 157 | save_current_migration_to_disk :: () #expand { 158 | make_directory_if_it_does_not_exist("migrations/0"); 159 | for `model_names write_entire_file( 160 | sprint("migrations/0/%.sql", it), 161 | `table_schemas[it_index] 162 | ); 163 | } 164 | 165 | migrations_list :: () -> [] string #must { 166 | files : [..] string; 167 | visitor :: (info: *File_Visit_Info, user_data: *[..] string) { 168 | if info.short_name != "0" then array_add(user_data, copy_string(info.short_name)); 169 | } 170 | visit_files("migrations", false, *files, visitor, visit_files=false, visit_directories=true); 171 | return files; 172 | } 173 | 174 | files_in_migration :: (migration: int) -> [] string #must { 175 | files : [..] string; 176 | visitor :: (info: *File_Visit_Info, user_data: *[..] string) { 177 | array_add(user_data, copy_string(info.short_name)); 178 | } 179 | visit_files(sprint("migrations/%", migration), false, *files, visitor); 180 | return files; 181 | } 182 | 183 | #import "Hash_Table"; 184 | -------------------------------------------------------------------------------- /src/Model_Cache.jai: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Model 4 | base struct for all database model structs 5 | Cached(T) 6 | pointer to database row object in the database cache 7 | when used as a model struct member, it represents a foreign key to another 8 | table. 9 | you can use @on_update=x and @on_delete=x, where x is any value of 10 | Foreign_Key_Action (WITHOUT the .) to append "ON UPDATE" & "ON DELETE" 11 | clauses to the foreign key relationship. 12 | for example: 13 | author: Cached(User); @on_update=SET_NULL @on_delete=SET_DEFAULT 14 | 15 | is_fetched(cached_obj) 16 | returns whether or not the object exists in the local database cache 17 | is_null(cached_obj) 18 | returns whether or not the object "is a null reference" (fetch_id == 0) 19 | reset_model_cache() 20 | flush the database cache in the context 21 | 22 | */ 23 | 24 | NOTE_DO_NOT_SERIALIZE :: "do_not_serialize"; 25 | NOTE_AUTOFETCH :: "autofetch"; 26 | //NOTE_FETCH :: "fetch"; 27 | 28 | Model :: struct { 29 | id: s64; 30 | created: s32; // UNIX timestamp for now 31 | modified: s32; // UNIX timestamp for now 32 | } 33 | ORM_INTERNAL_COLUMN_COUNT :: #run type_info(Model).members.count; 34 | 35 | Cached :: struct(type: Type) /*#modify { return is_a_model(type); }*/ { 36 | fetch_id: s64; 37 | using pointer: *type; 38 | } 39 | 40 | 41 | operator|| :: (cached_obj: $T/Cached, when_null: Code, caller_code := #caller_code) -> T #expand { 42 | if is_null(cached_obj) then #insert,scope(caller_code) when_null; 43 | return cached_obj; 44 | } 45 | operator|| :: (cached_objs: [] $T/Cached, when_null: Code, caller_code := #caller_code) -> [] T #expand { 46 | if cached_objs.count == 0 then #insert,scope(caller_code) when_null; 47 | return cached_objs; 48 | } 49 | 50 | 51 | operator! :: inline (cached_obj: $T/Cached) -> bool { return is_null(cached_obj); } 52 | operator! :: inline (cached_objs: [] $T/Cached) -> bool { return cached_objs.count == 0; } 53 | 54 | operator== :: (a: $T/Cached, b: T) -> bool { return a.fetch_id == b.fetch_id && a.pointer == b.pointer; } 55 | 56 | init_model_cache :: () #expand { 57 | using context.sqlite; 58 | assert(!is_open); 59 | database_already_existed := filename != ":memory:" && (#import "File_Utilities").file_exists(filename); 60 | set_pragmas(.[ 61 | "journal_mode = WAL", 62 | "synchronous = NORMAL", 63 | "foreign_keys = ON" 64 | ]); 65 | if !database_already_existed then { 66 | open(); 67 | for `TABLE_SCHEMAS assert_ok(exec(it)); 68 | close(); 69 | } 70 | } 71 | 72 | insert :: (obj: $T/Model) -> Cached(T) { 73 | assert(obj.id == 0, "Attempted to insert a % with an id already set!", T); 74 | 75 | SQL_STATEMENT :: #run -> string { 76 | sb_values, sb_question_marks: String_Builder; 77 | for serializable_members_of(T) { 78 | if it_index != 0 then append(*sb_values, ", "); 79 | append(*sb_values, it.name); 80 | if member_is_foreign_key(it) then append(*sb_values, "_id"); 81 | if it_index != 0 then append(*sb_question_marks, ", "); 82 | append(*sb_question_marks, "?"); 83 | } 84 | return sprint("INSERT INTO %1(%2) VALUES (%3) RETURNING id, strftime(\"%%s\", created);", 85 | /* 1 */ T, 86 | /* 2 */ builder_to_string(*sb_values), 87 | /* 3 */ builder_to_string(*sb_question_marks) 88 | ); 89 | } 90 | 91 | result, statement := prepare(SQL_STATEMENT); 92 | assert_ok(result); 93 | 94 | #insert -> string { 95 | sb: String_Builder; 96 | question_mark_index := 1; 97 | for serializable_members_of(T) { 98 | print_to_builder(*sb, ifx member_is_foreign_key(it) then #string XX 99 | assert_ok(ifx obj.%2.fetch_id == 0 then bind(statement, %1) else bind(statement, %1, obj.%2.fetch_id)); 100 | XX else #string XX 101 | assert_ok(bind(statement, %1, obj.%2)); 102 | XX, /* 1 */ question_mark_index, 103 | /* 2 */ it.name 104 | ); 105 | question_mark_index += 1; 106 | } 107 | return builder_to_string(*sb); 108 | } 109 | 110 | new_obj: *T; 111 | 112 | for statement { 113 | assert(it_index == 0); 114 | id := column_int64(statement, 0); 115 | #insert #run sprint(#string XX 116 | new_obj = table_set(*context.sqlite_model_cache._%, id, obj); 117 | XX, /* 1 */ T 118 | ); 119 | new_obj.id = id; 120 | new_obj.created = column_int(statement, 1); 121 | new_obj.modified = new_obj.created; 122 | } 123 | assert(!!new_obj); 124 | 125 | assert_ok(finalize(statement)); 126 | return .{new_obj.id, new_obj}; 127 | } 128 | 129 | set :: (cached_obj: $T/Cached, $field_name: string) { set(cached_obj, field_name, null); } 130 | set :: (cached_obj: $T/Cached, $field_name: string, value: $T2) #expand { 131 | SQL_STATEMENT :: #run sprint("UPDATE %1 SET %2%3 = ?, modified = CURRENT_TIMESTAMP WHERE id = ? RETURNING strftime(\"%%s\", modified);", 132 | /* 1 */ T.type, 133 | /* 2 */ field_name, 134 | /* 3 */ ifx #run field_is_foreign_key(T.type, field_name) && !ends_with(field_name, "_id") then "_id" 135 | ); 136 | 137 | #if #run type_info(T2).type == .POINTER then assert(value == null); 138 | 139 | result, statement := prepare(SQL_STATEMENT); 140 | assert_ok(result); 141 | 142 | #if #run ((type_info(T2).type == .STRUCT && (cast(*Type_Info_Struct) type_info(T2)).name == "Cached")) 143 | assert_ok(bind(statement, 1, value.fetch_id)); 144 | else 145 | assert_ok(bind(statement, 1, value)); 146 | 147 | assert_ok(bind(statement, 2, cached_obj.id)); 148 | 149 | for statement cached_obj.modified = column_int(statement, 0); 150 | 151 | #insert #run sprint(ifx #run type_info(T2).type == .POINTER then #string XX 152 | cached_obj.%1 = .{}; 153 | XX else #string XX 154 | cached_obj.%1 = value; 155 | XX, /* 1 */ ifx ends_with_nocase(field_name, "_id") then slice(field_name, 0, field_name.count-3) else field_name); 156 | 157 | assert_ok(finalize(statement)); 158 | } 159 | 160 | update :: (cached_obj: $T/Cached) { 161 | SQL_STATEMENT :: #run -> string { 162 | sb_fields: String_Builder; 163 | for serializable_members_of(T.type) { 164 | if it_index != 0 then append(*sb_fields, ", "); 165 | append(*sb_fields, sprint("% = ?", it.name)); 166 | } 167 | return sprint("UPDATE %1 SET %2, modified = CURRENT_TIMESTAMP WHERE id = ? RETURNING strftime(\"%%s\", modified);", 168 | /* 1 */ T.type, 169 | /* 2 */ builder_to_string(*sb_fields) 170 | ); 171 | } 172 | INDEX_OF_ID_QUESTION_MARK :: #run serializable_members_of(T.type).count+1; 173 | 174 | result, statement := prepare(SQL_STATEMENT); 175 | assert_ok(result); 176 | 177 | #insert -> string { 178 | sb: String_Builder; 179 | for serializable_members_of(T.type) { 180 | question_mark_index := it_index + 1; 181 | print_to_builder(*sb, ifx member_is_foreign_key(it) then #string XX 182 | result = ifx cached_obj.fetch_id == 0 then bind(statment, %1) else bind(statement, %1, cached_obj.%2); 183 | XX else #string XX 184 | result = bind(statement, %1, cached_obj.%2); 185 | XX, /* 1 */ question_mark_index, 186 | /* 2 */ it.name 187 | ); 188 | append(*sb, #string XX 189 | assert_ok(result); 190 | XX, ); 191 | } 192 | return builder_to_string(*sb); 193 | } 194 | 195 | result = bind(statement, INDEX_OF_ID_QUESTION_MARK, cached_obj.id); 196 | assert_ok(result); 197 | 198 | for statement cached_obj.pointer.modified = column_int(statement, 0); 199 | 200 | result = finalize(statement); 201 | assert_ok(result); 202 | } 203 | 204 | // update :: ($type: Type, set: string, where: string, ..params: Any) 205 | 206 | 207 | 208 | 209 | #scope_file 210 | 211 | Select_From_Exec_Body :: #code { 212 | fetch_row(*`obj, statement); 213 | #insert #run sprint(#string XX 214 | `obj_pointer = table_set(*context.sqlite_model_cache._%1, `obj.id, `obj); 215 | XX, /* 1 */ `T); 216 | `cached_obj = .{`obj.id, `obj_pointer}; 217 | 218 | #insert -> string { 219 | sb: String_Builder; 220 | fetches_and_autofetches: [..] string; 221 | fetches_and_autofetches_fk: [..] bool; 222 | autofetches_that_use_procs: [..] string; 223 | 224 | // get members with @autofetch 225 | for member: type_info(`T).members { 226 | is_autofetch := field_is_autofetch (`T, member.name); 227 | is_foreign_key := field_is_foreign_key (`T, member.name); 228 | is_able_to_be_serialized := is_serializable(member.type); 229 | is_do_not_serialize := field_is_do_not_serialize(`T, member.name); 230 | if is_autofetch { 231 | if (is_foreign_key || is_serializable) && !is_do_not_serialize { 232 | array_add(*fetches_and_autofetches, member.name); 233 | array_add(*fetches_and_autofetches_fk, is_foreign_key); 234 | } 235 | else if is_do_not_serialize then array_add(*autofetches_that_use_procs, member.name); 236 | else assert(false, "%1 member %2 is not fetchable!", 237 | /* 1 */ `T, 238 | /* 2 */ member.name); 239 | } 240 | } 241 | 242 | // handle members passed in through fetch=xxx,yyy,... parameter in select_from() 243 | split_fetch_names := split(`fetch, ","); 244 | if split_fetch_names[0] != "" then for fetch_member_name: split_fetch_names { 245 | found := false; 246 | for type_info(`T).members if it.name == fetch_member_name && member_is_foreign_key(it) { found = true; break; } 247 | assert(found, "could not fetch member %1 of %2 [%3]", 248 | /* 1 */ fetch_member_name, 249 | /* 2 */ `T, 250 | /* 3 */ `fetch 251 | ); 252 | if array_add_if_unique(*fetches_and_autofetches, fetch_member_name) then array_add(*fetches_and_autofetches_fk, true); 253 | else log("WARNING: requested fetch for %1, but it's @autofetch in %2!", //TODO: filename & line number 254 | /* 1 */ fetch_member_name, 255 | /* 2 */ `T 256 | ); 257 | } 258 | 259 | assert(fetches_and_autofetches.count == fetches_and_autofetches_fk.count); 260 | 261 | for fetches_and_autofetches print_to_builder(*sb, #string XX 262 | %1`_fetch(*`cached_obj.%2); 263 | XX, /* 1 */ ifx fetches_and_autofetches_fk[it_index] then tprint("if !is_fetched(`cached_obj.%1) then ", it), 264 | /* 2 */ it); 265 | for autofetches_that_use_procs print_to_builder(*sb, #string XX 266 | `T.fetch_%1(*`cached_obj); 267 | XX, /* 1 */ it); 268 | return builder_to_string(*sb); 269 | }; 270 | }; 271 | 272 | generate_sql_statement_for_select_from :: () -> string #expand { 273 | sb: String_Builder; 274 | for serializable_members_of(`T) { 275 | if it_index != 0 then append(*sb, ", "); 276 | append(*sb, it.name); 277 | if member_is_foreign_key(it) then append(*sb, "_id"); 278 | } 279 | x := sprint("SELECT id, strftime(\"%%s\", created), strftime(\"%%s\", modified), %1 FROM %2%3%4%5%6;", 280 | /* 1 */ builder_to_string(*sb), 281 | /* 2 */ `T, 282 | /* 3 */ ifx `where then sprint(" WHERE %" , `where ), 283 | /* 4 */ ifx `order_by.expr != "" 284 | then sprint(" ORDER BY % %", `order_by.expr, `order_by.dir), 285 | /* 5 */ ifx `limit then sprint(" LIMIT %" , `limit ), 286 | /* 6 */ ifx `limit then " OFFSET ?" 287 | ); 288 | return x; 289 | } 290 | 291 | #scope_export 292 | 293 | 294 | select_from :: ( 295 | $T : Type, // must be $T/Model 296 | $where := "", 297 | params : ..Any, 298 | $order_by : Order_By = .{}, 299 | $limit := 0, // must not be 1 300 | offset := 0, 301 | $fetch := "" 302 | ) -> [..] Cached(T) 303 | #modify { return is_a_model(T) && limit != 1; } { 304 | SQL_STATEMENT :: #run generate_sql_statement_for_select_from(); 305 | 306 | rows: [..] Cached(T); rows.allocator = temp; 307 | obj_pointer: *T; 308 | obj: T; 309 | cached_obj: Cached(T); 310 | 311 | new_params: [..] Any; new_params.allocator = temp; 312 | array_copy(*new_params, params); if limit then array_add(*new_params, offset); 313 | 314 | result := exec(SQL_STATEMENT, ..new_params, code=#code { 315 | #insert,scope(STATEMENT_SCOPE) `Select_From_Exec_Body; 316 | array_add(*`rows, .{`obj.id, `obj_pointer}); 317 | }); 318 | assert_ok(result); 319 | 320 | return rows; 321 | } 322 | 323 | 324 | select_from :: ( 325 | $T : Type, // must be $T/Model 326 | $where := "", 327 | params : ..Any, 328 | $order_by : Order_By = .{}, 329 | $limit := 0, // must be 1 330 | offset := 0, 331 | $fetch := "" 332 | ) -> Cached(T) 333 | #modify { return is_a_model(T) && limit == 1; } { 334 | SQL_STATEMENT :: #run generate_sql_statement_for_select_from(); 335 | 336 | obj_pointer: *T; 337 | obj: T; 338 | cached_obj: Cached(T); 339 | 340 | new_params: [..] Any; new_params.allocator = temp; 341 | array_copy(*new_params, params); array_add(*new_params, offset); 342 | 343 | result := exec(SQL_STATEMENT, ..new_params, code=Select_From_Exec_Body); 344 | assert_ok(result); 345 | 346 | return cached_obj; 347 | } 348 | 349 | 350 | select_by_id :: inline ($T: Type, id: s64, $fetch := "") -> Cached(T) 351 | #modify { return is_a_model(T); } 352 | { return select_from(T, where="id = ?", id, limit=1, fetch=fetch); } 353 | 354 | 355 | Order_By :: struct { 356 | expr: string = ""; 357 | dir: enum { ASC; DESC; } = .ASC; 358 | } 359 | 360 | 361 | 362 | delete :: (using cached_obj: *$T/Cached) { 363 | SQL_STATEMENT :: #run sprint("DELETE FROM % WHERE id = ?;", T.type); 364 | 365 | assert_ok(exec(SQL_STATEMENT, 366 | /* 1 */ T.type 367 | )); 368 | 369 | #insert #run sprint(#string XX 370 | table_remove(*context.sqlite_model_cache._%1, id); 371 | XX, /* 1 */ T.type); 372 | pointer = null; 373 | fetch_id = 0; 374 | } 375 | 376 | // delete_from :: ($type: Type, where: string, ..params: Any) 377 | 378 | fetch :: (cached: *$T/Cached) { 379 | assert(cached.fetch_id != 0); 380 | cached.pointer = select_by_id(T.type, cached.fetch_id).pointer; 381 | } 382 | #scope_file 383 | _fetch :: fetch; 384 | #scope_export 385 | 386 | is_a_model :: inline x => (#import "Compiler").is_subclass_of(cast(*Type_Info) x, "Model"); 387 | 388 | field_is_foreign_key :: ($type: Type, field_name: string) -> bool { 389 | assert(#compile_time); 390 | for serializable_members_of(type) if it.name == field_name return member_is_foreign_key(it); 391 | return false; 392 | } 393 | 394 | member_is_foreign_key :: (member: Type_Info_Struct_Member) -> bool { 395 | return member.type.type == .STRUCT && (cast(*Type_Info_Struct) member.type).name == "Cached"; 396 | } 397 | 398 | get_foreign_key_name_from :: (member: Type_Info_Struct_Member, model_name: string) -> string { 399 | member_info := (cast(*Type_Info_Struct) member.type); 400 | return (cast(*Type_Info_Struct) (cast(**Type_Info) *member_info.constant_storage[member_info.specified_parameters[0].offset_into_constant_storage]).*).name; // thanks, shwa! 401 | } 402 | 403 | has_autofetches :: ($T: Type) -> bool { 404 | for type_info(T).members if member_is_autofetch(it) then return true; 405 | return false; 406 | } 407 | 408 | field_is_autofetch :: ($T: Type, field_name: string) -> bool { 409 | assert(#compile_time); 410 | for type_info(T).members if it.name == field_name return member_is_autofetch(it); 411 | return false; 412 | } 413 | member_is_autofetch :: (member: Type_Info_Struct_Member) -> bool { 414 | for member.notes if it == NOTE_AUTOFETCH then return true; 415 | return false; 416 | } 417 | 418 | field_is_do_not_serialize :: ($T: Type, field_name: string) -> bool { 419 | assert(#compile_time); 420 | for type_info(T).members if it.name == field_name then return member_is_do_not_serialize(it); 421 | return false; 422 | } 423 | member_is_do_not_serialize :: (member: Type_Info_Struct_Member) -> bool { 424 | for member.notes if it == NOTE_DO_NOT_SERIALIZE then return true; 425 | return false; 426 | } 427 | 428 | is_internal_field_name :: (field_name: string) -> bool { 429 | return field_name == "id" || 430 | field_name == "created" || 431 | field_name == "modified"; 432 | } 433 | 434 | is_fetched :: inline (using cached: $T/Cached) -> bool { return pointer != null; } 435 | is_null :: inline (using cached: $T/Cached) -> bool { return fetch_id == 0; } 436 | 437 | #placeholder __reset_model_cache; 438 | reset_model_cache :: inline (reinit := true) { __reset_model_cache(reinit); } // :P 439 | 440 | 441 | #import "Hash_Table"; 442 | #import "String"; 443 | -------------------------------------------------------------------------------- /src/Result.jai: -------------------------------------------------------------------------------- 1 | Result :: enum { 2 | 3 | OK :: 0; // Successful result // 4 | // The SQLITE_OK result code means that the operation was successful and that there were no 5 | // errors. Most other result codes indicate an error. 6 | 7 | ERROR :: 1; // // /* Generic error */ 8 | // The SQLITE_ERROR result code is a generic error code that is used when no other more specific 9 | // error code is available. 10 | 11 | INTERNAL :: 2; // Generic error // 12 | // The SQLITE_INTERNAL result code indicates an internal malfunction. In a working version of 13 | // SQLite, an application should never see this result code. If application does encounter this 14 | // result code, it shows that there is a bug in the database engine. 15 | // 16 | // SQLite does not currently generate this result code. However, application-defined SQL 17 | // functions or virtual tables, or VFSes, or other extensions might cause this result code to be 18 | // returned. 19 | 20 | PERM :: 3; // Access permission denied // 21 | // The SQLITE_PERM result code indicates that the requested access mode for a newly created 22 | // database could not be provided. 23 | 24 | ABORT :: 4; // Callback routine requested an abort // 25 | // The SQLITE_ABORT result code indicates that an operation was aborted prior to completion, 26 | // usually be application request. See also: SQLITE_INTERRUPT. 27 | // 28 | // If the callback function to sqlite3_exec() returns non-zero, then sqlite3_exec() will return 29 | // SQLITE_ABORT. 30 | // 31 | // If a ROLLBACK operation occurs on the same database connection as a pending read or write, 32 | // then the pending read or write may fail with an SQLITE_ABORT or SQLITE_ABORT_ROLLBACK error. 33 | // 34 | // In addition to being a result code, the SQLITE_ABORT value is also used as a conflict 35 | // resolution mode returned from the sqlite3_vtab_on_conflict() interface. 36 | 37 | BUSY :: 5; // The database file is locked // 38 | // The SQLITE_BUSY result code indicates that the database file could not be written (or in some 39 | // cases read) because of concurrent activity by some other database connection, usually a 40 | // database connection in a separate process. 41 | // 42 | // For example, if process A is in the middle of a large write transaction and at the same time 43 | // process B attempts to start a new write transaction, process B will get back an SQLITE_BUSY 44 | // result because SQLite only supports one writer at a time. Process B will need to wait for 45 | // process A to finish its transaction before starting a new transaction. The 46 | // sqlite3_busy_timeout() and sqlite3_busy_handler() interfaces and the busy_timeout pragma are 47 | // available to process B to help it deal with SQLITE_BUSY errors. 48 | // 49 | // An SQLITE_BUSY error can occur at any point in a transaction: when the transaction is first 50 | // started, during any write or update operations, or when the transaction commits. To avoid 51 | // encountering SQLITE_BUSY errors in the middle of a transaction, the application can use 52 | // BEGIN IMMEDIATE instead of just BEGIN to start a transaction. The BEGIN IMMEDIATE command 53 | // might itself return SQLITE_BUSY, but if it succeeds, then SQLite guarantees that no 54 | // subsequent operations on the same database through the next COMMIT will return SQLITE_BUSY. 55 | // 56 | // See also: SQLITE_BUSY_RECOVERY and SQLITE_BUSY_SNAPSHOT. 57 | // 58 | // The SQLITE_BUSY result code differs from SQLITE_LOCKED in that SQLITE_BUSY indicates a 59 | // conflict with a separate database connection, probably in a separate process, whereas 60 | // SQLITE_LOCKED indicates a conflict within the same database connection (or sometimes a 61 | // database connection with a shared cache). 62 | 63 | LOCKED :: 6; // A table in the database is locked // 64 | // The SQLITE_LOCKED result code indicates that a write operation could not continue because of 65 | // a conflict within the same database connection or a conflict with a different 66 | // database connection that uses a shared cache. 67 | // For example, a DROP TABLE statement cannot be run while another thread is reading from that 68 | // table on the same database connection because dropping the table would delete the table out 69 | // from under the concurrent reader. 70 | // 71 | // The SQLITE_LOCKED result code differs from SQLITE_BUSY in that SQLITE_LOCKED indicates a 72 | // conflict on the same database connection (or on a connection with a shared cache) whereas 73 | // SQLITE_BUSY indicates a conflict with a different database connection, probably in a 74 | // different process. 75 | 76 | NOMEM :: 7; // A malloc() failed // 77 | // The SQLITE_NOMEM result code indicates that SQLite was unable to allocate all the memory it 78 | // needed to complete the operation. In other words, an internal call to sqlite3_malloc() or 79 | // sqlite3_realloc() has failed in a case where the memory being allocated was required in order 80 | // to continue the operation. 81 | 82 | READONLY :: 8; // Attempt to write a readonly database // 83 | // The SQLITE_READONLY result code is returned when an attempt is made to alter some data for 84 | // which the current database connection does not have write permission. 85 | 86 | INTERRUPT :: 9; // Operation terminated by sqlite3_interrupt() // 87 | // The SQLITE_INTERRUPT result code indicates that an operation was interrupted by the 88 | // sqlite3_interrupt() interface. See also: SQLITE_ABORT 89 | 90 | IOERR :: 10; // Some kind of disk I/O error occurred // 91 | // The SQLITE_IOERR result code says that the operation could not finish because the operating 92 | // system reported an I/O error. 93 | // 94 | // A full disk drive will normally give an SQLITE_FULL error rather than an SQLITE_IOERR error. 95 | // 96 | // There are many different extended result codes for I/O errors that identify the specific I/O 97 | // operation that failed. 98 | 99 | CORRUPT :: 11; // The database disk image is malformed // 100 | // The SQLITE_CORRUPT result code indicates that the database file has been corrupted. See the 101 | // How To Corrupt Your Database Files for further discussion on how corruption can occur. 102 | 103 | NOTFOUND :: 12; // Unknown opcode in sqlite3_file_control() // 104 | // The SQLITE_NOTFOUND result code is exposed in three ways: 105 | // 106 | // 1. SQLITE_NOTFOUND can be returned by the sqlite3_file_control() interface to indicate that 107 | // the file control opcode passed as the third argument was not recognized by the 108 | // underlying VFS. 109 | // 110 | // SQLITE_NOTFOUND can also be returned by the xSetSystemCall() method of an sqlite3_vfs object. 111 | // 112 | // SQLITE_NOTFOUND can be returned by sqlite3_vtab_rhs_value() to indicate that the right-hand 113 | // operand of a constraint is not available to the xBestIndex method that made the call. 114 | // 115 | // The SQLITE_NOTFOUND result code is also used internally by the SQLite implementation, but 116 | // those internal uses are not exposed to the application. 117 | 118 | FULL :: 13; // Insertion failed because database is full // 119 | // The SQLITE_FULL result code indicates that a write could not complete because the disk is 120 | // full. Note that this error can occur when trying to write information into the main database 121 | // file, or it can also occur when writing into temporary disk files. 122 | // 123 | // Sometimes applications encounter this error even though there is an abundance of primary disk 124 | // space because the error occurs when writing into temporary disk files on a system where 125 | // temporary files are stored on a separate partition with much less space that the primary disk. 126 | 127 | CANTOPEN :: 14; // Unable to open the database file // 128 | // The SQLITE_CANTOPEN result code indicates that SQLite was unable to open a file. The file in 129 | // question might be a primary database file or one of several temporary disk files. 130 | 131 | PROTOCOL :: 15; // Database lock protocol error // 132 | // The SQLITE_PROTOCOL result code indicates a problem with the file locking protocol used by 133 | // SQLite. The SQLITE_PROTOCOL error is currently only returned when using WAL mode and 134 | // attempting to start a new transaction. There is a race condition that can occur when two 135 | // separate database connections both try to start a transaction at the same time in WAL mode. 136 | // The loser of the race backs off and tries again, after a brief delay. If the same connection 137 | // loses the locking race dozens of times over a span of multiple seconds, it will eventually 138 | // give up and return SQLITE_PROTOCOL. The SQLITE_PROTOCOL error should appear in practice very, 139 | // very rarely, and only when there are many separate processes all competing intensely to write 140 | // to the same database. 141 | 142 | EMPTY :: 16; // Internal use only // 143 | // The SQLITE_EMPTY result code is not currently used. 144 | 145 | SCHEMA :: 17; // The database schema changed // 146 | // The SQLITE_SCHEMA result code indicates that the database schema has changed. This result 147 | // code can be returned from sqlite3_step() for a prepared statement that was generated using 148 | // sqlite3_prepare() or sqlite3_prepare16(). If the database schema was changed by some other 149 | // process in between the time that the statement was prepared and the time the statement was 150 | // run, this error can result. 151 | // 152 | // If a prepared statement is generated from sqlite3_prepare_v2() then the statement is 153 | // automatically re-prepared if the schema changes, up to SQLITE_MAX_SCHEMA_RETRY times 154 | // (default: 50). The sqlite3_step() interface will only return SQLITE_SCHEMA back to the 155 | // application if the failure persists after these many retries. 156 | 157 | TOOBIG :: 18; // String or BLOB exceeds size limit // 158 | // The SQLITE_TOOBIG error code indicates that a string or BLOB was too large. The default 159 | // maximum length of a string or BLOB in SQLite is 1,000,000,000 bytes. This maximum length can 160 | // be changed at compile-time using the SQLITE_MAX_LENGTH compile-time option, or at run-time 161 | // using the sqlite3_limit(db,SQLITE_LIMIT_LENGTH,...) interface. The SQLITE_TOOBIG error 162 | // results when SQLite encounters a string or BLOB that exceeds the compile-time or run-time 163 | // limit. 164 | // 165 | // The SQLITE_TOOBIG error code can also result when an oversized SQL statement is passed into 166 | // one of the sqlite3_prepare_v2() interfaces. The maximum length of an SQL statement defaults 167 | // to a much smaller value of 1,000,000,000 bytes. The maximum SQL statement length can be set 168 | // at compile-time using SQLITE_MAX_SQL_LENGTH or at run-time using 169 | // sqlite3_limit(db,SQLITE_LIMIT_SQL_LENGTH,...). 170 | 171 | CONSTRAINT :: 19; // Abort due to constraint violation // 172 | // The SQLITE_CONSTRAINT error code means that an SQL constraint violation occurred while trying 173 | // to process an SQL statement. Additional information about the failed constraint can be found 174 | // by consulting the accompanying error message (returned via sqlite3_errmsg() or 175 | // sqlite3_errmsg16()) or by looking at the extended error code. 176 | // 177 | // The SQLITE_CONSTRAINT code can also be used as the return value from the xBestIndex() method 178 | // of a virtual table implementation. When xBestIndex() returns SQLITE_CONSTRAINT, that 179 | // indicates that the particular combination of inputs submitted to xBestIndex() cannot result 180 | // in a usable query plan and should not be given further consideration. 181 | 182 | MISMATCH :: 20; // Data type mismatch // 183 | // The SQLITE_MISMATCH error code indicates a datatype mismatch. 184 | // 185 | // SQLite is normally very forgiving about mismatches between the type of a value and the 186 | // declared type of the container in which that value is to be stored. For example, SQLite 187 | // allows the application to store a large BLOB in a column with a declared type of BOOLEAN. But 188 | // in a few cases, SQLite is strict about types. The SQLITE_MISMATCH error is returned in those 189 | // few cases when the types do not match. 190 | // 191 | // The rowid of a table must be an integer. Attempt to set the rowid to anything other than an 192 | // integer (or a NULL which will be automatically converted into the next available integer 193 | // rowid) results in an SQLITE_MISMATCH error. 194 | 195 | MISUSE :: 21; // Library used incorrectly // 196 | // The SQLITE_MISUSE return code might be returned if the application uses any SQLite interface 197 | // in a way that is undefined or unsupported. For example, using a prepared statement after that 198 | // prepared statement has been finalized might result in an SQLITE_MISUSE error. 199 | // 200 | // SQLite tries to detect misuse and report the misuse using this result code. However, there is 201 | // no guarantee that the detection of misuse will be successful. Misuse detection is 202 | // probabilistic. Applications should never depend on an SQLITE_MISUSE return value. 203 | // 204 | // If SQLite ever returns SQLITE_MISUSE from any interface, that means that the application is 205 | // incorrectly coded and needs to be fixed. Do not ship an application that sometimes returns 206 | // SQLITE_MISUSE from a standard SQLite interface because that application contains potentially 207 | // serious bugs. 208 | 209 | NOLFS :: 22; // Uses OS features not supported on host // 210 | // The SQLITE_NOLFS error can be returned on systems that do not support large files when the 211 | // database grows to be larger than what the filesystem can handle. "NOLFS" stands for "NO Large 212 | // File Support". 213 | 214 | AUTH :: 23; // Authorization denied // 215 | // The SQLITE_AUTH error is returned when the authorizer callback indicates that an SQL 216 | // statement being prepared is not authorized. 217 | 218 | FORMAT :: 24; // Not used // 219 | // The SQLITE_FORMAT error code is not currently used by SQLite. 220 | RANGE :: 25; // 2nd parameter to sqlite3_bind out of range // 221 | // The SQLITE_RANGE error indices that the parameter number argument to one of the sqlite3_bind 222 | // routines or the column number in one of the sqlite3_column routines is out of range. 223 | 224 | NOTADB :: 26; // File opened that is not a database file // 225 | // When attempting to open a file, the SQLITE_NOTADB error indicates that the file being opened 226 | // does not appear to be an SQLite database file. 227 | 228 | NOTICE :: 27; // Notifications from sqlite3_log() // 229 | // The SQLITE_NOTICE result code is not returned by any C/C++ interface. However, SQLITE_NOTICE 230 | // (or rather one of its extended error codes) is sometimes used as the first argument in an 231 | // sqlite3_log() callback to indicate that an unusual operation is taking place. 232 | 233 | WARNING :: 28; // Warnings from sqlite3_log() // 234 | // The SQLITE_WARNING result code is not returned by any C/C++ interface. However, 235 | // SQLITE_WARNING (or rather one of its extended error codes) is sometimes used as the first 236 | // argument in an sqlite3_log() callback to indicate that an unusual and possibly ill-advised 237 | // operation is taking place. 238 | 239 | ROW :: 100; // sqlite3_step() has another row ready // 240 | // The SQLITE_ROW result code returned by sqlite3_step() indicates that another row of output is 241 | // available. 242 | 243 | DONE :: 101; // sqlite3_step() has finished executing // 244 | // The SQLITE_DONE result code indicates that an operation has completed. The SQLITE_DONE result 245 | // code is most commonly seen as a return value from sqlite3_step() indicating that the SQL 246 | // statement has run to completion. But SQLITE_DONE can also be returned by other multi-step 247 | // interfaces such as sqlite3_backup_step(). 248 | } -------------------------------------------------------------------------------- /src/SQLite.jai: -------------------------------------------------------------------------------- 1 | // This is the jai "fancy wrapper" for SQLite. 2 | // If you want the raw bindings instead for whatever reason, see ../lib/sqlite3.jai. 3 | 4 | Handle :: #type *sqlite3; 5 | Callback :: #type sqlite3_callback; 6 | Statement :: #type *sqlite3_stmt; 7 | Column_Type :: enum { INTEGER; FLOAT; BLOB; NULL; TEXT; } 8 | Foreign_Key_Action :: enum { NO_ACTION; RESTRICT; SET_NULL; SET_DEFAULT; CASCADE; } 9 | 10 | #load "Result.jai"; 11 | 12 | assert_ok :: (result: Result, loc := #caller_location) { assert(result == .OK, "%: %", result, errmsg(), loc=loc); } 13 | 14 | 15 | SQLite_Info :: struct { 16 | filename: string = ":memory:"; 17 | handle: Handle; 18 | is_open: bool; 19 | pragmas: [..] string; 20 | } 21 | /*#if !FROM_METAPROGRAM */#add_context sqlite: SQLite_Info; 22 | 23 | 24 | set_pragmas :: (new_pragmas: [] string) -> Result { 25 | using context.sqlite; 26 | result: Result; 27 | if is_open { 28 | assert(false, "(maybe don't do this just yet though)"); 29 | for new_pragmas { 30 | // it seems weird that it appends the pragmas if the database is open... 31 | result = exec(tprint("PRAGMA %;", it)); 32 | if result != .OK then return result; 33 | array_add(*pragmas, it); 34 | } 35 | } 36 | // ...yet replaces them when it's not... 37 | else array_copy(*pragmas, new_pragmas); 38 | return result; 39 | // ...but it makes sense, I think, for reasons I'm too tired to explain right now. 40 | } 41 | 42 | 43 | open :: () -> result: Result, error: string { 44 | using context.sqlite; 45 | result := cast(Result) sqlite3_open(xx temp_c_string(filename), *handle); 46 | error := ifx result != .OK then to_string(cast(*u8) sqlite3_errmsg(handle)); 47 | is_open = result == .OK; 48 | for pragmas { result = exec(tprint("PRAGMA %;", it)); if result != .OK then return result, error; } 49 | return result, error; 50 | } 51 | 52 | open_for :: ($code: Code, name: string="", $caller_code := #caller_code) { 53 | begin := current_time_monotonic(); 54 | #if VERBOSE then verbose_begin_open_for(name); 55 | #if VERBOSE then defer verbose_end\ _open_for(name); 56 | 57 | open(); defer close(); 58 | 59 | #insert,scope(caller_code) code; 60 | } 61 | 62 | close :: () -> Result { 63 | using context.sqlite; 64 | result := cast(Result) sqlite3_close(handle); 65 | if result == .OK then is_open = false; 66 | return result; 67 | } 68 | 69 | 70 | /*exec :: (sql: string, callback: Callback = null, callback_arg: *void = null) -> result: Result, error: string { 71 | #if VERBOSE then print_color("%\n", sql, color=.HI_MAGENTA); 72 | error_cstring: *s8; // TODO: reuse instead of allocating & freeing every time? 73 | result := cast(Result) sqlite3_exec(context.sqlite.handle, xx temp_c_string(sql), callback, callback_arg, *error_cstring); 74 | error := ifx result != .OK then to_string(cast(*u8) error_cstring); 75 | sqlite3_free(error_cstring); // TODO: reuse instead of allocating & freeing every time? 76 | return result, error; 77 | }*/ 78 | 79 | // this version of exec is not actually SQLite's exec, 80 | // but it does the same thing, just without a callback function 81 | exec :: ( 82 | sql: string, // the SQL statement 83 | params: ..Any, // parameters to bind 84 | $code: Code = #code,null, // run this code for each returned row 85 | $ignore_returned_rows := false // ignore returned rows 86 | ) -> Result 87 | #modify { if code != #code,null then ignore_returned_rows = true; return true; } 88 | #expand { 89 | result, statement := prepare(sql); 90 | if result != .OK then return result; 91 | 92 | parameter_count_passed_in := params.count; 93 | parameter_count_in_sql := bind_parameter_count(statement); 94 | assert(parameter_count_passed_in == parameter_count_in_sql, 95 | "Mismatch between number of params passed in [%1 (%4)] and the number of question marks in the SQL string [%2]\n%3\n\nparams: %5", 96 | /* 1 */ parameter_count_passed_in, 97 | /* 2 */ parameter_count_in_sql, 98 | /* 3 */ sql, 99 | /* 4 */ params.count, 100 | /* 5 */ params 101 | ); 102 | 103 | param_number: s32 = 1; 104 | for params { 105 | if it.type.type == { 106 | case .BOOL; 107 | result = bind(statement, param_number, (cast(* bool) it.value_pointer).*); 108 | case .ENUM; #through; 109 | case .INTEGER; 110 | if it.type.runtime_size <= 4 111 | result = bind(statement, param_number, (cast(* s32) it.value_pointer).*); 112 | else 113 | result = bind(statement, param_number, (cast(* s64) it.value_pointer).*); 114 | case .FLOAT; 115 | result = bind(statement, param_number, (cast(*float64) it.value_pointer).*); 116 | case .STRING; 117 | result = bind(statement, param_number, (cast(* string) it.value_pointer).*); 118 | } 119 | if result != .OK then return result; 120 | param_number += 1; 121 | } 122 | 123 | should_return := false; 124 | for statement { 125 | /* 126 | column_count :: () -> s32 #expand { return column_count (`statement); } 127 | column_double :: (column_number: s32) -> float64 #expand { return column_double(`statement, column_number); } 128 | column_int :: (column_number: s32) -> s32 #expand { return column_int (`statement, column_number); } 129 | column_int64 :: (column_number: s32) -> s64 #expand { return column_int64 (`statement, column_number); } 130 | column_text :: (column_number: s32) -> string #expand { return column_text (`statement, column_number); } 131 | column_name :: (column_number: s32) -> string #expand { return column_name (`statement, column_number); } 132 | column_type :: (column_number: s32) -> Column_Type #expand { return column_type (`statement, column_number); } 133 | */ 134 | assert(ignore_returned_rows); 135 | STATEMENT_SCOPE : Code : #this; // very cool that this works 136 | #if code != #code,null then #insert,scope() code; 137 | } 138 | if should_return then return result; 139 | 140 | result = finalize(statement); 141 | return result; 142 | } 143 | 144 | // this one returns a single Row_Type 145 | exec_row :: ($Row_Type: Type, sql: string, params: ..Any, $check_column_names := true) -> result: Result, row: Row_Type, success: bool { 146 | row: Row_Type; success: bool; 147 | return exec(sql, ..params, #code { assert(it_index == 0); fetch_row(*`row, statement, `check_column_names); `success = true; }), row, success; 148 | } 149 | 150 | // this one returns an array of Row_Type 151 | exec_rows :: ($Row_Type: Type, sql: string, params: ..Any, allocator := temp, $check_column_names := true) -> result: Result, rows: [..] Row_Type { 152 | rows: [..] Row_Type; rows.allocator = allocator; 153 | return exec(sql, ..params, #code { fetch_row(array_add(*`rows), statement, `check_column_names); }), rows; 154 | } 155 | 156 | // this one returns an array of Column_Type, just one value per row 157 | exec_column :: ($Column_Type: Type, sql: string, params: ..Any, allocator := temp, $unique := false) -> result: Result, column: [..] Column_Type { 158 | column: [..] Column_Type; column.allocator = allocator; 159 | return exec(sql, ..params, #code { 160 | value := fetch_value(`Column_Type, statement); 161 | #if `unique then array_add_if_unique(*`column, value); 162 | else array_add(*`column, value); 163 | }), column; 164 | } 165 | 166 | // this one returns just a single value of type Value_Type 167 | exec_value :: ($Value_Type: Type, sql: string, params: ..Any) -> result: Result, value: Value_Type, success: bool { 168 | value: Value_Type; success: bool; 169 | return exec(sql, ..params, #code { assert(it_index == 0); `value = fetch_value(`Value_Type, statement); `success = true; }), value, success; 170 | } 171 | 172 | 173 | prepare :: (sql: string) -> result: Result, statement: Statement { 174 | #if VERBOSE then verbose_begin(sql); 175 | sql_cstring := temp_c_string(sql); 176 | statement: Statement; 177 | return cast(Result) sqlite3_prepare_v2(context.sqlite.handle, cast(*s8) sql_cstring, cast(s32) c_style_strlen(sql_cstring), *statement, null), statement; 178 | } 179 | step :: (statement: Statement) -> Result { 180 | return cast(Result) sqlite3_step(statement); 181 | } 182 | finalize :: (statement: Statement) -> Result { 183 | #if VERBOSE then verbose_end(); 184 | return cast(Result) sqlite3_finalize(statement); 185 | } 186 | sql :: (statement: Statement) -> string { 187 | return copy_temporary_string(to_string(cast(*u8) sqlite3_sql(statement))); 188 | } 189 | #scope_file 190 | _sql :: sql; 191 | #scope_export 192 | expanded_sql :: (statement: Statement) -> string { 193 | return copy_temporary_string(to_string(cast(*u8) sqlite3_expanded_sql(statement))); 194 | } 195 | column_count :: (statement: Statement) -> s32 { 196 | return sqlite3_column_count(statement); 197 | } 198 | column_double :: (statement: Statement, column_number: s32) -> float64 { 199 | return sqlite3_column_double(statement, column_number); 200 | } 201 | column_int :: (statement: Statement, column_number: s32) -> s32 { 202 | return sqlite3_column_int(statement, column_number); 203 | } 204 | column_int64 :: (statement: Statement, column_number: s32) -> s64 { 205 | return sqlite3_column_int64(statement, column_number); 206 | } 207 | column_text :: (statement: Statement, column_number: s32) -> string { 208 | return copy_temporary_string(to_string(cast(*u8) sqlite3_column_text(statement, column_number))); 209 | } 210 | column_name :: (statement: Statement, column_number: s32) -> string { 211 | return copy_temporary_string(to_string(cast(*u8) sqlite3_column_name(statement, column_number))); 212 | } 213 | column_type :: (statement: Statement, column_number: s32) -> enum { INTEGER; FLOAT; BLOB; NULL; TEXT; } { 214 | return xx sqlite3_column_type(statement, column_number); 215 | } 216 | last_insert_rowid :: () -> s64 { 217 | return sqlite3_last_insert_rowid(context.sqlite.handle); 218 | } 219 | errmsg :: () -> string { 220 | return to_string(cast(*u8) sqlite3_errmsg(context.sqlite.handle)); 221 | } 222 | changes :: inline () -> int { return sqlite3_changes(context.sqlite.handle); } 223 | bind_parameter_count :: (statement: Statement) -> int { 224 | return sqlite3_bind_parameter_count(statement); 225 | } 226 | bind :: (statement: Statement, index: s32, value: float64) -> Result { 227 | #if VERBOSE then verbose_bind(value); 228 | return cast(Result) sqlite3_bind_double(statement, index, value); 229 | } 230 | bind :: (statement: Statement, index: s32, value: s32) -> Result { 231 | #if VERBOSE then verbose_bind(value); 232 | return cast(Result) sqlite3_bind_int(statement, index, value); 233 | } 234 | bind :: (statement: Statement, index: s32, value: s64) -> Result { 235 | #if VERBOSE then verbose_bind(value); 236 | return cast(Result) sqlite3_bind_int64(statement, index, value); 237 | } 238 | bind :: (statement: Statement, index: s32, value: string) -> Result { 239 | #if VERBOSE then verbose_bind(value); 240 | value_cstring := temp_c_string(value); 241 | return cast(Result) sqlite3_bind_text(statement, index, cast(*s8) value_cstring, cast(s32) c_style_strlen(value_cstring), null); 242 | } 243 | bind :: (statement: Statement, index: s32) -> Result { 244 | #if VERBOSE then verbose_bind(null); 245 | return cast(Result) sqlite3_bind_null(statement, index); 246 | } 247 | 248 | bind :: (statement: Statement, index: s32, value: bool) -> Result { 249 | #if VERBOSE then verbose_bind(value); 250 | return cast(Result) sqlite3_bind_int(statement, index, xx ifx value then 1); 251 | } 252 | 253 | bind :: (statement: Statement, index: s32, value: $T) -> Result 254 | #modify { return (cast(*Type_Info) T).type == .ENUM; } { 255 | #if VERBOSE then verbose_bind(value); 256 | #if #run type_info(T).runtime_size <= 4 257 | return cast(Result) sqlite3_bind_int (statement, index, cast(s32) value); 258 | else 259 | return cast(Result) sqlite3_bind_int64(statement, index, cast(s64) value); 260 | } 261 | 262 | for_expansion :: (statement: Statement, body: Code, flags: For_Flags) #expand { 263 | `it := void; `it_index := 0; 264 | while true { `result = step(statement); if `result == { 265 | case .ROW; defer `it_index += 1; #insert body; continue; 266 | case .BUSY; continue; 267 | case .DONE; break; 268 | case; assert_ok(`result); 269 | }} 270 | } 271 | 272 | sqlite_optional_cleanup :: () { 273 | #if USE_MODEL_CACHE then reset_model_cache(reinit=false); 274 | array_free(context.sqlite.pragmas); 275 | } 276 | 277 | #scope_module 278 | 279 | // this cuts down on code generation 280 | bind :: inline (statement: Statement, index: s32, $$value: *void) -> Result { assert(value == null); return bind(statement, index); } 281 | 282 | serializable_members_of :: ($type: Type) -> [..] Type_Info_Struct_Member { 283 | return serializable_members_of(cast(*Type_Info_Struct) type_info(type)); 284 | } 285 | 286 | serializable_members_of :: (info: *Type_Info_Struct) -> [..] Type_Info_Struct_Member { assert(#compile_time); 287 | members: [..] Type_Info_Struct_Member; 288 | for member: info.members { 289 | is_a_valid_type := is_serializable(member.type); 290 | #if USE_MODEL_CACHE || FROM_METAPROGRAM { if is_a_model(info) && member_is_foreign_key(member) then is_a_valid_type = true; } 291 | if !is_a_valid_type then continue; 292 | #if USE_MODEL_CACHE || FROM_METAPROGRAM { 293 | for member.notes if it == NOTE_DO_NOT_SERIALIZE /*|| 294 | it == NOTE_FETCH */ then continue member; 295 | } 296 | array_add(*members, member); 297 | } 298 | return members; 299 | } 300 | 301 | is_serializable :: (info) => info.type == .BOOL || 302 | info.type == .ENUM || 303 | info.type == .INTEGER || 304 | info.type == .FLOAT || 305 | info.type == .STRING; 306 | 307 | fetch_value :: ($Value_Type: Type, statement: Statement) -> Value_Type 308 | #modify { return is_serializable(cast(*Type_Info) Value_Type); } { 309 | value: Value_Type; 310 | #insert #run get_column_cast("value", 0, type_info(Value_Type)); 311 | return value; 312 | } 313 | 314 | fetch_row :: (obj: *$T, statement: Statement, $check_column_names := false) { 315 | #insert -> string { 316 | sb: String_Builder; 317 | column_number := 0; 318 | #if (USE_MODEL_CACHE || FROM_METAPROGRAM) && #run is_a_model(T) then column_number = ORM_INTERNAL_COLUMN_COUNT; 319 | for serializable_members_of(T) { 320 | handled := false; 321 | #if check_column_names then print_to_builder(*sb, #string XX 322 | { 323 | database_column_name := column_name(statement, %1); 324 | MEMBER_NAME :: "%2"; 325 | assert(database_column_name == "" || database_column_name == MEMBER_NAME, "Column name mismatch; expected %%1, got %%2", 326 | /* 1 */database_column_name, 327 | /* 2 */MEMBER_NAME); 328 | } 329 | XX, /* 1 */ column_number, 330 | /* 2 */ it.name); 331 | #if USE_MODEL_CACHE || FROM_METAPROGRAM then if member_is_foreign_key(it) then { print_to_builder(*sb, #string XX 332 | { 333 | id := column_int64(statement, %2); 334 | found := table_find_pointer(*context.sqlite_model_cache._%3, id); 335 | if found then obj.%1 = .{id, found}; else obj.%1 = .{id, null}; 336 | } 337 | XX, /* 1 */ it.name, 338 | /* 2 */ column_number, 339 | /* 3 */ get_foreign_key_name_from(it, sprint("%", T)) 340 | ); handled = true; } 341 | if !handled then { 342 | print_to_builder(*sb, " obj.%", get_column_cast(it.name, column_number, it.type)); 343 | } 344 | column_number += 1; 345 | } 346 | return builder_to_string(*sb); 347 | } 348 | #if (USE_MODEL_CACHE || FROM_METAPROGRAM) && #run is_a_model(T) { 349 | obj.id = column_int64(statement, 0); 350 | obj.created = column_int (statement, 1); 351 | obj.modified = column_int (statement, 2); 352 | } 353 | } 354 | 355 | get_column_cast :: (var_name: string, column_number: int, info: *Type_Info) -> string { 356 | if info.type == { 357 | case .BOOL; return tprint(#string XX 358 | %1 = cast(bool) column_int(statement, %2); 359 | XX, /* 1 */ var_name, 360 | /* 2 */ column_number 361 | ); 362 | case .ENUM; return tprint(#string XX 363 | %1 = xx column_int%3(statement, %2); 364 | XX, /* 1 */ var_name, 365 | /* 2 */ column_number, 366 | /* 3 */ ifx info.runtime_size > 4 then "64" 367 | ); 368 | case .INTEGER; return tprint(#string XX 369 | %1 = column_int%3(statement, %2); 370 | XX, /* 1 */ var_name, 371 | /* 2 */ column_number, 372 | /* 3 */ ifx info.runtime_size > 4 then "64" 373 | ); 374 | case .FLOAT; return tprint(#string XX 375 | %1 = %3column_double(statement, %2); 376 | XX, /* 1 */ var_name, 377 | /* 2 */ column_number, 378 | /* 3 */ ifx info.runtime_size == 4 then "xx " 379 | ); 380 | case .STRING; return tprint(#string XX 381 | %1 = column_text(statement, %2); 382 | XX, /* 1 */ var_name, 383 | /* 2 */ column_number 384 | ); 385 | case; assert(false, "this should never happen"); return ""; 386 | } 387 | } 388 | 389 | #scope_file 390 | 391 | #if VERBOSE then #load "Verbose.jai"; 392 | 393 | #import "Basic"; 394 | -------------------------------------------------------------------------------- /src/Verbose.jai: -------------------------------------------------------------------------------- 1 | #import "Print_Color"; 2 | #import "String"; 3 | 4 | COLOR_SCHEME :: struct { 5 | QUERY_TEXT :: Console_Color.MAGENTA; 6 | QUERY_PARAMETER :: Console_Color.HI_CYAN; 7 | QUERY_RULER :: Console_Color.BG_BLUE; 8 | OPEN_FOR_NAME :: Console_Color.YELLOW; 9 | OPEN_FOR_RULER :: Console_Color.BG_YELLOW; 10 | } 11 | 12 | MINIMUM_OPEN_FOR_HEADER_AND_FOOTER_WIDTH :: 40; 13 | 14 | #add_context sqlite_verbose: struct { 15 | statement: string; 16 | parameter_count: int; 17 | parameters: [100] string; 18 | open_for_begin: Apollo_Time; 19 | }; 20 | 21 | verbose_begin :: (statement: string) { 22 | context.sqlite_verbose.statement = statement; 23 | } 24 | 25 | verbose_bind :: (param: $T) { 26 | using context.sqlite_verbose; 27 | #if #run type_info(T).type == .ENUM then 28 | parameters[parameter_count] = tprint("% [%]", cast,force(s64) param, param); 29 | else 30 | #if #run type_info(T).type == .POINTER then 31 | parameters[parameter_count] = "NULL"; 32 | else 33 | #if #run type_info(T).type == .BOOL then 34 | parameters[parameter_count] = tprint("% [%]", ifx param then 1, ifx param then "TRUE" else "FALSE"); 35 | else 36 | #if #run type_info(T).type == .STRING then 37 | parameters[parameter_count] = tprint("\"%\"", param); 38 | else 39 | parameters[parameter_count] = tprint("%", param); 40 | parameter_count += 1; 41 | } 42 | 43 | verbose_end :: () { 44 | using context.sqlite_verbose; 45 | parameter_index := 0; 46 | for split(statement, "\n") { 47 | if open_for_begin != .{} { 48 | print_color(" ", color=COLOR_SCHEME.OPEN_FOR_RULER); 49 | } 50 | print_color(" ", color=COLOR_SCHEME.QUERY_RULER); 51 | write_string(" "); 52 | for split(it, "?") { 53 | with_console_color(COLOR_SCHEME.QUERY_TEXT, write_string(trim_left(it, "0123456789"))); 54 | if parameter_index < parameter_count then with_console_color(COLOR_SCHEME.QUERY_PARAMETER, write_string(parameters[it_index])); 55 | parameter_index += 1; 56 | } 57 | write_string("\n"); 58 | } 59 | parameter_count = 0; 60 | statement = ""; 61 | } 62 | 63 | verbose_begin_open_for :: (name: string) { 64 | using context.sqlite_verbose; 65 | open_for_begin = current_time_monotonic(); 66 | write_string("\n"); 67 | print_color(" ", color=COLOR_SCHEME.OPEN_FOR_RULER); 68 | print_color(" %\n", ifx name else "(unnamed block)", color=COLOR_SCHEME.OPEN_FOR_NAME); 69 | } 70 | 71 | verbose_end\ _open_for :: (name: string) { 72 | using context.sqlite_verbose; 73 | end := current_time_monotonic(); 74 | seconds := cast(float) to_nanoseconds(end-open_for_begin) / cast(float) 1_000_000_000; 75 | print_color(" ", color=COLOR_SCHEME.OPEN_FOR_RULER); write_string("\n"); 76 | print_color(" ", color=COLOR_SCHEME.OPEN_FOR_RULER); 77 | print_color(" %\n", ifx name else "(unnamed block)", color=COLOR_SCHEME.OPEN_FOR_NAME); 78 | with_console_color(COLOR_SCHEME.OPEN_FOR_RULER, write_string(tprint(" % seconds ", seconds))); 79 | 80 | write_string("\n\n"); 81 | open_for_begin = .{}; 82 | } 83 | --------------------------------------------------------------------------------