├── .github ├── release.yml └── workflows │ └── ci.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE.LGPL ├── Package.swift ├── README.md ├── Sources ├── SQLExt │ ├── CMakeLists.txt │ ├── Skip │ │ └── skip.yml │ └── sqlite │ │ ├── sqlite3.c │ │ ├── sqlite3.h │ │ ├── tomcrypt.h │ │ ├── tomcrypt_argchk.h │ │ ├── tomcrypt_cfg.h │ │ ├── tomcrypt_cipher.h │ │ ├── tomcrypt_custom.h │ │ ├── tomcrypt_hash.h │ │ ├── tomcrypt_mac.h │ │ ├── tomcrypt_macros.h │ │ ├── tomcrypt_math.h │ │ ├── tomcrypt_misc.h │ │ ├── tomcrypt_pk.h │ │ ├── tomcrypt_pkcs.h │ │ ├── tomcrypt_private.h │ │ └── tomcrypt_prng.h ├── SkipSQL │ ├── SQLContext.swift │ ├── SQLStatement.swift │ ├── SQLite.swift │ ├── SQLiteCLibrary.swift │ ├── SQLiteJLibrary.swift │ ├── SQLiteLibrary.swift │ └── Skip │ │ └── skip.yml └── SkipSQLPlus │ ├── SQLPlus.swift │ ├── SQLPlusCLibrary.swift │ ├── SQLPlusJLibrary.swift │ └── Skip │ └── skip.yml └── Tests ├── SkipSQLPlusTests ├── SQLContextTestConfiguration.swift ├── SQLContextTests.swift ├── SQLPlusTests.swift ├── Skip │ └── skip.yml └── XCSkipTests.swift └── SkipSQLTests ├── SQLContextTestConfiguration.swift ├── SQLContextTests.swift ├── Skip └── skip.yml └── XCSkipTests.swift /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | labels: 4 | - ignore-for-release 5 | authors: 6 | - skipbuilder 7 | categories: 8 | - title: Breaking Change 9 | labels: 10 | - Semver-Major 11 | - breaking-change 12 | - title: Enhancement 13 | labels: 14 | - Semver-Minor 15 | - enhancement 16 | - title: Other Changes 17 | labels: 18 | - "*" 19 | 20 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: skip-sql 2 | on: 3 | push: 4 | branches: '*' 5 | tags: "[0-9]+.[0-9]+.[0-9]+" 6 | schedule: 7 | - cron: '0 7,17 * * *' 8 | workflow_dispatch: 9 | pull_request: 10 | 11 | permissions: 12 | contents: write 13 | 14 | jobs: 15 | call-workflow: 16 | uses: skiptools/actions/.github/workflows/skip-framework.yml@v1 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | xcodebuild*.log 9 | 10 | java_pid*.hprof 11 | 12 | .*.swp 13 | .DS_Store 14 | 15 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 16 | *.xcscmblueprint 17 | *.xccheckout 18 | 19 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 20 | build/ 21 | DerivedData/ 22 | .android/ 23 | .kotlin/ 24 | *.moved-aside 25 | *.pbxuser 26 | !default.pbxuser 27 | *.mode1v3 28 | !default.mode1v3 29 | *.mode2v3 30 | !default.mode2v3 31 | *.perspectivev3 32 | !default.perspectivev3 33 | 34 | ## Obj-C/Swift specific 35 | *.hmap 36 | 37 | ## App packaging 38 | *.ipa 39 | *.dSYM.zip 40 | *.dSYM 41 | 42 | ## Playgrounds 43 | timeline.xctimeline 44 | playground.xcworkspace 45 | 46 | # Swift Package Manager 47 | # 48 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 49 | Packages/ 50 | Package.pins 51 | Package.resolved 52 | *.xcodeproj 53 | 54 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 55 | # hence it is not needed unless you have added a package configuration file to your project 56 | .swiftpm 57 | 58 | .build/ 59 | 60 | # CocoaPods 61 | # 62 | # We recommend against adding the Pods directory to your .gitignore. However 63 | # you should judge for yourself, the pros and cons are mentioned at: 64 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 65 | # 66 | # Pods/ 67 | # 68 | # Add this line if you want to avoid checking in source code from the Xcode workspace 69 | # *.xcworkspace 70 | 71 | # Carthage 72 | # 73 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 74 | # Carthage/Checkouts 75 | 76 | Carthage/Build/ 77 | 78 | # Accio dependency management 79 | Dependencies/ 80 | .accio/ 81 | 82 | # fastlane 83 | # 84 | # It is recommended to not store the screenshots in the git repo. 85 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 86 | # For more information about the recommended setup visit: 87 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 88 | 89 | fastlane/report.xml 90 | fastlane/Preview.html 91 | fastlane/screenshots/**/*.png 92 | fastlane/test_output 93 | 94 | # Code Injection 95 | # 96 | # After new code Injection tools there's a generated folder /iOSInjectionProject 97 | # https://github.com/johnno1962/injectionforxcode 98 | 99 | iOSInjectionProject/ 100 | 101 | 102 | 103 | # Ignore Gradle project-specific cache directory 104 | .gradle 105 | 106 | # Ignore Gradle build output directory 107 | build 108 | 109 | # gradle properties 110 | local.properties 111 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.7.2 2 | 3 | Released 2024-10-16 4 | 5 | - Bump cmake_minimum_required to 3.3 to fix skip export error 6 | - Eliminate redundant import of AndroidJUnit4 test runner 7 | - Fix reference to URL.documentsDirectory in README 8 | 9 | ## 0.7.1 10 | 11 | Released 2024-08-15 12 | 13 | 14 | ## 0.7.0 15 | 16 | Released 2024-08-15 17 | 18 | 19 | ## 0.6.3 20 | 21 | Released 2024-07-08 22 | 23 | - Update search paths for tomcrypt to point to intermediates/merged_native_libs/debug/mergeDebugNativeLibs/out/lib to accommodate change in android gradle plugin 8.5.0 24 | - Update README 25 | - ci: update workflow actions location 26 | 27 | ## 0.6.2 28 | 29 | Released 2024-03-05 30 | 31 | - Link to external skip-ltc module for SQLExt 32 | - Add algorithm tests 33 | - Disable HAVE_GETHOSTUUID since it is disallowed on iOS 34 | - Ignore -Wconversion to reduce warnings 35 | 36 | ## 0.6.1 37 | 38 | Released 2024-03-02 39 | 40 | - Harmonize build options between Android and Darwin 41 | - Add JSON tests 42 | - Add test cases 43 | 44 | ## 0.6.0 45 | 46 | Released 2024-02-28 47 | 48 | - Update error messages and add JSON tests 49 | - Add SQLite JSON test 50 | - Add SQLPlus tests 51 | - Add SQLPlus tests 52 | - Add SQLPlus module that includes custom build of sqlite 3.44.2 with extensions 53 | 54 | ## 0.5.1 55 | 56 | Released 2024-02-20 57 | 58 | - Blob statement parameter binding handling 59 | - Make UpdateHook class final 60 | 61 | ## 0.5.0 62 | 63 | Released 2024-02-05 64 | 65 | 66 | ## 0.4.3 67 | 68 | Released 2023-12-22 69 | 70 | 71 | ## 0.4.2 72 | 73 | Released 2023-12-11 74 | 75 | - Minor comment updates 76 | - Update README.md 77 | 78 | ## 0.4.1 79 | 80 | Released 2023-11-27 81 | 82 | - Dependency bump 83 | 84 | ## 0.4.0 85 | 86 | Released 2023-11-25 87 | 88 | - Use direct mappings to optimize JNA access to C sqlite API 89 | - Refactor into separate implementation files 90 | 91 | ## 0.3.12 92 | 93 | Released 2023-11-25 94 | 95 | - Require statements and connections to be closed 96 | 97 | ## 0.3.11 98 | 99 | Released 2023-11-25 100 | 101 | - Add SQLContext.interrupt() 102 | 103 | ## 0.3.10 104 | 105 | Released 2023-11-25 106 | 107 | - Fix in-memory database creation string 108 | 109 | ## 0.3.9 110 | 111 | Released 2023-11-25 112 | 113 | - Add parameter inspection functions 114 | 115 | ## 0.3.8 116 | 117 | Released 2023-11-24 118 | 119 | - Use SQLITE_TRANSIENT for bound strings and blobs 120 | 121 | ## 0.3.7 122 | 123 | Released 2023-11-21 124 | 125 | - Doc updates 126 | - Docs 127 | 128 | ## 0.3.6 129 | 130 | Released 2023-11-20 131 | 132 | 133 | ## 0.3.5 134 | 135 | Released 2023-11-19 136 | 137 | - Add onUpdate hook and improve API 138 | - Add updateHook 139 | 140 | ## 0.3.4 141 | 142 | Released 2023-11-16 143 | 144 | - Update API 145 | 146 | ## 0.3.3 147 | 148 | Released 2023-11-14 149 | 150 | 151 | ## 0.3.2 152 | 153 | Released 2023-11-14 154 | 155 | 156 | ## 0.3.1 157 | 158 | Released 2023-11-02 159 | 160 | - More API and tests 161 | - Add blob accessor and transaction handling; test cases 162 | - Add SQLType and SQLValue and test cases 163 | - Add row accessor and test case 164 | - SQLStatement.next; SQLConnection.close 165 | 166 | ## 0.3.0 167 | 168 | Released 2023-10-31 169 | 170 | - Import SQLite3 through SkipFFI 171 | 172 | ## 0.2.0 173 | 174 | Released 2023-10-23 175 | 176 | 177 | ## 0.1.8 178 | 179 | Released 2023-09-24 180 | 181 | 182 | ## 0.1.7 183 | 184 | Released 2023-09-11 185 | 186 | - Elide SQLite version check since different emulators have different versions installed 187 | 188 | ## 0.1.6 189 | 190 | Released 2023-09-09 191 | 192 | - Have tests use NSTemporaryDirectory() rather than /tmp/ (which doesn't exist on the Android emulator) 193 | 194 | ## 0.1.5 195 | 196 | Released 2023-09-07 197 | 198 | 199 | ## 0.1.4 200 | 201 | Released 2023-09-07 202 | 203 | 204 | ## 0.1.3 205 | 206 | Released 2023-09-06 207 | 208 | - Modernize package 209 | 210 | ## 0.1.2 211 | 212 | Released 2023-09-04 213 | 214 | 215 | ## 0.1.1 216 | 217 | Released 2023-09-03 218 | 219 | 220 | ## 0.1.0 221 | 222 | Released 2023-09-02 223 | 224 | 225 | ## 0.0.11 226 | 227 | Released 2023-09-01 228 | 229 | 230 | ## 0.0.10 231 | 232 | Released 2023-08-31 233 | 234 | 235 | ## 0.0.9 236 | 237 | Released 2023-08-31 238 | 239 | 240 | ## 0.0.8 241 | 242 | Released 2023-08-25 243 | 244 | 245 | ## 0.0.7 246 | 247 | Released 2023-08-21 248 | 249 | - Update dependencies 250 | 251 | ## 0.0.6 252 | 253 | Released 2023-08-21 254 | 255 | 256 | ## 0.0.5 257 | 258 | Released 2023-08-20 259 | 260 | 261 | ## 0.0.4 262 | 263 | Released 2023-08-20 264 | 265 | 266 | ## 0.0.3 267 | 268 | Released 2023-08-20 269 | 270 | 271 | ## 0.0.2 272 | 273 | Released 2023-08-20 274 | 275 | 276 | -------------------------------------------------------------------------------- /LICENSE.LGPL: -------------------------------------------------------------------------------- 1 | This software is licensed under the LGPL3, included below. 2 | 3 | As a special exception to the GNU Lesser General Public License version 3 4 | ("LGPL3"), the copyright holders of this Library give you permission to 5 | convey to a third party a Combined Work that links statically or dynamically 6 | to this Library without providing any Minimal Corresponding Source or 7 | Minimal Application Code as set out in 4d or providing the installation 8 | information set out in section 4e, provided that you comply with the other 9 | provisions of LGPL3 and provided that you meet, for the Application the 10 | terms and conditions of the license(s) which apply to the Application. 11 | 12 | Except as stated in this special exception, the provisions of LGPL3 will 13 | continue to comply in full to this Library. If you modify this Library, you 14 | may apply this exception to your version of this Library, but you are not 15 | obliged to do so. If you do not wish to do so, delete this exception 16 | statement from your version. This exception does not (and cannot) modify any 17 | license terms which apply to the Application, with which you must still 18 | comply. 19 | 20 | 21 | GNU LESSER GENERAL PUBLIC LICENSE 22 | Version 3, 29 June 2007 23 | 24 | Copyright (C) 2007 Free Software Foundation, Inc. 25 | Everyone is permitted to copy and distribute verbatim copies 26 | of this license document, but changing it is not allowed. 27 | 28 | 29 | This version of the GNU Lesser General Public License incorporates 30 | the terms and conditions of version 3 of the GNU General Public 31 | License, supplemented by the additional permissions listed below. 32 | 33 | 0. Additional Definitions. 34 | 35 | As used herein, "this License" refers to version 3 of the GNU Lesser 36 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 37 | General Public License. 38 | 39 | "The Library" refers to a covered work governed by this License, 40 | other than an Application or a Combined Work as defined below. 41 | 42 | An "Application" is any work that makes use of an interface provided 43 | by the Library, but which is not otherwise based on the Library. 44 | Defining a subclass of a class defined by the Library is deemed a mode 45 | of using an interface provided by the Library. 46 | 47 | A "Combined Work" is a work produced by combining or linking an 48 | Application with the Library. The particular version of the Library 49 | with which the Combined Work was made is also called the "Linked 50 | Version". 51 | 52 | The "Minimal Corresponding Source" for a Combined Work means the 53 | Corresponding Source for the Combined Work, excluding any source code 54 | for portions of the Combined Work that, considered in isolation, are 55 | based on the Application, and not on the Linked Version. 56 | 57 | The "Corresponding Application Code" for a Combined Work means the 58 | object code and/or source code for the Application, including any data 59 | and utility programs needed for reproducing the Combined Work from the 60 | Application, but excluding the System Libraries of the Combined Work. 61 | 62 | 1. Exception to Section 3 of the GNU GPL. 63 | 64 | You may convey a covered work under sections 3 and 4 of this License 65 | without being bound by section 3 of the GNU GPL. 66 | 67 | 2. Conveying Modified Versions. 68 | 69 | If you modify a copy of the Library, and, in your modifications, a 70 | facility refers to a function or data to be supplied by an Application 71 | that uses the facility (other than as an argument passed when the 72 | facility is invoked), then you may convey a copy of the modified 73 | version: 74 | 75 | a) under this License, provided that you make a good faith effort to 76 | ensure that, in the event an Application does not supply the 77 | function or data, the facility still operates, and performs 78 | whatever part of its purpose remains meaningful, or 79 | 80 | b) under the GNU GPL, with none of the additional permissions of 81 | this License applicable to that copy. 82 | 83 | 3. Object Code Incorporating Material from Library Header Files. 84 | 85 | The object code form of an Application may incorporate material from 86 | a header file that is part of the Library. You may convey such object 87 | code under terms of your choice, provided that, if the incorporated 88 | material is not limited to numerical parameters, data structure 89 | layouts and accessors, or small macros, inline functions and templates 90 | (ten or fewer lines in length), you do both of the following: 91 | 92 | a) Give prominent notice with each copy of the object code that the 93 | Library is used in it and that the Library and its use are 94 | covered by this License. 95 | 96 | b) Accompany the object code with a copy of the GNU GPL and this license 97 | document. 98 | 99 | 4. Combined Works. 100 | 101 | You may convey a Combined Work under terms of your choice that, 102 | taken together, effectively do not restrict modification of the 103 | portions of the Library contained in the Combined Work and reverse 104 | engineering for debugging such modifications, if you also do each of 105 | the following: 106 | 107 | a) Give prominent notice with each copy of the Combined Work that 108 | the Library is used in it and that the Library and its use are 109 | covered by this License. 110 | 111 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 112 | document. 113 | 114 | c) For a Combined Work that displays copyright notices during 115 | execution, include the copyright notice for the Library among 116 | these notices, as well as a reference directing the user to the 117 | copies of the GNU GPL and this license document. 118 | 119 | d) Do one of the following: 120 | 121 | 0) Convey the Minimal Corresponding Source under the terms of this 122 | License, and the Corresponding Application Code in a form 123 | suitable for, and under terms that permit, the user to 124 | recombine or relink the Application with a modified version of 125 | the Linked Version to produce a modified Combined Work, in the 126 | manner specified by section 6 of the GNU GPL for conveying 127 | Corresponding Source. 128 | 129 | 1) Use a suitable shared library mechanism for linking with the 130 | Library. A suitable mechanism is one that (a) uses at run time 131 | a copy of the Library already present on the user's computer 132 | system, and (b) will operate properly with a modified version 133 | of the Library that is interface-compatible with the Linked 134 | Version. 135 | 136 | e) Provide Installation Information, but only if you would otherwise 137 | be required to provide such information under section 6 of the 138 | GNU GPL, and only to the extent that such information is 139 | necessary to install and execute a modified version of the 140 | Combined Work produced by recombining or relinking the 141 | Application with a modified version of the Linked Version. (If 142 | you use option 4d0, the Installation Information must accompany 143 | the Minimal Corresponding Source and Corresponding Application 144 | Code. If you use option 4d1, you must provide the Installation 145 | Information in the manner specified by section 6 of the GNU GPL 146 | for conveying Corresponding Source.) 147 | 148 | 5. Combined Libraries. 149 | 150 | You may place library facilities that are a work based on the 151 | Library side by side in a single library together with other library 152 | facilities that are not Applications and are not covered by this 153 | License, and convey such a combined library under terms of your 154 | choice, if you do both of the following: 155 | 156 | a) Accompany the combined library with a copy of the same work based 157 | on the Library, uncombined with any other library facilities, 158 | conveyed under the terms of this License. 159 | 160 | b) Give prominent notice with the combined library that part of it 161 | is a work based on the Library, and explaining where to find the 162 | accompanying uncombined form of the same work. 163 | 164 | 6. Revised Versions of the GNU Lesser General Public License. 165 | 166 | The Free Software Foundation may publish revised and/or new versions 167 | of the GNU Lesser General Public License from time to time. Such new 168 | versions will be similar in spirit to the present version, but may 169 | differ in detail to address new problems or concerns. 170 | 171 | Each version is given a distinguishing version number. If the 172 | Library as you received it specifies that a certain numbered version 173 | of the GNU Lesser General Public License "or any later version" 174 | applies to it, you have the option of following the terms and 175 | conditions either of that published version or of any later version 176 | published by the Free Software Foundation. If the Library as you 177 | received it does not specify a version number of the GNU Lesser 178 | General Public License, you may choose any version of the GNU Lesser 179 | General Public License ever published by the Free Software Foundation. 180 | 181 | If the Library as you received it specifies that a proxy can decide 182 | whether future versions of the GNU Lesser General Public License shall 183 | apply, that proxy's public statement of acceptance of any version is 184 | permanent authorization for you to choose that version for the 185 | Library. 186 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.9 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "skip-sql", 6 | defaultLocalization: "en", 7 | platforms: [.iOS(.v16), .macOS(.v13), .tvOS(.v16), .watchOS(.v9), .macCatalyst(.v16)], 8 | products: [ 9 | .library(name: "SkipSQL", targets: ["SkipSQL"]), 10 | .library(name: "SkipSQLPlus", type: .dynamic, targets: ["SkipSQLPlus"]), 11 | ], 12 | dependencies: [ 13 | .package(url: "https://source.skip.tools/skip.git", from: "1.1.11"), 14 | .package(url: "https://source.skip.tools/skip-foundation.git", from: "1.1.11"), 15 | .package(url: "https://source.skip.tools/skip-unit.git", from: "1.0.1"), 16 | .package(url: "https://source.skip.tools/skip-ffi.git", from: "1.0.0"), 17 | .package(url: "https://source.skip.tools/skip-ltc.git", "0.0.0"..<"2.0.0"), 18 | ], 19 | targets: [ 20 | .target(name: "SkipSQL", dependencies: [ 21 | .product(name: "SkipFoundation", package: "skip-foundation"), 22 | .product(name: "SkipFFI", package: "skip-ffi") 23 | ], plugins: [.plugin(name: "skipstone", package: "skip")]), 24 | .testTarget(name: "SkipSQLTests", dependencies: [ 25 | "SkipSQL", 26 | .product(name: "SkipTest", package: "skip") 27 | ], plugins: [.plugin(name: "skipstone", package: "skip")]), 28 | .target(name: "SkipSQLPlus", dependencies: [ 29 | "SkipSQL", 30 | "SQLExt", 31 | ], plugins: [.plugin(name: "skipstone", package: "skip")]), 32 | .testTarget(name: "SkipSQLPlusTests", dependencies: [ 33 | "SkipSQLPlus", 34 | .product(name: "SkipTest", package: "skip") 35 | ], plugins: [.plugin(name: "skipstone", package: "skip")]), 36 | .target(name: "SQLExt", dependencies: [ 37 | .product(name: "SkipLTC", package: "skip-ltc"), 38 | .product(name: "SkipUnit", package: "skip-unit") 39 | ], sources: ["sqlite"], 40 | publicHeadersPath: "sqlite", 41 | cSettings: [ 42 | .headerSearchPath("sqlite"), 43 | .define("SQLITE_DQS", to: "0"), 44 | .define("SQLITE_ENABLE_API_ARMOR"), 45 | .define("SQLITE_ENABLE_COLUMN_METADATA"), 46 | .define("SQLITE_ENABLE_DBSTAT_VTAB"), 47 | .define("SQLITE_ENABLE_FTS3"), 48 | .define("SQLITE_ENABLE_FTS3_PARENTHESIS"), 49 | .define("SQLITE_ENABLE_FTS3_TOKENIZER"), 50 | .define("SQLITE_ENABLE_FTS4"), 51 | .define("SQLITE_ENABLE_FTS5"), 52 | .define("SQLITE_ENABLE_MEMORY_MANAGEMENT"), 53 | .define("SQLITE_ENABLE_PREUPDATE_HOOK"), 54 | .define("SQLITE_ENABLE_RTREE"), 55 | .define("SQLITE_ENABLE_SESSION"), 56 | .define("SQLITE_ENABLE_STMTVTAB"), 57 | .define("SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION"), 58 | .define("SQLITE_ENABLE_UNLOCK_NOTIFY"), 59 | .define("SQLITE_MAX_VARIABLE_NUMBER", to: "250000"), 60 | .define("SQLITE_LIKE_DOESNT_MATCH_BLOBS"), 61 | .define("SQLITE_OMIT_DEPRECATED"), 62 | .define("SQLITE_OMIT_SHARED_CACHE"), 63 | .define("SQLITE_SECURE_DELETE"), 64 | .define("SQLITE_THREADSAFE", to: "2"), 65 | .define("SQLITE_USE_URI"), 66 | .define("SQLITE_ENABLE_SNAPSHOT"), 67 | .define("SQLITE_HAS_CODEC"), 68 | .define("SQLITE_TEMP_STORE", to: "2"), 69 | .define("HAVE_GETHOSTUUID", to: "0"), 70 | .define("SQLCIPHER_CRYPTO_LIBTOMCRYPT"), 71 | //.unsafeFlags(["-Wno-shorten-64-to-32", "-Wno-ambiguous-macro"]), // enabled manually in libs 72 | ], 73 | plugins: [.plugin(name: "skipstone", package: "skip")]), 74 | 75 | ] 76 | ) 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SkipSQL 2 | 3 | The SkipSQL module is a dual-platform [Skip Lite](https://skip.tools) framework that provides access to sqlite database in Darwin and Android systems. 4 | 5 | ## Usage 6 | 7 | ### Connection example 8 | 9 | To connect 10 | ```swift 11 | let dbpath = URL.documentsDirectory.appendingPathComponent("db.sqlite") 12 | 13 | let ctx = try SQLContext(path: dbpath, flags: [.create, .readWrite]) 14 | defer { ctx.close() } 15 | 16 | try sqlite.exec(sql: "CREATE TABLE IF NOT EXISTS SOME_TABLE (STRING TEXT)") 17 | 18 | try sqlite.exec(sql: "INSERT INTO SOME_TABLE (STRING) VALUES ('ABC')") 19 | 20 | let rows: [[SQLValue]] = ctx.query(sql: "SELECT STRING FROM SOME_TABLE") 21 | assert(rows[0][0] == SQLValue.string("ABC")) 22 | 23 | ``` 24 | 25 | ### In-memory databases 26 | 27 | When passing `nil` as the path, the `SQLContext` will reside entirely in memory, and will not persist once the context is closed. This can be useful for unit testing and performing in-memory calculations, or as a temporary engine for calculations and sorting. 28 | 29 | ```swift 30 | let ctx = try SQLContext(path: nil) 31 | defer { ctx.close() } 32 | 33 | let rows: [[SQLValue]] = ctx.query(sql: "SELECT 1, 1.1+2.2, 'AB'||'C'") 34 | 35 | assert(rows[0][0] == SQLValue.integer(1)) 36 | assert(rows[0][1] == SQLValue.float(3.3)) 37 | assert(rows[0][2] == SQLValue.text("ABC")) 38 | 39 | ``` 40 | 41 | ### Transactions 42 | 43 | Performing multiple operations in the context of a transaction will ensure that either all the operations succeed (`COMMIT`) or fail (`ROLLBACK`) together. 44 | 45 | ```swift 46 | try ctx.transaction { 47 | try ctx.exec(sql: "INSERT INTO TABLE_NAME VALUES(1)") 48 | try ctx.exec(sql: "INSERT INTO TABLE_NAME VALUES(2)") 49 | } 50 | ``` 51 | 52 | The default transaction type is `.deferred`, but it can be specified as a parameter to `transaction` to override the default, or `nil` to perform the operation without a transaction. 53 | 54 | ### Bound parameters 55 | 56 | Retaining a prepared `SQLStatement` will mean that the SQL doesn't need to be re-parsed each time a query or insert/update statement is performed. 57 | 58 | SQL statements with a `?` symbol will expect those parameters to be applied with the `bind` function before the statement is executed. 59 | 60 | ```swift 61 | 62 | let insert = try sqlite.prepare(sql: "INSERT INTO TABLE_NAME (NUM, STR) VALUES (?, ?)") 63 | defer { insert.close() } 64 | 65 | // insert 1,000 rows in a single transaction, re-using the insert statement 66 | try sqlite.transaction { 67 | for i in 1...1_000 { 68 | let params: [SQLValue] = [ 69 | SQLValue.integer(Int64(i)), 70 | SQLValue.text("Row #\(i)") 71 | ] 72 | try insert.update(parameters: params) 73 | } 74 | } 75 | 76 | ``` 77 | 78 | 79 | ### Schema Migration 80 | 81 | There is no built-in support for schema migrations. Following is a part of a sample of how you might perform migrations in your own app. 82 | 83 | 84 | ```swift 85 | // track the version of the schema in the database, which can be used for schema migration 86 | try ctx.exec(sql: "CREATE TABLE IF NOT EXISTS DB_SCHEMA_VERSION (id INTEGER PRIMARY KEY, version INTEGER)") 87 | try ctx.exec(sql: "INSERT OR IGNORE INTO DB_SCHEMA_VERSION (id, version) VALUES (0, 0)") 88 | var currentVersion = try ctx.query(sql: "SELECT version FROM DB_SCHEMA_VERSION").first?.first?.integerValue ?? 0 89 | 90 | func migrateSchema(v version: Int64, ddl: String) throws { 91 | if currentVersion < version { 92 | let startTime = Date.now 93 | try ctx.transaction { 94 | try ctx.exec(sql: ddl) // perform the DDL operation 95 | // then update the schema version 96 | try ctx.exec(sql: "UPDATE DB_SCHEMA_VERSION SET version = ?", parameters: [SQLValue.integer(version)]) 97 | } 98 | currentVersion = version 99 | logger.log("updated database schema to \(version) in \(startTime.durationToNow)") 100 | } 101 | } 102 | 103 | // the initial creation script for a new database 104 | try migrateSchema(v: 1, ddl: """ 105 | CREATE TABLE DATA_ITEM (ID INTEGER PRIMARY KEY AUTOINCREMENT) 106 | """) 107 | // migrate records to have new description column 108 | try migrateSchema(v: 2, ddl: """ 109 | ALTER TABLE DATA_ITEM ADD COLUMN DESCRIPTION TEXT 110 | """) 111 | ``` 112 | 113 | ### Concurrency 114 | 115 | As a thin layer over a SQLite connection, SkipSQL itself performs no locking or manages threads in any way. It is up to the application layer to set up reader/writer locks, or else just perform all the operations in an isolated context (e.g., using an actor). 116 | 117 | The SQLite guide on [Locking And Concurrency](https://www.sqlite.org/lockingv3.html) can provide additional guidance. 118 | 119 | 120 | ## Implementation 121 | 122 | SkipSQL speaks directly to the low-level SQLite3 C library that is included with all Darwin/iOS/Android operating systems. 123 | On Darwin/iOS, it communicates directly through Swift's C bridging support. 124 | On Android, it uses the [SkipFFI](https://source.skip.tools/skip-ffi) module to interact directly with the underlying sqlite installation on Android. 125 | (For performance and a consistent API, SkipSQL eschews Android's `android.database.sqlite` Java wrapper, and uses JNA to directly access the SQLite C API.) 126 | 127 | ## SQLite Versions 128 | 129 | ### Vendored SQLite Versions 130 | 131 | Because SkipSQL uses the version of SQLite that is shipped with the platform, care should be taken when using recent SQLite features, such as the [`json`](https://sqlite.org/json1.html) function, which is new in SQLite 3.38. This would raise an error on Android versions below 14.0 (API 34) and iOS versions below 16.0. 132 | 133 | Be aware that some very useful SQL features may only have been added to more recent versions of SQLite, such as strict tables (added in 3.37). This may impact the Android API version you can deploy back to, so be sure to test your code on the oldest available Android emulator and iOS simulator for your project. 134 | 135 | Also be aware that the availability of some SQL features are contingent on the compile flags used to build the vendored sqlite implementation provided as part of the OS, such as `SQLITE_ENABLE_JSON1` enabling the various [`json_`](https://www.sqlite.org/json1.html) operations. In the case of Android, be aware that local Robolectric testing will be insufficient to identify any limitations resulting from sqlite compile flags, since local testing will use the local (i.e., macOS-vendored) version of SQLite. Testing against an Android emulator (or device) should be performed when developing new SQL operations. 136 | 137 | 138 | | OS Version | SQLite Version | 139 | |------------------------|----------------| 140 | | Android 9 (API 28) | 3.22 | 141 | | iOS 13 | 3.28 | 142 | | Android 10 (API 30) | 3.28 | 143 | | iOS 14 | 3.32 | 144 | | Android 11 (API 31) | 3.32 | 145 | | Android 12 (API 32) | 3.32 | 146 | | Android 13 (API 33) | 3.32 | 147 | | iOS 15 | 3.36 | 148 | | iOS 16 | 3.39 | 149 | | Android 14 (API 34) | 3.39 | 150 | | Android 15 (API 35) | 3.42 | 151 | | SQLPlus | 3.44 | 152 | 153 | 154 | --- 155 | 156 | ### SQLPlus 157 | 158 | The `skip-sql` framework includes an additional `SQLPlus` module, 159 | which creates a local build with the following extensions enabled: 160 | 161 | - Full Text Search (FTS) 162 | - Encryption (sqlcipher) 163 | 164 | The `SQLPlus` module uses sqlite version 3.44.2, which means 165 | that it will be safe to use newer sqlite features like 166 | the [`json`](https://sqlite.org/json1.html) function, 167 | regardless of the Android API and iOS versions of the 168 | deployment platform. 169 | 170 | This comes at the cost of additional build time for the native libraries, 171 | as well as a larger artifact size (around 1MB on iOS and 4MB on Android). 172 | 173 | #### Using SQLPlus 174 | 175 | The SQLPlus extensions can be used by importing the `SkipSQLPlus` module 176 | and passing `configuration: .plus` to the `SQLContext` constructor, like so: 177 | 178 | ```swift 179 | import SkipSQL 180 | import SkipSQLPlus 181 | 182 | let dbpath = URL.documentsDirectory.appendingPathComponent("db.sqlite") 183 | let db = try SQLContext(path: dbpath.path, flags: [.create, .readWrite], configuration: .plus) 184 | // do something with the database 185 | db.close() 186 | ``` 187 | 188 | #### JSON 189 | 190 | SQLPlus enables the [`json`](https://sqlite.org/json1.html) extensions: 191 | 192 | 193 | ```swift 194 | let sqlplus = SQLContext(configuration: .plus) 195 | try sqlplus.exec(sql: #"CREATE TABLE users (id INTEGER PRIMARY KEY, profile JSON)"#) 196 | 197 | try sqlplus.exec(sql: #"INSERT INTO users (id, profile) VALUES (1, '{"name": "Alice", "age": 30}')"#) 198 | try sqlplus.exec(sql: #"INSERT INTO users (id, profile) VALUES (2, '{"name": "Bob", "age": 25}')"#) 199 | 200 | let j1 = try sqlplus.query(sql: #"SELECT json_extract(profile, '$.name') as name FROM users WHERE id = ?"#, parameters: [.integer(1)]).first 201 | assert j1 == [.text("Alice")] 202 | 203 | let j2 = try sqlplus.query(sql: #"SELECT json_extract(profile, '$.name') as name, json_extract(profile, '$.age') as age FROM users WHERE id = ?"#, parameters: [.integer(2)]).first 204 | assert j2 == [.text("Bob"), .integer(25)] 205 | ``` 206 | 207 | 208 | #### Encryption 209 | 210 | SQLPlus contains the SQLCipher extension, which adds 256 bit AES encryption of database files and other security features like: 211 | 212 | - On-the-fly encryption 213 | - Tamper detection 214 | - Memory sanitization 215 | - Strong key derivation 216 | 217 | SQLCipher is based on SQLite and stable upstream release features are periodically integrated. The extension is documented at the official [SQLCipher site](https://www.zetetic.net/sqlcipher/). It is used by many mobile applications like the [Signal](https://github.com/signalapp/sqlcipher) iOS and Android app to 218 | secure local database files. Cryptographic algorithms are provided by the [LibTomCrypt](https://github.com/libtom/libtomcrypt) C library, which is included alongside the sqlcipher sources. 219 | 220 | An example of creating an encryped database: 221 | 222 | ```swift 223 | import SkipSQL 224 | import SkipSQLPlus 225 | 226 | let dbpath = URL.documentsDirectory.appendingPathComponent("encrypted.sqlite") 227 | let db = try SQLContext(path: dbpath.path, flags: [.create, .readWrite], configuration: .plus) 228 | _ = try db.query(sql: "PRAGMA key = 'password'") 229 | try db.exec(sql: #"CREATE TABLE SOME_TABLE(col)"#) 230 | try db.exec(sql: #"INSERT INTO SOME_TABLE(col) VALUES(?)"#, parameters: [.text("SOME SECRET STRING")]) 231 | try db.close() 232 | ``` 233 | 234 | 235 | ## Building 236 | 237 | This project is a Swift Package Manager module that uses the 238 | [Skip](https://skip.tools) plugin to transpile Swift into Kotlin. 239 | 240 | Building the module requires that Skip be installed using 241 | [Homebrew](https://brew.sh) with `brew install skiptools/skip/skip`. 242 | This will also install the necessary build prerequisites: 243 | Kotlin, Gradle, and the Android build tools. 244 | 245 | ## Testing 246 | 247 | The module can be tested using the standard `swift test` command 248 | or by running the test target for the macOS destination in Xcode, 249 | which will run the Swift tests as well as the transpiled 250 | Kotlin JUnit tests in the Robolectric Android simulation environment. 251 | 252 | Parity testing can be performed with `skip test`, 253 | which will output a table of the test results for both platforms. 254 | 255 | ## Contributing 256 | 257 | We welcome contributions to this package in the form of enhancements and bug fixes. 258 | 259 | The general flow for contributing to this and any other Skip package is: 260 | 261 | 1. Fork this repository and enable actions from the "Actions" tab 262 | 2. Check out your fork locally 263 | 3. When developing alongside a Skip app, add the package to a [shared workspace](https://skip.tools/docs/contributing) to see your changes incorporated in the app 264 | 4. Push your changes to your fork and ensure the CI checks all pass in the Actions tab 265 | 5. Add your name to the Skip [Contributor Agreement](https://github.com/skiptools/clabot-config) 266 | 6. Open a Pull Request from your fork with a description of your changes 267 | 268 | ## License 269 | 270 | This software is licensed under the 271 | [GNU Lesser General Public License v3.0](https://spdx.org/licenses/LGPL-3.0-only.html), 272 | with the following 273 | [linking exception](https://spdx.org/licenses/LGPL-3.0-linking-exception.html) 274 | to clarify that distribution to restricted environments (e.g., app stores) 275 | is permitted: 276 | 277 | > This software is licensed under the LGPL3, included below. 278 | > As a special exception to the GNU Lesser General Public License version 3 279 | > ("LGPL3"), the copyright holders of this Library give you permission to 280 | > convey to a third party a Combined Work that links statically or dynamically 281 | > to this Library without providing any Minimal Corresponding Source or 282 | > Minimal Application Code as set out in 4d or providing the installation 283 | > information set out in section 4e, provided that you comply with the other 284 | > provisions of LGPL3 and provided that you meet, for the Application the 285 | > terms and conditions of the license(s) which apply to the Application. 286 | > Except as stated in this special exception, the provisions of LGPL3 will 287 | > continue to comply in full to this Library. If you modify this Library, you 288 | > may apply this exception to your version of this Library, but you are not 289 | > obliged to do so. If you do not wish to do so, delete this exception 290 | > statement from your version. This exception does not (and cannot) modify any 291 | > license terms which apply to the Application, with which you must still 292 | > comply. 293 | 294 | -------------------------------------------------------------------------------- /Sources/SQLExt/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.3) 2 | 3 | project(sqlext LANGUAGES C) 4 | 5 | file(GLOB_RECURSE SOURCES sqlite/*.c) 6 | add_library(sqlext SHARED ${SOURCES}) 7 | include_directories(sqlext PUBLIC sqlite/) 8 | 9 | # these should match the definitions in the Package.swift 10 | # so the Android build and the Swift build options match 11 | add_compile_definitions(SQLITE_DQS=0) 12 | add_compile_definitions(SQLITE_ENABLE_API_ARMOR) 13 | add_compile_definitions(SQLITE_ENABLE_COLUMN_METADATA) 14 | add_compile_definitions(SQLITE_ENABLE_DBSTAT_VTAB) 15 | add_compile_definitions(SQLITE_ENABLE_FTS3) 16 | add_compile_definitions(SQLITE_ENABLE_FTS3_PARENTHESIS) 17 | add_compile_definitions(SQLITE_ENABLE_FTS3_TOKENIZER) 18 | add_compile_definitions(SQLITE_ENABLE_FTS4) 19 | add_compile_definitions(SQLITE_ENABLE_FTS5) 20 | add_compile_definitions(SQLITE_ENABLE_MEMORY_MANAGEMENT) 21 | add_compile_definitions(SQLITE_ENABLE_PREUPDATE_HOOK) 22 | add_compile_definitions(SQLITE_ENABLE_RTREE) 23 | add_compile_definitions(SQLITE_ENABLE_SESSION) 24 | add_compile_definitions(SQLITE_ENABLE_STMTVTAB) 25 | add_compile_definitions(SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION) 26 | add_compile_definitions(SQLITE_ENABLE_UNLOCK_NOTIFY) 27 | add_compile_definitions(SQLITE_MAX_VARIABLE_NUMBER=250000) 28 | add_compile_definitions(SQLITE_LIKE_DOESNT_MATCH_BLOBS) 29 | add_compile_definitions(SQLITE_OMIT_DEPRECATED) 30 | add_compile_definitions(SQLITE_OMIT_SHARED_CACHE) 31 | add_compile_definitions(SQLITE_SECURE_DELETE) 32 | add_compile_definitions(SQLITE_THREADSAFE=2) 33 | add_compile_definitions(SQLITE_USE_URI) 34 | add_compile_definitions(SQLITE_ENABLE_SNAPSHOT) 35 | add_compile_definitions(SQLITE_HAS_CODEC) 36 | add_compile_definitions(SQLITE_TEMP_STORE=2) 37 | add_compile_definitions(HAVE_GETHOSTUUID=0) 38 | add_compile_definitions(SQLCIPHER_CRYPTO_LIBTOMCRYPT) 39 | 40 | 41 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -frtti -fexceptions") 42 | 43 | #set(CMAKE_FIND_LIBRARY_PREFIXES "lib") 44 | #set(CMAKE_FIND_LIBRARY_SUFFIXES ".so") 45 | 46 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) 47 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) 48 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH) 49 | 50 | set(CMAKE_FIND_DEBUG_MODE ON) 51 | 52 | get_filename_component(CMAKE_PARENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY) 53 | #message("CMAKE FINDING LIBRARY FOR ABI: ${ANDROID_ABI} in: ${CMAKE_PARENT_SOURCE_DIR} for build type: ${CMAKE_BUILD_TYPE}") 54 | 55 | if(CMAKE_BUILD_TYPE STREQUAL "Release") 56 | set(BUILD_MODE "Release") 57 | elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") 58 | set(BUILD_MODE "Release") 59 | elseif(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel") 60 | set(BUILD_MODE "Release") 61 | elseif(CMAKE_BUILD_TYPE STREQUAL "Debug") 62 | set(BUILD_MODE "Debug") 63 | else() 64 | message(WARNING "CMAKE_BUILD_TYPE is set to an unsupported value: ${CMAKE_BUILD_TYPE}. Defaulting to Debug.") 65 | set(BUILD_MODE "Debug") 66 | endif() 67 | 68 | string(TOLOWER "${BUILD_MODE}" BUILD_MODE_LOWER) 69 | 70 | #message("CHECKING CMAKE LIBRARY: ${CMAKE_PARENT_SOURCE_DIR}/../LibTomCrypt/") 71 | 72 | find_library(TOMCRYPT 73 | NAMES tomcrypt 74 | REQUIRED 75 | PATHS 76 | 77 | # the output paths for the LibTomCrypt project 78 | # it would be nice if we could discover this automatically based on the gradle dependency 79 | # after updating to the android-gradle-plugin 8.5.0, the output has moved to mergeDebugNativeLibs/mergeReleaseNativeLibs 80 | #${CMAKE_PARENT_SOURCE_DIR}/../LibTomCrypt/build/intermediates/merged_native_libs/${BUILD_MODE_LOWER}/out/lib/${ANDROID_ABI}/ 81 | ${CMAKE_PARENT_SOURCE_DIR}/../LibTomCrypt/build/intermediates/merged_native_libs/${BUILD_MODE_LOWER}/merge${BUILD_MODE}NativeLibs/out/lib/${ANDROID_ABI}/ 82 | ${CMAKE_PARENT_SOURCE_DIR}/../LibTomCrypt/.build/*/intermediates/merged_native_libs/${BUILD_MODE_LOWER}/merge${BUILD_MODE}NativeLibs/out/lib/${ANDROID_ABI}/ 83 | 84 | NO_DEFAULT_PATH 85 | NO_CMAKE_FIND_ROOT_PATH 86 | ) 87 | 88 | 89 | #message("CMAKE FIND LIBRARY FOR: ${ANDROID_ABI}: ${TOMCRYPT}") 90 | 91 | target_link_libraries(sqlext ${TOMCRYPT}) 92 | 93 | # sqlite has calls to __android_log_print 94 | target_link_libraries(sqlext log) 95 | 96 | # support 16 KB page sizes: https://developer.android.com/guide/practices/page-sizes 97 | target_link_options(${CMAKE_PROJECT_NAME} PRIVATE "-Wl,-z,max-page-size=16384") 98 | -------------------------------------------------------------------------------- /Sources/SQLExt/Skip/skip.yml: -------------------------------------------------------------------------------- 1 | # This skip.yml file will generate a build.gradle.kts that uses the CMakeLists.txt for a native build. 2 | # 3 | # android { 4 | # namespace = group as String 5 | # compileSdk = libs.versions.android.sdk.compile.get().toInt() 6 | # defaultConfig { 7 | # minSdk = libs.versions.android.sdk.min.get().toInt() 8 | # } 9 | # externalNativeBuild { 10 | # cmake { 11 | # path = file("ext/CMakeLists.txt") 12 | # } 13 | # } 14 | # } 15 | 16 | # the blocks to add to the build.gradle.kts 17 | build: 18 | contents: 19 | - block: 'android' 20 | export: false 21 | contents: 22 | - block: 'externalNativeBuild' 23 | contents: 24 | - block: 'cmake' 25 | contents: 26 | - 'path = file("ext/CMakeLists.txt")' 27 | - block: 'defaultConfig' 28 | contents: 29 | - block: 'externalNativeBuild' 30 | contents: 31 | - block: 'cmake' 32 | contents: 33 | # activating trace helps diagnose issues with not finding build dependencies 34 | #- 'arguments += listOf("--trace")' 35 | -------------------------------------------------------------------------------- /Sources/SQLExt/sqlite/tomcrypt.h: -------------------------------------------------------------------------------- 1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */ 2 | /* SPDX-License-Identifier: Unlicense */ 3 | 4 | #ifndef TOMCRYPT_H_ 5 | #define TOMCRYPT_H_ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | /* use configuration data */ 16 | #include "tomcrypt_custom.h" 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | /* version */ 23 | #define CRYPT 0x0118 24 | #define SCRYPT "1.18.2-develop" 25 | 26 | /* max size of either a cipher/hash block or symmetric key [largest of the two] */ 27 | #define MAXBLOCKSIZE 144 28 | 29 | #ifndef TAB_SIZE 30 | /* descriptor table size */ 31 | #define TAB_SIZE 34 32 | #endif 33 | 34 | /* error codes [will be expanded in future releases] */ 35 | enum { 36 | CRYPT_OK=0, /* Result OK */ 37 | CRYPT_ERROR, /* Generic Error */ 38 | CRYPT_NOP, /* Not a failure but no operation was performed */ 39 | 40 | CRYPT_INVALID_KEYSIZE, /* Invalid key size given */ 41 | CRYPT_INVALID_ROUNDS, /* Invalid number of rounds */ 42 | CRYPT_FAIL_TESTVECTOR, /* Algorithm failed test vectors */ 43 | 44 | CRYPT_BUFFER_OVERFLOW, /* Not enough space for output */ 45 | CRYPT_INVALID_PACKET, /* Invalid input packet given */ 46 | 47 | CRYPT_INVALID_PRNGSIZE, /* Invalid number of bits for a PRNG */ 48 | CRYPT_ERROR_READPRNG, /* Could not read enough from PRNG */ 49 | 50 | CRYPT_INVALID_CIPHER, /* Invalid cipher specified */ 51 | CRYPT_INVALID_HASH, /* Invalid hash specified */ 52 | CRYPT_INVALID_PRNG, /* Invalid PRNG specified */ 53 | 54 | CRYPT_MEM, /* Out of memory */ 55 | 56 | CRYPT_PK_TYPE_MISMATCH, /* Not equivalent types of PK keys */ 57 | CRYPT_PK_NOT_PRIVATE, /* Requires a private PK key */ 58 | 59 | CRYPT_INVALID_ARG, /* Generic invalid argument */ 60 | CRYPT_FILE_NOTFOUND, /* File Not Found */ 61 | 62 | CRYPT_PK_INVALID_TYPE, /* Invalid type of PK key */ 63 | 64 | CRYPT_OVERFLOW, /* An overflow of a value was detected/prevented */ 65 | 66 | CRYPT_PK_ASN1_ERROR, /* An error occurred while en- or decoding ASN.1 data */ 67 | 68 | CRYPT_INPUT_TOO_LONG, /* The input was longer than expected. */ 69 | 70 | CRYPT_PK_INVALID_SIZE, /* Invalid size input for PK parameters */ 71 | 72 | CRYPT_INVALID_PRIME_SIZE,/* Invalid size of prime requested */ 73 | CRYPT_PK_INVALID_PADDING, /* Invalid padding on input */ 74 | 75 | CRYPT_HASH_OVERFLOW /* Hash applied to too many bits */ 76 | }; 77 | 78 | #include "tomcrypt_cfg.h" 79 | #include "tomcrypt_macros.h" 80 | #include "tomcrypt_cipher.h" 81 | #include "tomcrypt_hash.h" 82 | #include "tomcrypt_mac.h" 83 | #include "tomcrypt_prng.h" 84 | #include "tomcrypt_pk.h" 85 | #include "tomcrypt_math.h" 86 | #include "tomcrypt_misc.h" 87 | #include "tomcrypt_argchk.h" 88 | #include "tomcrypt_pkcs.h" 89 | 90 | #ifdef __cplusplus 91 | } 92 | #endif 93 | 94 | #endif /* TOMCRYPT_H_ */ 95 | 96 | -------------------------------------------------------------------------------- /Sources/SQLExt/sqlite/tomcrypt_argchk.h: -------------------------------------------------------------------------------- 1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */ 2 | /* SPDX-License-Identifier: Unlicense */ 3 | 4 | /* Defines the LTC_ARGCHK macro used within the library */ 5 | /* ARGTYPE is defined in tomcrypt_cfg.h */ 6 | 7 | /* ARGTYPE is per default defined to 0 */ 8 | #if ARGTYPE == 0 9 | 10 | #include 11 | 12 | LTC_NORETURN void crypt_argchk(const char *v, const char *s, int d); 13 | #define LTC_ARGCHK(x) do { if (!(x)) { crypt_argchk(#x, __FILE__, __LINE__); } }while(0) 14 | #define LTC_ARGCHKVD(x) do { if (!(x)) { crypt_argchk(#x, __FILE__, __LINE__); } }while(0) 15 | 16 | #elif ARGTYPE == 1 17 | 18 | /* fatal type of error */ 19 | #define LTC_ARGCHK(x) assert((x)) 20 | #define LTC_ARGCHKVD(x) LTC_ARGCHK(x) 21 | 22 | #elif ARGTYPE == 2 23 | 24 | #define LTC_ARGCHK(x) if (!(x)) { fprintf(stderr, "\nwarning: ARGCHK failed at %s:%d\n", __FILE__, __LINE__); } 25 | #define LTC_ARGCHKVD(x) LTC_ARGCHK(x) 26 | 27 | #elif ARGTYPE == 3 28 | 29 | #define LTC_ARGCHK(x) LTC_UNUSED_PARAM(x) 30 | #define LTC_ARGCHKVD(x) LTC_ARGCHK(x) 31 | 32 | #elif ARGTYPE == 4 33 | 34 | #define LTC_ARGCHK(x) if (!(x)) return CRYPT_INVALID_ARG; 35 | #define LTC_ARGCHKVD(x) if (!(x)) return; 36 | 37 | #endif 38 | 39 | -------------------------------------------------------------------------------- /Sources/SQLExt/sqlite/tomcrypt_cfg.h: -------------------------------------------------------------------------------- 1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */ 2 | /* SPDX-License-Identifier: Unlicense */ 3 | 4 | /* This is the build config file. 5 | * 6 | * With this you can setup what to include/exclude automatically during any build. Just comment 7 | * out the line that #define's the word for the thing you want to remove. phew! 8 | */ 9 | 10 | #ifndef TOMCRYPT_CFG_H 11 | #define TOMCRYPT_CFG_H 12 | 13 | #if defined(_WIN32) || defined(_MSC_VER) 14 | #define LTC_CALL __cdecl 15 | #elif !defined(LTC_CALL) 16 | #define LTC_CALL 17 | #endif 18 | 19 | #ifndef LTC_EXPORT 20 | #define LTC_EXPORT 21 | #endif 22 | 23 | /* certain platforms use macros for these, making the prototypes broken */ 24 | #ifndef LTC_NO_PROTOTYPES 25 | 26 | /* you can change how memory allocation works ... */ 27 | LTC_EXPORT void * LTC_CALL XMALLOC(size_t n); 28 | LTC_EXPORT void * LTC_CALL XREALLOC(void *p, size_t n); 29 | LTC_EXPORT void * LTC_CALL XCALLOC(size_t n, size_t s); 30 | LTC_EXPORT void LTC_CALL XFREE(void *p); 31 | 32 | LTC_EXPORT void LTC_CALL XQSORT(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *)); 33 | 34 | 35 | /* change the clock function too */ 36 | LTC_EXPORT clock_t LTC_CALL XCLOCK(void); 37 | 38 | /* various other functions */ 39 | LTC_EXPORT void * LTC_CALL XMEMCPY(void *dest, const void *src, size_t n); 40 | LTC_EXPORT int LTC_CALL XMEMCMP(const void *s1, const void *s2, size_t n); 41 | LTC_EXPORT void * LTC_CALL XMEMSET(void *s, int c, size_t n); 42 | 43 | LTC_EXPORT int LTC_CALL XSTRCMP(const char *s1, const char *s2); 44 | 45 | #endif 46 | 47 | /* some compilers do not like "inline" (or maybe "static inline"), namely: HP cc, IBM xlc */ 48 | #if defined(__GNUC__) || defined(__xlc__) 49 | #define LTC_INLINE __inline__ 50 | #elif defined(_MSC_VER) || defined(__HP_cc) 51 | #define LTC_INLINE __inline 52 | #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L 53 | #define LTC_INLINE inline 54 | #else 55 | #define LTC_INLINE 56 | #endif 57 | 58 | #if defined(__clang__) || defined(__GNUC_MINOR__) 59 | #define LTC_NORETURN __attribute__ ((noreturn)) 60 | #elif defined(_MSC_VER) 61 | #define LTC_NORETURN __declspec(noreturn) 62 | #else 63 | #define LTC_NORETURN 64 | #endif 65 | 66 | /* type of argument checking, 0=default, 1=fatal and 2=error+continue, 3=nothing */ 67 | #ifndef ARGTYPE 68 | #define ARGTYPE 0 69 | #endif 70 | 71 | #undef LTC_ENCRYPT 72 | #define LTC_ENCRYPT 0 73 | #undef LTC_DECRYPT 74 | #define LTC_DECRYPT 1 75 | 76 | /* Controls endianess and size of registers. Leave uncommented to get platform neutral [slower] code 77 | * 78 | * Note: in order to use the optimized macros your platform must support unaligned 32 and 64 bit read/writes. 79 | * The x86 platforms allow this but some others [ARM for instance] do not. On those platforms you **MUST** 80 | * use the portable [slower] macros. 81 | */ 82 | /* detect x86/i386/ARM 32bit */ 83 | #if defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_ARM) 84 | #define ENDIAN_LITTLE 85 | #define ENDIAN_32BITWORD 86 | #define LTC_FAST 87 | #endif 88 | 89 | /* detect amd64/x64/arm64 */ 90 | #if defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) || defined(_M_ARM64) 91 | #define ENDIAN_LITTLE 92 | #define ENDIAN_64BITWORD 93 | #define LTC_FAST 94 | #if defined(__SSE4_1__) 95 | #if __SSE4_1__ == 1 96 | #define LTC_AMD64_SSE4_1 97 | #endif 98 | #endif 99 | #endif 100 | 101 | /* detect PPC32 */ 102 | #if defined(LTC_PPC32) 103 | #define ENDIAN_BIG 104 | #define ENDIAN_32BITWORD 105 | #define LTC_FAST 106 | #endif 107 | 108 | /* detects MIPS R5900 processors (PS2) */ 109 | #if (defined(__R5900) || defined(R5900) || defined(__R5900__)) && (defined(_mips) || defined(__mips__) || defined(mips)) 110 | #define ENDIAN_64BITWORD 111 | #if defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) 112 | #define ENDIAN_BIG 113 | #else 114 | #define ENDIAN_LITTLE 115 | #endif 116 | #endif 117 | 118 | /* detect AIX */ 119 | #if defined(_AIX) && defined(_BIG_ENDIAN) 120 | #define ENDIAN_BIG 121 | #if defined(__LP64__) || defined(_ARCH_PPC64) 122 | #define ENDIAN_64BITWORD 123 | #else 124 | #define ENDIAN_32BITWORD 125 | #endif 126 | #endif 127 | 128 | /* detect HP-UX */ 129 | #if defined(__hpux) || defined(__hpux__) 130 | #define ENDIAN_BIG 131 | #if defined(__ia64) || defined(__ia64__) || defined(__LP64__) 132 | #define ENDIAN_64BITWORD 133 | #else 134 | #define ENDIAN_32BITWORD 135 | #endif 136 | #endif 137 | 138 | /* detect Apple OS X */ 139 | #if defined(__APPLE__) && defined(__MACH__) 140 | #if defined(__LITTLE_ENDIAN__) || defined(__x86_64__) 141 | #define ENDIAN_LITTLE 142 | #else 143 | #define ENDIAN_BIG 144 | #endif 145 | #if defined(__LP64__) || defined(__x86_64__) 146 | #define ENDIAN_64BITWORD 147 | #else 148 | #define ENDIAN_32BITWORD 149 | #endif 150 | #endif 151 | 152 | /* detect SPARC and SPARC64 */ 153 | #if defined(__sparc__) || defined(__sparc) 154 | #define ENDIAN_BIG 155 | #if defined(__arch64__) || defined(__sparcv9) || defined(__sparc_v9__) 156 | #define ENDIAN_64BITWORD 157 | #else 158 | #define ENDIAN_32BITWORD 159 | #endif 160 | #endif 161 | 162 | /* detect IBM S390(x) */ 163 | #if defined(__s390x__) || defined(__s390__) 164 | #define ENDIAN_BIG 165 | #if defined(__s390x__) 166 | #define ENDIAN_64BITWORD 167 | #else 168 | #define ENDIAN_32BITWORD 169 | #endif 170 | #endif 171 | 172 | /* detect PPC64 */ 173 | #if defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) 174 | #define ENDIAN_64BITWORD 175 | #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 176 | #define ENDIAN_BIG 177 | #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 178 | #define ENDIAN_LITTLE 179 | #endif 180 | #define LTC_FAST 181 | #endif 182 | 183 | /* endianness fallback */ 184 | #if !defined(ENDIAN_BIG) && !defined(ENDIAN_LITTLE) 185 | #if defined(_BYTE_ORDER) && _BYTE_ORDER == _BIG_ENDIAN || \ 186 | defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \ 187 | defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ || \ 188 | defined(__BIG_ENDIAN__) || \ 189 | defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \ 190 | defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) || \ 191 | defined(__m68k__) 192 | #define ENDIAN_BIG 193 | #elif defined(_BYTE_ORDER) && _BYTE_ORDER == _LITTLE_ENDIAN || \ 194 | defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || \ 195 | defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || \ 196 | defined(__LITTLE_ENDIAN__) || \ 197 | defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \ 198 | defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || \ 199 | defined(_M_ARM) || defined(_M_ARM64) 200 | #define ENDIAN_LITTLE 201 | #else 202 | #error Cannot detect endianness 203 | #endif 204 | #endif 205 | 206 | /* ulong64: 64-bit data type */ 207 | #ifdef _MSC_VER 208 | #define CONST64(n) n ## ui64 209 | typedef unsigned __int64 ulong64; 210 | typedef __int64 long64; 211 | #else 212 | #define CONST64(n) n ## uLL 213 | typedef unsigned long long ulong64; 214 | typedef long long long64; 215 | #endif 216 | 217 | /* ulong32: "32-bit at least" data type */ 218 | #if defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) || \ 219 | defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) || \ 220 | defined(__s390x__) || defined(__arch64__) || defined(__aarch64__) || \ 221 | defined(__sparcv9) || defined(__sparc_v9__) || defined(__sparc64__) || \ 222 | defined(__ia64) || defined(__ia64__) || defined(__itanium__) || defined(_M_IA64) || \ 223 | defined(__LP64__) || defined(_LP64) || defined(__64BIT__) || defined(_M_ARM64) 224 | typedef unsigned ulong32; 225 | #if !defined(ENDIAN_64BITWORD) && !defined(ENDIAN_32BITWORD) 226 | #define ENDIAN_64BITWORD 227 | #endif 228 | #else 229 | typedef unsigned long ulong32; 230 | #if !defined(ENDIAN_64BITWORD) && !defined(ENDIAN_32BITWORD) 231 | #define ENDIAN_32BITWORD 232 | #endif 233 | #endif 234 | 235 | #if defined(ENDIAN_64BITWORD) && !defined(_MSC_VER) 236 | typedef unsigned long long ltc_mp_digit; 237 | #else 238 | typedef unsigned long ltc_mp_digit; 239 | #endif 240 | 241 | /* No asm is a quick way to disable anything "not portable" */ 242 | #ifdef LTC_NO_ASM 243 | #define ENDIAN_NEUTRAL 244 | #undef ENDIAN_32BITWORD 245 | #undef ENDIAN_64BITWORD 246 | #undef LTC_FAST 247 | #define LTC_NO_BSWAP 248 | #define LTC_NO_ROLC 249 | #define LTC_NO_ROTATE 250 | #endif 251 | 252 | /* No LTC_FAST if: explicitly disabled OR non-gcc/non-clang compiler OR old gcc OR using -ansi -std=c99 */ 253 | #if defined(LTC_NO_FAST) || (__GNUC__ < 4) || defined(__STRICT_ANSI__) 254 | #undef LTC_FAST 255 | #endif 256 | 257 | #ifdef LTC_FAST 258 | #define LTC_FAST_TYPE_PTR_CAST(x) ((LTC_FAST_TYPE*)(void*)(x)) 259 | #ifdef ENDIAN_64BITWORD 260 | typedef ulong64 __attribute__((__may_alias__)) LTC_FAST_TYPE; 261 | #else 262 | typedef ulong32 __attribute__((__may_alias__)) LTC_FAST_TYPE; 263 | #endif 264 | #endif 265 | 266 | #if !defined(ENDIAN_NEUTRAL) && (defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE)) && !(defined(ENDIAN_32BITWORD) || defined(ENDIAN_64BITWORD)) 267 | #error You must specify a word size as well as endianess in tomcrypt_cfg.h 268 | #endif 269 | 270 | #if !(defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE)) 271 | #define ENDIAN_NEUTRAL 272 | #endif 273 | 274 | #if (defined(ENDIAN_32BITWORD) && defined(ENDIAN_64BITWORD)) 275 | #error Cannot be 32 and 64 bit words... 276 | #endif 277 | 278 | /* gcc 4.3 and up has a bswap builtin; detect it by gcc version. 279 | * clang also supports the bswap builtin, and although clang pretends 280 | * to be gcc (macro-wise, anyway), clang pretends to be a version 281 | * prior to gcc 4.3, so we can't detect bswap that way. Instead, 282 | * clang has a __has_builtin mechanism that can be used to check 283 | * for builtins: 284 | * http://clang.llvm.org/docs/LanguageExtensions.html#feature_check */ 285 | #ifndef __has_builtin 286 | #define __has_builtin(x) 0 287 | #endif 288 | #if !defined(LTC_NO_BSWAP) && defined(__GNUC__) && \ 289 | ((__GNUC__ * 100 + __GNUC_MINOR__ >= 403) || \ 290 | (__has_builtin(__builtin_bswap32) && __has_builtin(__builtin_bswap64))) 291 | #define LTC_HAVE_BSWAP_BUILTIN 292 | #endif 293 | 294 | #if !defined(LTC_NO_ROTATE) && (__has_builtin(__builtin_rotateleft32) && __has_builtin(__builtin_rotateright32)) 295 | #define LTC_HAVE_ROTATE_BUILTIN 296 | #endif 297 | 298 | #if defined(__GNUC__) 299 | #define LTC_ALIGN(n) __attribute__((aligned(n))) 300 | #else 301 | #define LTC_ALIGN(n) 302 | #endif 303 | 304 | /* Choose Windows Vista as minimum Version if we're compiling with at least VS2019 305 | * This is done in order to test the bcrypt RNG and can still be overridden by the user. */ 306 | #if defined(_MSC_VER) && _MSC_VER >= 1920 307 | # ifndef _WIN32_WINNT 308 | # define _WIN32_WINNT 0x0600 309 | # endif 310 | # ifndef WINVER 311 | # define WINVER 0x0600 312 | # endif 313 | #endif 314 | 315 | #if defined(_MSC_VER) && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 && !defined(LTC_WIN32_BCRYPT) 316 | # define LTC_WIN32_BCRYPT 317 | #endif 318 | 319 | /* Define `LTC_NO_NULL_TERMINATION_CHECK` in the user code 320 | * before including `tomcrypt.h` to disable this functionality. 321 | */ 322 | #if defined(__GNUC__) && __GNUC__ >= 4 && !defined(LTC_NO_NULL_TERMINATION_CHECK) 323 | # define LTC_NULL_TERMINATED __attribute__((sentinel)) 324 | #else 325 | # define LTC_NULL_TERMINATED 326 | #endif 327 | 328 | #if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 405) 329 | # define LTC_DEPRECATED(s) __attribute__((deprecated("replaced by " #s))) 330 | # define PRIVATE_LTC_DEPRECATED_PRAGMA(s) _Pragma(#s) 331 | # define LTC_DEPRECATED_PRAGMA(s) PRIVATE_LTC_DEPRECATED_PRAGMA(GCC warning s) 332 | #elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 301) 333 | # define LTC_DEPRECATED(s) __attribute__((deprecated)) 334 | # define LTC_DEPRECATED_PRAGMA(s) 335 | #elif defined(_MSC_VER) && _MSC_VER >= 1500 336 | /* supported since Visual Studio 2008 */ 337 | # define LTC_DEPRECATED(s) __declspec(deprecated("replaced by " #s)) 338 | # define LTC_DEPRECATED_PRAGMA(s) __pragma(message(s)) 339 | #else 340 | # define LTC_DEPRECATED(s) 341 | # define LTC_DEPRECATED_PRAGMA(s) 342 | #endif 343 | 344 | #endif /* TOMCRYPT_CFG_H */ 345 | -------------------------------------------------------------------------------- /Sources/SQLExt/sqlite/tomcrypt_hash.h: -------------------------------------------------------------------------------- 1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */ 2 | /* SPDX-License-Identifier: Unlicense */ 3 | 4 | /* ---- HASH FUNCTIONS ---- */ 5 | #if defined(LTC_SHA3) || defined(LTC_KECCAK) 6 | struct sha3_state { 7 | ulong64 saved; /* the portion of the input message that we didn't consume yet */ 8 | ulong64 s[25]; 9 | unsigned char sb[25 * 8]; /* used for storing `ulong64 s[25]` as little-endian bytes */ 10 | unsigned short byte_index; /* 0..7--the next byte after the set one (starts from 0; 0--none are buffered) */ 11 | unsigned short word_index; /* 0..24--the next word to integrate input (starts from 0) */ 12 | unsigned short capacity_words; /* the double size of the hash output in words (e.g. 16 for Keccak 512) */ 13 | unsigned short xof_flag; 14 | }; 15 | #endif 16 | 17 | #ifdef LTC_SHA512 18 | struct sha512_state { 19 | ulong64 length, state[8]; 20 | unsigned long curlen; 21 | unsigned char buf[128]; 22 | }; 23 | #endif 24 | 25 | #ifdef LTC_SHA256 26 | struct sha256_state { 27 | ulong64 length; 28 | ulong32 state[8], curlen; 29 | unsigned char buf[64]; 30 | }; 31 | #endif 32 | 33 | #ifdef LTC_SHA1 34 | struct sha1_state { 35 | ulong64 length; 36 | ulong32 state[5], curlen; 37 | unsigned char buf[64]; 38 | }; 39 | #endif 40 | 41 | #ifdef LTC_MD5 42 | struct md5_state { 43 | ulong64 length; 44 | ulong32 state[4], curlen; 45 | unsigned char buf[64]; 46 | }; 47 | #endif 48 | 49 | #ifdef LTC_MD4 50 | struct md4_state { 51 | ulong64 length; 52 | ulong32 state[4], curlen; 53 | unsigned char buf[64]; 54 | }; 55 | #endif 56 | 57 | #ifdef LTC_TIGER 58 | struct tiger_state { 59 | ulong64 state[3], length; 60 | unsigned long curlen; 61 | unsigned char buf[64]; 62 | }; 63 | #endif 64 | 65 | #ifdef LTC_MD2 66 | struct md2_state { 67 | unsigned char chksum[16], X[48], buf[16]; 68 | unsigned long curlen; 69 | }; 70 | #endif 71 | 72 | #ifdef LTC_RIPEMD128 73 | struct rmd128_state { 74 | ulong64 length; 75 | unsigned char buf[64]; 76 | ulong32 curlen, state[4]; 77 | }; 78 | #endif 79 | 80 | #ifdef LTC_RIPEMD160 81 | struct rmd160_state { 82 | ulong64 length; 83 | unsigned char buf[64]; 84 | ulong32 curlen, state[5]; 85 | }; 86 | #endif 87 | 88 | #ifdef LTC_RIPEMD256 89 | struct rmd256_state { 90 | ulong64 length; 91 | unsigned char buf[64]; 92 | ulong32 curlen, state[8]; 93 | }; 94 | #endif 95 | 96 | #ifdef LTC_RIPEMD320 97 | struct rmd320_state { 98 | ulong64 length; 99 | unsigned char buf[64]; 100 | ulong32 curlen, state[10]; 101 | }; 102 | #endif 103 | 104 | #ifdef LTC_WHIRLPOOL 105 | struct whirlpool_state { 106 | ulong64 length, state[8]; 107 | unsigned char buf[64]; 108 | ulong32 curlen; 109 | }; 110 | #endif 111 | 112 | #ifdef LTC_CHC_HASH 113 | struct chc_state { 114 | ulong64 length; 115 | unsigned char state[MAXBLOCKSIZE], buf[MAXBLOCKSIZE]; 116 | ulong32 curlen; 117 | }; 118 | #endif 119 | 120 | #ifdef LTC_BLAKE2S 121 | struct blake2s_state { 122 | ulong32 h[8]; 123 | ulong32 t[2]; 124 | ulong32 f[2]; 125 | unsigned char buf[64]; 126 | unsigned long curlen; 127 | unsigned long outlen; 128 | unsigned char last_node; 129 | }; 130 | #endif 131 | 132 | #ifdef LTC_BLAKE2B 133 | struct blake2b_state { 134 | ulong64 h[8]; 135 | ulong64 t[2]; 136 | ulong64 f[2]; 137 | unsigned char buf[128]; 138 | unsigned long curlen; 139 | unsigned long outlen; 140 | unsigned char last_node; 141 | }; 142 | #endif 143 | 144 | typedef union Hash_state { 145 | char dummy[1]; 146 | #ifdef LTC_CHC_HASH 147 | struct chc_state chc; 148 | #endif 149 | #ifdef LTC_WHIRLPOOL 150 | struct whirlpool_state whirlpool; 151 | #endif 152 | #if defined(LTC_SHA3) || defined(LTC_KECCAK) 153 | struct sha3_state sha3; 154 | #endif 155 | #ifdef LTC_SHA512 156 | struct sha512_state sha512; 157 | #endif 158 | #ifdef LTC_SHA256 159 | struct sha256_state sha256; 160 | #endif 161 | #ifdef LTC_SHA1 162 | struct sha1_state sha1; 163 | #endif 164 | #ifdef LTC_MD5 165 | struct md5_state md5; 166 | #endif 167 | #ifdef LTC_MD4 168 | struct md4_state md4; 169 | #endif 170 | #ifdef LTC_MD2 171 | struct md2_state md2; 172 | #endif 173 | #ifdef LTC_TIGER 174 | struct tiger_state tiger; 175 | #endif 176 | #ifdef LTC_RIPEMD128 177 | struct rmd128_state rmd128; 178 | #endif 179 | #ifdef LTC_RIPEMD160 180 | struct rmd160_state rmd160; 181 | #endif 182 | #ifdef LTC_RIPEMD256 183 | struct rmd256_state rmd256; 184 | #endif 185 | #ifdef LTC_RIPEMD320 186 | struct rmd320_state rmd320; 187 | #endif 188 | #ifdef LTC_BLAKE2S 189 | struct blake2s_state blake2s; 190 | #endif 191 | #ifdef LTC_BLAKE2B 192 | struct blake2b_state blake2b; 193 | #endif 194 | 195 | void *data; 196 | } hash_state; 197 | 198 | /** hash descriptor */ 199 | extern struct ltc_hash_descriptor { 200 | /** name of hash */ 201 | const char *name; 202 | /** internal ID */ 203 | unsigned char ID; 204 | /** Size of digest in octets */ 205 | unsigned long hashsize; 206 | /** Input block size in octets */ 207 | unsigned long blocksize; 208 | /** ASN.1 OID */ 209 | unsigned long OID[16]; 210 | /** Length of DER encoding */ 211 | unsigned long OIDlen; 212 | 213 | /** Init a hash state 214 | @param hash The hash to initialize 215 | @return CRYPT_OK if successful 216 | */ 217 | int (*init)(hash_state *hash); 218 | /** Process a block of data 219 | @param hash The hash state 220 | @param in The data to hash 221 | @param inlen The length of the data (octets) 222 | @return CRYPT_OK if successful 223 | */ 224 | int (*process)(hash_state *hash, const unsigned char *in, unsigned long inlen); 225 | /** Produce the digest and store it 226 | @param hash The hash state 227 | @param out [out] The destination of the digest 228 | @return CRYPT_OK if successful 229 | */ 230 | int (*done)(hash_state *hash, unsigned char *out); 231 | /** Self-test 232 | @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled 233 | */ 234 | int (*test)(void); 235 | 236 | /* accelerated hmac callback: if you need to-do multiple packets just use the generic hmac_memory and provide a hash callback */ 237 | int (*hmac_block)(const unsigned char *key, unsigned long keylen, 238 | const unsigned char *in, unsigned long inlen, 239 | unsigned char *out, unsigned long *outlen); 240 | 241 | } hash_descriptor[]; 242 | 243 | #ifdef LTC_CHC_HASH 244 | int chc_register(int cipher); 245 | int chc_init(hash_state * md); 246 | int chc_process(hash_state * md, const unsigned char *in, unsigned long inlen); 247 | int chc_done(hash_state * md, unsigned char *out); 248 | int chc_test(void); 249 | extern const struct ltc_hash_descriptor chc_desc; 250 | #endif 251 | 252 | #ifdef LTC_WHIRLPOOL 253 | int whirlpool_init(hash_state * md); 254 | int whirlpool_process(hash_state * md, const unsigned char *in, unsigned long inlen); 255 | int whirlpool_done(hash_state * md, unsigned char *out); 256 | int whirlpool_test(void); 257 | extern const struct ltc_hash_descriptor whirlpool_desc; 258 | #endif 259 | 260 | #if defined(LTC_SHA3) || defined(LTC_KECCAK) 261 | /* sha3_NNN_init are shared by SHA3 and KECCAK */ 262 | int sha3_512_init(hash_state * md); 263 | int sha3_384_init(hash_state * md); 264 | int sha3_256_init(hash_state * md); 265 | int sha3_224_init(hash_state * md); 266 | /* sha3_process is the same for all variants of SHA3 + KECCAK */ 267 | int sha3_process(hash_state * md, const unsigned char *in, unsigned long inlen); 268 | #endif 269 | 270 | #ifdef LTC_SHA3 271 | int sha3_512_test(void); 272 | extern const struct ltc_hash_descriptor sha3_512_desc; 273 | int sha3_384_test(void); 274 | extern const struct ltc_hash_descriptor sha3_384_desc; 275 | int sha3_256_test(void); 276 | extern const struct ltc_hash_descriptor sha3_256_desc; 277 | int sha3_224_test(void); 278 | extern const struct ltc_hash_descriptor sha3_224_desc; 279 | int sha3_done(hash_state *md, unsigned char *out); 280 | /* SHAKE128 + SHAKE256 */ 281 | int sha3_shake_init(hash_state *md, int num); 282 | #define sha3_shake_process(a,b,c) sha3_process(a,b,c) 283 | int sha3_shake_done(hash_state *md, unsigned char *out, unsigned long outlen); 284 | int sha3_shake_test(void); 285 | int sha3_shake_memory(int num, const unsigned char *in, unsigned long inlen, unsigned char *out, const unsigned long *outlen); 286 | #endif 287 | 288 | #ifdef LTC_KECCAK 289 | #define keccak_512_init(a) sha3_512_init(a) 290 | #define keccak_384_init(a) sha3_384_init(a) 291 | #define keccak_256_init(a) sha3_256_init(a) 292 | #define keccak_224_init(a) sha3_224_init(a) 293 | #define keccak_process(a,b,c) sha3_process(a,b,c) 294 | extern const struct ltc_hash_descriptor keccak_512_desc; 295 | int keccak_512_test(void); 296 | extern const struct ltc_hash_descriptor keccak_384_desc; 297 | int keccak_384_test(void); 298 | extern const struct ltc_hash_descriptor keccak_256_desc; 299 | int keccak_256_test(void); 300 | extern const struct ltc_hash_descriptor keccak_224_desc; 301 | int keccak_224_test(void); 302 | int keccak_done(hash_state *md, unsigned char *out); 303 | #endif 304 | 305 | #ifdef LTC_SHA512 306 | int sha512_init(hash_state * md); 307 | int sha512_process(hash_state * md, const unsigned char *in, unsigned long inlen); 308 | int sha512_done(hash_state * md, unsigned char *out); 309 | int sha512_test(void); 310 | extern const struct ltc_hash_descriptor sha512_desc; 311 | #endif 312 | 313 | #ifdef LTC_SHA384 314 | #ifndef LTC_SHA512 315 | #error LTC_SHA512 is required for LTC_SHA384 316 | #endif 317 | int sha384_init(hash_state * md); 318 | #define sha384_process sha512_process 319 | int sha384_done(hash_state * md, unsigned char *out); 320 | int sha384_test(void); 321 | extern const struct ltc_hash_descriptor sha384_desc; 322 | #endif 323 | 324 | #ifdef LTC_SHA512_256 325 | #ifndef LTC_SHA512 326 | #error LTC_SHA512 is required for LTC_SHA512_256 327 | #endif 328 | int sha512_256_init(hash_state * md); 329 | #define sha512_256_process sha512_process 330 | int sha512_256_done(hash_state * md, unsigned char *out); 331 | int sha512_256_test(void); 332 | extern const struct ltc_hash_descriptor sha512_256_desc; 333 | #endif 334 | 335 | #ifdef LTC_SHA512_224 336 | #ifndef LTC_SHA512 337 | #error LTC_SHA512 is required for LTC_SHA512_224 338 | #endif 339 | int sha512_224_init(hash_state * md); 340 | #define sha512_224_process sha512_process 341 | int sha512_224_done(hash_state * md, unsigned char *out); 342 | int sha512_224_test(void); 343 | extern const struct ltc_hash_descriptor sha512_224_desc; 344 | #endif 345 | 346 | #ifdef LTC_SHA256 347 | int sha256_init(hash_state * md); 348 | int sha256_process(hash_state * md, const unsigned char *in, unsigned long inlen); 349 | int sha256_done(hash_state * md, unsigned char *out); 350 | int sha256_test(void); 351 | extern const struct ltc_hash_descriptor sha256_desc; 352 | 353 | #ifdef LTC_SHA224 354 | #ifndef LTC_SHA256 355 | #error LTC_SHA256 is required for LTC_SHA224 356 | #endif 357 | int sha224_init(hash_state * md); 358 | #define sha224_process sha256_process 359 | int sha224_done(hash_state * md, unsigned char *out); 360 | int sha224_test(void); 361 | extern const struct ltc_hash_descriptor sha224_desc; 362 | #endif 363 | #endif 364 | 365 | #ifdef LTC_SHA1 366 | int sha1_init(hash_state * md); 367 | int sha1_process(hash_state * md, const unsigned char *in, unsigned long inlen); 368 | int sha1_done(hash_state * md, unsigned char *out); 369 | int sha1_test(void); 370 | extern const struct ltc_hash_descriptor sha1_desc; 371 | #endif 372 | 373 | #ifdef LTC_BLAKE2S 374 | extern const struct ltc_hash_descriptor blake2s_256_desc; 375 | int blake2s_256_init(hash_state * md); 376 | int blake2s_256_test(void); 377 | 378 | extern const struct ltc_hash_descriptor blake2s_224_desc; 379 | int blake2s_224_init(hash_state * md); 380 | int blake2s_224_test(void); 381 | 382 | extern const struct ltc_hash_descriptor blake2s_160_desc; 383 | int blake2s_160_init(hash_state * md); 384 | int blake2s_160_test(void); 385 | 386 | extern const struct ltc_hash_descriptor blake2s_128_desc; 387 | int blake2s_128_init(hash_state * md); 388 | int blake2s_128_test(void); 389 | 390 | int blake2s_init(hash_state * md, unsigned long outlen, const unsigned char *key, unsigned long keylen); 391 | int blake2s_process(hash_state * md, const unsigned char *in, unsigned long inlen); 392 | int blake2s_done(hash_state * md, unsigned char *out); 393 | #endif 394 | 395 | #ifdef LTC_BLAKE2B 396 | extern const struct ltc_hash_descriptor blake2b_512_desc; 397 | int blake2b_512_init(hash_state * md); 398 | int blake2b_512_test(void); 399 | 400 | extern const struct ltc_hash_descriptor blake2b_384_desc; 401 | int blake2b_384_init(hash_state * md); 402 | int blake2b_384_test(void); 403 | 404 | extern const struct ltc_hash_descriptor blake2b_256_desc; 405 | int blake2b_256_init(hash_state * md); 406 | int blake2b_256_test(void); 407 | 408 | extern const struct ltc_hash_descriptor blake2b_160_desc; 409 | int blake2b_160_init(hash_state * md); 410 | int blake2b_160_test(void); 411 | 412 | int blake2b_init(hash_state * md, unsigned long outlen, const unsigned char *key, unsigned long keylen); 413 | int blake2b_process(hash_state * md, const unsigned char *in, unsigned long inlen); 414 | int blake2b_done(hash_state * md, unsigned char *out); 415 | #endif 416 | 417 | #ifdef LTC_MD5 418 | int md5_init(hash_state * md); 419 | int md5_process(hash_state * md, const unsigned char *in, unsigned long inlen); 420 | int md5_done(hash_state * md, unsigned char *out); 421 | int md5_test(void); 422 | extern const struct ltc_hash_descriptor md5_desc; 423 | #endif 424 | 425 | #ifdef LTC_MD4 426 | int md4_init(hash_state * md); 427 | int md4_process(hash_state * md, const unsigned char *in, unsigned long inlen); 428 | int md4_done(hash_state * md, unsigned char *out); 429 | int md4_test(void); 430 | extern const struct ltc_hash_descriptor md4_desc; 431 | #endif 432 | 433 | #ifdef LTC_MD2 434 | int md2_init(hash_state * md); 435 | int md2_process(hash_state * md, const unsigned char *in, unsigned long inlen); 436 | int md2_done(hash_state * md, unsigned char *out); 437 | int md2_test(void); 438 | extern const struct ltc_hash_descriptor md2_desc; 439 | #endif 440 | 441 | #ifdef LTC_TIGER 442 | int tiger_init(hash_state * md); 443 | int tiger_process(hash_state * md, const unsigned char *in, unsigned long inlen); 444 | int tiger_done(hash_state * md, unsigned char *out); 445 | int tiger_test(void); 446 | extern const struct ltc_hash_descriptor tiger_desc; 447 | #endif 448 | 449 | #ifdef LTC_RIPEMD128 450 | int rmd128_init(hash_state * md); 451 | int rmd128_process(hash_state * md, const unsigned char *in, unsigned long inlen); 452 | int rmd128_done(hash_state * md, unsigned char *out); 453 | int rmd128_test(void); 454 | extern const struct ltc_hash_descriptor rmd128_desc; 455 | #endif 456 | 457 | #ifdef LTC_RIPEMD160 458 | int rmd160_init(hash_state * md); 459 | int rmd160_process(hash_state * md, const unsigned char *in, unsigned long inlen); 460 | int rmd160_done(hash_state * md, unsigned char *out); 461 | int rmd160_test(void); 462 | extern const struct ltc_hash_descriptor rmd160_desc; 463 | #endif 464 | 465 | #ifdef LTC_RIPEMD256 466 | int rmd256_init(hash_state * md); 467 | int rmd256_process(hash_state * md, const unsigned char *in, unsigned long inlen); 468 | int rmd256_done(hash_state * md, unsigned char *out); 469 | int rmd256_test(void); 470 | extern const struct ltc_hash_descriptor rmd256_desc; 471 | #endif 472 | 473 | #ifdef LTC_RIPEMD320 474 | int rmd320_init(hash_state * md); 475 | int rmd320_process(hash_state * md, const unsigned char *in, unsigned long inlen); 476 | int rmd320_done(hash_state * md, unsigned char *out); 477 | int rmd320_test(void); 478 | extern const struct ltc_hash_descriptor rmd320_desc; 479 | #endif 480 | 481 | 482 | int find_hash(const char *name); 483 | int find_hash_id(unsigned char ID); 484 | int find_hash_oid(const unsigned long *ID, unsigned long IDlen); 485 | int find_hash_any(const char *name, int digestlen); 486 | int register_hash(const struct ltc_hash_descriptor *hash); 487 | int unregister_hash(const struct ltc_hash_descriptor *hash); 488 | int register_all_hashes(void); 489 | int hash_is_valid(int idx); 490 | 491 | LTC_MUTEX_PROTO(ltc_hash_mutex) 492 | 493 | int hash_memory(int hash, 494 | const unsigned char *in, unsigned long inlen, 495 | unsigned char *out, unsigned long *outlen); 496 | int hash_memory_multi(int hash, unsigned char *out, unsigned long *outlen, 497 | const unsigned char *in, unsigned long inlen, ...) 498 | LTC_NULL_TERMINATED; 499 | 500 | #ifndef LTC_NO_FILE 501 | int hash_filehandle(int hash, FILE *in, unsigned char *out, unsigned long *outlen); 502 | int hash_file(int hash, const char *fname, unsigned char *out, unsigned long *outlen); 503 | #endif 504 | -------------------------------------------------------------------------------- /Sources/SQLExt/sqlite/tomcrypt_macros.h: -------------------------------------------------------------------------------- 1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */ 2 | /* SPDX-License-Identifier: Unlicense */ 3 | 4 | 5 | #define LTC_TMPVAR__(n, l) n ## l 6 | #define LTC_TMPVAR_(n, l) LTC_TMPVAR__(n, l) 7 | #define LTC_TMPVAR(n) LTC_TMPVAR_(LTC_ ## n ## _, __LINE__) 8 | 9 | /* ---- HELPER MACROS ---- */ 10 | #ifdef ENDIAN_NEUTRAL 11 | 12 | #define STORE32L(x, y) \ 13 | do { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \ 14 | (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } while(0) 15 | 16 | #define LOAD32L(x, y) \ 17 | do { x = ((ulong32)((y)[3] & 255)<<24) | \ 18 | ((ulong32)((y)[2] & 255)<<16) | \ 19 | ((ulong32)((y)[1] & 255)<<8) | \ 20 | ((ulong32)((y)[0] & 255)); } while(0) 21 | 22 | #define STORE64L(x, y) \ 23 | do { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \ 24 | (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \ 25 | (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \ 26 | (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } while(0) 27 | 28 | #define LOAD64L(x, y) \ 29 | do { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \ 30 | (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \ 31 | (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \ 32 | (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); } while(0) 33 | 34 | #define STORE32H(x, y) \ 35 | do { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ 36 | (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } while(0) 37 | 38 | #define LOAD32H(x, y) \ 39 | do { x = ((ulong32)((y)[0] & 255)<<24) | \ 40 | ((ulong32)((y)[1] & 255)<<16) | \ 41 | ((ulong32)((y)[2] & 255)<<8) | \ 42 | ((ulong32)((y)[3] & 255)); } while(0) 43 | 44 | #define STORE64H(x, y) \ 45 | do { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ 46 | (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ 47 | (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ 48 | (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } while(0) 49 | 50 | #define LOAD64H(x, y) \ 51 | do { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \ 52 | (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \ 53 | (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \ 54 | (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); } while(0) 55 | 56 | 57 | #elif defined(ENDIAN_LITTLE) 58 | 59 | #ifdef LTC_HAVE_BSWAP_BUILTIN 60 | 61 | #define STORE32H(x, y) \ 62 | do { ulong32 ttt = __builtin_bswap32 ((x)); \ 63 | XMEMCPY ((y), &ttt, 4); } while(0) 64 | 65 | #define LOAD32H(x, y) \ 66 | do { XMEMCPY (&(x), (y), 4); \ 67 | (x) = __builtin_bswap32 ((x)); } while(0) 68 | 69 | #elif !defined(LTC_NO_BSWAP) && (defined(INTEL_CC) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__) || defined(__x86_64__)))) 70 | 71 | #define STORE32H(x, y) \ 72 | asm __volatile__ ( \ 73 | "bswapl %0 \n\t" \ 74 | "movl %0,(%1)\n\t" \ 75 | "bswapl %0 \n\t" \ 76 | ::"r"(x), "r"(y): "memory"); 77 | 78 | #define LOAD32H(x, y) \ 79 | asm __volatile__ ( \ 80 | "movl (%1),%0\n\t" \ 81 | "bswapl %0\n\t" \ 82 | :"=r"(x): "r"(y): "memory"); 83 | 84 | #else 85 | 86 | #define STORE32H(x, y) \ 87 | do { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ 88 | (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } while(0) 89 | 90 | #define LOAD32H(x, y) \ 91 | do { x = ((ulong32)((y)[0] & 255)<<24) | \ 92 | ((ulong32)((y)[1] & 255)<<16) | \ 93 | ((ulong32)((y)[2] & 255)<<8) | \ 94 | ((ulong32)((y)[3] & 255)); } while(0) 95 | 96 | #endif 97 | 98 | #ifdef LTC_HAVE_BSWAP_BUILTIN 99 | 100 | #define STORE64H(x, y) \ 101 | do { ulong64 ttt = __builtin_bswap64 ((x)); \ 102 | XMEMCPY ((y), &ttt, 8); } while(0) 103 | 104 | #define LOAD64H(x, y) \ 105 | do { XMEMCPY (&(x), (y), 8); \ 106 | (x) = __builtin_bswap64 ((x)); } while(0) 107 | 108 | /* x86_64 processor */ 109 | #elif !defined(LTC_NO_BSWAP) && (defined(__GNUC__) && defined(__x86_64__)) 110 | 111 | #define STORE64H(x, y) \ 112 | asm __volatile__ ( \ 113 | "bswapq %0 \n\t" \ 114 | "movq %0,(%1)\n\t" \ 115 | "bswapq %0 \n\t" \ 116 | ::"r"(x), "r"(y): "memory"); 117 | 118 | #define LOAD64H(x, y) \ 119 | asm __volatile__ ( \ 120 | "movq (%1),%0\n\t" \ 121 | "bswapq %0\n\t" \ 122 | :"=r"(x): "r"(y): "memory"); 123 | 124 | #else 125 | 126 | #define STORE64H(x, y) \ 127 | do { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ 128 | (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ 129 | (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ 130 | (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } while(0) 131 | 132 | #define LOAD64H(x, y) \ 133 | do { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \ 134 | (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \ 135 | (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \ 136 | (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); } while(0) 137 | 138 | #endif 139 | 140 | #ifdef ENDIAN_32BITWORD 141 | 142 | #define STORE32L(x, y) \ 143 | do { ulong32 ttt = (x); XMEMCPY(y, &ttt, 4); } while(0) 144 | 145 | #define LOAD32L(x, y) \ 146 | do { XMEMCPY(&(x), y, 4); } while(0) 147 | 148 | #define STORE64L(x, y) \ 149 | do { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \ 150 | (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \ 151 | (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \ 152 | (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } while(0) 153 | 154 | #define LOAD64L(x, y) \ 155 | do { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \ 156 | (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \ 157 | (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \ 158 | (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); } while(0) 159 | 160 | #else /* 64-bit words then */ 161 | 162 | #define STORE32L(x, y) \ 163 | do { ulong32 ttt = (x); XMEMCPY(y, &ttt, 4); } while(0) 164 | 165 | #define LOAD32L(x, y) \ 166 | do { XMEMCPY(&(x), y, 4); x &= 0xFFFFFFFF; } while(0) 167 | 168 | #define STORE64L(x, y) \ 169 | do { ulong64 ttt = (x); XMEMCPY(y, &ttt, 8); } while(0) 170 | 171 | #define LOAD64L(x, y) \ 172 | do { XMEMCPY(&(x), y, 8); } while(0) 173 | 174 | #endif /* ENDIAN_64BITWORD */ 175 | 176 | #elif defined(ENDIAN_BIG) 177 | 178 | #define STORE32L(x, y) \ 179 | do { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \ 180 | (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } while(0) 181 | 182 | #define LOAD32L(x, y) \ 183 | do { x = ((ulong32)((y)[3] & 255)<<24) | \ 184 | ((ulong32)((y)[2] & 255)<<16) | \ 185 | ((ulong32)((y)[1] & 255)<<8) | \ 186 | ((ulong32)((y)[0] & 255)); } while(0) 187 | 188 | #define STORE64L(x, y) \ 189 | do { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \ 190 | (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \ 191 | (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \ 192 | (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } while(0) 193 | 194 | #define LOAD64L(x, y) \ 195 | do { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48) | \ 196 | (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32) | \ 197 | (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16) | \ 198 | (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); } while(0) 199 | 200 | #ifdef ENDIAN_32BITWORD 201 | 202 | #define STORE32H(x, y) \ 203 | do { ulong32 ttt = (x); XMEMCPY(y, &ttt, 4); } while(0) 204 | 205 | #define LOAD32H(x, y) \ 206 | do { XMEMCPY(&(x), y, 4); } while(0) 207 | 208 | #define STORE64H(x, y) \ 209 | do { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ 210 | (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ 211 | (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ 212 | (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } while(0) 213 | 214 | #define LOAD64H(x, y) \ 215 | do { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48)| \ 216 | (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32)| \ 217 | (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16)| \ 218 | (((ulong64)((y)[6] & 255))<<8)| (((ulong64)((y)[7] & 255))); } while(0) 219 | 220 | #else /* 64-bit words then */ 221 | 222 | #define STORE32H(x, y) \ 223 | do { ulong32 ttt = (x); XMEMCPY(y, &ttt, 4); } while(0) 224 | 225 | #define LOAD32H(x, y) \ 226 | do { XMEMCPY(&(x), y, 4); x &= 0xFFFFFFFF; } while(0) 227 | 228 | #define STORE64H(x, y) \ 229 | do { ulong64 ttt = (x); XMEMCPY(y, &ttt, 8); } while(0) 230 | 231 | #define LOAD64H(x, y) \ 232 | do { XMEMCPY(&(x), y, 8); } while(0) 233 | 234 | #endif /* ENDIAN_64BITWORD */ 235 | #endif /* ENDIAN_BIG */ 236 | 237 | #define BSWAP(x) ( ((x>>24)&0x000000FFUL) | ((x<<24)&0xFF000000UL) | \ 238 | ((x>>8)&0x0000FF00UL) | ((x<<8)&0x00FF0000UL) ) 239 | 240 | 241 | /* 32-bit Rotates */ 242 | #if defined(_MSC_VER) 243 | #define LTC_ROx_BUILTIN 244 | 245 | /* instrinsic rotate */ 246 | #include 247 | #pragma intrinsic(_rotr,_rotl) 248 | #define ROR(x,n) _rotr(x,n) 249 | #define ROL(x,n) _rotl(x,n) 250 | #define RORc(x,n) ROR(x,n) 251 | #define ROLc(x,n) ROL(x,n) 252 | 253 | #elif defined(LTC_HAVE_ROTATE_BUILTIN) 254 | #define LTC_ROx_BUILTIN 255 | 256 | #define ROR(x,n) __builtin_rotateright32(x,n) 257 | #define ROL(x,n) __builtin_rotateleft32(x,n) 258 | #define ROLc(x,n) ROL(x,n) 259 | #define RORc(x,n) ROR(x,n) 260 | 261 | #elif !defined(__STRICT_ANSI__) && defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(INTEL_CC) && !defined(LTC_NO_ASM) 262 | #define LTC_ROx_ASM 263 | 264 | static inline ulong32 ROL(ulong32 word, int i) 265 | { 266 | asm ("roll %%cl,%0" 267 | :"=r" (word) 268 | :"0" (word),"c" (i)); 269 | return word; 270 | } 271 | 272 | static inline ulong32 ROR(ulong32 word, int i) 273 | { 274 | asm ("rorl %%cl,%0" 275 | :"=r" (word) 276 | :"0" (word),"c" (i)); 277 | return word; 278 | } 279 | 280 | #ifndef LTC_NO_ROLC 281 | 282 | #define ROLc(word,i) ({ \ 283 | ulong32 LTC_TMPVAR(ROLc) = (word); \ 284 | __asm__ ("roll %2, %0" : \ 285 | "=r" (LTC_TMPVAR(ROLc)) : \ 286 | "0" (LTC_TMPVAR(ROLc)), \ 287 | "I" (i)); \ 288 | LTC_TMPVAR(ROLc); \ 289 | }) 290 | #define RORc(word,i) ({ \ 291 | ulong32 LTC_TMPVAR(RORc) = (word); \ 292 | __asm__ ("rorl %2, %0" : \ 293 | "=r" (LTC_TMPVAR(RORc)) : \ 294 | "0" (LTC_TMPVAR(RORc)), \ 295 | "I" (i)); \ 296 | LTC_TMPVAR(RORc); \ 297 | }) 298 | 299 | #else 300 | 301 | #define ROLc ROL 302 | #define RORc ROR 303 | 304 | #endif 305 | 306 | #elif !defined(__STRICT_ANSI__) && defined(LTC_PPC32) 307 | #define LTC_ROx_ASM 308 | 309 | static inline ulong32 ROL(ulong32 word, int i) 310 | { 311 | asm ("rotlw %0,%0,%2" 312 | :"=r" (word) 313 | :"0" (word),"r" (i)); 314 | return word; 315 | } 316 | 317 | static inline ulong32 ROR(ulong32 word, int i) 318 | { 319 | asm ("rotlw %0,%0,%2" 320 | :"=r" (word) 321 | :"0" (word),"r" (32-i)); 322 | return word; 323 | } 324 | 325 | #ifndef LTC_NO_ROLC 326 | 327 | static inline ulong32 ROLc(ulong32 word, const int i) 328 | { 329 | asm ("rotlwi %0,%0,%2" 330 | :"=r" (word) 331 | :"0" (word),"I" (i)); 332 | return word; 333 | } 334 | 335 | static inline ulong32 RORc(ulong32 word, const int i) 336 | { 337 | asm ("rotrwi %0,%0,%2" 338 | :"=r" (word) 339 | :"0" (word),"I" (i)); 340 | return word; 341 | } 342 | 343 | #else 344 | 345 | #define ROLc ROL 346 | #define RORc ROR 347 | 348 | #endif 349 | 350 | 351 | #else 352 | 353 | /* rotates the hard way */ 354 | #define ROL(x, y) ( (((ulong32)(x)<<(ulong32)((y)&31)) | (((ulong32)(x)&0xFFFFFFFFUL)>>(ulong32)((32-((y)&31))&31))) & 0xFFFFFFFFUL) 355 | #define ROR(x, y) ( ((((ulong32)(x)&0xFFFFFFFFUL)>>(ulong32)((y)&31)) | ((ulong32)(x)<<(ulong32)((32-((y)&31))&31))) & 0xFFFFFFFFUL) 356 | #define ROLc(x, y) ( (((ulong32)(x)<<(ulong32)((y)&31)) | (((ulong32)(x)&0xFFFFFFFFUL)>>(ulong32)((32-((y)&31))&31))) & 0xFFFFFFFFUL) 357 | #define RORc(x, y) ( ((((ulong32)(x)&0xFFFFFFFFUL)>>(ulong32)((y)&31)) | ((ulong32)(x)<<(ulong32)((32-((y)&31))&31))) & 0xFFFFFFFFUL) 358 | 359 | #endif 360 | 361 | 362 | /* 64-bit Rotates */ 363 | #if defined(_MSC_VER) 364 | 365 | /* instrinsic rotate */ 366 | #include 367 | #pragma intrinsic(_rotr64,_rotr64) 368 | #define ROR64(x,n) _rotr64(x,n) 369 | #define ROL64(x,n) _rotl64(x,n) 370 | #define ROR64c(x,n) ROR64(x,n) 371 | #define ROL64c(x,n) ROL64(x,n) 372 | 373 | #elif defined(LTC_HAVE_ROTATE_BUILTIN) 374 | 375 | #define ROR64(x,n) __builtin_rotateright64(x,n) 376 | #define ROL64(x,n) __builtin_rotateleft64(x,n) 377 | #define ROR64c(x,n) ROR64(x,n) 378 | #define ROL64c(x,n) ROL64(x,n) 379 | 380 | #elif !defined(__STRICT_ANSI__) && defined(__GNUC__) && defined(__x86_64__) && !defined(INTEL_CC) && !defined(LTC_NO_ASM) 381 | 382 | static inline ulong64 ROL64(ulong64 word, int i) 383 | { 384 | asm("rolq %%cl,%0" 385 | :"=r" (word) 386 | :"0" (word),"c" (i)); 387 | return word; 388 | } 389 | 390 | static inline ulong64 ROR64(ulong64 word, int i) 391 | { 392 | asm("rorq %%cl,%0" 393 | :"=r" (word) 394 | :"0" (word),"c" (i)); 395 | return word; 396 | } 397 | 398 | #ifndef LTC_NO_ROLC 399 | 400 | #define ROL64c(word,i) ({ \ 401 | ulong64 LTC_TMPVAR(ROL64c) = word; \ 402 | __asm__ ("rolq %2, %0" : \ 403 | "=r" (LTC_TMPVAR(ROL64c)) : \ 404 | "0" (LTC_TMPVAR(ROL64c)), \ 405 | "J" (i)); \ 406 | LTC_TMPVAR(ROL64c); \ 407 | }) 408 | #define ROR64c(word,i) ({ \ 409 | ulong64 LTC_TMPVAR(ROR64c) = word; \ 410 | __asm__ ("rorq %2, %0" : \ 411 | "=r" (LTC_TMPVAR(ROR64c)) : \ 412 | "0" (LTC_TMPVAR(ROR64c)), \ 413 | "J" (i)); \ 414 | LTC_TMPVAR(ROR64c); \ 415 | }) 416 | 417 | #else /* LTC_NO_ROLC */ 418 | 419 | #define ROL64c ROL64 420 | #define ROR64c ROR64 421 | 422 | #endif 423 | 424 | #else /* Not x86_64 */ 425 | 426 | #define ROL64(x, y) \ 427 | ( (((x)<<((ulong64)(y)&63)) | \ 428 | (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>(((ulong64)64-((y)&63))&63))) & CONST64(0xFFFFFFFFFFFFFFFF)) 429 | 430 | #define ROR64(x, y) \ 431 | ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \ 432 | ((x)<<(((ulong64)64-((y)&63))&63))) & CONST64(0xFFFFFFFFFFFFFFFF)) 433 | 434 | #define ROL64c(x, y) \ 435 | ( (((x)<<((ulong64)(y)&63)) | \ 436 | (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>(((ulong64)64-((y)&63))&63))) & CONST64(0xFFFFFFFFFFFFFFFF)) 437 | 438 | #define ROR64c(x, y) \ 439 | ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \ 440 | ((x)<<(((ulong64)64-((y)&63))&63))) & CONST64(0xFFFFFFFFFFFFFFFF)) 441 | 442 | #endif 443 | 444 | #ifndef MAX 445 | #define MAX(x, y) ( ((x)>(y))?(x):(y) ) 446 | #endif 447 | 448 | #ifndef MIN 449 | #define MIN(x, y) ( ((x)<(y))?(x):(y) ) 450 | #endif 451 | 452 | #ifndef LTC_UNUSED_PARAM 453 | #define LTC_UNUSED_PARAM(x) (void)(x) 454 | #endif 455 | 456 | /* there is no snprintf before Visual C++ 2015 */ 457 | #if defined(_MSC_VER) && _MSC_VER < 1900 458 | #define snprintf _snprintf 459 | #endif 460 | -------------------------------------------------------------------------------- /Sources/SQLExt/sqlite/tomcrypt_misc.h: -------------------------------------------------------------------------------- 1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */ 2 | /* SPDX-License-Identifier: Unlicense */ 3 | 4 | /* ---- LTC_BASE64 Routines ---- */ 5 | #ifdef LTC_BASE64 6 | int base64_encode(const unsigned char *in, unsigned long inlen, 7 | char *out, unsigned long *outlen); 8 | 9 | int base64_decode(const char *in, unsigned long inlen, 10 | unsigned char *out, unsigned long *outlen); 11 | int base64_strict_decode(const char *in, unsigned long inlen, 12 | unsigned char *out, unsigned long *outlen); 13 | int base64_sane_decode(const char *in, unsigned long inlen, 14 | unsigned char *out, unsigned long *outlen); 15 | #endif 16 | 17 | #ifdef LTC_BASE64_URL 18 | int base64url_encode(const unsigned char *in, unsigned long inlen, 19 | char *out, unsigned long *outlen); 20 | int base64url_strict_encode(const unsigned char *in, unsigned long inlen, 21 | char *out, unsigned long *outlen); 22 | 23 | int base64url_decode(const char *in, unsigned long inlen, 24 | unsigned char *out, unsigned long *outlen); 25 | int base64url_strict_decode(const char *in, unsigned long inlen, 26 | unsigned char *out, unsigned long *outlen); 27 | int base64url_sane_decode(const char *in, unsigned long inlen, 28 | unsigned char *out, unsigned long *outlen); 29 | #endif 30 | 31 | /* ---- BASE32 Routines ---- */ 32 | #ifdef LTC_BASE32 33 | typedef enum { 34 | BASE32_RFC4648 = 0, 35 | BASE32_BASE32HEX = 1, 36 | BASE32_ZBASE32 = 2, 37 | BASE32_CROCKFORD = 3 38 | } base32_alphabet; 39 | int base32_encode(const unsigned char *in, unsigned long inlen, 40 | char *out, unsigned long *outlen, 41 | base32_alphabet id); 42 | int base32_decode(const char *in, unsigned long inlen, 43 | unsigned char *out, unsigned long *outlen, 44 | base32_alphabet id); 45 | #endif 46 | 47 | /* ---- BASE16 Routines ---- */ 48 | #ifdef LTC_BASE16 49 | int base16_encode(const unsigned char *in, unsigned long inlen, 50 | char *out, unsigned long *outlen, 51 | unsigned int options); 52 | int base16_decode(const char *in, unsigned long inlen, 53 | unsigned char *out, unsigned long *outlen); 54 | #endif 55 | 56 | #ifdef LTC_BCRYPT 57 | int bcrypt_pbkdf_openbsd(const void *secret, unsigned long secret_len, 58 | const unsigned char *salt, unsigned long salt_len, 59 | unsigned int rounds, int hash_idx, 60 | unsigned char *out, unsigned long *outlen); 61 | #endif 62 | 63 | /* ===> LTC_HKDF -- RFC5869 HMAC-based Key Derivation Function <=== */ 64 | #ifdef LTC_HKDF 65 | 66 | int hkdf_test(void); 67 | 68 | int hkdf_extract(int hash_idx, 69 | const unsigned char *salt, unsigned long saltlen, 70 | const unsigned char *in, unsigned long inlen, 71 | unsigned char *out, unsigned long *outlen); 72 | 73 | int hkdf_expand(int hash_idx, 74 | const unsigned char *info, unsigned long infolen, 75 | const unsigned char *in, unsigned long inlen, 76 | unsigned char *out, unsigned long outlen); 77 | 78 | int hkdf(int hash_idx, 79 | const unsigned char *salt, unsigned long saltlen, 80 | const unsigned char *info, unsigned long infolen, 81 | const unsigned char *in, unsigned long inlen, 82 | unsigned char *out, unsigned long outlen); 83 | 84 | #endif /* LTC_HKDF */ 85 | 86 | /* ---- MEM routines ---- */ 87 | int mem_neq(const void *a, const void *b, size_t len); 88 | void zeromem(volatile void *out, size_t outlen); 89 | void burn_stack(unsigned long len); 90 | 91 | const char *error_to_string(int err); 92 | 93 | extern const char *crypt_build_settings; 94 | 95 | /* ---- HMM ---- */ 96 | int crypt_fsa(void *mp, ...) LTC_NULL_TERMINATED; 97 | 98 | /* ---- Dynamic language support ---- */ 99 | int crypt_get_constant(const char* namein, int *valueout); 100 | int crypt_list_all_constants(char *names_list, unsigned int *names_list_size); 101 | 102 | int crypt_get_size(const char* namein, unsigned int *sizeout); 103 | int crypt_list_all_sizes(char *names_list, unsigned int *names_list_size); 104 | 105 | #ifdef LTM_DESC 106 | LTC_DEPRECATED(crypt_mp_init) void init_LTM(void); 107 | #endif 108 | #ifdef TFM_DESC 109 | LTC_DEPRECATED(crypt_mp_init) void init_TFM(void); 110 | #endif 111 | #ifdef GMP_DESC 112 | LTC_DEPRECATED(crypt_mp_init) void init_GMP(void); 113 | #endif 114 | int crypt_mp_init(const char* mpi); 115 | 116 | #ifdef LTC_ADLER32 117 | typedef struct adler32_state_s 118 | { 119 | unsigned short s[2]; 120 | } adler32_state; 121 | 122 | void adler32_init(adler32_state *ctx); 123 | void adler32_update(adler32_state *ctx, const unsigned char *input, unsigned long length); 124 | void adler32_finish(const adler32_state *ctx, void *hash, unsigned long size); 125 | int adler32_test(void); 126 | #endif 127 | 128 | #ifdef LTC_CRC32 129 | typedef struct crc32_state_s 130 | { 131 | ulong32 crc; 132 | } crc32_state; 133 | 134 | void crc32_init(crc32_state *ctx); 135 | void crc32_update(crc32_state *ctx, const unsigned char *input, unsigned long length); 136 | void crc32_finish(const crc32_state *ctx, void *hash, unsigned long size); 137 | int crc32_test(void); 138 | #endif 139 | 140 | 141 | #ifdef LTC_PADDING 142 | 143 | enum padding_type { 144 | LTC_PAD_PKCS7 = 0x0000U, 145 | #ifdef LTC_RNG_GET_BYTES 146 | LTC_PAD_ISO_10126 = 0x1000U, 147 | #endif 148 | LTC_PAD_ANSI_X923 = 0x2000U, 149 | LTC_PAD_SSH = 0x3000U, 150 | /* The following padding modes don't contain the padding 151 | * length as last byte of the padding. 152 | */ 153 | LTC_PAD_ONE_AND_ZERO = 0x8000U, 154 | LTC_PAD_ZERO = 0x9000U, 155 | LTC_PAD_ZERO_ALWAYS = 0xA000U, 156 | }; 157 | 158 | int padding_pad(unsigned char *data, unsigned long length, unsigned long* padded_length, unsigned long mode); 159 | int padding_depad(const unsigned char *data, unsigned long *length, unsigned long mode); 160 | #endif /* LTC_PADDING */ 161 | 162 | #ifdef LTC_SSH 163 | typedef enum ssh_data_type_ { 164 | LTC_SSHDATA_EOL, 165 | LTC_SSHDATA_BYTE, 166 | LTC_SSHDATA_BOOLEAN, 167 | LTC_SSHDATA_UINT32, 168 | LTC_SSHDATA_UINT64, 169 | LTC_SSHDATA_STRING, 170 | LTC_SSHDATA_MPINT, 171 | LTC_SSHDATA_NAMELIST, 172 | } ssh_data_type; 173 | 174 | /* VA list handy helpers with tuples of */ 175 | int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...) LTC_NULL_TERMINATED; 176 | int ssh_decode_sequence_multi(const unsigned char *in, unsigned long *inlen, ...) LTC_NULL_TERMINATED; 177 | #endif /* LTC_SSH */ 178 | 179 | int compare_testvector(const void* is, const unsigned long is_len, const void* should, const unsigned long should_len, const char* what, int which); 180 | -------------------------------------------------------------------------------- /Sources/SQLExt/sqlite/tomcrypt_pkcs.h: -------------------------------------------------------------------------------- 1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */ 2 | /* SPDX-License-Identifier: Unlicense */ 3 | 4 | /* PKCS Header Info */ 5 | 6 | /* ===> PKCS #1 -- RSA Cryptography <=== */ 7 | #ifdef LTC_PKCS_1 8 | 9 | enum ltc_pkcs_1_v1_5_blocks 10 | { 11 | LTC_PKCS_1_EMSA = 1, /* Block type 1 (PKCS #1 v1.5 signature padding) */ 12 | LTC_PKCS_1_EME = 2 /* Block type 2 (PKCS #1 v1.5 encryption padding) */ 13 | }; 14 | 15 | enum ltc_pkcs_1_paddings 16 | { 17 | LTC_PKCS_1_V1_5 = 1, /* PKCS #1 v1.5 padding (\sa ltc_pkcs_1_v1_5_blocks) */ 18 | LTC_PKCS_1_OAEP = 2, /* PKCS #1 v2.0 encryption padding */ 19 | LTC_PKCS_1_PSS = 3, /* PKCS #1 v2.1 signature padding */ 20 | LTC_PKCS_1_V1_5_NA1 = 4 /* PKCS #1 v1.5 padding - No ASN.1 (\sa ltc_pkcs_1_v1_5_blocks) */ 21 | }; 22 | 23 | int pkcs_1_mgf1( int hash_idx, 24 | const unsigned char *seed, unsigned long seedlen, 25 | unsigned char *mask, unsigned long masklen); 26 | 27 | int pkcs_1_i2osp(void *n, unsigned long modulus_len, unsigned char *out); 28 | int pkcs_1_os2ip(void *n, unsigned char *in, unsigned long inlen); 29 | 30 | /* *** v1.5 padding */ 31 | int pkcs_1_v1_5_encode(const unsigned char *msg, 32 | unsigned long msglen, 33 | int block_type, 34 | unsigned long modulus_bitlen, 35 | prng_state *prng, 36 | int prng_idx, 37 | unsigned char *out, 38 | unsigned long *outlen); 39 | 40 | int pkcs_1_v1_5_decode(const unsigned char *msg, 41 | unsigned long msglen, 42 | int block_type, 43 | unsigned long modulus_bitlen, 44 | unsigned char *out, 45 | unsigned long *outlen, 46 | int *is_valid); 47 | 48 | /* *** v2.1 padding */ 49 | int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen, 50 | const unsigned char *lparam, unsigned long lparamlen, 51 | unsigned long modulus_bitlen, prng_state *prng, 52 | int prng_idx, 53 | int mgf_hash, int lparam_hash, 54 | unsigned char *out, unsigned long *outlen); 55 | 56 | int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen, 57 | const unsigned char *lparam, unsigned long lparamlen, 58 | unsigned long modulus_bitlen, 59 | int mgf_hash, int lparam_hash, 60 | unsigned char *out, unsigned long *outlen, 61 | int *res); 62 | 63 | int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen, 64 | unsigned long saltlen, prng_state *prng, 65 | int prng_idx, int hash_idx, 66 | unsigned long modulus_bitlen, 67 | unsigned char *out, unsigned long *outlen); 68 | 69 | int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, 70 | const unsigned char *sig, unsigned long siglen, 71 | unsigned long saltlen, int hash_idx, 72 | unsigned long modulus_bitlen, int *res); 73 | 74 | #endif /* LTC_PKCS_1 */ 75 | 76 | /* ===> PKCS #5 -- Password Based Cryptography <=== */ 77 | #ifdef LTC_PKCS_5 78 | 79 | /* Algorithm #1 (PBKDF1) */ 80 | int pkcs_5_alg1(const unsigned char *password, unsigned long password_len, 81 | const unsigned char *salt, 82 | int iteration_count, int hash_idx, 83 | unsigned char *out, unsigned long *outlen); 84 | 85 | /* Algorithm #1 (PBKDF1) - OpenSSL-compatible variant for arbitrarily-long keys. 86 | Compatible with EVP_BytesToKey() */ 87 | int pkcs_5_alg1_openssl(const unsigned char *password, 88 | unsigned long password_len, 89 | const unsigned char *salt, 90 | int iteration_count, int hash_idx, 91 | unsigned char *out, unsigned long *outlen); 92 | 93 | /* Algorithm #2 (PBKDF2) */ 94 | int pkcs_5_alg2(const unsigned char *password, unsigned long password_len, 95 | const unsigned char *salt, unsigned long salt_len, 96 | int iteration_count, int hash_idx, 97 | unsigned char *out, unsigned long *outlen); 98 | 99 | int pkcs_5_test (void); 100 | #endif /* LTC_PKCS_5 */ 101 | 102 | -------------------------------------------------------------------------------- /Sources/SQLExt/sqlite/tomcrypt_prng.h: -------------------------------------------------------------------------------- 1 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis */ 2 | /* SPDX-License-Identifier: Unlicense */ 3 | 4 | /* ---- PRNG Stuff ---- */ 5 | #ifdef LTC_YARROW 6 | struct yarrow_prng { 7 | int cipher, hash; 8 | unsigned char pool[MAXBLOCKSIZE]; 9 | symmetric_CTR ctr; 10 | }; 11 | #endif 12 | 13 | #ifdef LTC_RC4 14 | struct rc4_prng { 15 | rc4_state s; 16 | }; 17 | #endif 18 | 19 | #ifdef LTC_CHACHA20_PRNG 20 | struct chacha20_prng { 21 | chacha_state s; /* chacha state */ 22 | unsigned char ent[40]; /* entropy buffer */ 23 | unsigned long idx; /* entropy counter */ 24 | }; 25 | #endif 26 | 27 | #ifdef LTC_FORTUNA 28 | struct fortuna_prng { 29 | hash_state pool[LTC_FORTUNA_POOLS]; /* the pools */ 30 | 31 | symmetric_key skey; 32 | 33 | unsigned char K[32], /* the current key */ 34 | IV[16]; /* IV for CTR mode */ 35 | 36 | unsigned long pool_idx, /* current pool we will add to */ 37 | pool0_len; /* length of 0'th pool */ 38 | ulong64 wd; 39 | ulong64 reset_cnt; /* number of times we have reseeded */ 40 | }; 41 | #endif 42 | 43 | #ifdef LTC_SOBER128 44 | struct sober128_prng { 45 | sober128_state s; /* sober128 state */ 46 | unsigned char ent[40]; /* entropy buffer */ 47 | unsigned long idx; /* entropy counter */ 48 | }; 49 | #endif 50 | 51 | typedef struct { 52 | union { 53 | char dummy[1]; 54 | #ifdef LTC_YARROW 55 | struct yarrow_prng yarrow; 56 | #endif 57 | #ifdef LTC_RC4 58 | struct rc4_prng rc4; 59 | #endif 60 | #ifdef LTC_CHACHA20_PRNG 61 | struct chacha20_prng chacha; 62 | #endif 63 | #ifdef LTC_FORTUNA 64 | struct fortuna_prng fortuna; 65 | #endif 66 | #ifdef LTC_SOBER128 67 | struct sober128_prng sober128; 68 | #endif 69 | } u; 70 | short ready; /* ready flag 0-1 */ 71 | LTC_MUTEX_TYPE(lock) /* lock */ 72 | } prng_state; 73 | 74 | /** PRNG descriptor */ 75 | extern struct ltc_prng_descriptor { 76 | /** Name of the PRNG */ 77 | const char *name; 78 | /** size in bytes of exported state */ 79 | int export_size; 80 | /** Start a PRNG state 81 | @param prng [out] The state to initialize 82 | @return CRYPT_OK if successful 83 | */ 84 | int (*start)(prng_state *prng); 85 | /** Add entropy to the PRNG 86 | @param in The entropy 87 | @param inlen Length of the entropy (octets)\ 88 | @param prng The PRNG state 89 | @return CRYPT_OK if successful 90 | */ 91 | int (*add_entropy)(const unsigned char *in, unsigned long inlen, prng_state *prng); 92 | /** Ready a PRNG state to read from 93 | @param prng The PRNG state to ready 94 | @return CRYPT_OK if successful 95 | */ 96 | int (*ready)(prng_state *prng); 97 | /** Read from the PRNG 98 | @param out [out] Where to store the data 99 | @param outlen Length of data desired (octets) 100 | @param prng The PRNG state to read from 101 | @return Number of octets read 102 | */ 103 | unsigned long (*read)(unsigned char *out, unsigned long outlen, prng_state *prng); 104 | /** Terminate a PRNG state 105 | @param prng The PRNG state to terminate 106 | @return CRYPT_OK if successful 107 | */ 108 | int (*done)(prng_state *prng); 109 | /** Export a PRNG state 110 | @param out [out] The destination for the state 111 | @param outlen [in/out] The max size and resulting size of the PRNG state 112 | @param prng The PRNG to export 113 | @return CRYPT_OK if successful 114 | */ 115 | int (*pexport)(unsigned char *out, unsigned long *outlen, prng_state *prng); 116 | /** Import a PRNG state 117 | @param in The data to import 118 | @param inlen The length of the data to import (octets) 119 | @param prng The PRNG to initialize/import 120 | @return CRYPT_OK if successful 121 | */ 122 | int (*pimport)(const unsigned char *in, unsigned long inlen, prng_state *prng); 123 | /** Self-test the PRNG 124 | @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled 125 | */ 126 | int (*test)(void); 127 | } prng_descriptor[]; 128 | 129 | #ifdef LTC_YARROW 130 | int yarrow_start(prng_state *prng); 131 | int yarrow_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng); 132 | int yarrow_ready(prng_state *prng); 133 | unsigned long yarrow_read(unsigned char *out, unsigned long outlen, prng_state *prng); 134 | int yarrow_done(prng_state *prng); 135 | int yarrow_export(unsigned char *out, unsigned long *outlen, prng_state *prng); 136 | int yarrow_import(const unsigned char *in, unsigned long inlen, prng_state *prng); 137 | int yarrow_test(void); 138 | extern const struct ltc_prng_descriptor yarrow_desc; 139 | #endif 140 | 141 | #ifdef LTC_FORTUNA 142 | int fortuna_start(prng_state *prng); 143 | int fortuna_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng); 144 | int fortuna_add_random_event(unsigned long source, unsigned long pool, const unsigned char *in, unsigned long inlen, prng_state *prng); 145 | int fortuna_ready(prng_state *prng); 146 | unsigned long fortuna_read(unsigned char *out, unsigned long outlen, prng_state *prng); 147 | int fortuna_done(prng_state *prng); 148 | int fortuna_export(unsigned char *out, unsigned long *outlen, prng_state *prng); 149 | int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prng); 150 | int fortuna_update_seed(const unsigned char *in, unsigned long inlen, prng_state *prng); 151 | int fortuna_test(void); 152 | extern const struct ltc_prng_descriptor fortuna_desc; 153 | #endif 154 | 155 | #ifdef LTC_RC4 156 | int rc4_start(prng_state *prng); 157 | int rc4_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng); 158 | int rc4_ready(prng_state *prng); 159 | unsigned long rc4_read(unsigned char *out, unsigned long outlen, prng_state *prng); 160 | int rc4_done(prng_state *prng); 161 | int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng); 162 | int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng); 163 | int rc4_test(void); 164 | extern const struct ltc_prng_descriptor rc4_desc; 165 | #endif 166 | 167 | #ifdef LTC_CHACHA20_PRNG 168 | int chacha20_prng_start(prng_state *prng); 169 | int chacha20_prng_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng); 170 | int chacha20_prng_ready(prng_state *prng); 171 | unsigned long chacha20_prng_read(unsigned char *out, unsigned long outlen, prng_state *prng); 172 | int chacha20_prng_done(prng_state *prng); 173 | int chacha20_prng_export(unsigned char *out, unsigned long *outlen, prng_state *prng); 174 | int chacha20_prng_import(const unsigned char *in, unsigned long inlen, prng_state *prng); 175 | int chacha20_prng_test(void); 176 | extern const struct ltc_prng_descriptor chacha20_prng_desc; 177 | #endif 178 | 179 | #ifdef LTC_SPRNG 180 | int sprng_start(prng_state *prng); 181 | int sprng_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng); 182 | int sprng_ready(prng_state *prng); 183 | unsigned long sprng_read(unsigned char *out, unsigned long outlen, prng_state *prng); 184 | int sprng_done(prng_state *prng); 185 | int sprng_export(unsigned char *out, unsigned long *outlen, prng_state *prng); 186 | int sprng_import(const unsigned char *in, unsigned long inlen, prng_state *prng); 187 | int sprng_test(void); 188 | extern const struct ltc_prng_descriptor sprng_desc; 189 | #endif 190 | 191 | #ifdef LTC_SOBER128 192 | int sober128_start(prng_state *prng); 193 | int sober128_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng); 194 | int sober128_ready(prng_state *prng); 195 | unsigned long sober128_read(unsigned char *out, unsigned long outlen, prng_state *prng); 196 | int sober128_done(prng_state *prng); 197 | int sober128_export(unsigned char *out, unsigned long *outlen, prng_state *prng); 198 | int sober128_import(const unsigned char *in, unsigned long inlen, prng_state *prng); 199 | int sober128_test(void); 200 | extern const struct ltc_prng_descriptor sober128_desc; 201 | #endif 202 | 203 | int find_prng(const char *name); 204 | int register_prng(const struct ltc_prng_descriptor *prng); 205 | int unregister_prng(const struct ltc_prng_descriptor *prng); 206 | int register_all_prngs(void); 207 | int prng_is_valid(int idx); 208 | LTC_MUTEX_PROTO(ltc_prng_mutex) 209 | 210 | /* Slow RNG you **might** be able to use to seed a PRNG with. Be careful as this 211 | * might not work on all platforms as planned 212 | */ 213 | unsigned long rng_get_bytes(unsigned char *out, 214 | unsigned long outlen, 215 | void (*callback)(void)); 216 | 217 | int rng_make_prng(int bits, int wprng, prng_state *prng, void (*callback)(void)); 218 | 219 | #ifdef LTC_PRNG_ENABLE_LTC_RNG 220 | extern unsigned long (*ltc_rng)(unsigned char *out, unsigned long outlen, 221 | void (*callback)(void)); 222 | #endif 223 | 224 | -------------------------------------------------------------------------------- /Sources/SkipSQL/SQLContext.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2023–2025 Skip 2 | // SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception 3 | import Foundation 4 | import OSLog 5 | #if SKIP 6 | import SkipFFI 7 | #endif 8 | 9 | let logger: Logger = Logger(subsystem: "skip.sql", category: "SQL") 10 | 11 | /// A context for performing operations on a SQLite database. 12 | public final class SQLContext { 13 | /// The SQLite3 library to use. 14 | fileprivate let SQLite3: SQLiteLibrary 15 | 16 | /// The logging level for this context; SQL statements and warnings will be sent to this log. 17 | public var logLevel: OSLogType? = nil 18 | 19 | /// The pointer to the SQLite database. 20 | private let db: OpaquePointer 21 | private var closed = false 22 | 23 | /// The rowid of the most recent successful `INSERT` into a rowid table. 24 | public var lastInsertRowID: Int64 { 25 | SQLite3.sqlite3_last_insert_rowid(db) 26 | } 27 | 28 | /// The number of rows modified, inserted or deleted by the most recently completed INSERT, UPDATE or DELETE statement. 29 | public var changes: Int32 { 30 | SQLite3.sqlite3_changes(db) 31 | } 32 | 33 | /// The total number of rows inserted, modified or deleted by all [INSERT], [UPDATE] or [DELETE] statements completed since the database connection was opened, including those executed as part of triggers. 34 | public var totalChanges: Int32 { 35 | SQLite3.sqlite3_total_changes(db) 36 | } 37 | 38 | deinit { 39 | #if !SKIP 40 | #if DEBUG 41 | //assert(isClosed, "SQLContext must be closed before deinit") 42 | #endif 43 | #endif 44 | } 45 | 46 | /// Create an in-memory `SQLContext`. 47 | public init(configuration: SQLiteConfiguration = .platform) { 48 | // try! because creating an in-memory context should never fail 49 | self.SQLite3 = configuration.library 50 | self.db = try! Self.connect(path: ":memory:", configuration: configuration)! 51 | } 52 | 53 | /// Create a new `SQLContext` with the given options, either in-memory (the default), or on a file path. 54 | /// - Parameters: 55 | /// - path: The path to the local file, or ":memory:" for an in-memory database. 56 | /// - flags: The flags to use to open the database. 57 | public init(path: String, flags: OpenFlags? = nil, logLevel: OSLogType? = nil, configuration: SQLiteConfiguration = .platform) throws { 58 | self.logLevel = logLevel 59 | self.SQLite3 = configuration.library 60 | self.db = try Self.connect(path: path, flags: flags, configuration: configuration)! 61 | 62 | if let logLevel = logLevel { 63 | logger.log(level: logLevel, "opened database: \(path)") 64 | } 65 | } 66 | 67 | private static func connect(path: String, flags: OpenFlags? = nil, configuration: SQLiteConfiguration = .platform) throws -> OpaquePointer? { 68 | var db: OpaquePointer? = nil 69 | let library = configuration.library 70 | try check(library, db: db, code: withUnsafeMutablePointer(to: &db) { ptr in 71 | if let flags = flags { 72 | return library.sqlite3_open_v2(path, ptr, flags.rawValue, nil) 73 | } else { 74 | return library.sqlite3_open(path, ptr) 75 | } 76 | }) 77 | 78 | return db 79 | } 80 | 81 | public struct OpenFlags: OptionSet { 82 | public let rawValue: Int32 83 | 84 | public init(rawValue: Int32) { 85 | self.rawValue = rawValue 86 | } 87 | 88 | public static let readOnly = OpenFlags(rawValue: 0x00000001) 89 | public static let readWrite = OpenFlags(rawValue: 0x00000002) 90 | public static let create = OpenFlags(rawValue: 0x00000004) 91 | public static let uri = OpenFlags(rawValue: 0x00000040) 92 | public static let memory = OpenFlags(rawValue: 0x00000080) 93 | public static let nomutex = OpenFlags(rawValue: 0x00008000) 94 | public static let fullMutex = OpenFlags(rawValue: 0x00010000) 95 | public static let sharedCache = OpenFlags(rawValue: 0x00020000) 96 | public static let privateCache = OpenFlags(rawValue: 0x00040000) 97 | } 98 | 99 | public func exec(_ expr: SQLExpression) throws { 100 | try checkClosed() 101 | let stmnt = try prepare(sql: expr.template) 102 | var err: Error? = nil 103 | do { 104 | try stmnt.update(parameters: expr.bindings) 105 | } catch let e { 106 | err = e 107 | } 108 | // always close the statements; we don't use a `defer` block because they can't throw 109 | try stmnt.close() 110 | if let err = err { 111 | throw err 112 | } 113 | } 114 | 115 | /// Execute the given SQL statement. 116 | public func exec(sql: String, parameters: [SQLValue] = []) throws { 117 | try exec(SQLExpression(sql, parameters)) 118 | } 119 | 120 | /// See 121 | public func interrupt() { 122 | SQLite3.sqlite3_interrupt(db) 123 | } 124 | 125 | /// True if the context has been closed. 126 | public var isClosed: Bool { 127 | closed 128 | } 129 | 130 | /// Close the connection. 131 | public func close() throws { 132 | if !closed { 133 | try check(SQLite3, db: db, code: SQLite3.sqlite3_close(db)) 134 | closed = true 135 | } 136 | } 137 | 138 | /// Prepares the given SQL as a statement, which can be executed with parameter bindings. 139 | public func prepare(sql: String) throws -> SQLStatement { 140 | try checkClosed() 141 | if let logLevel = self.logLevel { 142 | logger.log(level: logLevel, "prepare: \(sql)") 143 | } 144 | var stmntPtr: OpaquePointer? = nil 145 | 146 | try check(SQLite3, db: db, code: withUnsafeMutablePointer(to: &stmntPtr) { ptr in 147 | SQLite3.sqlite3_prepare_v2(db, sql, Int32(-1), ptr, nil) 148 | }) 149 | 150 | if stmntPtr == nil { 151 | throw SQLStatementCreationError() 152 | } 153 | 154 | return SQLStatement(stmnt: stmntPtr!, SQLite3: self.SQLite3) 155 | } 156 | 157 | /// How a transaction is being performed. 158 | public enum TransactionMode: String { 159 | case deferred = "DEFERRED" 160 | case immediate = "IMMEDIATE" 161 | case exclusive = "EXCLUSIVE" 162 | } 163 | 164 | /// Performs the given operation in the context of a transaction. 165 | /// 166 | /// Specifying `.none` as the transaction mode will execute the command without a transaction. 167 | public func transaction(_ mode: TransactionMode? = .deferred, block: () throws -> T) throws -> T { 168 | if let mode = mode { 169 | return try perform( 170 | "BEGIN \(mode.rawValue) TRANSACTION", 171 | block, 172 | "COMMIT TRANSACTION", or: "ROLLBACK TRANSACTION") 173 | } else { 174 | return try block() 175 | } 176 | } 177 | 178 | /// Performs the given operation within the databases mutex lock. 179 | public func mutex(block: () throws -> T) rethrows -> T { 180 | let lock = SQLite3.sqlite3_db_mutex(db) 181 | SQLite3.sqlite3_mutex_enter(lock) 182 | defer { 183 | SQLite3.sqlite3_mutex_leave(lock) 184 | // SQLite3.sqlite3_mutex_free(lock) // don't free! 185 | } 186 | return try block() 187 | } 188 | 189 | /// Performs the given operation in the context of a begin and commit/rollback statement. 190 | fileprivate func perform(_ begin: String, _ block: () throws -> T, _ commit: String, or rollback: String) throws -> T { 191 | try exec(sql: begin) 192 | do { 193 | let result = try block() 194 | try exec(sql: commit) 195 | return result 196 | } catch { 197 | try exec(sql: rollback) 198 | throw error 199 | } 200 | } 201 | 202 | private func checkClosed() throws { 203 | if closed { 204 | throw SQLContextClosedError() 205 | } 206 | } 207 | 208 | /// Issue a query and return all the rows in a single batch 209 | public func query(sql: String, parameters: [SQLValue] = []) throws -> [[SQLValue]] { 210 | try cursor(SQLExpression(sql, parameters)).map({ try $0.get() }) 211 | } 212 | 213 | /// Issues a SQL query with the optional parameters and returns all the values. 214 | public func cursor(_ expr: SQLExpression) throws -> RowCursor<[SQLValue]> { 215 | let stmnt = try prepare(sql: expr.template) 216 | if !expr.bindings.isEmpty { 217 | try stmnt.bind(parameters: expr.bindings) 218 | } 219 | return RowCursor(statement: stmnt, creator: { $0.rowValues() }) 220 | } 221 | 222 | 223 | // MARK: trace 224 | 225 | public typealias TraceAction = (String) -> Void 226 | private var traceHook: TraceHook? 227 | 228 | #if !SKIP 229 | typealias TraceBox = @convention(block) (UnsafeRawPointer) -> Void 230 | private typealias TraceHook = TraceBox 231 | #else 232 | private final class TraceHook : sqlite3_trace_hook { 233 | let action: TraceAction 234 | let context: SQLContext 235 | 236 | init(action: TraceAction, context: SQLContext) { 237 | self.action = action 238 | self.context = context 239 | } 240 | 241 | override func callback(type: sqlite3_unsigned, ctx: OpaquePointer?, pointer: OpaquePointer?, px: OpaquePointer?) -> Int32 { 242 | if let pointer, 243 | let expandedSQL: sqlite3_cstring_mutptr = context.SQLite3.sqlite3_expanded_sql(pointer) { 244 | action(expandedSQL.getString(0)) 245 | context.SQLite3.sqlite3_free(expandedSQL) 246 | } 247 | return 0 248 | } 249 | } 250 | #endif 251 | 252 | /// Adds a callback that will be invoked with the expanded SQL whenever a statement is executed 253 | public func trace(_ action: TraceAction?) { 254 | guard let action else { 255 | // disable trace 256 | _ = SQLite3.sqlite3_trace_v2(db, 0, nil, nil) 257 | self.traceHook = nil 258 | return 259 | } 260 | 261 | #if !SKIP 262 | let box: TraceBox = { (pointer: UnsafeRawPointer) in 263 | if let expandedSQL: sqlite3_cstring_mutptr = self.SQLite3.sqlite3_expanded_sql(OpaquePointer(pointer)) { 264 | action(String(cString: expandedSQL)) 265 | self.SQLite3.sqlite3_free(expandedSQL) 266 | } 267 | } 268 | 269 | _ = SQLite3.sqlite3_trace_v2(db, UInt32(SQLITE_TRACE_STMT), { 270 | (_: UInt32, context: UnsafeMutableRawPointer?, pointer: UnsafeMutableRawPointer?, _: UnsafeMutableRawPointer?) in 271 | if let pointer { 272 | unsafeBitCast(context, to: TraceBox.self)(pointer) 273 | } 274 | return Int32(0) 275 | }, 276 | unsafeBitCast(box, to: UnsafeMutableRawPointer.self) 277 | ) 278 | traceHook = box 279 | #else 280 | self.traceHook = TraceHook(action: action, context: self) // need to retain or it will be garbage collected eventually 281 | // The Kotlin update mechanism is different; it uses a TraceHook implementation, and doesn't pass a context pointer 282 | SQLite3.sqlite3_trace_v2(db, SQLITE_TRACE_STMT, self.traceHook, nil) 283 | #endif 284 | } 285 | 286 | 287 | // MARK: onUpdate 288 | 289 | private var updateHook: UpdateHook? = nil 290 | 291 | /// An action that can be registered to receive updates whenever a ROWID table changes. 292 | public typealias UpdateAction = (_ action: SQLAction, _ rowid: Int64, _ dbname: String, _ tblname: String) -> Void 293 | 294 | #if !SKIP 295 | private typealias UpdateHook = UpdateAction 296 | #else 297 | private final class UpdateHook : sqlite3_update_hook { 298 | let updateAction: UpdateAction 299 | 300 | init(action: UpdateAction) { 301 | self.updateAction = action 302 | } 303 | 304 | override func callback(ptr: OpaquePointer?, operation: Int32, databaseName: OpaquePointer?, tableName: OpaquePointer?, rowid: Int64) { 305 | if let operation = SQLAction(rawValue: operation), 306 | let dbnamePtr = databaseName, let tblnamePtr = tableName { 307 | updateAction(operation, rowid, String(cString: dbnamePtr), String(cString: tblnamePtr)) 308 | } 309 | } 310 | } 311 | #endif 312 | 313 | /// Registers a function to be invoked whenever a ROWID table is changed. 314 | /// 315 | /// As described at https://www.sqlite.org/c3ref/update_hook.html , a given connection can only have a single update hook at a time, so setting this function will replace any pre-existing update hook. 316 | public func onUpdate(hook: UpdateAction?) { 317 | guard let hook else { 318 | // clear the update hook 319 | self.updateHook = nil 320 | return 321 | } 322 | #if !SKIP 323 | self.updateHook = hook 324 | let updateActionPtr = Unmanaged.passRetained(hook as AnyObject).toOpaque() 325 | func callback(updateActionPtr: UnsafeMutableRawPointer?, operation: Int32, dbname: UnsafePointer?, tblname: UnsafePointer?, rowid: sqlite3_int64) -> Void { 326 | if let operation = SQLAction(rawValue: operation), 327 | let updateActionPtr = updateActionPtr, 328 | let hook = Unmanaged.fromOpaque(updateActionPtr).takeUnretainedValue() as? UpdateAction, 329 | let dbnamePtr = dbname, let tblnamePtr = tblname { 330 | hook(operation, rowid, String(cString: dbnamePtr), String(cString: tblnamePtr)) 331 | } 332 | } 333 | _ = SQLite3.sqlite3_update_hook(db, callback, updateActionPtr) 334 | #else 335 | self.updateHook = UpdateHook(action: hook) // need to retain or it will be garbage collected eventually 336 | // The Kotlin update mechanism is different; it uses a SQLiteUpdateHookCallback implementation, and doesn't pass a userData pointer 337 | SQLite3.sqlite3_update_hook(db, self.updateHook, nil) 338 | #endif 339 | } 340 | } 341 | 342 | public struct SQLExpression { 343 | public var template: String 344 | public var bindings: [SQLValue] 345 | 346 | public init(_ template: String, _ bindings: [SQLValue] = []) { 347 | self.template = template 348 | self.bindings = bindings 349 | } 350 | } 351 | 352 | extension String { 353 | /// Encodes the String so the given mark is doubled in the resulting string. 354 | public func quote(_ mark: Character = "\"") -> String { 355 | var quoted = "" 356 | quoted += mark.description 357 | for character in self { 358 | quoted += character.description 359 | if character == mark { 360 | quoted += character.description 361 | } 362 | } 363 | quoted += mark.description 364 | return quoted 365 | } 366 | } 367 | 368 | /// A lazy sequence of rows from the database 369 | public class RowCursor : Sequence { 370 | public typealias Element = Result 371 | let statement: SQLStatement 372 | let creator: (SQLStatement) throws -> Row 373 | 374 | public init(statement: SQLStatement, creator: @escaping (SQLStatement) throws -> Row) { 375 | self.statement = statement 376 | self.creator = creator 377 | } 378 | 379 | public func close() { 380 | do { 381 | try statement.close() 382 | } catch { 383 | } 384 | } 385 | 386 | 387 | #if !SKIP 388 | public func makeIterator() -> RowIterator { 389 | RowIterator(statement: statement, creator: creator) 390 | } 391 | #else 392 | override var iterable: kotlin.collections.Iterable { 393 | AbstractIterable { 394 | RowIterator(statement: statement, creator: creator) 395 | } 396 | } 397 | #endif 398 | } 399 | 400 | #if !SKIP 401 | typealias RowIteratorType = IteratorProtocol 402 | #else 403 | typealias RowIteratorType = kotlin.collections.Iterator> 404 | 405 | class AbstractIterable : kotlin.collections.Iterable> { 406 | let makeIterator: () -> RowIterator 407 | 408 | init(makeIterator: () -> RowIterator) { 409 | self.makeIterator = makeIterator 410 | } 411 | 412 | override func iterator() -> RowIterator { 413 | makeIterator() 414 | } 415 | } 416 | #endif 417 | 418 | public class RowIterator : RowIteratorType { 419 | public typealias Element = Result 420 | let stmnt: SQLStatement 421 | let creator: (SQLStatement) throws -> Row 422 | var errorOccurred = false 423 | 424 | init(statement: SQLStatement, creator: @escaping (SQLStatement) throws -> Row) { 425 | self.stmnt = statement 426 | self.creator = creator 427 | } 428 | 429 | deinit { 430 | close() 431 | } 432 | 433 | func close() { 434 | do { 435 | try stmnt.close() 436 | } catch { 437 | // ignore 438 | } 439 | } 440 | 441 | #if !SKIP 442 | public func next() -> Element? { 443 | if errorOccurred { 444 | return nil 445 | } 446 | do { 447 | if try stmnt.next() == false { return nil } 448 | return Result.success(try creator(stmnt)) 449 | } catch { 450 | errorOccurred = true 451 | return Result.failure(error) 452 | } 453 | } 454 | #else 455 | var nextElement: Element? = nil 456 | 457 | override func next() -> Element { 458 | if let nextElement = nextElement { 459 | return nextElement 460 | } else { 461 | throw java.util.NoSuchElementException() 462 | } 463 | } 464 | 465 | override func hasNext() -> Bool { 466 | if errorOccurred { 467 | return false 468 | } 469 | do { 470 | if try stmnt.next() == false { 471 | close() 472 | return false 473 | } 474 | nextElement = Result.success(try creator(stmnt)) 475 | return true 476 | } catch { 477 | errorOccurred = true 478 | nextElement = Result.failure(error) 479 | close() 480 | return false 481 | } 482 | } 483 | #endif 484 | } 485 | -------------------------------------------------------------------------------- /Sources/SkipSQL/SQLStatement.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2023–2025 Skip 2 | // SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception 3 | #if SKIP 4 | import SkipFFI 5 | #endif 6 | import Foundation 7 | import OSLog 8 | 9 | /// A database prepared statement. 10 | public final class SQLStatement { 11 | /// The SQLite3 library to use. 12 | fileprivate let SQLite3: SQLiteLibrary 13 | 14 | /// The pointer to the SQLite statement. 15 | fileprivate let stmnt: OpaquePointer 16 | fileprivate var closed = false 17 | 18 | deinit { 19 | #if !SKIP 20 | #if DEBUG 21 | // assert(isClosed, "SQLStatement must be closed before deinit") 22 | #endif 23 | #endif 24 | } 25 | 26 | internal init(stmnt: OpaquePointer, SQLite3: SQLiteLibrary) { 27 | self.stmnt = stmnt 28 | self.SQLite3 = SQLite3 29 | } 30 | 31 | /// The database pointer that created this statement. 32 | private var db: OpaquePointer { 33 | SQLite3.sqlite3_db_handle(stmnt) 34 | } 35 | 36 | public lazy var columnCount: Int32 = SQLite3.sqlite3_column_count(stmnt) 37 | 38 | public lazy var columnNames: [String] = Array((0..= 1, "bind index in sqlite starts at 1") 59 | switch value { 60 | case .null: 61 | try check(SQLite3, db: db, code: SQLite3.sqlite3_bind_null(stmnt, index)) 62 | case .long(let long): 63 | try check(SQLite3, db: db, code: SQLite3.sqlite3_bind_int64(stmnt, index, long)) 64 | case .text(let text): 65 | try check(SQLite3, db: db, code: SQLite3.sqlite3_bind_text(stmnt, index, text, -1, SQLITE_TRANSIENT)) 66 | case .real(let real): 67 | try check(SQLite3, db: db, code: SQLite3.sqlite3_bind_double(stmnt, index, real)) 68 | case .blob(let blob): 69 | let size = Int32(blob.count) 70 | if size == 0 { 71 | try check(SQLite3, db: db, code: SQLite3.sqlite3_bind_zeroblob(stmnt, index, size)) 72 | } else { 73 | try blob.withUnsafeBytes { ptr in 74 | try check(SQLite3, db: db, code: SQLite3.sqlite3_bind_blob(stmnt, index, ptr.baseAddress, size, SQLITE_TRANSIENT)) 75 | } 76 | } 77 | } 78 | } 79 | 80 | /// Perform an update with the prepared statemement, resetting it once the update is complete. 81 | /// - Parameter params: the parameters to bind to the SQL statement 82 | public func update(parameters: [SQLValue] = []) throws { 83 | try checkClosed() 84 | defer { reset() } 85 | if !parameters.isEmpty { 86 | try bind(parameters: parameters) 87 | } 88 | let result = SQLite3.sqlite3_step(stmnt) 89 | try check(SQLite3, db: db, code: result, permit: [Int32(SQLITE_DONE)]) 90 | } 91 | 92 | /// Binds the given parameters to the statement. The parameter count must match the number of `?` parameters in the statement. 93 | public func bind(parameters: [SQLValue]) throws { 94 | for (i, param) in parameters.enumerated() { 95 | try bind(param, at: Int32(i + 1)) // column index starts at 1 96 | } 97 | } 98 | 99 | /// After a prepared statement has been prepared this function must be called one or more times to evaluate the statement. 100 | public func next() throws -> Bool { 101 | try checkClosed() 102 | let result = SQLite3.sqlite3_step(stmnt) 103 | if result == SQLITE_ROW { 104 | return true 105 | } else if result == SQLITE_DONE { 106 | return false 107 | } else { 108 | try check(SQLite3, db: db, code: result) // try to extract the error message 109 | throw SQLStatementError(code: result) 110 | } 111 | } 112 | 113 | /// True if the statement has been closed. 114 | public var isClosed: Bool { 115 | closed 116 | } 117 | 118 | /// The application must close every prepared statement in order to avoid 119 | /// resource leaks. It is a grievous error for the application to try to use 120 | /// a prepared statement after it has been closed. 121 | public func close() throws { 122 | if !closed { 123 | reset() // need to reset interrupted statemets or an interrupted error will be throws 124 | try check(SQLite3, db: db, code: SQLite3.sqlite3_finalize(stmnt)) 125 | closed = true 126 | } 127 | } 128 | 129 | public func reset() { 130 | reset(clearBindings: true) 131 | } 132 | 133 | internal func reset(clearBindings: Bool) { 134 | _ = SQLite3.sqlite3_reset(stmnt) 135 | if clearBindings { 136 | _ = SQLite3.sqlite3_clear_bindings(stmnt) 137 | } 138 | } 139 | 140 | /// Returns the type of the column at the given index. 141 | public func type(at idx: Int32) -> SQLType { 142 | SQLType(rawValue: SQLite3.sqlite3_column_type(stmnt, idx)) ?? .null 143 | } 144 | 145 | /// Returns the integer at the given index, coercing if necessary according to https://www.sqlite.org/datatype3.html 146 | public func long(at idx: Int32) -> Int64 { 147 | SQLite3.sqlite3_column_int64(stmnt, idx) 148 | } 149 | 150 | @available(*, deprecated, renamed: "long") 151 | public func integer(at idx: Int32) -> Int64 { 152 | long(at: idx) 153 | } 154 | 155 | /// Returns the double at the given index, coercing if necessary according to https://www.sqlite.org/datatype3.html 156 | public func real(at idx: Int32) -> Double { 157 | SQLite3.sqlite3_column_double(stmnt, idx) 158 | } 159 | 160 | @available(*, deprecated, renamed: "real") 161 | public func double(at idx: Int32) -> Double { 162 | real(at: idx) 163 | } 164 | 165 | /// Returns the string at the given index, coercing if necessary according to https://www.sqlite.org/datatype3.html 166 | public func text(at idx: Int32) -> String? { 167 | strptr(SQLite3.sqlite3_column_text(stmnt, idx)) 168 | } 169 | 170 | @available(*, deprecated, renamed: "text") 171 | public func string(at idx: Int32) -> String? { 172 | text(at: idx) 173 | } 174 | 175 | /// Returns the blob Data at the given index, coercing if necessary according to https://www.sqlite.org/datatype3.html 176 | public func blob(at idx: Int32) -> Data? { 177 | if let pointer = SQLite3.sqlite3_column_blob(stmnt, idx) { 178 | let length = SQLite3.sqlite3_column_bytes(stmnt, idx) 179 | #if !SKIP 180 | return Data(bytes: pointer, count: Int(length)) 181 | #else 182 | let byteArray = pointer.getByteArray(0, length) 183 | return Data(platformValue: byteArray) 184 | #endif 185 | } else { 186 | // The return value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer. 187 | // https://www.sqlite.org/c3ref/column_blob.html 188 | return nil 189 | } 190 | } 191 | 192 | /// Returns the value at the given index, based on the type returned from `type(at:)`. 193 | public func value(at idx: Int32) -> SQLValue { 194 | switch type(at: idx) { 195 | case SQLType.long: 196 | return SQLValue.long(long(at: idx)) 197 | case SQLType.real: 198 | return SQLValue.real(real(at: idx)) 199 | case SQLType.text: 200 | if let string = text(at: idx) { 201 | return SQLValue.text(string) 202 | } else { 203 | return SQLValue.null 204 | } 205 | case SQLType.blob: 206 | if let blob = blob(at: idx) { 207 | return SQLValue.blob(blob) 208 | } else { 209 | return SQLValue.null 210 | } 211 | case SQLType.null: 212 | return SQLValue.null 213 | } 214 | } 215 | 216 | public func rowValues() -> [SQLValue] { 217 | Array((0.. [SQLValue]? { 222 | try checkClosed() 223 | 224 | if !(try next()) { 225 | return nil 226 | } 227 | 228 | let values = rowValues() 229 | 230 | if close { 231 | try self.close() 232 | } 233 | 234 | return values 235 | } 236 | 237 | /// Returns the values of the current row as an array of strings, coercing if necessary according to https://www.sqlite.org/datatype3.html 238 | public func stringValues() -> [String?] { 239 | Array((0.. SQLValue { 204 | .real(value) 205 | } 206 | 207 | @available(*, deprecated, renamed: "long") 208 | static func integer(_ value: Int64) -> SQLValue { 209 | .long(value) 210 | } 211 | } 212 | 213 | public struct SQLContextClosedError : Error { 214 | } 215 | 216 | public struct SQLStatementCreationError : Error { 217 | } 218 | 219 | public struct SQLStatementClosedError : Error { 220 | } 221 | 222 | public struct InternalError : Error { 223 | public let code: Int32 224 | 225 | public init(code: Int32) { 226 | self.code = code 227 | } 228 | } 229 | 230 | public struct SQLError : Error, CustomStringConvertible { 231 | public let msg: String 232 | public let code: Int32 233 | 234 | public init(msg: String, code: Int32) { 235 | self.msg = msg 236 | self.code = code 237 | } 238 | 239 | public var description: String { 240 | "SQLite error code \(code): \(msg)" 241 | } 242 | 243 | public var localizedDescription: String { 244 | "SQLite error code \(code): \(msg)" 245 | } 246 | } 247 | 248 | public struct SQLStatementError : Error { 249 | public let code: Int32 250 | } 251 | 252 | 253 | internal func check(_ SQLite3: SQLiteLibrary, db: OpaquePointer?, code: Int32, permit: Set? = nil) throws { 254 | if code != 0 && permit?.contains(code) != true { 255 | if let db = db, let msg = SQLite3.sqlite3_errmsg(db) { 256 | throw SQLError(msg: String(cString: msg), code: code) 257 | } else { 258 | throw SQLError(msg: "Unknown SQLite error", code: code) 259 | } 260 | } 261 | } 262 | 263 | #if SKIP 264 | internal func strptr(_ ptr: OpaquePointer?) -> String? { 265 | guard let ptr = ptr else { return nil } 266 | return String(cString: ptr) 267 | } 268 | #else 269 | internal func strptr(_ ptr: UnsafePointer?) -> String? { 270 | guard let ptr = ptr else { return nil } 271 | return String(cString: ptr) 272 | } 273 | 274 | internal func strptr(_ ptr: UnsafePointer?) -> String? { 275 | guard let ptr = ptr else { return nil } 276 | return String(cString: ptr) 277 | } 278 | #endif 279 | 280 | 281 | #if SKIP 282 | 283 | 284 | // MARK: SQLite Result Codes 285 | 286 | let SQLITE_OK = 0 /* Successful result */ 287 | let SQLITE_ERROR = 1 /* Generic error */ 288 | let SQLITE_INTERNAL = 2 /* Internal logic error in SQLite */ 289 | let SQLITE_PERM = 3 /* Access permission denied */ 290 | let SQLITE_ABORT = 4 /* Callback routine requested an abort */ 291 | let SQLITE_BUSY = 5 /* The database file is locked */ 292 | let SQLITE_LOCKED = 6 /* A table in the database is locked */ 293 | let SQLITE_NOMEM = 7 /* A malloc() failed */ 294 | let SQLITE_READONLY = 8 /* Attempt to write a readonly database */ 295 | let SQLITE_INTERRUPT = 9 /* Operation terminated by sqlite3_interrupt()*/ 296 | let SQLITE_IOERR = 10 /* Some kind of disk I/O error occurred */ 297 | let SQLITE_CORRUPT = 11 /* The database disk image is malformed */ 298 | let SQLITE_NOTFOUND = 12 /* Unknown opcode in sqlite3_file_control() */ 299 | let SQLITE_FULL = 13 /* Insertion failed because database is full */ 300 | let SQLITE_CANTOPEN = 14 /* Unable to open the database file */ 301 | let SQLITE_PROTOCOL = 15 /* Database lock protocol error */ 302 | let SQLITE_EMPTY = 16 /* Internal use only */ 303 | let SQLITE_SCHEMA = 17 /* The database schema changed */ 304 | let SQLITE_TOOBIG = 18 /* String or BLOB exceeds size limit */ 305 | let SQLITE_CONSTRAINT = 19 /* Abort due to constraint violation */ 306 | let SQLITE_MISMATCH = 20 /* Data type mismatch */ 307 | let SQLITE_MISUSE = 21 /* Library used incorrectly */ 308 | let SQLITE_NOLFS = 22 /* Uses OS features not supported on host */ 309 | let SQLITE_AUTH = 23 /* Authorization denied */ 310 | let SQLITE_FORMAT = 24 /* Not used */ 311 | let SQLITE_RANGE = 25 /* 2nd parameter to sqlite3_bind out of range */ 312 | let SQLITE_NOTADB = 26 /* File opened that is not a database file */ 313 | let SQLITE_NOTICE = 27 /* Notifications from sqlite3_log() */ 314 | let SQLITE_WARNING = 28 /* Warnings from sqlite3_log() */ 315 | let SQLITE_ROW = 100 /* sqlite3_step() has another row ready */ 316 | let SQLITE_DONE = 101 /* sqlite3_step() has finished executing */ 317 | 318 | // MARK Extended Result Codes 319 | 320 | let SQLITE_ERROR_MISSING_COLLSEQ = (SQLITE_ERROR | (1<<8)) 321 | let SQLITE_ERROR_RETRY = (SQLITE_ERROR | (2<<8)) 322 | let SQLITE_ERROR_SNAPSHOT = (SQLITE_ERROR | (3<<8)) 323 | let SQLITE_IOERR_READ = (SQLITE_IOERR | (1<<8)) 324 | let SQLITE_IOERR_SHORT_READ = (SQLITE_IOERR | (2<<8)) 325 | let SQLITE_IOERR_WRITE = (SQLITE_IOERR | (3<<8)) 326 | let SQLITE_IOERR_FSYNC = (SQLITE_IOERR | (4<<8)) 327 | let SQLITE_IOERR_DIR_FSYNC = (SQLITE_IOERR | (5<<8)) 328 | let SQLITE_IOERR_TRUNCATE = (SQLITE_IOERR | (6<<8)) 329 | let SQLITE_IOERR_FSTAT = (SQLITE_IOERR | (7<<8)) 330 | let SQLITE_IOERR_UNLOCK = (SQLITE_IOERR | (8<<8)) 331 | let SQLITE_IOERR_RDLOCK = (SQLITE_IOERR | (9<<8)) 332 | let SQLITE_IOERR_DELETE = (SQLITE_IOERR | (10<<8)) 333 | let SQLITE_IOERR_BLOCKED = (SQLITE_IOERR | (11<<8)) 334 | let SQLITE_IOERR_NOMEM = (SQLITE_IOERR | (12<<8)) 335 | let SQLITE_IOERR_ACCESS = (SQLITE_IOERR | (13<<8)) 336 | let SQLITE_IOERR_CHECKRESERVEDLOCK = (SQLITE_IOERR | (14<<8)) 337 | let SQLITE_IOERR_LOCK = (SQLITE_IOERR | (15<<8)) 338 | let SQLITE_IOERR_CLOSE = (SQLITE_IOERR | (16<<8)) 339 | let SQLITE_IOERR_DIR_CLOSE = (SQLITE_IOERR | (17<<8)) 340 | let SQLITE_IOERR_SHMOPEN = (SQLITE_IOERR | (18<<8)) 341 | let SQLITE_IOERR_SHMSIZE = (SQLITE_IOERR | (19<<8)) 342 | let SQLITE_IOERR_SHMLOCK = (SQLITE_IOERR | (20<<8)) 343 | let SQLITE_IOERR_SHMMAP = (SQLITE_IOERR | (21<<8)) 344 | let SQLITE_IOERR_SEEK = (SQLITE_IOERR | (22<<8)) 345 | let SQLITE_IOERR_DELETE_NOENT = (SQLITE_IOERR | (23<<8)) 346 | let SQLITE_IOERR_MMAP = (SQLITE_IOERR | (24<<8)) 347 | let SQLITE_IOERR_GETTEMPPATH = (SQLITE_IOERR | (25<<8)) 348 | let SQLITE_IOERR_CONVPATH = (SQLITE_IOERR | (26<<8)) 349 | let SQLITE_IOERR_VNODE = (SQLITE_IOERR | (27<<8)) 350 | let SQLITE_IOERR_AUTH = (SQLITE_IOERR | (28<<8)) 351 | let SQLITE_IOERR_BEGIN_ATOMIC = (SQLITE_IOERR | (29<<8)) 352 | let SQLITE_IOERR_COMMIT_ATOMIC = (SQLITE_IOERR | (30<<8)) 353 | let SQLITE_IOERR_ROLLBACK_ATOMIC = (SQLITE_IOERR | (31<<8)) 354 | let SQLITE_IOERR_DATA = (SQLITE_IOERR | (32<<8)) 355 | let SQLITE_IOERR_CORRUPTFS = (SQLITE_IOERR | (33<<8)) 356 | let SQLITE_IOERR_IN_PAGE = (SQLITE_IOERR | (34<<8)) 357 | let SQLITE_LOCKED_SHAREDCACHE = (SQLITE_LOCKED | (1<<8)) 358 | let SQLITE_LOCKED_VTAB = (SQLITE_LOCKED | (2<<8)) 359 | let SQLITE_BUSY_RECOVERY = (SQLITE_BUSY | (1<<8)) 360 | let SQLITE_BUSY_SNAPSHOT = (SQLITE_BUSY | (2<<8)) 361 | let SQLITE_BUSY_TIMEOUT = (SQLITE_BUSY | (3<<8)) 362 | let SQLITE_CANTOPEN_NOTEMPDIR = (SQLITE_CANTOPEN | (1<<8)) 363 | let SQLITE_CANTOPEN_ISDIR = (SQLITE_CANTOPEN | (2<<8)) 364 | let SQLITE_CANTOPEN_FULLPATH = (SQLITE_CANTOPEN | (3<<8)) 365 | let SQLITE_CANTOPEN_CONVPATH = (SQLITE_CANTOPEN | (4<<8)) 366 | let SQLITE_CANTOPEN_DIRTYWAL = (SQLITE_CANTOPEN | (5<<8)) /* Not Used */ 367 | let SQLITE_CANTOPEN_SYMLINK = (SQLITE_CANTOPEN | (6<<8)) 368 | let SQLITE_CORRUPT_VTAB = (SQLITE_CORRUPT | (1<<8)) 369 | let SQLITE_CORRUPT_SEQUENCE = (SQLITE_CORRUPT | (2<<8)) 370 | let SQLITE_CORRUPT_INDEX = (SQLITE_CORRUPT | (3<<8)) 371 | let SQLITE_READONLY_RECOVERY = (SQLITE_READONLY | (1<<8)) 372 | let SQLITE_READONLY_CANTLOCK = (SQLITE_READONLY | (2<<8)) 373 | let SQLITE_READONLY_ROLLBACK = (SQLITE_READONLY | (3<<8)) 374 | let SQLITE_READONLY_DBMOVED = (SQLITE_READONLY | (4<<8)) 375 | let SQLITE_READONLY_CANTINIT = (SQLITE_READONLY | (5<<8)) 376 | let SQLITE_READONLY_DIRECTORY = (SQLITE_READONLY | (6<<8)) 377 | let SQLITE_ABORT_ROLLBACK = (SQLITE_ABORT | (2<<8)) 378 | let SQLITE_CONSTRAINT_CHECK = (SQLITE_CONSTRAINT | (1<<8)) 379 | let SQLITE_CONSTRAINT_COMMITHOOK = (SQLITE_CONSTRAINT | (2<<8)) 380 | let SQLITE_CONSTRAINT_FOREIGNKEY = (SQLITE_CONSTRAINT | (3<<8)) 381 | let SQLITE_CONSTRAINT_FUNCTION = (SQLITE_CONSTRAINT | (4<<8)) 382 | let SQLITE_CONSTRAINT_NOTNULL = (SQLITE_CONSTRAINT | (5<<8)) 383 | let SQLITE_CONSTRAINT_PRIMARYKEY = (SQLITE_CONSTRAINT | (6<<8)) 384 | let SQLITE_CONSTRAINT_TRIGGER = (SQLITE_CONSTRAINT | (7<<8)) 385 | let SQLITE_CONSTRAINT_UNIQUE = (SQLITE_CONSTRAINT | (8<<8)) 386 | let SQLITE_CONSTRAINT_VTAB = (SQLITE_CONSTRAINT | (9<<8)) 387 | let SQLITE_CONSTRAINT_ROWID = (SQLITE_CONSTRAINT | (10<<8)) 388 | let SQLITE_CONSTRAINT_PINNED = (SQLITE_CONSTRAINT | (11<<8)) 389 | let SQLITE_CONSTRAINT_DATATYPE = (SQLITE_CONSTRAINT | (12<<8)) 390 | let SQLITE_NOTICE_RECOVER_WAL = (SQLITE_NOTICE | (1<<8)) 391 | let SQLITE_NOTICE_RECOVER_ROLLBACK = (SQLITE_NOTICE | (2<<8)) 392 | let SQLITE_NOTICE_RBU = (SQLITE_NOTICE | (3<<8)) 393 | let SQLITE_WARNING_AUTOINDEX = (SQLITE_WARNING | (1<<8)) 394 | let SQLITE_AUTH_USER = (SQLITE_AUTH | (1<<8)) 395 | let SQLITE_OK_LOAD_PERMANENTLY = (SQLITE_OK | (1<<8)) 396 | let SQLITE_OK_SYMLINK = (SQLITE_OK | (2<<8)) /* internal use only */ 397 | 398 | 399 | // MARK: SQLite Open File Flags 400 | 401 | let SQLITE_OPEN_READONLY = 0x00000001 /* Ok for sqlite3_open_v2() */ 402 | let SQLITE_OPEN_READWRITE = 0x00000002 /* Ok for sqlite3_open_v2() */ 403 | let SQLITE_OPEN_CREATE = 0x00000004 /* Ok for sqlite3_open_v2() */ 404 | let SQLITE_OPEN_DELETEONCLOSE = 0x00000008 /* VFS only */ 405 | let SQLITE_OPEN_EXCLUSIVE = 0x00000010 /* VFS only */ 406 | let SQLITE_OPEN_AUTOPROXY = 0x00000020 /* VFS only */ 407 | let SQLITE_OPEN_URI = 0x00000040 /* Ok for sqlite3_open_v2() */ 408 | let SQLITE_OPEN_MEMORY = 0x00000080 /* Ok for sqlite3_open_v2() */ 409 | let SQLITE_OPEN_MAIN_DB = 0x00000100 /* VFS only */ 410 | let SQLITE_OPEN_TEMP_DB = 0x00000200 /* VFS only */ 411 | let SQLITE_OPEN_TRANSIENT_DB = 0x00000400 /* VFS only */ 412 | let SQLITE_OPEN_MAIN_JOURNAL = 0x00000800 /* VFS only */ 413 | let SQLITE_OPEN_TEMP_JOURNAL = 0x00001000 /* VFS only */ 414 | let SQLITE_OPEN_SUBJOURNAL = 0x00002000 /* VFS only */ 415 | let SQLITE_OPEN_SUPER_JOURNAL = 0x00004000 /* VFS only */ 416 | let SQLITE_OPEN_NOMUTEX = 0x00008000 /* Ok for sqlite3_open_v2() */ 417 | let SQLITE_OPEN_FULLMUTEX = 0x00010000 /* Ok for sqlite3_open_v2() */ 418 | let SQLITE_OPEN_SHAREDCACHE = 0x00020000 /* Ok for sqlite3_open_v2() */ 419 | let SQLITE_OPEN_PRIVATECACHE = 0x00040000 /* Ok for sqlite3_open_v2() */ 420 | let SQLITE_OPEN_WAL = 0x00080000 /* VFS only */ 421 | let SQLITE_OPEN_NOFOLLOW = 0x01000000 /* Ok for sqlite3_open_v2() */ 422 | let SQLITE_OPEN_EXRESCODE = 0x02000000 /* Extended result codes */ 423 | 424 | let SQLITE_TRANSIENT = Int64(-1) 425 | 426 | #endif 427 | 428 | 429 | // https://sqlite.org/c3ref/c_trace.html 430 | 431 | let SQLITE_TRACE_STMT = 0x01 432 | let SQLITE_TRACE_PROFILE = 0x02 433 | let SQLITE_TRACE_ROW = 0x04 434 | let SQLITE_TRACE_CLOSE = 0x08 435 | 436 | -------------------------------------------------------------------------------- /Sources/SkipSQL/SQLiteCLibrary.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2023–2025 Skip 2 | // SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception 3 | #if !SKIP 4 | import SQLite3 5 | 6 | public typealias sqlite3_int64 = SQLite3.sqlite3_int64 7 | /// An action that can be registered to receive updates whenever a ROWID table changes 8 | /// `((UnsafeMutableRawPointer?, Int32, UnsafePointer?, UnsafePointer?, sqlite3_int64) -> Void)` 9 | public typealias sqlite3_update_hook = @convention(c) (_ updateActionPtr: UnsafeMutableRawPointer?, _ operation: Int32, _ dbname: UnsafePointer?, _ tblname: UnsafePointer?, _ rowid: sqlite3_int64) -> () 10 | 11 | /// A trace callback is invoked with four arguments: callback(T,C,P,X). The T argument is one of the `SQLITE_TRACE` constants to indicate why the callback was invoked. The C argument is a copy of the context pointer. The P and X arguments are pointers whose meanings depend on T. 12 | public typealias sqlite3_trace_hook = @convention(c) (_ type: UInt32, _ context: UnsafeMutableRawPointer?, _ p: UnsafeMutableRawPointer?, _ px: UnsafeMutableRawPointer?) -> Int32 13 | 14 | public let SQLITE_DONE = 101 15 | public let SQLITE_ROW = 100 16 | 17 | public typealias sqlite3_destructor_type = SQLite3.sqlite3_destructor_type 18 | public typealias sqlite3_callback = SQLite3.sqlite3_callback 19 | 20 | public let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self) 21 | 22 | /// The vendored SQLite3 library on Darwin platforms. 23 | /// The version of this library will vary between OS version, so some features (e.g., JSON support) might not be available. 24 | final class SQLiteCLibrary : SQLiteLibrary { 25 | static let shared = SQLiteCLibrary() 26 | 27 | init() { 28 | } 29 | 30 | func sqlite3_sleep(_ duration: Int32) -> Int32 { 31 | SQLite3.sqlite3_sleep(duration) 32 | } 33 | 34 | func sqlite3_open(_ filename: String, _ ppDb: sqlite3_openarg?) -> Int32 { 35 | SQLite3.sqlite3_open(filename, ppDb) 36 | } 37 | 38 | func sqlite3_open_v2(_ filename: String, _ ppDb: sqlite3_openarg?, _ flags: Int32, _ vfs: String?) -> Int32 { 39 | SQLite3.sqlite3_open_v2(filename, ppDb, flags, vfs) 40 | } 41 | 42 | func sqlite3_close(_ db: OpaquePointer) -> Int32 { 43 | SQLite3.sqlite3_close(db) 44 | } 45 | 46 | func sqlite3_errcode(_ db: OpaquePointer) -> Int32 { 47 | SQLite3.sqlite3_errcode(db) 48 | } 49 | 50 | func sqlite3_errmsg(_ db: OpaquePointer) -> sqlite3_cstring_ptr? { 51 | SQLite3.sqlite3_errmsg(db) 52 | } 53 | 54 | func sqlite3_last_insert_rowid(_ db: OpaquePointer) -> Int64 { 55 | SQLite3.sqlite3_last_insert_rowid(db) 56 | } 57 | 58 | func sqlite3_total_changes(_ db: OpaquePointer) -> Int32 { 59 | SQLite3.sqlite3_total_changes(db) 60 | } 61 | 62 | func sqlite3_changes(_ db: OpaquePointer) -> Int32 { 63 | SQLite3.sqlite3_changes(db) 64 | } 65 | 66 | func sqlite3_interrupt(_ db: OpaquePointer) { 67 | SQLite3.sqlite3_interrupt(db) 68 | } 69 | 70 | func sqlite3_exec(_ db: OpaquePointer, _ sql: String, _ callback: sqlite3_callback?, _ pArg: UnsafeMutableRawPointer?, _ errmsg: sqlite_error_ptr?) -> Int32 { 71 | SQLite3.sqlite3_exec(db, sql, callback, pArg, errmsg) 72 | } 73 | 74 | func sqlite3_prepare_v2(_ db: OpaquePointer, _ sql: String, _ nBytes: Int32, _ ppStmt: sqlite3_openarg, _ tail: UnsafeMutablePointer?>?) -> Int32 { 75 | SQLite3.sqlite3_prepare_v2(db, sql, nBytes, ppStmt, tail) 76 | } 77 | 78 | func sqlite3_step(_ stmt: OpaquePointer) -> Int32 { 79 | SQLite3.sqlite3_step(stmt) 80 | } 81 | 82 | func sqlite3_finalize(_ stmt: OpaquePointer) -> Int32 { 83 | SQLite3.sqlite3_finalize(stmt) 84 | } 85 | 86 | func sqlite3_reset(_ stmt: OpaquePointer) -> Int32 { 87 | SQLite3.sqlite3_reset(stmt) 88 | } 89 | 90 | func sqlite3_column_count(_ stmt: OpaquePointer) -> Int32 { 91 | SQLite3.sqlite3_column_count(stmt) 92 | } 93 | 94 | func sqlite3_bind_parameter_count(_ stmnt: OpaquePointer) -> Int32 { 95 | SQLite3.sqlite3_bind_parameter_count(stmnt) 96 | } 97 | 98 | func sqlite3_bind_parameter_name(_ stmnt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_cstring_ptr? { 99 | SQLite3.sqlite3_bind_parameter_name(stmnt, columnIndex) 100 | } 101 | 102 | func sqlite3_bind_parameter_index(_ stmnt: OpaquePointer, _ name: String) -> Int32 { 103 | SQLite3.sqlite3_bind_parameter_index(stmnt, name) 104 | } 105 | 106 | func sqlite3_clear_bindings(_ stmnt: OpaquePointer) -> Int32 { 107 | SQLite3.sqlite3_clear_bindings(stmnt) 108 | } 109 | 110 | func sqlite3_column_name(_ stmt: OpaquePointer!, _ columnIndex: Int32) -> sqlite3_cstring_ptr? { 111 | SQLite3.sqlite3_column_name(stmt!, columnIndex) 112 | } 113 | 114 | func sqlite3_column_decltype(_ stmt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_cstring_ptr? { 115 | SQLite3.sqlite3_column_decltype(stmt, columnIndex) 116 | } 117 | 118 | func sqlite3_sql(_ stmt: OpaquePointer) -> sqlite3_cstring_ptr? { 119 | SQLite3.sqlite3_sql(stmt) 120 | } 121 | 122 | func sqlite3_expanded_sql(_ stmt: OpaquePointer) -> sqlite3_cstring_mutptr? { 123 | SQLite3.sqlite3_expanded_sql(stmt) 124 | } 125 | 126 | func sqlite3_db_handle(_ stmt: OpaquePointer) -> OpaquePointer { 127 | SQLite3.sqlite3_db_handle(stmt) 128 | } 129 | 130 | func sqlite3_bind_null(_ stmt: OpaquePointer, _ paramIndex: Int32) -> Int32 { 131 | SQLite3.sqlite3_bind_null(stmt, paramIndex) 132 | } 133 | 134 | func sqlite3_bind_int(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: Int32) -> Int32 { 135 | SQLite3.sqlite3_bind_int(stmt, paramIndex, value) 136 | } 137 | 138 | func sqlite3_bind_int64(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: Int64) -> Int32 { 139 | SQLite3.sqlite3_bind_int64(stmt, paramIndex, value) 140 | } 141 | 142 | func sqlite3_bind_double(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: Double) -> Int32 { 143 | SQLite3.sqlite3_bind_double(stmt, paramIndex, value) 144 | } 145 | 146 | func sqlite3_bind_text(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: String, _ length: Int32, _ destructor: sqlite3_destructor_type) -> Int32 { 147 | SQLite3.sqlite3_bind_text(stmt, paramIndex, value, length, destructor) 148 | } 149 | 150 | func sqlite3_bind_blob(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: UnsafeRawPointer?, _ length: Int32, _ destructor: sqlite3_destructor_type) -> Int32 { 151 | SQLite3.sqlite3_bind_blob(stmt, paramIndex, value, length, destructor) 152 | } 153 | 154 | func sqlite3_bind_zeroblob(_ stmt: OpaquePointer, _ paramIndex: Int32, _ length: Int32) -> Int32 { 155 | SQLite3.sqlite3_bind_zeroblob(stmt, paramIndex, length) 156 | } 157 | 158 | func sqlite3_column_type(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int32 { 159 | SQLite3.sqlite3_column_type(stmt, columnIndex) 160 | } 161 | 162 | func sqlite3_column_int(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int32 { 163 | SQLite3.sqlite3_column_int(stmt, columnIndex) 164 | } 165 | 166 | func sqlite3_column_int64(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int64 { 167 | SQLite3.sqlite3_column_int64(stmt, columnIndex) 168 | } 169 | 170 | func sqlite3_column_double(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Double { 171 | SQLite3.sqlite3_column_double(stmt, columnIndex) 172 | } 173 | 174 | func sqlite3_column_text(_ stmt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_uint8_ptr? { 175 | SQLite3.sqlite3_column_text(stmt, columnIndex) 176 | } 177 | 178 | func sqlite3_column_blob(_ stmt: OpaquePointer, _ columnIndex: Int32) -> UnsafeRawPointer? { 179 | SQLite3.sqlite3_column_blob(stmt, columnIndex) 180 | } 181 | 182 | func sqlite3_column_bytes(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int32 { 183 | SQLite3.sqlite3_column_bytes(stmt, columnIndex) 184 | } 185 | 186 | func sqlite3_backup_init(_ destDb: OpaquePointer, _ destName: String, _ sourceDb: OpaquePointer?, _ sourceName: String) -> OpaquePointer { 187 | SQLite3.sqlite3_backup_init(destDb, destName, sourceDb, sourceName) 188 | } 189 | 190 | func sqlite3_backup_step(_ backup: OpaquePointer, _ pages: Int32) -> Int32 { 191 | SQLite3.sqlite3_backup_step(backup, pages) 192 | } 193 | 194 | func sqlite3_backup_finish(_ backup: OpaquePointer) -> Int32 { 195 | SQLite3.sqlite3_backup_finish(backup) 196 | } 197 | 198 | func sqlite3_backup_remaining(_ backup: OpaquePointer) -> Int32 { 199 | SQLite3.sqlite3_backup_remaining(backup) 200 | } 201 | 202 | func sqlite3_backup_pagecount(_ backup: OpaquePointer) -> Int32 { 203 | SQLite3.sqlite3_backup_pagecount(backup) 204 | } 205 | 206 | func sqlite3_initialize() -> Int32 { 207 | SQLite3.sqlite3_initialize() 208 | } 209 | 210 | func sqlite3_shutdown() -> Int32 { 211 | SQLite3.sqlite3_shutdown() 212 | } 213 | 214 | func sqlite3_extended_result_codes(_ db: OpaquePointer, _ on: Int32) -> Int32 { 215 | SQLite3.sqlite3_extended_result_codes(db, on) 216 | } 217 | 218 | func sqlite3_free(_ ptr: sqlite3_pointer_type) { 219 | SQLite3.sqlite3_free(ptr) 220 | } 221 | 222 | func sqlite3_db_mutex(_ db: OpaquePointer?) -> OpaquePointer? { 223 | SQLite3.sqlite3_db_mutex(db) 224 | } 225 | 226 | func sqlite3_mutex_free(_ lock: OpaquePointer?) { 227 | SQLite3.sqlite3_mutex_free(lock) 228 | } 229 | 230 | func sqlite3_mutex_enter(_ lock: OpaquePointer?) { 231 | SQLite3.sqlite3_mutex_enter(lock) 232 | } 233 | 234 | func sqlite3_mutex_leave(_ lock: OpaquePointer?) { 235 | SQLite3.sqlite3_mutex_leave(lock) 236 | } 237 | 238 | func sqlite3_update_hook(_ db: OpaquePointer?, _ callback: sqlite3_update_hook?, _ pArg: UnsafeMutableRawPointer?) -> UnsafeMutableRawPointer? { 239 | SQLite3.sqlite3_update_hook(db, callback, pArg) 240 | } 241 | 242 | func sqlite3_trace_v2(_ db: OpaquePointer?, _ mask: sqlite3_unsigned, _ callback: sqlite3_trace_hook?, _ pCtx: UnsafeMutableRawPointer?) -> Int32 { 243 | SQLite3.sqlite3_trace_v2(db, mask, callback, pCtx) 244 | } 245 | } 246 | #endif 247 | 248 | -------------------------------------------------------------------------------- /Sources/SkipSQL/SQLiteJLibrary.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2023–2025 Skip 2 | // SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception 3 | #if SKIP 4 | import Foundation 5 | import OSLog 6 | import SkipFFI 7 | 8 | /// The argument to `sqlite3_update_hook` 9 | public protocol sqlite3_update_hook : NativeCallback { 10 | // public typealias sqlite3_update_hook = @convention(c) (_ updateActionPtr: UnsafeMutableRawPointer?, _ operation: Int32, _ dbname: UnsafePointer?, _ tblname: UnsafePointer?, _ rowid: sqlite3_int64) -> () 11 | func callback(userData: OpaquePointer?, operation: Int32, databaseName: OpaquePointer?, tableName: OpaquePointer?, rowid: Int64) 12 | } 13 | 14 | /// The argument to `sqlite3_trace_v2` 15 | public protocol sqlite3_trace_hook : NativeCallback { 16 | // public typealias sqlite3_trace_hook = @convention(c) (_ type: UInt32, _ context: UnsafeMutableRawPointer?, _ p: UnsafeMutableRawPointer?, _ px: UnsafeMutableRawPointer?) -> Int32 17 | func callback(type: sqlite3_unsigned, context: OpaquePointer?, p: OpaquePointer?, px: OpaquePointer?) -> Int32 18 | } 19 | 20 | 21 | /// A concrete implementation of the `SQLiteLibrary` interface that declares `external` methods to use [JNA Direct Mapping](https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md) to cache native method lookups. 22 | internal final class SQLiteJNALibrary : SQLiteLibrary { 23 | static let shared = SQLiteJNALibrary() 24 | 25 | private init() { 26 | do { 27 | com.sun.jna.Native.register((SQLiteJNALibrary.self as kotlin.reflect.KClass).java, "sqlite3") 28 | } catch let error as java.lang.UnsatisfiedLinkError { // "Unable to load library 'sqlite3'" 29 | com.sun.jna.Native.register((SQLiteJNALibrary.self as kotlin.reflect.KClass).java, nil as String?) 30 | } 31 | } 32 | 33 | /* SKIP INSERT: external */ func sqlite3_sleep(_ duration: Int32) -> Int32 34 | /* SKIP INSERT: external override */ public func sqlite3_open(_ filename: String, _ ppDb: sqlite3_openarg?) -> Int32 35 | /* SKIP INSERT: external override */ public func sqlite3_open_v2(_ filename: String, _ ppDb: sqlite3_openarg?, _ flags: Int32, _ vfs: String?) -> Int32 36 | /* SKIP INSERT: external */ func sqlite3_close(_ db: OpaquePointer) -> Int32 37 | /* SKIP INSERT: external */ func sqlite3_errcode(_ db: OpaquePointer) -> Int32 38 | /* SKIP INSERT: external */ func sqlite3_errmsg(_ db: OpaquePointer) -> sqlite3_cstring_ptr? 39 | /* SKIP INSERT: external */ func sqlite3_last_insert_rowid(_ db: OpaquePointer) -> Int64 40 | /* SKIP INSERT: external */ func sqlite3_total_changes(_ db: OpaquePointer) -> Int32 41 | /* SKIP INSERT: external */ func sqlite3_changes(_ db: OpaquePointer) -> Int32 42 | // /* SKIP INSERT: external */ func sqlite3_total_changes64(_ db: OpaquePointer) -> Int64 43 | // /* SKIP INSERT: external */ func sqlite3_changes64(_ db: OpaquePointer) -> Int64 // unavailable on Android 44 | /* SKIP INSERT: external */ func sqlite3_interrupt(_ db: OpaquePointer) 45 | /* SKIP INSERT: external override */ public func sqlite3_exec(_ db: OpaquePointer, _ sql: String, _ callback: sqlite3_callback?, _ pArg: UnsafeMutableRawPointer?, _ errmsg: sqlite_error_ptr?) -> Int32 46 | /* SKIP INSERT: external override */ public func sqlite3_prepare_v2(_ db: OpaquePointer, _ sql: String, _ nBytes: Int32, _ ppStmt: sqlite3_openarg, _ tail: sqlite_tail_ptr?) -> Int32 47 | /* SKIP INSERT: external */ func sqlite3_step(_ stmt: OpaquePointer) -> Int32 48 | /* SKIP INSERT: external */ func sqlite3_finalize(_ stmt: OpaquePointer) -> Int32 49 | /* SKIP INSERT: external */ func sqlite3_reset(_ stmt: OpaquePointer) -> Int32 50 | /* SKIP INSERT: external */ func sqlite3_column_count(_ stmt: OpaquePointer) -> Int32 51 | /* SKIP INSERT: external */ func sqlite3_bind_parameter_count(_ stmnt: OpaquePointer) -> Int32 52 | /* SKIP INSERT: external */ func sqlite3_bind_parameter_name(_ stmnt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_cstring_ptr? 53 | /* SKIP INSERT: external */ func sqlite3_bind_parameter_index(_ stmnt: OpaquePointer, _ name: String) -> Int32 54 | /* SKIP INSERT: external */ func sqlite3_clear_bindings(_ stmnt: OpaquePointer) -> Int32 55 | /* SKIP INSERT: external */ func sqlite3_column_name(_ stmt: OpaquePointer!, _ columnIndex: Int32) -> sqlite3_cstring_ptr? 56 | // /* SKIP INSERT: external */ func sqlite3_column_database_name(_ stmt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_cstring_ptr? // unavailable on Android 57 | // /* SKIP INSERT: external */ func sqlite3_column_origin_name(_ stmt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_cstring_ptr? 58 | /* SKIP INSERT: external */ func sqlite3_column_decltype(_ stmt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_cstring_ptr? 59 | /* SKIP INSERT: external */ func sqlite3_sql(_ stmt: OpaquePointer) -> sqlite3_cstring_ptr? 60 | /* SKIP INSERT: external */ func sqlite3_expanded_sql(_ stmt: OpaquePointer) -> sqlite3_cstring_mutptr? 61 | /* SKIP INSERT: external */ func sqlite3_db_handle(_ stmt: OpaquePointer) -> OpaquePointer 62 | /* SKIP INSERT: external */ func sqlite3_bind_null(_ stmt: OpaquePointer, _ paramIndex: Int32) -> Int32 63 | /* SKIP INSERT: external */ func sqlite3_bind_int(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: Int32) -> Int32 64 | /* SKIP INSERT: external */ func sqlite3_bind_int64(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: Int64) -> Int32 65 | /* SKIP INSERT: external */ func sqlite3_bind_double(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: Double) -> Int32 66 | /* SKIP INSERT: external */ func sqlite3_bind_text(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: String, _ length: Int32, _ destructor: sqlite3_destructor_type) -> Int32 67 | /* SKIP INSERT: external override */ public func sqlite3_bind_blob(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: UnsafeRawPointer?, _ length: Int32, _ destructor: sqlite3_destructor_type) -> Int32 68 | /* SKIP INSERT: external */ func sqlite3_bind_zeroblob(_ stmt: OpaquePointer, _ paramIndex: Int32, _ length: Int32) -> Int32 69 | /* SKIP INSERT: external */ func sqlite3_column_type(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int32 70 | /* SKIP INSERT: external */ func sqlite3_column_int(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int32 71 | /* SKIP INSERT: external */ func sqlite3_column_int64(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int64 72 | /* SKIP INSERT: external */ func sqlite3_column_double(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Double 73 | /* SKIP INSERT: external */ func sqlite3_column_text(_ stmt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_uint8_ptr? 74 | /* SKIP INSERT: external */ func sqlite3_column_blob(_ stmt: OpaquePointer, _ columnIndex: Int32) -> UnsafeRawPointer? 75 | /* SKIP INSERT: external */ func sqlite3_column_bytes(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int32 76 | /* SKIP INSERT: external */ func sqlite3_backup_init(_ destDb: OpaquePointer, _ destName: String, _ sourceDb: OpaquePointer?, _ sourceName: String) -> OpaquePointer 77 | /* SKIP INSERT: external */ func sqlite3_backup_step(_ backup: OpaquePointer, _ pages: Int32) -> Int32 78 | /* SKIP INSERT: external */ func sqlite3_backup_finish(_ backup: OpaquePointer) -> Int32 79 | /* SKIP INSERT: external */ func sqlite3_backup_remaining(_ backup: OpaquePointer) -> Int32 80 | /* SKIP INSERT: external */ func sqlite3_backup_pagecount(_ backup: OpaquePointer) -> Int32 81 | /* SKIP INSERT: external */ func sqlite3_initialize() -> Int32 82 | /* SKIP INSERT: external */ func sqlite3_shutdown() -> Int32 83 | /* SKIP INSERT: external */ func sqlite3_extended_result_codes(_ db: OpaquePointer, _ on: Int32) -> Int32 84 | /* SKIP INSERT: external */ func sqlite3_free(_ ptr: OpaquePointer) 85 | /* SKIP INSERT: external */ func sqlite3_db_mutex(_ db: OpaquePointer?) -> OpaquePointer? 86 | /* SKIP INSERT: external */ func sqlite3_mutex_free(_ lock: OpaquePointer?) 87 | /* SKIP INSERT: external */ func sqlite3_mutex_enter(_ lock: OpaquePointer?) 88 | /* SKIP INSERT: external */ func sqlite3_mutex_leave(_ lock: OpaquePointer?) 89 | /* SKIP INSERT: external */ func sqlite3_update_hook(_ db: OpaquePointer?, _ callback: sqlite3_update_hook?, _ pArg: UnsafeMutableRawPointer?) -> UnsafeMutableRawPointer? 90 | /* SKIP INSERT: external */ func sqlite3_trace_v2(_ db: OpaquePointer?, _ mask: sqlite3_unsigned, _ callback: sqlite3_trace_hook?, _ pCtx: UnsafeMutableRawPointer?) -> Int32 91 | } 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /Sources/SkipSQL/SQLiteLibrary.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2023–2025 Skip 2 | // SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception 3 | #if SKIP 4 | import SkipFFI 5 | 6 | public typealias NativeLibrary = com.sun.jna.Library 7 | public typealias NativeCallback = com.sun.jna.Callback 8 | 9 | public typealias sqlite3_openarg = UnsafeMutableRawPointer 10 | public typealias sqlite3_cstring_ptr = OpaquePointer 11 | public typealias sqlite3_cstring_mutptr = OpaquePointer 12 | public typealias sqlite3_uint8_ptr = OpaquePointer 13 | public typealias sqlite_error_ptr = UnsafeMutableRawPointer 14 | public typealias sqlite3_destructor_type = Int64 15 | public typealias sqlite3_callback = UnsafeMutableRawPointer 16 | 17 | public typealias UnsafeRawPointer = OpaquePointer 18 | public typealias sqlite_tail_ptr = UnsafeMutableRawPointer 19 | 20 | //public typealias sqlite3_pointer_type = UnsafeMutableRawPointer 21 | public typealias sqlite3_pointer_type = OpaquePointer 22 | 23 | public typealias sqlite3_unsigned = Int32 // JNA has no UInt understanding 24 | 25 | #else 26 | public typealias NativeLibrary = AnyObject 27 | public typealias NativeCallback = AnyObject 28 | 29 | public typealias sqlite3_openarg = UnsafeMutablePointer // UnsafeMutableRawPointer? 30 | public typealias sqlite3_cstring_ptr = UnsafePointer 31 | public typealias sqlite3_cstring_mutptr = UnsafeMutablePointer 32 | public typealias sqlite3_uint8_ptr = UnsafePointer 33 | 34 | public typealias sqlite_error_ptr = UnsafeMutablePointer?> 35 | //typealias sqlite3_destructor_type = (@convention(c) (UnsafeMutableRawPointer?) -> Void) 36 | public typealias sqlite_tail_ptr = UnsafeMutablePointer?> 37 | 38 | public typealias sqlite3_unsigned = UInt32 39 | public typealias sqlite3_pointer_type = UnsafeMutableRawPointer 40 | #endif 41 | 42 | public protocol SQLiteLibrary : NativeLibrary { 43 | func sqlite3_sleep(_ duration: Int32) -> Int32 44 | 45 | // Database Connection API 46 | func sqlite3_open(_ filename: String, _ ppDb: sqlite3_openarg?) -> Int32 47 | func sqlite3_open_v2(_ filename: String, _ ppDb: sqlite3_openarg?, _ flags: Int32, _ vfs: String?) -> Int32 48 | func sqlite3_close(_ db: OpaquePointer) -> Int32 49 | func sqlite3_errcode(_ db: OpaquePointer) -> Int32 50 | func sqlite3_errmsg(_ db: OpaquePointer) -> sqlite3_cstring_ptr? 51 | func sqlite3_last_insert_rowid(_ db: OpaquePointer) -> Int64 52 | func sqlite3_total_changes(_ db: OpaquePointer) -> Int32 53 | func sqlite3_changes(_ db: OpaquePointer) -> Int32 54 | func sqlite3_interrupt(_ db: OpaquePointer) 55 | 56 | func sqlite3_exec(_ db: OpaquePointer, _ sql: String, _ callback: sqlite3_callback?, _ pArg: UnsafeMutableRawPointer?, _ errmsg: sqlite_error_ptr?) -> Int32 57 | func sqlite3_prepare_v2(_ db: OpaquePointer, _ sql: String, _ nBytes: Int32, _ ppStmt: sqlite3_openarg, _ tail: sqlite_tail_ptr?) -> Int32 58 | 59 | // Statement API 60 | func sqlite3_step(_ stmt: OpaquePointer) -> Int32 61 | func sqlite3_finalize(_ stmt: OpaquePointer) -> Int32 62 | func sqlite3_reset(_ stmt: OpaquePointer) -> Int32 63 | func sqlite3_column_count(_ stmt: OpaquePointer) -> Int32 64 | func sqlite3_bind_parameter_count(_ stmnt: OpaquePointer) -> Int32 65 | func sqlite3_bind_parameter_name(_ stmnt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_cstring_ptr? 66 | func sqlite3_bind_parameter_index(_ stmnt: OpaquePointer, _ name: String) -> Int32 67 | func sqlite3_clear_bindings(_ stmnt: OpaquePointer) -> Int32 68 | 69 | func sqlite3_column_name(_ stmt: OpaquePointer!, _ columnIndex: Int32) -> sqlite3_cstring_ptr? 70 | 71 | // Unavailable in Android's sqlite build 72 | //func sqlite3_column_table_name(_ stmt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_cstring_ptr? 73 | 74 | //func sqlite3_column_origin_name(_ stmt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_cstring_ptr? 75 | func sqlite3_column_decltype(_ stmt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_cstring_ptr? 76 | 77 | func sqlite3_sql(_ stmt: OpaquePointer) -> sqlite3_cstring_ptr? 78 | func sqlite3_expanded_sql(_ stmt: OpaquePointer) -> sqlite3_cstring_mutptr? 79 | func sqlite3_db_handle(_ stmt: OpaquePointer) -> OpaquePointer 80 | 81 | // Parameter Binding 82 | func sqlite3_bind_null(_ stmt: OpaquePointer, _ paramIndex: Int32) -> Int32 83 | func sqlite3_bind_int(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: Int32) -> Int32 84 | func sqlite3_bind_int64(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: Int64) -> Int32 85 | func sqlite3_bind_double(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: Double) -> Int32 86 | func sqlite3_bind_text(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: String, _ length: Int32, _ destructor: sqlite3_destructor_type) -> Int32 87 | func sqlite3_bind_blob(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: UnsafeRawPointer?, _ length: Int32, _ destructor: sqlite3_destructor_type) -> Int32 88 | func sqlite3_bind_zeroblob(_ stmt: OpaquePointer, _ paramIndex: Int32, _ length: Int32) -> Int32 89 | 90 | 91 | // Column Value API 92 | func sqlite3_column_type(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int32 93 | func sqlite3_column_int(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int32 94 | func sqlite3_column_int64(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int64 95 | func sqlite3_column_double(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Double 96 | func sqlite3_column_text(_ stmt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_uint8_ptr? 97 | func sqlite3_column_blob(_ stmt: OpaquePointer, _ columnIndex: Int32) -> UnsafeRawPointer? 98 | func sqlite3_column_bytes(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int32 99 | 100 | // Backup API 101 | func sqlite3_backup_init(_ destDb: OpaquePointer, _ destName: String, _ sourceDb: OpaquePointer?, _ sourceName: String) -> OpaquePointer 102 | func sqlite3_backup_step(_ backup: OpaquePointer, _ pages: Int32) -> Int32 103 | func sqlite3_backup_finish(_ backup: OpaquePointer) -> Int32 104 | func sqlite3_backup_remaining(_ backup: OpaquePointer) -> Int32 105 | func sqlite3_backup_pagecount(_ backup: OpaquePointer) -> Int32 106 | 107 | // Other Functions 108 | func sqlite3_initialize() -> Int32 109 | func sqlite3_shutdown() -> Int32 110 | //func sqlite3_config(option: Int32, values: Object...) -> Int32 111 | func sqlite3_extended_result_codes(_ db: OpaquePointer, _ on: Int32) -> Int32 112 | #if SKIP 113 | // otherwise: 'sqlite3_free' hides member of supertype 'SQLiteLibrary' and needs an 'override' modifier. 114 | func sqlite3_free(_ ptr: OpaquePointer) 115 | #else 116 | func sqlite3_free(_ ptr: sqlite3_pointer_type) 117 | #endif 118 | 119 | // Locks 120 | func sqlite3_db_mutex(_ db: OpaquePointer?) -> OpaquePointer? 121 | func sqlite3_mutex_free(_ lock: OpaquePointer?) 122 | func sqlite3_mutex_enter(_ lock: OpaquePointer?) 123 | func sqlite3_mutex_leave(_ lock: OpaquePointer?) 124 | //func int sqlite3_mutex_try(sqlite3_mutex*); 125 | 126 | func sqlite3_update_hook(_ db: OpaquePointer?, _ callback: sqlite3_update_hook?, _ pArg: UnsafeMutableRawPointer?) -> UnsafeMutableRawPointer? 127 | 128 | func sqlite3_trace_v2(_ db: OpaquePointer?, _ mask: sqlite3_unsigned, _ callback: sqlite3_trace_hook?, _ pCtx: UnsafeMutableRawPointer?) -> Int32 129 | } 130 | -------------------------------------------------------------------------------- /Sources/SkipSQL/Skip/skip.yml: -------------------------------------------------------------------------------- 1 | # skip.tools per-configuration file 2 | 3 | #skip: 4 | # package: 'skip.sql' 5 | 6 | # the blocks to add to the build.gradle.kts 7 | build: 8 | contents: 9 | - block: 'dependencies' 10 | contents: 11 | -------------------------------------------------------------------------------- /Sources/SkipSQLPlus/SQLPlus.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2023–2025 Skip 2 | // SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception 3 | import SkipSQL 4 | 5 | extension SQLiteConfiguration { 6 | /// The platform-provided SQLite library. 7 | /// 8 | /// This will use the the vendored sqlite libraries that are provided by the operating system. 9 | /// The version will vary. 10 | public static let plus: SQLiteConfiguration = { 11 | #if SKIP 12 | SQLiteConfiguration(library: SQLPlusJNALibrary.shared) 13 | #else 14 | SQLiteConfiguration(library: SQLPlusCLibrary.shared) 15 | #endif 16 | }() 17 | } 18 | -------------------------------------------------------------------------------- /Sources/SkipSQLPlus/SQLPlusCLibrary.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2023–2025 Skip 2 | // SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception 3 | #if !SKIP 4 | import SQLExt 5 | import SkipSQL 6 | 7 | /// A `SQLiteLibrary` implementation that uses the locally built `SQLExt` library 8 | /// to provide a consistent SQLite build with full-text-search (FTS) and encryption (sqlcipher) 9 | /// extensions enabled. 10 | internal final class SQLPlusCLibrary : SQLiteLibrary { 11 | static let shared = SQLPlusCLibrary() 12 | 13 | init() { 14 | } 15 | 16 | func sqlite3_sleep(_ duration: Int32) -> Int32 { 17 | SQLExt.sqlite3_sleep(duration) 18 | } 19 | 20 | func sqlite3_open(_ filename: String, _ ppDb: sqlite3_openarg?) -> Int32 { 21 | SQLExt.sqlite3_open(filename, ppDb) 22 | } 23 | 24 | func sqlite3_open_v2(_ filename: String, _ ppDb: sqlite3_openarg?, _ flags: Int32, _ vfs: String?) -> Int32 { 25 | SQLExt.sqlite3_open_v2(filename, ppDb, flags, vfs) 26 | } 27 | 28 | func sqlite3_close(_ db: OpaquePointer) -> Int32 { 29 | SQLExt.sqlite3_close(db) 30 | } 31 | 32 | func sqlite3_errcode(_ db: OpaquePointer) -> Int32 { 33 | SQLExt.sqlite3_errcode(db) 34 | } 35 | 36 | func sqlite3_errmsg(_ db: OpaquePointer) -> sqlite3_cstring_ptr? { 37 | SQLExt.sqlite3_errmsg(db) 38 | } 39 | 40 | func sqlite3_last_insert_rowid(_ db: OpaquePointer) -> Int64 { 41 | SQLExt.sqlite3_last_insert_rowid(db) 42 | } 43 | 44 | func sqlite3_total_changes(_ db: OpaquePointer) -> Int32 { 45 | SQLExt.sqlite3_total_changes(db) 46 | } 47 | 48 | func sqlite3_changes(_ db: OpaquePointer) -> Int32 { 49 | SQLExt.sqlite3_changes(db) 50 | } 51 | 52 | func sqlite3_interrupt(_ db: OpaquePointer) { 53 | SQLExt.sqlite3_interrupt(db) 54 | } 55 | 56 | func sqlite3_exec(_ db: OpaquePointer, _ sql: String, _ callback: sqlite3_callback?, _ pArg: UnsafeMutableRawPointer?, _ errmsg: sqlite_error_ptr?) -> Int32 { 57 | SQLExt.sqlite3_exec(db, sql, callback, pArg, errmsg) 58 | } 59 | 60 | func sqlite3_prepare_v2(_ db: OpaquePointer, _ sql: String, _ nBytes: Int32, _ ppStmt: sqlite3_openarg, _ tail: UnsafeMutablePointer?>?) -> Int32 { 61 | SQLExt.sqlite3_prepare_v2(db, sql, nBytes, ppStmt, tail) 62 | } 63 | 64 | func sqlite3_step(_ stmt: OpaquePointer) -> Int32 { 65 | SQLExt.sqlite3_step(stmt) 66 | } 67 | 68 | func sqlite3_finalize(_ stmt: OpaquePointer) -> Int32 { 69 | SQLExt.sqlite3_finalize(stmt) 70 | } 71 | 72 | func sqlite3_reset(_ stmt: OpaquePointer) -> Int32 { 73 | SQLExt.sqlite3_reset(stmt) 74 | } 75 | 76 | func sqlite3_column_count(_ stmt: OpaquePointer) -> Int32 { 77 | SQLExt.sqlite3_column_count(stmt) 78 | } 79 | 80 | func sqlite3_bind_parameter_count(_ stmnt: OpaquePointer) -> Int32 { 81 | SQLExt.sqlite3_bind_parameter_count(stmnt) 82 | } 83 | 84 | func sqlite3_bind_parameter_name(_ stmnt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_cstring_ptr? { 85 | SQLExt.sqlite3_bind_parameter_name(stmnt, columnIndex) 86 | } 87 | 88 | func sqlite3_bind_parameter_index(_ stmnt: OpaquePointer, _ name: String) -> Int32 { 89 | SQLExt.sqlite3_bind_parameter_index(stmnt, name) 90 | } 91 | 92 | func sqlite3_clear_bindings(_ stmnt: OpaquePointer) -> Int32 { 93 | SQLExt.sqlite3_clear_bindings(stmnt) 94 | } 95 | 96 | func sqlite3_column_name(_ stmt: OpaquePointer!, _ columnIndex: Int32) -> sqlite3_cstring_ptr? { 97 | SQLExt.sqlite3_column_name(stmt!, columnIndex) 98 | } 99 | 100 | func sqlite3_column_decltype(_ stmt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_cstring_ptr? { 101 | SQLExt.sqlite3_column_decltype(stmt, columnIndex) 102 | } 103 | 104 | func sqlite3_sql(_ stmt: OpaquePointer) -> sqlite3_cstring_ptr? { 105 | SQLExt.sqlite3_sql(stmt) 106 | } 107 | 108 | func sqlite3_expanded_sql(_ stmt: OpaquePointer) -> sqlite3_cstring_mutptr? { 109 | SQLExt.sqlite3_expanded_sql(stmt) 110 | } 111 | 112 | func sqlite3_db_handle(_ stmt: OpaquePointer) -> OpaquePointer { 113 | SQLExt.sqlite3_db_handle(stmt) 114 | } 115 | 116 | func sqlite3_bind_null(_ stmt: OpaquePointer, _ paramIndex: Int32) -> Int32 { 117 | SQLExt.sqlite3_bind_null(stmt, paramIndex) 118 | } 119 | 120 | func sqlite3_bind_int(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: Int32) -> Int32 { 121 | SQLExt.sqlite3_bind_int(stmt, paramIndex, value) 122 | } 123 | 124 | func sqlite3_bind_int64(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: Int64) -> Int32 { 125 | SQLExt.sqlite3_bind_int64(stmt, paramIndex, value) 126 | } 127 | 128 | func sqlite3_bind_double(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: Double) -> Int32 { 129 | SQLExt.sqlite3_bind_double(stmt, paramIndex, value) 130 | } 131 | 132 | func sqlite3_bind_text(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: String, _ length: Int32, _ destructor: sqlite3_destructor_type) -> Int32 { 133 | SQLExt.sqlite3_bind_text(stmt, paramIndex, value, length, destructor) 134 | } 135 | 136 | func sqlite3_bind_blob(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: UnsafeRawPointer?, _ length: Int32, _ destructor: sqlite3_destructor_type) -> Int32 { 137 | SQLExt.sqlite3_bind_blob(stmt, paramIndex, value, length, destructor) 138 | } 139 | 140 | func sqlite3_bind_zeroblob(_ stmt: OpaquePointer, _ paramIndex: Int32, _ length: Int32) -> Int32 { 141 | SQLExt.sqlite3_bind_zeroblob(stmt, paramIndex, length) 142 | } 143 | 144 | func sqlite3_column_type(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int32 { 145 | SQLExt.sqlite3_column_type(stmt, columnIndex) 146 | } 147 | 148 | func sqlite3_column_int(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int32 { 149 | SQLExt.sqlite3_column_int(stmt, columnIndex) 150 | } 151 | 152 | func sqlite3_column_int64(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int64 { 153 | SQLExt.sqlite3_column_int64(stmt, columnIndex) 154 | } 155 | 156 | func sqlite3_column_double(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Double { 157 | SQLExt.sqlite3_column_double(stmt, columnIndex) 158 | } 159 | 160 | func sqlite3_column_text(_ stmt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_uint8_ptr? { 161 | SQLExt.sqlite3_column_text(stmt, columnIndex) 162 | } 163 | 164 | func sqlite3_column_blob(_ stmt: OpaquePointer, _ columnIndex: Int32) -> UnsafeRawPointer? { 165 | SQLExt.sqlite3_column_blob(stmt, columnIndex) 166 | } 167 | 168 | func sqlite3_column_bytes(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int32 { 169 | SQLExt.sqlite3_column_bytes(stmt, columnIndex) 170 | } 171 | 172 | func sqlite3_backup_init(_ destDb: OpaquePointer, _ destName: String, _ sourceDb: OpaquePointer?, _ sourceName: String) -> OpaquePointer { 173 | SQLExt.sqlite3_backup_init(destDb, destName, sourceDb, sourceName) 174 | } 175 | 176 | func sqlite3_backup_step(_ backup: OpaquePointer, _ pages: Int32) -> Int32 { 177 | SQLExt.sqlite3_backup_step(backup, pages) 178 | } 179 | 180 | func sqlite3_backup_finish(_ backup: OpaquePointer) -> Int32 { 181 | SQLExt.sqlite3_backup_finish(backup) 182 | } 183 | 184 | func sqlite3_backup_remaining(_ backup: OpaquePointer) -> Int32 { 185 | SQLExt.sqlite3_backup_remaining(backup) 186 | } 187 | 188 | func sqlite3_backup_pagecount(_ backup: OpaquePointer) -> Int32 { 189 | SQLExt.sqlite3_backup_pagecount(backup) 190 | } 191 | 192 | func sqlite3_initialize() -> Int32 { 193 | SQLExt.sqlite3_initialize() 194 | } 195 | 196 | func sqlite3_shutdown() -> Int32 { 197 | SQLExt.sqlite3_shutdown() 198 | } 199 | 200 | func sqlite3_extended_result_codes(_ db: OpaquePointer, _ on: Int32) -> Int32 { 201 | SQLExt.sqlite3_extended_result_codes(db, on) 202 | } 203 | 204 | func sqlite3_free(_ ptr: sqlite3_pointer_type) { 205 | SQLExt.sqlite3_free(ptr) 206 | } 207 | 208 | func sqlite3_db_mutex(_ db: OpaquePointer?) -> OpaquePointer? { 209 | SQLExt.sqlite3_db_mutex(db) 210 | } 211 | 212 | func sqlite3_mutex_free(_ lock: OpaquePointer?) { 213 | SQLExt.sqlite3_mutex_free(lock) 214 | } 215 | 216 | func sqlite3_mutex_enter(_ lock: OpaquePointer?) { 217 | SQLExt.sqlite3_mutex_enter(lock) 218 | } 219 | 220 | func sqlite3_mutex_leave(_ lock: OpaquePointer?) { 221 | SQLExt.sqlite3_mutex_leave(lock) 222 | } 223 | 224 | func sqlite3_update_hook(_ db: OpaquePointer?, _ callback: sqlite3_update_hook?, _ pArg: UnsafeMutableRawPointer?) -> UnsafeMutableRawPointer? { 225 | SQLExt.sqlite3_update_hook(db, callback, pArg) 226 | } 227 | 228 | func sqlite3_trace_v2(_ db: OpaquePointer?, _ mask: sqlite3_unsigned, _ callback: sqlite3_trace_hook?, _ pCtx: UnsafeMutableRawPointer?) -> Int32 { 229 | SQLExt.sqlite3_trace_v2(db, mask, callback, pCtx) 230 | } 231 | } 232 | #endif 233 | 234 | -------------------------------------------------------------------------------- /Sources/SkipSQLPlus/SQLPlusJLibrary.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2023–2025 Skip 2 | // SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception 3 | #if SKIP 4 | import Foundation 5 | import OSLog 6 | import SkipFFI 7 | import SkipSQL 8 | 9 | /// A concrete implementation of the `SQLiteLibrary` interface that declared `external` methods to use [JNA Direct Mapping](https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md) to cache native method lookups. 10 | /// 11 | /// Note that this is identical to the `SkipSQL.SQLLiteJNALibrary`, but it is registered 12 | /// to the locally-built `sqlext` library. 13 | internal final class SQLPlusJNALibrary : SQLiteLibrary { 14 | static let shared = registerNatives(SQLPlusJNALibrary(), frameworkName: "SkipSQLPlus", libraryName: "sqlext") 15 | 16 | /* SKIP INSERT: external */ func sqlite3_sleep(_ duration: Int32) -> Int32 17 | /* SKIP INSERT: external override */ public func sqlite3_open(_ filename: String, _ ppDb: sqlite3_openarg?) -> Int32 18 | /* SKIP INSERT: external override */ public func sqlite3_open_v2(_ filename: String, _ ppDb: sqlite3_openarg?, _ flags: Int32, _ vfs: String?) -> Int32 19 | /* SKIP INSERT: external */ func sqlite3_close(_ db: OpaquePointer) -> Int32 20 | /* SKIP INSERT: external */ func sqlite3_errcode(_ db: OpaquePointer) -> Int32 21 | /* SKIP INSERT: external */ func sqlite3_errmsg(_ db: OpaquePointer) -> sqlite3_cstring_ptr? 22 | /* SKIP INSERT: external */ func sqlite3_last_insert_rowid(_ db: OpaquePointer) -> Int64 23 | /* SKIP INSERT: external */ func sqlite3_total_changes(_ db: OpaquePointer) -> Int32 24 | /* SKIP INSERT: external */ func sqlite3_changes(_ db: OpaquePointer) -> Int32 25 | // /* SKIP INSERT: external */ func sqlite3_total_changes64(_ db: OpaquePointer) -> Int64 26 | // /* SKIP INSERT: external */ func sqlite3_changes64(_ db: OpaquePointer) -> Int64 // unavailable on Android 27 | /* SKIP INSERT: external */ func sqlite3_interrupt(_ db: OpaquePointer) 28 | /* SKIP INSERT: external override */ public func sqlite3_exec(_ db: OpaquePointer, _ sql: String, _ callback: sqlite3_callback?, _ pArg: UnsafeMutableRawPointer?, _ errmsg: sqlite_error_ptr?) -> Int32 29 | /* SKIP INSERT: external override */ public func sqlite3_prepare_v2(_ db: OpaquePointer, _ sql: String, _ nBytes: Int32, _ ppStmt: sqlite3_openarg, _ tail: sqlite_tail_ptr?) -> Int32 30 | /* SKIP INSERT: external */ func sqlite3_step(_ stmt: OpaquePointer) -> Int32 31 | /* SKIP INSERT: external */ func sqlite3_finalize(_ stmt: OpaquePointer) -> Int32 32 | /* SKIP INSERT: external */ func sqlite3_reset(_ stmt: OpaquePointer) -> Int32 33 | /* SKIP INSERT: external */ func sqlite3_column_count(_ stmt: OpaquePointer) -> Int32 34 | /* SKIP INSERT: external */ func sqlite3_bind_parameter_count(_ stmnt: OpaquePointer) -> Int32 35 | /* SKIP INSERT: external */ func sqlite3_bind_parameter_name(_ stmnt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_cstring_ptr? 36 | /* SKIP INSERT: external */ func sqlite3_bind_parameter_index(_ stmnt: OpaquePointer, _ name: String) -> Int32 37 | /* SKIP INSERT: external */ func sqlite3_clear_bindings(_ stmnt: OpaquePointer) -> Int32 38 | /* SKIP INSERT: external */ func sqlite3_column_name(_ stmt: OpaquePointer!, _ columnIndex: Int32) -> sqlite3_cstring_ptr? 39 | // /* SKIP INSERT: external */ func sqlite3_column_database_name(_ stmt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_cstring_ptr? // unavailable on Android 40 | // /* SKIP INSERT: external */ func sqlite3_column_origin_name(_ stmt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_cstring_ptr? 41 | /* SKIP INSERT: external */ func sqlite3_column_decltype(_ stmt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_cstring_ptr? 42 | /* SKIP INSERT: external */ func sqlite3_sql(_ stmt: OpaquePointer) -> sqlite3_cstring_ptr? 43 | /* SKIP INSERT: external */ func sqlite3_expanded_sql(_ stmt: OpaquePointer) -> sqlite3_cstring_mutptr? 44 | /* SKIP INSERT: external */ func sqlite3_db_handle(_ stmt: OpaquePointer) -> OpaquePointer 45 | /* SKIP INSERT: external */ func sqlite3_bind_null(_ stmt: OpaquePointer, _ paramIndex: Int32) -> Int32 46 | /* SKIP INSERT: external */ func sqlite3_bind_int(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: Int32) -> Int32 47 | /* SKIP INSERT: external */ func sqlite3_bind_int64(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: Int64) -> Int32 48 | /* SKIP INSERT: external */ func sqlite3_bind_double(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: Double) -> Int32 49 | /* SKIP INSERT: external */ func sqlite3_bind_text(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: String, _ length: Int32, _ destructor: sqlite3_destructor_type) -> Int32 50 | /* SKIP INSERT: external override */ public func sqlite3_bind_blob(_ stmt: OpaquePointer, _ paramIndex: Int32, _ value: UnsafeRawPointer?, _ length: Int32, _ destructor: sqlite3_destructor_type) -> Int32 51 | /* SKIP INSERT: external */ func sqlite3_bind_zeroblob(_ stmt: OpaquePointer, _ paramIndex: Int32, _ length: Int32) -> Int32 52 | /* SKIP INSERT: external */ func sqlite3_column_type(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int32 53 | /* SKIP INSERT: external */ func sqlite3_column_int(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int32 54 | /* SKIP INSERT: external */ func sqlite3_column_int64(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int64 55 | /* SKIP INSERT: external */ func sqlite3_column_double(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Double 56 | /* SKIP INSERT: external */ func sqlite3_column_text(_ stmt: OpaquePointer, _ columnIndex: Int32) -> sqlite3_uint8_ptr? 57 | /* SKIP INSERT: external */ func sqlite3_column_blob(_ stmt: OpaquePointer, _ columnIndex: Int32) -> UnsafeRawPointer? 58 | /* SKIP INSERT: external */ func sqlite3_column_bytes(_ stmt: OpaquePointer, _ columnIndex: Int32) -> Int32 59 | /* SKIP INSERT: external */ func sqlite3_backup_init(_ destDb: OpaquePointer, _ destName: String, _ sourceDb: OpaquePointer?, _ sourceName: String) -> OpaquePointer 60 | /* SKIP INSERT: external */ func sqlite3_backup_step(_ backup: OpaquePointer, _ pages: Int32) -> Int32 61 | /* SKIP INSERT: external */ func sqlite3_backup_finish(_ backup: OpaquePointer) -> Int32 62 | /* SKIP INSERT: external */ func sqlite3_backup_remaining(_ backup: OpaquePointer) -> Int32 63 | /* SKIP INSERT: external */ func sqlite3_backup_pagecount(_ backup: OpaquePointer) -> Int32 64 | /* SKIP INSERT: external */ func sqlite3_initialize() -> Int32 65 | /* SKIP INSERT: external */ func sqlite3_shutdown() -> Int32 66 | /* SKIP INSERT: external */ func sqlite3_extended_result_codes(_ db: OpaquePointer, _ on: Int32) -> Int32 67 | /* SKIP INSERT: external */ func sqlite3_free(_ ptr: OpaquePointer) 68 | /* SKIP INSERT: external */ func sqlite3_db_mutex(_ db: OpaquePointer?) -> OpaquePointer? 69 | /* SKIP INSERT: external */ func sqlite3_mutex_free(_ lock: OpaquePointer?) 70 | /* SKIP INSERT: external */ func sqlite3_mutex_enter(_ lock: OpaquePointer?) 71 | /* SKIP INSERT: external */ func sqlite3_mutex_leave(_ lock: OpaquePointer?) 72 | /* SKIP INSERT: external */ func sqlite3_update_hook(_ db: OpaquePointer?, _ callback: sqlite3_update_hook?, _ pArg: UnsafeMutableRawPointer?) -> UnsafeMutableRawPointer? 73 | /* SKIP INSERT: external */ func sqlite3_trace_v2(_ db: OpaquePointer?, _ mask: sqlite3_unsigned, _ callback: sqlite3_trace_hook?, _ pCtx: UnsafeMutableRawPointer?) -> Int32 74 | } 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /Sources/SkipSQLPlus/Skip/skip.yml: -------------------------------------------------------------------------------- 1 | # skip.tools per-configuration file 2 | 3 | #skip: 4 | # package: 'skip.sql' 5 | 6 | # the blocks to add to the build.gradle.kts 7 | build: 8 | contents: 9 | - block: 'dependencies' 10 | contents: 11 | -------------------------------------------------------------------------------- /Tests/SkipSQLPlusTests/SQLContextTestConfiguration.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2023–2025 Skip 2 | // SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception 3 | import SkipSQL 4 | import SkipSQLPlus 5 | 6 | extension SQLiteConfiguration { 7 | /// The shared SQLContextTests uses thus local variable to determine the configuration to use 8 | public static let test = SQLiteConfiguration.plus 9 | } 10 | -------------------------------------------------------------------------------- /Tests/SkipSQLPlusTests/SQLContextTests.swift: -------------------------------------------------------------------------------- 1 | ../SkipSQLTests/SQLContextTests.swift -------------------------------------------------------------------------------- /Tests/SkipSQLPlusTests/SQLPlusTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2023–2025 Skip 2 | // SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception 3 | import XCTest 4 | import OSLog 5 | import Foundation 6 | import SkipSQL 7 | import SkipSQLPlus 8 | 9 | final class SQLPlusTests: XCTestCase { 10 | let logger: Logger = Logger(subsystem: "skip.sql", category: "SQLPlusTests") 11 | 12 | func testSQLPlus() throws { 13 | let sqlplus = SQLContext(configuration: .plus) 14 | _ = try sqlplus.query(sql: "SELECT 1") 15 | _ = try sqlplus.query(sql: "SELECT CURRENT_TIMESTAMP") 16 | _ = try sqlplus.query(sql: "PRAGMA compile_options") 17 | 18 | // ensure that FTS works 19 | _ = try sqlplus.query(sql: "CREATE VIRTUAL TABLE \"documents\" USING fts5(content)") 20 | 21 | let stmnt = try sqlplus.prepare(sql: "SELECT 1") 22 | XCTAssertEqual("SELECT 1", stmnt.sql) 23 | 24 | XCTAssertEqual(0, stmnt.parameterCount) 25 | try stmnt.close() 26 | 27 | // the locally built SQLite version (contrast with the macOS version 3.43.2) 28 | XCTAssertEqual([SQLValue.text("3.46.1")], try sqlplus.query(sql: "SELECT sqlite_version()").first) 29 | XCTAssertEqual([SQLValue.text("ATOMIC_INTRINSICS=1")], try sqlplus.query(sql: "PRAGMA compile_options").first) 30 | XCTAssertEqual([SQLValue.text("4.6.1 community")], try sqlplus.query(sql: "PRAGMA cipher_version").first) 31 | //XCTAssertEqual([SQLValue.text("PRAGMA cipher_default_kdf_iter = 256000")], try sqlplus.query(sql: "PRAGMA cipher_default_settings").first) 32 | //XCTAssertEqual([SQLValue.text("XXX")], try sqlplus.query(sql: "PRAGMA cipher_provider").first) 33 | //XCTAssertEqual([SQLValue.text("XXX")], try sqlplus.query(sql: "PRAGMA cipher_provider_version").first) 34 | } 35 | 36 | func testSQLiteJSON() throws { 37 | let sqlplus = SQLContext(configuration: .plus) 38 | // The $[#] path feature in the JSON functions was added in version 3.31.0 39 | XCTAssertEqual([SQLValue.text("3.46.1")], try sqlplus.query(sql: "SELECT sqlite_version()").first) 40 | 41 | try sqlplus.exec(sql: #"CREATE TABLE users (id INTEGER PRIMARY KEY, profile JSON)"#) 42 | 43 | try sqlplus.exec(sql: #"INSERT INTO users (id, profile) VALUES (1, ?)"#, parameters: [.text(#"{"name": "Alice", "age": 30}"#)]) 44 | try sqlplus.exec(sql: #"INSERT INTO users (id, profile) VALUES (2, ?)"#, parameters: [.text(#"{"name": "Bob", "age": 25}"#)]) 45 | 46 | let j1 = try sqlplus.query(sql: "SELECT json_extract(profile, '$.name') as name FROM users WHERE id = ?", parameters: [.integer(1)]).first 47 | XCTAssertEqual([.text("Alice")], j1) 48 | 49 | let j2 = try sqlplus.query(sql: "SELECT json_extract(profile, '$.name') as name, json_extract(profile, '$.age') as age FROM users WHERE id = ?", parameters: [.integer(2)]).first 50 | XCTAssertEqual([.text("Bob"), .integer(25)], j2) 51 | 52 | XCTAssertEqual([.text("[1]")], try sqlplus.query(sql: "SELECT JSON_QUOTE(JSON('[1]'))").first) 53 | XCTAssertEqual([.integer(0)], try sqlplus.query(sql: "SELECT JSON_VALID('{\"x\":35')").first) 54 | XCTAssertEqual([.text("array")], try sqlplus.query(sql: "SELECT JSON_TYPE('{\"a\":[2,3.5,true,false,null,\"x\"]}', '$.a')").first) 55 | XCTAssertEqual([.text("[1,3,4]")], try sqlplus.query(sql: "SELECT JSON_REMOVE('[0,1,2,3,4]', '$[2]','$[0]')").first) 56 | XCTAssertEqual([.text("[1,3,4]")], try sqlplus.query(sql: "SELECT JSON_REMOVE('[0,1,2,3,4]', '$[2]','$[0]')").first) 57 | XCTAssertEqual([.text("{\"a\":1,\"b\":2,\"c\":3,\"d\":4}")], try sqlplus.query(sql: "SELECT JSON_PATCH('{\"a\":1,\"b\":2}','{\"c\":3,\"d\":4}')").first) 58 | XCTAssertEqual([.text("{\"c\":{\"e\":5}}")], try sqlplus.query(sql: "SELECT JSON_OBJECT('c', JSON('{\"e\":5}'))").first) 59 | XCTAssertEqual([.text("{\"a\":99,\"c\":4}")], try sqlplus.query(sql: "SELECT JSON_SET('{\"a\":2,\"c\":4}', '$.a', 99)").first) 60 | XCTAssertEqual([.text("{\"a\":99,\"c\":4}")], try sqlplus.query(sql: "SELECT JSON_REPLACE('{\"a\":2,\"c\":4}', '$.a', 99)").first) 61 | XCTAssertEqual([.text("[1,2,3,4,99]")], try sqlplus.query(sql: "SELECT JSON_INSERT('[1,2,3,4]','$[#]',99)").first) 62 | XCTAssertEqual([.text("[[4,5],2]")], try sqlplus.query(sql: "SELECT JSON_EXTRACT('{\"a\":2,\"c\":[4,5]}','$.c','$.a')").first) 63 | XCTAssertEqual([.integer(3)], try sqlplus.query(sql: "SELECT JSON_ARRAY_LENGTH('{\"one\":[1,2,3]}', '$.one')").first) 64 | XCTAssertEqual([.integer(4)], try sqlplus.query(sql: "SELECT JSON_ARRAY_LENGTH('[1,2,3,4]')").first) 65 | XCTAssertEqual([.text("[1,2,\"3\",4]")], try sqlplus.query(sql: "SELECT JSON_ARRAY(1, 2, '3', 4)").first) 66 | XCTAssertEqual([.text("{\"a\":1,\"b\":2,\"c\":3,\"d\":4}")], try sqlplus.query(sql: "SELECT JSON_PATCH('{\"a\":1,\"b\":2}', '{\"c\":3,\"d\":4}')").first) 67 | } 68 | 69 | func testSQLCipher() throws { 70 | func createDB(key: String?, plaintextHeader: Int? = nil, string: String) throws -> Data { 71 | let dbPath = URL.temporaryDirectory.appendingPathComponent(UUID().uuidString).appendingPathExtension("db") 72 | 73 | logger.log("testEncryption: checking db: \(dbPath.path)") 74 | let db = try SQLContext(path: dbPath.path, flags: [.create, .readWrite], configuration: .plus) 75 | if let key = key { 76 | _ = try db.query(sql: "PRAGMA key = '\(key)'") 77 | } 78 | if let plaintextHeader = plaintextHeader { 79 | _ = try db.query(sql: "PRAGMA cipher_plaintext_header_size = \(plaintextHeader)") 80 | } 81 | 82 | //_ = try db.query(sql: #"PRAGMA cipher_plaintext_header_size = 32"#) 83 | //_ = try db.query(sql: #"PRAGMA cipher_salt = "x'01010101010101010101010101010101'""#) 84 | //_ = try db.query(sql: #"PRAGMA user_version = 1; -- force header write"#) 85 | 86 | try db.exec(sql: #"CREATE TABLE SOME_TABLE(col)"#) 87 | try db.exec(sql: #"INSERT INTO SOME_TABLE(col) VALUES(?)"#, parameters: [.text(string)]) 88 | 89 | try db.close() 90 | 91 | let dbContents = try Data(contentsOf: dbPath) 92 | return dbContents 93 | } 94 | 95 | let str = "SOME_STRING" 96 | let data1 = try createDB(key: nil, string: str) 97 | let data2 = try createDB(key: "passkey", string: str) 98 | let data3 = try createDB(key: "passkey", plaintextHeader: 32, string: str) 99 | 100 | // check the header of the database file 101 | // an encrypted data (that does not use PRAGMA cipher_plaintext_header_size = X) should not contains the standard sqlite header 102 | let sqliteHeader = "SQLite format 3" 103 | XCTAssertEqual(sqliteHeader.utf8.hex(), "53514c69746520666f726d61742033") 104 | 105 | XCTAssertTrue(data1.hex().hasPrefix(sqliteHeader.utf8.hex()), "unencrypted database should have contained the SQLite header") 106 | XCTAssertFalse(data2.hex().hasPrefix(sqliteHeader.utf8.hex()), "encrypted database should not have contained the SQLite header") 107 | XCTAssertTrue(data3.hex().hasPrefix(sqliteHeader.utf8.hex()), "encrypted database should have contained the SQLite header when using cipher_plaintext_header_size") 108 | 109 | XCTAssertTrue(data1.hex().contains(str.utf8.hex()), "unencrypted database should have contained the test string") 110 | XCTAssertFalse(data2.hex().contains(str.utf8.hex()), "encrypted database should not have contained the test string") 111 | XCTAssertFalse(data3.hex().contains(str.utf8.hex()), "encrypted database should not have contained the test string") 112 | 113 | 114 | } 115 | } 116 | 117 | extension Sequence where Element == UInt8 { 118 | /// Convert this sequence of bytes into a hex string 119 | public func hex() -> String { 120 | #if SKIP 121 | // java.util.IllegalFormatConversionException: x != kotlin.UByte 122 | //map { String(format: "%02x", $0) }.joined() 123 | // This declaration needs opt-in. Its usage must be marked with '@kotlin.ExperimentalStdlibApi' or '@OptIn(kotlin.ExperimentalStdlibApi::class)' 124 | //kotlin.ByteArray(self).toHexString() 125 | map { String(format: "%02x", Int($0)) }.joined() 126 | #else 127 | map { String(format: "%02x", $0) }.joined() 128 | #endif 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /Tests/SkipSQLPlusTests/Skip/skip.yml: -------------------------------------------------------------------------------- 1 | # skip.tools per-configuration file 2 | 3 | # the blocks to add to the build.gradle.kts 4 | #build: 5 | # contents: 6 | # - block: 'dependencies' 7 | # contents: 8 | # - '// no new dependencies in SkipSQLKtTests' 9 | # skip.tools per-configuration file 10 | -------------------------------------------------------------------------------- /Tests/SkipSQLPlusTests/XCSkipTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2023–2025 Skip 2 | // SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception 3 | #if os(macOS) 4 | import SkipTest 5 | 6 | /// This test case will run the transpiled tests for the Skip module. 7 | @available(macOS 13, macCatalyst 16, *) 8 | final class XCSkipTests: XCTestCase, XCGradleHarness { 9 | public func testSkipModule() async throws { 10 | // Run the transpiled JUnit tests for the current test module. 11 | // These tests will be executed locally using Robolectric. 12 | // Connected device or emulator tests can be run by setting the 13 | // `ANDROID_SERIAL` environment variable to an `adb devices` 14 | // ID in the scheme's Run settings. 15 | // 16 | // Note that it isn't currently possible to filter the tests to run. 17 | try await runGradleTests() 18 | } 19 | } 20 | #endif 21 | -------------------------------------------------------------------------------- /Tests/SkipSQLTests/SQLContextTestConfiguration.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2023–2025 Skip 2 | // SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception 3 | import SkipSQL 4 | 5 | extension SQLiteConfiguration { 6 | /// The shared SQLContextTests uses thus local variable to determine the configuration to use 7 | public static let test = SQLiteConfiguration.platform 8 | } 9 | -------------------------------------------------------------------------------- /Tests/SkipSQLTests/Skip/skip.yml: -------------------------------------------------------------------------------- 1 | # skip.tools per-configuration file 2 | 3 | # the blocks to add to the build.gradle.kts 4 | #build: 5 | # contents: 6 | # - block: 'dependencies' 7 | # contents: 8 | # - '// no new dependencies in SkipSQLKtTests' 9 | # skip.tools per-configuration file 10 | -------------------------------------------------------------------------------- /Tests/SkipSQLTests/XCSkipTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2023–2025 Skip 2 | // SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception 3 | #if os(macOS) 4 | import SkipTest 5 | 6 | /// This test case will run the transpiled tests for the Skip module. 7 | @available(macOS 13, macCatalyst 16, *) 8 | final class XCSkipTests: XCTestCase, XCGradleHarness { 9 | public func testSkipModule() async throws { 10 | // Run the transpiled JUnit tests for the current test module. 11 | // These tests will be executed locally using Robolectric. 12 | // Connected device or emulator tests can be run by setting the 13 | // `ANDROID_SERIAL` environment variable to an `adb devices` 14 | // ID in the scheme's Run settings. 15 | // 16 | // Note that it isn't currently possible to filter the tests to run. 17 | try await runGradleTests() 18 | } 19 | } 20 | #endif 21 | --------------------------------------------------------------------------------