Repository: stephencelis/SQLite.swift
Branch: master
Commit: 964c300fb073
Files: 115
Total size: 851.7 KB
Directory structure:
gitextract_03naq3tg/
├── .github/
│ ├── FUNDING.yml
│ ├── issue_template.md
│ ├── pull_request_template.md
│ └── workflows/
│ └── build.yml
├── .gitignore
├── .swiftlint.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Documentation/
│ ├── Index.md
│ ├── Linux.md
│ ├── Planning.md
│ ├── Release.md
│ └── Upgrading.md
├── Gemfile
├── LICENSE.txt
├── Makefile
├── Package.swift
├── README.md
├── SQLite.playground/
│ ├── Contents.swift
│ ├── contents.xcplayground
│ └── playground.xcworkspace/
│ └── contents.xcworkspacedata
├── SQLite.swift.podspec
├── SQLite.xcodeproj/
│ ├── project.pbxproj
│ ├── project.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata/
│ └── xcschemes/
│ ├── SQLite Mac.xcscheme
│ ├── SQLite iOS.xcscheme
│ ├── SQLite tvOS.xcscheme
│ ├── SQLite visionOS.xcscheme
│ └── SQLite watchOS.xcscheme
├── Sources/
│ └── SQLite/
│ ├── Core/
│ │ ├── Backup.swift
│ │ ├── Blob.swift
│ │ ├── Connection+Aggregation.swift
│ │ ├── Connection+Attach.swift
│ │ ├── Connection+Pragmas.swift
│ │ ├── Connection.swift
│ │ ├── Errors.swift
│ │ ├── Result.swift
│ │ ├── SQLiteFeature.swift
│ │ ├── SQLiteVersion.swift
│ │ ├── Statement.swift
│ │ ├── URIQueryParameter.swift
│ │ └── Value.swift
│ ├── Extensions/
│ │ ├── Cipher.swift
│ │ ├── FTS4.swift
│ │ ├── FTS5.swift
│ │ └── RTree.swift
│ ├── Foundation.swift
│ ├── Helpers.swift
│ ├── Info.plist
│ ├── PrivacyInfo.xcprivacy
│ ├── SQLite.h
│ ├── Schema/
│ │ ├── Connection+Schema.swift
│ │ ├── SchemaChanger.swift
│ │ ├── SchemaDefinitions.swift
│ │ └── SchemaReader.swift
│ └── Typed/
│ ├── AggregateFunctions.swift
│ ├── Coding.swift
│ ├── Collation.swift
│ ├── CoreFunctions.swift
│ ├── CustomFunctions.swift
│ ├── DateAndTimeFunctions.swift
│ ├── Expression.swift
│ ├── Operators.swift
│ ├── Query+with.swift
│ ├── Query.swift
│ ├── Schema.swift
│ ├── Setter.swift
│ └── WindowFunctions.swift
├── Tests/
│ ├── .swiftlint.yml
│ ├── SPM/
│ │ ├── .gitignore
│ │ ├── Package.swift
│ │ └── Sources/
│ │ └── test/
│ │ └── main.swift
│ ├── SQLite visionOS.xctestplan
│ ├── SQLiteTests/
│ │ ├── Core/
│ │ │ ├── BlobTests.swift
│ │ │ ├── Connection+AttachTests.swift
│ │ │ ├── Connection+PragmaTests.swift
│ │ │ ├── ConnectionTests.swift
│ │ │ ├── CoreFunctionsTests.swift
│ │ │ ├── ResultTests.swift
│ │ │ ├── StatementTests.swift
│ │ │ └── ValueTests.swift
│ │ ├── Extensions/
│ │ │ ├── CipherTests.swift
│ │ │ ├── FTS4Tests.swift
│ │ │ ├── FTS5IntegrationTests.swift
│ │ │ ├── FTS5Tests.swift
│ │ │ └── RTreeTests.swift
│ │ ├── Fixtures.swift
│ │ ├── FoundationTests.swift
│ │ ├── Info.plist
│ │ ├── Schema/
│ │ │ ├── Connection+SchemaTests.swift
│ │ │ ├── SchemaChangerTests.swift
│ │ │ ├── SchemaDefinitionsTests.swift
│ │ │ ├── SchemaReaderTests.swift
│ │ │ └── SchemaTests.swift
│ │ ├── TestHelpers.swift
│ │ └── Typed/
│ │ ├── AggregateFunctionsTests.swift
│ │ ├── CustomAggregationTests.swift
│ │ ├── CustomFunctionsTests.swift
│ │ ├── DateAndTimeFunctionTests.swift
│ │ ├── ExpressionTests.swift
│ │ ├── OperatorsTests.swift
│ │ ├── QueryIntegrationTests.swift
│ │ ├── QueryTests.swift
│ │ ├── RowTests.swift
│ │ ├── SelectTests.swift
│ │ ├── SetterTests.swift
│ │ └── WindowFunctionsTests.swift
│ └── Tuist/
│ └── SQLite-Test/
│ ├── .gitignore
│ ├── Project.swift
│ ├── SQLite-Test/
│ │ ├── Sources/
│ │ │ └── SQLiteTestApp.swift
│ │ └── Tests/
│ │ └── SQLiteTestTests.swift
│ ├── Tuist/
│ │ └── Package.swift
│ └── Tuist.swift
└── run-tests.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/FUNDING.yml
================================================
github: [stephencelis, jberkel, NathanFallet]
================================================
FILE: .github/issue_template.md
================================================
> Issues are used to track bugs and feature requests.
> Need help or have a general question? Ask on Stack Overflow (tag sqlite.swift).
## Build Information
- Include the SQLite.swift version, commit or branch experiencing the issue.
- Mention Xcode and OS X versions affected.
- How do do you integrate SQLite.swift in your project?
- manual
- CocoaPods
- Carthage
- Swift Package manager
## General guidelines
- Be as descriptive as possible.
- Provide as much information needed to _reliably reproduce_ the issue.
- Attach screenshots if possible.
- Better yet: attach GIFs or link to video.
- Even better: link to a sample project exhibiting the issue.
================================================
FILE: .github/pull_request_template.md
================================================
Thanks for taking the time to submit a pull request.
Before submitting, please do the following:
- Run `make lint` to check if there are any format errors (install [swiftlint](https://github.com/realm/SwiftLint#installation) first)
- Run `swift test` to see if the tests pass.
- Write new tests for new functionality.
- Update documentation comments where applicable.
================================================
FILE: .github/workflows/build.yml
================================================
name: Build and test
on:
push:
branches:
- master
pull_request:
branches:
- master
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
build:
strategy:
matrix:
os: [macos-15, macos-26]
runs-on: ${{ matrix.os }}
env:
IOS_SIMULATOR: ${{ matrix.os == 'macos-15' && 'iPhone 16' || 'iPhone 16e' }}
IOS_VERSION: ${{ matrix.os == 'macos-15' && '18.5' || '26.0.1' }}
steps:
- uses: actions/checkout@v4
- name: "xcrun simctl list"
run: "xcrun simctl list"
- name: Update pod repo
run: pod repo update
- name: "Lint"
run: make lint
- name: "Run tests (PACKAGE_MANAGER_COMMAND: test)"
env:
PACKAGE_MANAGER_COMMAND: test -Xswiftc -warnings-as-errors
run: ./run-tests.sh
- name: "Run tests (PACKAGE_MANAGER_COMMAND: test --traits SQLiteSwiftCSQLite)"
env:
PACKAGE_MANAGER_COMMAND: test -Xswiftc -warnings-as-errors --traits SQLiteSwiftCSQLite
run: ./run-tests.sh
- name: "Run tests (PACKAGE_MANAGER_COMMAND: test --traits SQLiteSwiftCSQLite,FTS5)"
env:
PACKAGE_MANAGER_COMMAND: test -Xswiftc -warnings-as-errors --traits SQLiteSwiftCSQLite,FTS5
run: ./run-tests.sh
- name: "Run tests (PACKAGE_MANAGER_COMMAND: test --traits SQLCipher)"
env:
PACKAGE_MANAGER_COMMAND: test -Xswiftc -warnings-as-errors --traits SQLCipher
run: ./run-tests.sh
- name: "Run tests (SPM integration test)"
env:
SPM: run
run: ./run-tests.sh
- name: "Run tests (BUILD_SCHEME: SQLite iOS)"
env:
BUILD_SCHEME: SQLite iOS
run: ./run-tests.sh
- name: "Run tests (BUILD_SCHEME: SQLite Mac)"
env:
BUILD_SCHEME: SQLite Mac
run: ./run-tests.sh
- name: "Run tests (VALIDATOR_SUBSPEC: none)"
env:
VALIDATOR_SUBSPEC: none
run: ./run-tests.sh
- name: "Run tests (VALIDATOR_SUBSPEC: standard)"
env:
VALIDATOR_SUBSPEC: standard
run: ./run-tests.sh
- name: "Run tests (VALIDATOR_SUBSPEC: standalone)"
env:
VALIDATOR_SUBSPEC: standalone
run: ./run-tests.sh
- name: "Run tests (VALIDATOR_SUBSPEC: SQLCipher)"
env:
VALIDATOR_SUBSPEC: SQLCipher
run: ./run-tests.sh
- name: "Run tests (tuist)"
run: |
brew install tuist
cd Tests/Tuist/SQLite-Test
tuist install
tuist test
build-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install
run: |
sudo apt-get update -qq
sudo apt-get install -y libsqlite3-dev
- name: Test (default trait)
run: swift test
- name: Test (SQLiteSwiftCSQLite)
run: swift test --traits SQLiteSwiftCSQLite
- name: "Run tests (SPM integration test)"
env:
SPM: run
run: ./run-tests.sh
build-android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests on Android
uses: skiptools/swift-android-action@v2
with:
# Ubuntu runners low on space causes the emulator to fail to install
free-disk-space: true
swift-build-flags: --traits SQLiteSwiftCSQLite
================================================
FILE: .gitignore
================================================
# OS X
.DS_Store
# Xcode
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
# Carthage
/Carthage/
# Makefile
bin/
# Swift Package Manager
.build
Packages/
.swiftpm/
Package.resolved
Derived/
================================================
FILE: .swiftlint.yml
================================================
opt_in_rules:
- shorthand_optional_binding
disabled_rules: # rule identifiers to exclude from running
- todo
- function_name_whitespace
- large_tuple
- closure_parameter_position
- inclusive_language # sqlite_master etc.
- blanket_disable_command
included: # paths to include during linting. `--path` is ignored if present. takes precendence over `excluded`.
- Sources
- Tests
- Package.swift
excluded: # paths to ignore during linting. overridden by `included`.
- "*/.build/*"
identifier_name:
excluded:
- db
- in
- to
- by
- or
- eq
- gt
- lt
- fn
- a
- b
- q
- SQLITE_TRANSIENT
type_body_length:
warning: 350
error: 350
function_body_length:
warning: 60
error: 60
line_length:
warning: 150
error: 150
ignores_comments: true
file_length:
warning: 500
error: 500
ignore_comment_only_lines: true
================================================
FILE: CHANGELOG.md
================================================
0.16.0 (28-01-2026), [diff][diff-0.16.0]
========================================
* Revert trait changes for Linux
* Remove SwiftToolchainCSQLite (replaced with fork)
0.15.5 (22-01-2026), [diff][diff-0.15.5]
========================================
* Support more package traits ([#1341][]), including FTS5 ([#1343][])
* SQLCipher package manager integration ([#1336][], [#1340][])
* Provide a dynamic library in SPM ([#1342][])
* Added sendability conformance ([#1332][])
0.15.4 (13-06-2025), [diff][diff-0.15.4]
========================================
* Fix cross compilation for linux on macOS fails ([#1317][])
* Support creating tables in schema changer ([#1315][])
* Update oldest supported platform versions ([#1280][])
* Add CustomStringConvertible for Setter ([#1279][])
0.15.3 (19-04-2024), [diff][diff-0.15.3]
========================================
* Update `podspec` to include privacy manifest ([#1265][])
0.15.2 (16-04-2024), [diff][diff-0.15.2]
========================================
* fix: visionos to CocoaPods ([#1260][])
0.15.1 (14-04-2024), [diff][diff-0.15.1]
========================================
* Update CoreFunctions.swift fix typo ([#1249][])
* Fix #1247 support nil case when decoding optionals ([#1248][])
* Change deployment targets for Xcode 15 and add dependency on custom Cocoapods fork ([#1255][])
* Add VisionOS support ([#1237][])
0.15.0 (24-02-2024), [diff][diff-0.15.0]
========================================
* Fix incorrect behavior when preparing `SELECT *` preceded by a `WITH` ([#1179][])
* Adds support for returning extended error codes ([#1178][])
* Fix typos ([#1182][])
* fix Xcode build error ([#1192][])
* Make the IndexDefinition properties public ([#1196][])
* Fix GitHub Actions build badge ([#1200][])
* Run CI on macOS 13 ([#1206][])
* SchemaReader: return the correct column definition for a composite primary key ([#1217][])
* Add optional support for decoding ([#1224][])
* make fromDatatypeValue throw ([#1242][])
* Implements built-in window functions ([#1228][])
* Fix column affinity parsing to match how SQLite determines affinity ([#1218][])
* Handle FK definitions w/o key references ([#1210][])
* Add privacy manifest ([#1245][])
* New minimum deployment targets: iOS/tvOS 11.0, watchOS 4.0
0.14.1 (01-11-2022), [diff][diff-0.14.1]
========================================
* Reverted `Blob` changes (See [#1167][] for rationale).
0.14.0 (27-10-2022), [diff][diff-0.14.0]
========================================
For breaking changes, see [Upgrading.md](Documentation/Upgrading.md).
* Support more complex schema changes and queries ([#1073][], [#1146][] [#1148][])
* Support `ATTACH`/`DETACH` ([#30][], [#1142][])
* Expose connection flags (via `URIQueryParameter`) to open db ([#1074][])
* Support `WITH` clause ([#1139][])
* Add `Value` conformance for `NSURL` ([#1110][], [#1141][])
* Add decoding for `UUID` ([#1137][])
* SQLCipher: improve documentation ([#1098][]), add `sqlcipher_export` ([#1101][])
* Fix `insertMany([Encodable])` ([#1130][], [#1138][])
* Fix incorrect spelling of `remove_diacritics` ([#1128][])
* Fix project build order ([#1131][])
* Blob performance improvements ([#416][], [#1167][])
* Various performance improvements ([#1109][], [#1115][], [#1132][])
* Removed FTS3/4 tokenizer integration (`registerTokenizer`, [#1104][], [#1144][])
0.13.3 (27-03-2022), [diff][diff-0.13.3]
========================================
* UUID Fix ([#1112][])
* Add prepareRowIterator method to an extension of Statement. ([#1119][])
* Adding primary key support to column with references ([#1121][])
0.13.2 (25-01-2022), [diff][diff-0.13.2]
========================================
* Closing bracket position ([#1100][])
* Native user_version support in Connection ([#1105][])
0.13.1 (17-11-2021), [diff][diff-0.13.1]
========================================
* Support for database backup ([#919][])
* Support for custom SQL aggregates ([#881][])
* Restore previous behavior in `FailableIterator` ([#1075][])
* Fix compilation on Linux ([#1077][])
* Align platform versions in SPM manifest and Xcode ([#1094][])
* Revert OSX deployment target back to 10.10 ([#1095][])
0.13.0 (22-08-2021), [diff][diff-0.13.0]
========================================
* Swift 5.3 support
* Xcode 12.5 support
* Bumps minimum deployment versions
* Fixes up Package.swift to build SQLiteObjc module
0.12.1, 0.12.2 (21-06-2019) [diff][diff-0.12.2]
========================================
* CocoaPods modular headers support
0.12.0 (24-04-2019) [diff][diff-0.12.0]
========================================
* Version with Swift 5 Support
0.11.6 (19-04-2019), [diff][diff-0.11.6]
========================================
* Swift 4.2, SQLCipher 4.x ([#866][])
0.11.5 (04-14-2018), [diff][diff-0.11.5]
========================================
* Swift 4.1 ([#797][])
0.11.4 (30-09-2017), [diff][diff-0.11.4]
========================================
* Collate `.nocase` strictly enforces `NOT NULL` even when using Optional ([#697][])
* Fix transactions not being rolled back when committing fails ([#426][])
* Add possibility to have expression on right hand side of like ([#591][])
* Added Date and Time functions ([#142][])
* Add Swift4 Coding support ([#733][])
* Preliminary Linux support ([#315][], [#681][])
* Add `RowIterator` for more safety ([#647][], [#726][])
* Make `Row.get` throw instead of crash ([#649][])
* Fix create/drop index functions ([#666][])
* Revert deployment target to 8.0 ([#625][], [#671][], [#717][])
* Added support for the union query clause ([#723][])
* Add support for `ORDER` and `LIMIT` on `UPDATE` and `DELETE` ([#657][], [#722][])
* Swift 4 support ([#668][])
0.11.3 (30-03-2017), [diff][diff-0.11.3]
========================================
* Fix compilation problems when using Carthage ([#615][])
* Add `WITHOUT ROWID` table option ([#541][])
* Argument count fixed for binary custom functions ([#481][])
* Documentation updates
* Tested with Xcode 8.3 / iOS 10.3
0.11.2 (25-12-2016), [diff][diff-0.11.2]
========================================
* Fixed SQLCipher integration with read-only databases ([#559][])
* Preliminary Swift Package Manager support ([#548][], [#560][])
* Fixed null pointer when fetching an empty BLOB ([#561][])
* Allow `where` as alias for `filter` ([#571][])
0.11.1 (06-12-2016), [diff][diff-0.11.1]
========================================
* Integrate SQLCipher via CocoaPods ([#546][], [#553][])
* Made lastInsertRowid consistent with other SQLite wrappers ([#532][])
* Fix for `~=` operator used with Double ranges
* Various documentation updates
0.11.0 (19-10-2016)
===================
* Swift3 migration ([diff][diff-0.11.0])
[diff-0.11.0]: https://github.com/stephencelis/SQLite.swift/compare/0.10.1...0.11.0
[diff-0.11.1]: https://github.com/stephencelis/SQLite.swift/compare/0.11.0...0.11.1
[diff-0.11.2]: https://github.com/stephencelis/SQLite.swift/compare/0.11.1...0.11.2
[diff-0.11.3]: https://github.com/stephencelis/SQLite.swift/compare/0.11.2...0.11.3
[diff-0.11.4]: https://github.com/stephencelis/SQLite.swift/compare/0.11.3...0.11.4
[diff-0.11.5]: https://github.com/stephencelis/SQLite.swift/compare/0.11.4...0.11.5
[diff-0.11.6]: https://github.com/stephencelis/SQLite.swift/compare/0.11.5...0.11.6
[diff-0.12.0]: https://github.com/stephencelis/SQLite.swift/compare/0.11.6...0.12.0
[diff-0.12.2]: https://github.com/stephencelis/SQLite.swift/compare/0.12.0...0.12.2
[diff-0.13.0]: https://github.com/stephencelis/SQLite.swift/compare/0.12.2...0.13.0
[diff-0.13.1]: https://github.com/stephencelis/SQLite.swift/compare/0.13.0...0.13.1
[diff-0.13.2]: https://github.com/stephencelis/SQLite.swift/compare/0.13.1...0.13.2
[diff-0.13.3]: https://github.com/stephencelis/SQLite.swift/compare/0.13.2...0.13.3
[diff-0.14.0]: https://github.com/stephencelis/SQLite.swift/compare/0.13.3...0.14.0
[diff-0.14.1]: https://github.com/stephencelis/SQLite.swift/compare/0.14.0...0.14.1
[diff-0.15.0]: https://github.com/stephencelis/SQLite.swift/compare/0.14.0...0.15.0
[diff-0.15.1]: https://github.com/stephencelis/SQLite.swift/compare/0.15.0...0.15.1
[diff-0.15.2]: https://github.com/stephencelis/SQLite.swift/compare/0.15.1...0.15.2
[diff-0.15.3]: https://github.com/stephencelis/SQLite.swift/compare/0.15.2...0.15.3
[diff-0.15.4]: https://github.com/stephencelis/SQLite.swift/compare/0.15.3...0.15.4
[diff-0.15.5]: https://github.com/stephencelis/SQLite.swift/compare/0.15.4...0.15.5
[diff-0.16.0]: https://github.com/stephencelis/SQLite.swift/compare/0.15.5...0.16.0
[#30]: https://github.com/stephencelis/SQLite.swift/issues/30
[#142]: https://github.com/stephencelis/SQLite.swift/issues/142
[#315]: https://github.com/stephencelis/SQLite.swift/issues/315
[#416]: https://github.com/stephencelis/SQLite.swift/pull/416
[#426]: https://github.com/stephencelis/SQLite.swift/pull/426
[#481]: https://github.com/stephencelis/SQLite.swift/pull/481
[#532]: https://github.com/stephencelis/SQLite.swift/issues/532
[#541]: https://github.com/stephencelis/SQLite.swift/issues/541
[#546]: https://github.com/stephencelis/SQLite.swift/issues/546
[#548]: https://github.com/stephencelis/SQLite.swift/pull/548
[#553]: https://github.com/stephencelis/SQLite.swift/pull/553
[#559]: https://github.com/stephencelis/SQLite.swift/pull/559
[#560]: https://github.com/stephencelis/SQLite.swift/pull/560
[#561]: https://github.com/stephencelis/SQLite.swift/issues/561
[#571]: https://github.com/stephencelis/SQLite.swift/issues/571
[#591]: https://github.com/stephencelis/SQLite.swift/pull/591
[#615]: https://github.com/stephencelis/SQLite.swift/pull/615
[#625]: https://github.com/stephencelis/SQLite.swift/issues/625
[#647]: https://github.com/stephencelis/SQLite.swift/pull/647
[#649]: https://github.com/stephencelis/SQLite.swift/pull/649
[#657]: https://github.com/stephencelis/SQLite.swift/issues/657
[#666]: https://github.com/stephencelis/SQLite.swift/pull/666
[#668]: https://github.com/stephencelis/SQLite.swift/pull/668
[#671]: https://github.com/stephencelis/SQLite.swift/issues/671
[#681]: https://github.com/stephencelis/SQLite.swift/issues/681
[#697]: https://github.com/stephencelis/SQLite.swift/issues/697
[#717]: https://github.com/stephencelis/SQLite.swift/issues/717
[#722]: https://github.com/stephencelis/SQLite.swift/pull/722
[#723]: https://github.com/stephencelis/SQLite.swift/pull/723
[#733]: https://github.com/stephencelis/SQLite.swift/pull/733
[#726]: https://github.com/stephencelis/SQLite.swift/pull/726
[#797]: https://github.com/stephencelis/SQLite.swift/pull/797
[#866]: https://github.com/stephencelis/SQLite.swift/pull/866
[#881]: https://github.com/stephencelis/SQLite.swift/pull/881
[#919]: https://github.com/stephencelis/SQLite.swift/pull/919
[#1073]: https://github.com/stephencelis/SQLite.swift/issues/1073
[#1074]: https://github.com/stephencelis/SQLite.swift/issues/1074
[#1075]: https://github.com/stephencelis/SQLite.swift/pull/1075
[#1077]: https://github.com/stephencelis/SQLite.swift/issues/1077
[#1094]: https://github.com/stephencelis/SQLite.swift/pull/1094
[#1095]: https://github.com/stephencelis/SQLite.swift/pull/1095
[#1098]: https://github.com/stephencelis/SQLite.swift/issues/1098
[#1100]: https://github.com/stephencelis/SQLite.swift/pull/1100
[#1101]: https://github.com/stephencelis/SQLite.swift/issues/1101
[#1104]: https://github.com/stephencelis/SQLite.swift/issues/1104
[#1105]: https://github.com/stephencelis/SQLite.swift/pull/1105
[#1109]: https://github.com/stephencelis/SQLite.swift/issues/1109
[#1110]: https://github.com/stephencelis/SQLite.swift/pull/1110
[#1112]: https://github.com/stephencelis/SQLite.swift/pull/1112
[#1115]: https://github.com/stephencelis/SQLite.swift/pull/1115
[#1119]: https://github.com/stephencelis/SQLite.swift/pull/1119
[#1121]: https://github.com/stephencelis/SQLite.swift/pull/1121
[#1128]: https://github.com/stephencelis/SQLite.swift/issues/1128
[#1130]: https://github.com/stephencelis/SQLite.swift/issues/1130
[#1131]: https://github.com/stephencelis/SQLite.swift/pull/1131
[#1132]: https://github.com/stephencelis/SQLite.swift/pull/1132
[#1137]: https://github.com/stephencelis/SQLite.swift/pull/1137
[#1138]: https://github.com/stephencelis/SQLite.swift/pull/1138
[#1139]: https://github.com/stephencelis/SQLite.swift/pull/1139
[#1141]: https://github.com/stephencelis/SQLite.swift/pull/1141
[#1142]: https://github.com/stephencelis/SQLite.swift/pull/1142
[#1144]: https://github.com/stephencelis/SQLite.swift/pull/1144
[#1146]: https://github.com/stephencelis/SQLite.swift/pull/1146
[#1148]: https://github.com/stephencelis/SQLite.swift/pull/1148
[#1167]: https://github.com/stephencelis/SQLite.swift/pull/1167
[#1179]: https://github.com/stephencelis/SQLite.swift/pull/1179
[#1178]: https://github.com/stephencelis/SQLite.swift/pull/1178
[#1182]: https://github.com/stephencelis/SQLite.swift/pull/1182
[#1192]: https://github.com/stephencelis/SQLite.swift/pull/1192
[#1196]: https://github.com/stephencelis/SQLite.swift/pull/1196
[#1200]: https://github.com/stephencelis/SQLite.swift/pull/1200
[#1206]: https://github.com/stephencelis/SQLite.swift/pull/1206
[#1217]: https://github.com/stephencelis/SQLite.swift/pull/1217
[#1224]: https://github.com/stephencelis/SQLite.swift/pull/1224
[#1242]: https://github.com/stephencelis/SQLite.swift/pull/1242
[#1228]: https://github.com/stephencelis/SQLite.swift/pull/1228
[#1218]: https://github.com/stephencelis/SQLite.swift/pull/1218
[#1210]: https://github.com/stephencelis/SQLite.swift/pull/1210
[#1245]: https://github.com/stephencelis/SQLite.swift/pull/1245
[#1249]: https://github.com/stephencelis/SQLite.swift/pull/1249
[#1248]: https://github.com/stephencelis/SQLite.swift/pull/1248
[#1255]: https://github.com/stephencelis/SQLite.swift/pull/1255
[#1237]: https://github.com/stephencelis/SQLite.swift/pull/1237
[#1260]: https://github.com/stephencelis/SQLite.swift/pull/1260
[#1265]: https://github.com/stephencelis/SQLite.swift/pull/1265
[#1279]: https://github.com/stephencelis/SQLite.swift/pull/1279
[#1280]: https://github.com/stephencelis/SQLite.swift/pull/1280
[#1315]: https://github.com/stephencelis/SQLite.swift/pull/1315
[#1317]: https://github.com/stephencelis/SQLite.swift/pull/1317
[#1332]: https://github.com/stephencelis/SQLite.swift/pull/1332
[#1336]: https://github.com/stephencelis/SQLite.swift/pull/1336
[#1340]: https://github.com/stephencelis/SQLite.swift/pull/1340
[#1341]: https://github.com/stephencelis/SQLite.swift/pull/1341
[#1342]: https://github.com/stephencelis/SQLite.swift/pull/1342
[#1343]: https://github.com/stephencelis/SQLite.swift/pull/1343
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
The where and when to open an [issue](#issues) or [pull
request](#pull-requests).
## Issues
Issues are used to track **bugs** and **feature requests**. Need **help** or
have a **general question**? [Ask on Stack Overflow][] (tag `sqlite.swift`).
Before reporting a bug or requesting a feature, [run a few searches][Search] to
see if a similar issue has already been opened and ensure you’re not submitting
a duplicate.
If you find a similar issue, read the existing conversation and see if it
addresses everything. If it doesn’t, continue the conversation there.
If your searches return empty, see the [bug](#bugs) or [feature
request](#feature-requests) guidelines below.
[Ask on Stack Overflow]: https://stackoverflow.com/questions/tagged/sqlite.swift
[Search]: https://github.com/stephencelis/SQLite.swift/search?type=Issues
### Bugs
Think you’ve discovered a new **bug**? Let’s try troubleshooting a few things
first.
- **Is it an installation issue?**
If this is your first time building SQLite.swift in your project, you may
encounter a build error, _e.g._:
No such module 'SQLite'
Please carefully re-read the [installation instructions][] to make sure
everything is in order.
- **Have you read the documentation?**
If you can’t seem to get something working, check
[the documentation][See Documentation] to see if the solution is there.
- **Are you up-to-date?**
If you’re perusing [the documentation][See Documentation] online and find
that an example is just not working, please upgrade to the latest version
of SQLite.swift and try again before continuing.
- **Is it an unhelpful build error?**
While Swift error messaging is improving with each release, complex
expressions still lend themselves to misleading errors. If you encounter an
error on a complex line, breaking it down into smaller pieces generally
yields a more understandable error.
- **Is it an _even more_ unhelpful build error?**
Have you updated Xcode recently? Did your project stop building out of the
blue?
Hold down the **option** key and select **Clean Build Folder…** from the
**Product** menu (⌥⇧⌘K).
Made it through everything above and still having trouble? Sorry!
[Open an issue][]! And _please_:
- Be as descriptive as possible.
- Provide as much information needed to _reliably reproduce_ the issue.
- Attach screenshots if possible.
- Better yet: attach GIFs or link to video.
- Even better: link to a sample project exhibiting the issue.
- Include the SQLite.swift commit or branch experiencing the issue.
- Include devices and operating systems affected.
- Include build information: the Xcode and macOS versions affected.
[installation instructions]: Documentation/Index.md#installation
[See Documentation]: Documentation/Index.md#sqliteswift-documentation
[Open an issue]: https://github.com/stephencelis/SQLite.swift/issues/new
### Feature Requests
Have an innovative **feature request**? [Open an issue][]! Be thorough! Provide
context and examples. Be open to discussion.
## Pull Requests
Interested in contributing but don’t know where to start? Try the [`help
wanted`][help wanted] label.
Ready to submit a fix or a feature? [Submit a pull request][]! And _please_:
- If code changes, run the tests and make sure everything still works.
- Write new tests for new functionality.
- Update documentation comments where applicable.
- Maintain the existing style.
- Don’t forget to have fun.
While we cannot guarantee a merge to every pull request, we do read each one
and love your input.
[help wanted]: https://github.com/stephencelis/SQLite.swift/labels/help%20wanted
[Submit a pull request]: https://github.com/stephencelis/SQLite.swift/fork
================================================
FILE: Documentation/Index.md
================================================
# SQLite.swift Documentation
- [SQLite.swift Documentation](#sqliteswift-documentation)
- [Installation](#installation)
- [Swift Package Manager](#swift-package-manager)
- [Using SQLite.swift with SQLCipher](#using-sqliteswift-with-sqlcipher)
- [Carthage](#carthage)
- [CocoaPods](#cocoapods)
- [Requiring a specific version of SQLite](#requiring-a-specific-version-of-sqlite)
- [Manual](#manual)
- [Getting Started](#getting-started)
- [Connecting to a Database](#connecting-to-a-database)
- [Read-Write Databases](#read-write-databases)
- [Read-Only Databases](#read-only-databases)
- [In a shared group container](#in-a-shared-group-container)
- [In-Memory Databases](#in-memory-databases)
- [URI parameters](#uri-parameters)
- [Thread-Safety](#thread-safety)
- [Building Type-Safe SQL](#building-type-safe-sql)
- [Expressions](#expressions)
- [Compound Expressions](#compound-expressions)
- [Queries](#queries)
- [Creating a Table](#creating-a-table)
- [Create Table Options](#create-table-options)
- [Column Constraints](#column-constraints)
- [Table Constraints](#table-constraints)
- [Inserting Rows](#inserting-rows)
- [Handling SQLite errors](#handling-sqlite-errors)
- [Setters](#setters)
- [Infix Setters](#infix-setters)
- [Postfix Setters](#postfix-setters)
- [Selecting Rows](#selecting-rows)
- [Iterating and Accessing Values](#iterating-and-accessing-values)
- [Failable iteration](#failable-iteration)
- [Plucking Rows](#plucking-rows)
- [Building Complex Queries](#building-complex-queries)
- [Selecting Columns](#selecting-columns)
- [Joining Other Tables](#joining-other-tables)
- [Column Namespacing](#column-namespacing)
- [Table Aliasing](#table-aliasing)
- [Filtering Rows](#filtering-rows)
- [Filter Operators and Functions](#filter-operators-and-functions)
- [Infix Filter Operators](#infix-filter-operators)
- [Prefix Filter Operators](#prefix-filter-operators)
- [Filtering Functions](#filtering-functions)
- [Sorting Rows](#sorting-rows)
- [Limiting and Paging Results](#limiting-and-paging-results)
- [Recursive and Hierarchical Queries](#recursive-and-hierarchical-queries)
- [Aggregation](#aggregation)
- [Upserting Rows](#upserting-rows)
- [Updating Rows](#updating-rows)
- [Deleting Rows](#deleting-rows)
- [Transactions and Savepoints](#transactions-and-savepoints)
- [Querying the Schema](#querying-the-schema)
- [Indexes and Columns](#indexes-and-columns)
- [Altering the Schema](#altering-the-schema)
- [Renaming Tables](#renaming-tables)
- [Dropping Tables](#dropping-tables)
- [Adding Columns](#adding-columns)
- [Added Column Constraints](#added-column-constraints)
- [SchemaChanger](#schemachanger)
- [Adding Columns](#adding-columns-1)
- [Renaming Columns](#renaming-columns)
- [Dropping Columns](#dropping-columns)
- [Renaming/Dropping Tables](#renamingdropping-tables)
- [Creating Tables](#creating-tables)
- [Indexes](#indexes)
- [Creating Indexes](#creating-indexes)
- [Dropping Indexes](#dropping-indexes)
- [Migrations and Schema Versioning](#migrations-and-schema-versioning)
- [Custom Types](#custom-types)
- [Date-Time Values](#date-time-values)
- [Binary Data](#binary-data)
- [Codable Types](#codable-types)
- [Inserting Codable Types](#inserting-codable-types)
- [Updating Codable Types](#updating-codable-types)
- [Retrieving Codable Types](#retrieving-codable-types)
- [Restrictions](#restrictions)
- [Other Operators](#other-operators)
- [Other Infix Operators](#other-infix-operators)
- [Other Prefix Operators](#other-prefix-operators)
- [Core SQLite Functions](#core-sqlite-functions)
- [Aggregate SQLite Functions](#aggregate-sqlite-functions)
- [Window SQLite Functions](#window-sqlite-functions)
- [Date and Time functions](#date-and-time-functions)
- [Custom SQL Functions](#custom-sql-functions)
- [Custom Aggregations](#custom-aggregations)
- [Custom Collations](#custom-collations)
- [Full-text Search](#full-text-search)
- [FTS5](#fts5)
- [Executing Arbitrary SQL](#executing-arbitrary-sql)
- [Online Database Backup](#online-database-backup)
- [Attaching and detaching databases](#attaching-and-detaching-databases)
- [Logging](#logging)
- [Vacuum](#vacuum)
[↩]: #sqliteswift-documentation
## Installation
### Swift Package Manager
The [Swift Package Manager][] is a tool for managing the distribution of
Swift code. It’s integrated with the Swift build system to automate the
process of downloading, compiling, and linking dependencies.
1. Add the following to your `Package.swift` file:
```swift
dependencies: [
.package(url: "https://github.com/stephencelis/SQLite.swift.git", from: "0.16.0")
]
```
2. Build your project:
```sh
$ swift build
```
#### Available traits
The Swift package manager now supports [traits][], which can be used to configure
SQLite.swift for different use cases.
```swift
dependencies: [
.package(url: "https://github.com/stephencelis/SQLite.swift.git",
from: "0.16.0",
traits: ["XXX"])
]
```
| Trait | Description | SQLite version |
|--------------------------|---------------------------------------------------------|--------------------------------------|
| `SystemSQLite` (default) | Uses the system SQLite (provided by Apple) | macOS 15.7.x: `3.43.2`, 26: `3.50.2` |
| `SQLiteSwiftCSQLite` | Embeds a [custom SQLite][] based on [swift-toolchain][] | `3.50.4` |
| `StandaloneSQLite` | Only used by CocoaPods | |
| `SQLCipher` | Embeds [SQLCipher][] (see below) | 4.13.0: `3.51.2` |
| `FTS5` | Enables FTS5, only works with `SQLiteSwiftCSQLite` | |
[traits]: https://docs.swift.org/swiftpm/documentation/packagemanagerdocs/packagetraits/
[custom SQLite]: https://github.com/stephencelis/CSQLite/tree/SQLite.swift
[swift-toolchain]: https://github.com/swiftlang/swift-toolchain-sqlite
#### Using SQLite.swift with SQLCipher
If you want to use [SQLCipher][] with SQLite.swift you can specify the `SQLCipher` trait when consuming SQLite.swift.
```swift
depdencies: [
.package(url: "https://github.com/stephencelis/SQLite.swift.git", from: "0.16.0", traits: ["SQLCipher"])
]
```
As of Xcode 26.2 (17C52), there's no direct way in the Xcode UI to select trait variations so you'll need to use a local wrapper package to pull in the SQLite.swift dependency with the `SQLCipher` trait enabled:
```swift
// swift-tools-version: 6.1
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "AppDependencies",
platforms: [
.macOS(.v10_14),
.iOS(.v13),
.macCatalyst(.v13),
.watchOS(.v8),
.tvOS(.v15),
.visionOS(.v1)
],
products: [
.library(
name: "AppDependencies",
targets: ["AppDependencies"]),
],
dependencies: [
.package(
url: "https://github.com/stephencelis/SQLite.swift.git",
from: "0.16.0",
traits: ["SQLCipher"])
],
targets: [
.target(
name: "AppDependencies",
dependencies: [
.product(
name: "SQLite",
package: "SQLite.swift")
],
// necessary if you have other Package dependencies which explicitly link sqlite3
linkerSettings: [
.linkedFramework("SQLCipher")
]
)
]
)
```
_Note: It's important to include the linkerSettings to link SQLCipher framework first if you have any other Package dependencies in your wrapper package which explicitly link standard sqlite3. This ensures SQLCipher is linked first and properly used._
Within Xcode add your local `AppDependencies` wrapper package as a package dependency and SQLite.swift with SQLCipher functionality will be accessible.
Using the `SQLCipher` trait will cause SQLite.swift to include a dependency on SQLCipher.swift and enable `Connection` methods to set and change the database key:
```swift
import SQLite
let db = try Connection("path/to/encrypted.sqlite3")
try db.key("secret")
try db.rekey("new secret") // changes encryption key on already encrypted db
```
To encrypt an existing database:
```swift
let db = try Connection("path/to/unencrypted.sqlite3")
try db.sqlcipher_export(.uri("encrypted.sqlite3"), key: "secret")
```
[Swift Package Manager]: https://swift.org/package-manager
[SQLCipher]: https://www.zetetic.net/sqlcipher/
### Carthage
[Carthage][] is a simple, decentralized dependency manager for Cocoa. To
install SQLite.swift with Carthage:
1. Make sure Carthage is [installed][Carthage Installation].
2. Update your Cartfile to include the following:
```ruby
github "stephencelis/SQLite.swift" ~> 0.16.0
```
3. Run `carthage update` and [add the appropriate framework][Carthage Usage].
[Carthage]: https://github.com/Carthage/Carthage
[Carthage Installation]: https://github.com/Carthage/Carthage#installing-carthage
[Carthage Usage]: https://github.com/Carthage/Carthage#adding-frameworks-to-an-application
### CocoaPods
[CocoaPods][] is a dependency manager for Cocoa projects. To install SQLite.swift with CocoaPods:
1. Make sure CocoaPods is [installed][CocoaPods Installation] (SQLite.swift
requires version 1.6.1 or greater).
```sh
# Using the default Ruby install will require you to use sudo when
# installing and updating gems.
[sudo] gem install cocoapods
```
2. Update your Podfile to include the following:
```ruby
use_frameworks!
target 'YourAppTargetName' do
pod 'SQLite.swift', '~> 0.16.0'
end
```
3. Run `pod install --repo-update`.
#### Requiring a specific version of SQLite
If you want to use a more recent version of SQLite than what is provided
with the OS you can require the `standalone` subspec:
```ruby
target 'YourAppTargetName' do
pod 'SQLite.swift/standalone', '~> 0.16.0'
end
```
By default this will use the most recent version of SQLite without any
extras. If you want you can further customize this by adding another
dependency to sqlite3 or one of its subspecs:
```ruby
target 'YourAppTargetName' do
pod 'SQLite.swift/standalone', '~> 0.16.0'
pod 'sqlite3/fts5', '= 3.15.0' # SQLite 3.15.0 with FTS5 enabled
end
```
See the [sqlite3 podspec][sqlite3pod] for more details.
[CocoaPods]: https://cocoapods.org
[CocoaPods Installation]: https://guides.cocoapods.org/using/getting-started.html#getting-started
[sqlite3pod]: https://github.com/clemensg/sqlite3pod
### Manual
To install SQLite.swift as an Xcode sub-project:
1. Drag the **SQLite.xcodeproj** file into your own project.
([Submodule](http://git-scm.com/book/en/Git-Tools-Submodules), clone, or
[download](https://github.com/stephencelis/SQLite.swift/archive/master.zip)
the project first.)

2. In your target’s **General** tab, click the **+** button under **Linked
Frameworks and Libraries**.
3. Select the appropriate **SQLite.framework** for your platform.
4. **Add**.
You should now be able to `import SQLite` from any of your target’s source
files and begin using SQLite.swift.
Some additional steps are required to install the application on an actual
device:
5. In the **General** tab, click the **+** button under **Embedded
Binaries**.
6. Select the appropriate **SQLite.framework** for your platform.
7. **Add**.
## Getting Started
To use SQLite.swift classes or structures in your target’s source file, first
import the `SQLite` module.
```swift
import SQLite
```
### Connecting to a Database
Database connections are established using the `Connection` class. A
connection is initialized with a path to a database. SQLite will attempt to
create the database file if it does not already exist.
```swift
let db = try Connection("path/to/db.sqlite3")
```
#### Read-Write Databases
On iOS, you can create a writable database in your app’s **Documents**
directory.
```swift
let path = NSSearchPathForDirectoriesInDomains(
.documentDirectory, .userDomainMask, true
).first!
let db = try Connection("\(path)/db.sqlite3")
```
If you have bundled it in your application, you can use FileManager to copy it to the Documents directory:
```swift
func copyDatabaseIfNeeded(sourcePath: String) -> Bool {
let documents = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let destinationPath = documents + "/db.sqlite3"
let exists = FileManager.default.fileExists(atPath: destinationPath)
guard !exists else { return false }
do {
try FileManager.default.copyItem(atPath: sourcePath, toPath: destinationPath)
return true
} catch {
print("error during file copy: \(error)")
return false
}
}
```
On macOS, you can use your app’s **Application Support** directory:
```swift
// set the path corresponding to application support
var path = NSSearchPathForDirectoriesInDomains(
.applicationSupportDirectory, .userDomainMask, true
).first! + "/" + Bundle.main.bundleIdentifier!
// create parent directory inside application support if it doesn’t exist
try FileManager.default.createDirectory(
atPath: path, withIntermediateDirectories: true, attributes: nil
)
let db = try Connection("\(path)/db.sqlite3")
```
#### Read-Only Databases
If you bundle a database with your app (_i.e._, you’ve copied a database file
into your Xcode project and added it to your application target), you can
establish a _read-only_ connection to it.
```swift
let path = Bundle.main.path(forResource: "db", ofType: "sqlite3")!
let db = try Connection(path, readonly: true)
```
> _Note:_ Signed applications cannot modify their bundle resources. If you
> bundle a database file with your app for the purpose of bootstrapping, copy
> it to a writable location _before_ establishing a connection (see
> [Read-Write Databases](#read-write-databases), above, for typical, writable
> locations).
>
> See these two Stack Overflow questions for more information about iOS apps
> with SQLite databases: [1](https://stackoverflow.com/questions/34609746/what-different-between-store-database-in-different-locations-in-ios),
> [2](https://stackoverflow.com/questions/34614968/ios-how-to-copy-pre-seeded-database-at-the-first-running-app-with-sqlite-swift).
> We welcome changes to the above sample code to show how to successfully copy and use a bundled "seed"
> database for writing in an app.
#### In a shared group container
It is not recommend to store databases in a [shared group container],
some users have reported crashes ([#1042](https://github.com/stephencelis/SQLite.swift/issues/1042)).
[shared group container]: https://developer.apple.com/documentation/foundation/filemanager/1412643-containerurl#
#### In-Memory Databases
If you omit the path, SQLite.swift will provision an [in-memory
database](https://www.sqlite.org/inmemorydb.html).
```swift
let db = try Connection() // equivalent to `Connection(.inMemory)`
```
To create a temporary, disk-backed database, pass an empty file name.
```swift
let db = try Connection(.temporary)
```
In-memory databases are automatically deleted when the database connection is
closed.
#### URI parameters
We can pass `.uri` to the `Connection` initializer to control more aspects of
the database connection with the help of `URIQueryParameter`s:
```swift
let db = try Connection(.uri("file.sqlite", parameters: [.cache(.private), .noLock(true)]))
```
See [Uniform Resource Identifiers](https://www.sqlite.org/uri.html#recognized_query_parameters) for more details.
#### Thread-Safety
Every Connection comes equipped with its own serial queue for statement
execution and can be safely accessed across threads. Threads that open
transactions and savepoints will block other threads from executing
statements while the transaction is open.
If you maintain multiple connections for a single database, consider setting a timeout
(in seconds) *or* a busy handler. There can only be one active at a time, so setting a busy
handler will effectively override `busyTimeout`.
```swift
db.busyTimeout = 5 // error after 5 seconds (does multiple retries)
db.busyHandler({ tries in
tries < 3 // error after 3 tries
})
```
> _Note:_ The default timeout is 0, so if you see `database is locked`
> errors, you may be trying to access the same database simultaneously from
> multiple connections.
## Building Type-Safe SQL
SQLite.swift comes with a typed expression layer that directly maps
[Swift types](https://developer.apple.com/library/prerelease/ios/documentation/General/Reference/SwiftStandardLibraryReference/)
to their [SQLite counterparts](https://www.sqlite.org/datatype3.html).
| Swift Type | SQLite Type |
| --------------- | ----------- |
| `Int64`* | `INTEGER` |
| `Double` | `REAL` |
| `String` | `TEXT` |
| `nil` | `NULL` |
| `SQLite.Blob`† | `BLOB` |
| `URL` | `TEXT` |
| `UUID` | `TEXT` |
| `Date` | `TEXT` |
> *While `Int64` is the basic, raw type (to preserve 64-bit integers on
> 32-bit platforms), `Int` and `Bool` work transparently.
>
> †SQLite.swift defines its own `Blob` structure, which safely wraps the
> underlying bytes.
>
> See [Custom Types](#custom-types) for more information about extending
> other classes and structures to work with SQLite.swift.
>
> See [Executing Arbitrary SQL](#executing-arbitrary-sql) to forego the typed
> layer and execute raw SQL, instead.
These expressions (in the form of the structure,
[`Expression`](#expressions)) build on one another and, with a query
([`QueryType`](#queries)), can create and execute SQL statements.
### Expressions
Expressions are generic structures associated with a type ([built-in
](#building-type-safe-sql) or [custom](#custom-types)), raw SQL, and
(optionally) values to bind to that SQL. Typically, you will only explicitly
create expressions to describe your columns, and typically only once per
column.
```swift
let id = Expression("id")
let email = Expression("email")
let balance = Expression("balance")
let verified = Expression("verified")
```
Use optional generics for expressions that can evaluate to `NULL`.
```swift
let name = Expression("name")
```
> _Note:_ The default `Expression` initializer is for [quoted
> identifiers](https://www.sqlite.org/lang_keywords.html) (_i.e._, column
> names). To build a literal SQL expression, use `init(literal:)`.
>
### Compound Expressions
Expressions can be combined with other expressions and types using
[filter operators and functions](#filter-operators-and-functions)
(as well as other [non-filter operators](#other-operators) and
[functions](#core-sqlite-functions)). These building blocks can create complex SQLite statements.
### Queries
Queries are structures that reference a database and table name, and can be
used to build a variety of statements using expressions. We can create a
query by initializing a `Table`, `View`, or `VirtualTable`.
```swift
let users = Table("users")
```
Assuming [the table exists](#creating-a-table), we can immediately [insert
](#inserting-rows), [select](#selecting-rows), [update](#updating-rows), and
[delete](#deleting-rows) rows.
## Creating a Table
We can build [`CREATE TABLE`
statements](https://www.sqlite.org/lang_createtable.html) by calling the
`create` function on a `Table`. The following is a basic example of
SQLite.swift code (using the [expressions](#expressions) and
[query](#queries) above) and the corresponding SQL it generates.
```swift
try db.run(users.create { t in // CREATE TABLE "users" (
t.column(id, primaryKey: true) // "id" INTEGER PRIMARY KEY NOT NULL,
t.column(email, unique: true) // "email" TEXT UNIQUE NOT NULL,
t.column(name) // "name" TEXT
}) // )
```
> _Note:_ `Expression` structures (in this case, the `id` and `email`
> columns), generate `NOT NULL` constraints automatically, while
> `Expression` structures (`name`) do not.
### Create Table Options
The `Table.create` function has several default parameters we can override.
- `temporary` adds a `TEMPORARY` clause to the `CREATE TABLE` statement (to
create a temporary table that will automatically drop when the database
connection closes). Default: `false`.
```swift
try db.run(users.create(temporary: true) { t in /* ... */ })
// CREATE TEMPORARY TABLE "users" -- ...
```
- `ifNotExists` adds an `IF NOT EXISTS` clause to the `CREATE TABLE`
statement (which will bail out gracefully if the table already exists).
Default: `false`.
```swift
try db.run(users.create(ifNotExists: true) { t in /* ... */ })
// CREATE TABLE "users" IF NOT EXISTS -- ...
```
### Column Constraints
The `column` function is used for a single column definition. It takes an
[expression](#expressions) describing the column name and type, and accepts
several parameters that map to various column constraints and clauses.
- `primaryKey` adds a `PRIMARY KEY` constraint to a single column.
```swift
t.column(id, primaryKey: true)
// "id" INTEGER PRIMARY KEY NOT NULL
t.column(id, primaryKey: .autoincrement)
// "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
```
> _Note:_ The `primaryKey` parameter cannot be used alongside
> `references`. If you need to create a column that has a default value
> and is also a primary and/or foreign key, use the `primaryKey` and
> `foreignKey` functions mentioned under
> [Table Constraints](#table-constraints).
>
> Primary keys cannot be optional (_e.g._, `Expression`).
>
> Only an `INTEGER PRIMARY KEY` can take `.autoincrement`.
- `unique` adds a `UNIQUE` constraint to the column. (See the `unique`
function under [Table Constraints](#table-constraints) for uniqueness
over multiple columns).
```swift
t.column(email, unique: true)
// "email" TEXT UNIQUE NOT NULL
```
- `check` attaches a `CHECK` constraint to a column definition in the form
of a boolean expression (`Expression`). Boolean expressions can be
easily built using
[filter operators and functions](#filter-operators-and-functions).
(See also the `check` function under
[Table Constraints](#table-constraints).)
```swift
t.column(email, check: email.like("%@%"))
// "email" TEXT NOT NULL CHECK ("email" LIKE '%@%')
```
- `defaultValue` adds a `DEFAULT` clause to a column definition and _only_
accepts a value (or expression) matching the column’s type. This value is
used if none is explicitly provided during
[an `INSERT`](#inserting-rows).
```swift
t.column(name, defaultValue: "Anonymous")
// "name" TEXT DEFAULT 'Anonymous'
```
> _Note:_ The `defaultValue` parameter cannot be used alongside
> `primaryKey` and `references`. If you need to create a column that has
> a default value and is also a primary and/or foreign key, use the
> `primaryKey` and `foreignKey` functions mentioned under
> [Table Constraints](#table-constraints).
- `collate` adds a `COLLATE` clause to `Expression` (and
`Expression`) column definitions with
[a collating sequence](https://www.sqlite.org/datatype3.html#collation)
defined in the `Collation` enumeration.
```swift
t.column(email, collate: .nocase)
// "email" TEXT NOT NULL COLLATE "NOCASE"
t.column(name, collate: .rtrim)
// "name" TEXT COLLATE "RTRIM"
```
- `references` adds a `REFERENCES` clause to `Expression` (and
`Expression`) column definitions and accepts a table
(`SchemaType`) or namespaced column expression. (See the `foreignKey`
function under [Table Constraints](#table-constraints) for non-integer
foreign key support.)
```swift
t.column(user_id, references: users, id)
// "user_id" INTEGER REFERENCES "users" ("id")
```
> _Note:_ The `references` parameter cannot be used alongside
> `primaryKey` and `defaultValue`. If you need to create a column that
> has a default value and is also a primary and/or foreign key, use the
> `primaryKey` and `foreignKey` functions mentioned under
> [Table Constraints](#table-constraints).
### Table Constraints
Additional constraints may be provided outside the scope of a single column
using the following functions.
- `primaryKey` adds a `PRIMARY KEY` constraint to the table. Unlike [the
column constraint, above](#column-constraints), it supports all SQLite
types, [ascending and descending orders](#sorting-rows), and composite
(multiple column) keys.
```swift
t.primaryKey(email.asc, name)
// PRIMARY KEY("email" ASC, "name")
```
- `unique` adds a `UNIQUE` constraint to the table. Unlike
[the column constraint, above](#column-constraints), it
supports composite (multiplecolumn) constraints.
```swift
t.unique(local, domain)
// UNIQUE("local", "domain")
```
- `check` adds a `CHECK` constraint to the table in the form of a boolean
expression (`Expression`). Boolean expressions can be easily built
using [filter operators and functions](#filter-operators-and-functions).
(See also the `check` parameter under
[Column Constraints](#column-constraints).)
```swift
t.check(balance >= 0)
// CHECK ("balance" >= 0.0)
```
- `foreignKey` adds a `FOREIGN KEY` constraint to the table. Unlike [the
`references` constraint, above](#column-constraints), it supports all
SQLite types, both [`ON UPDATE` and `ON DELETE`
actions](https://www.sqlite.org/foreignkeys.html#fk_actions), and
composite (multiple column) keys.
```swift
t.foreignKey(user_id, references: users, id, delete: .setNull)
// FOREIGN KEY("user_id") REFERENCES "users"("id") ON DELETE SET NULL
```
## Inserting Rows
We can insert rows into a table by calling a [query’s](#queries) `insert`
function with a list of [setters](#setters)—typically [typed column
expressions](#expressions) and values (which can also be expressions)—each
joined by the `<-` operator.
```swift
try db.run(users.insert(email <- "alice@mac.com", name <- "Alice"))
// INSERT INTO "users" ("email", "name") VALUES ('alice@mac.com', 'Alice')
try db.run(users.insert(or: .replace, email <- "alice@mac.com", name <- "Alice B."))
// INSERT OR REPLACE INTO "users" ("email", "name") VALUES ('alice@mac.com', 'Alice B.')
```
The `insert` function, when run successfully, returns an `Int64` representing
the inserted row’s [`ROWID`][ROWID].
```swift
do {
let rowid = try db.run(users.insert(email <- "alice@mac.com"))
print("inserted id: \(rowid)")
} catch {
print("insertion failed: \(error)")
}
```
Multiple rows can be inserted at once by similarly calling `insertMany` with an array of
per-row [setters](#setters).
```swift
do {
let lastRowid = try db.run(users.insertMany([mail <- "alice@mac.com"], [email <- "geoff@mac.com"]))
print("last inserted id: \(lastRowid)")
} catch {
print("insertion failed: \(error)")
}
```
The [`update`](#updating-rows) and [`delete`](#deleting-rows) functions
follow similar patterns.
> _Note:_ If `insert` is called without any arguments, the statement will run
> with a `DEFAULT VALUES` clause. The table must not have any constraints
> that aren’t fulfilled by default values.
>
> ```swift
> try db.run(timestamps.insert())
> // INSERT INTO "timestamps" DEFAULT VALUES
> ```
### Handling SQLite errors
You can pattern match on the error to selectively catch SQLite errors. For example, to
specifically handle constraint errors ([SQLITE_CONSTRAINT](https://sqlite.org/rescode.html#constraint)):
```swift
do {
try db.run(users.insert(email <- "alice@mac.com"))
try db.run(users.insert(email <- "alice@mac.com"))
} catch let Result.error(message, code, statement) where code == SQLITE_CONSTRAINT {
print("constraint failed: \(message), in \(statement)")
} catch let error {
print("insertion failed: \(error)")
}
```
The `Result.error` type contains the English-language text that describes the error (`message`),
the error `code` (see [SQLite result code list](https://sqlite.org/rescode.html#primary_result_code_list)
for details) and a optional reference to the `statement` which produced the error.
### Setters
SQLite.swift typically uses the `<-` operator to set values during [inserts
](#inserting-rows) and [updates](#updating-rows).
```swift
try db.run(counter.update(count <- 0))
// UPDATE "counters" SET "count" = 0 WHERE ("id" = 1)
```
There are also a number of convenience setters that take the existing value
into account using native Swift operators.
For example, to atomically increment a column, we can use `++`:
```swift
try db.run(counter.update(count++)) // equivalent to `counter.update(count -> count + 1)`
// UPDATE "counters" SET "count" = "count" + 1 WHERE ("id" = 1)
```
To take an amount and “move” it via transaction, we can use `-=` and `+=`:
```swift
let amount = 100.0
try db.transaction {
try db.run(alice.update(balance -= amount))
try db.run(betty.update(balance += amount))
}
// BEGIN DEFERRED TRANSACTION
// UPDATE "users" SET "balance" = "balance" - 100.0 WHERE ("id" = 1)
// UPDATE "users" SET "balance" = "balance" + 100.0 WHERE ("id" = 2)
// COMMIT TRANSACTION
```
###### Infix Setters
| Operator | Types |
| -------- | ------------------ |
| `<-` | `Value -> Value` |
| `+=` | `Number -> Number` |
| `-=` | `Number -> Number` |
| `*=` | `Number -> Number` |
| `/=` | `Number -> Number` |
| `%=` | `Int -> Int` |
| `<<=` | `Int -> Int` |
| `>>=` | `Int -> Int` |
| `&=` | `Int -> Int` |
| `\|\|=` | `Int -> Int` |
| `^=` | `Int -> Int` |
| `+=` | `String -> String` |
###### Postfix Setters
| Operator | Types |
| -------- | ------------ |
| `++` | `Int -> Int` |
| `--` | `Int -> Int` |
## Selecting Rows
[Query structures](#queries) are `SELECT` statements waiting to happen. They
execute via [iteration](#iterating-and-accessing-values) and [other means
](#plucking-values) of sequence access.
### Iterating and Accessing Values
Prepared [queries](#queries) execute lazily upon iteration. Each row is
returned as a `Row` object, which can be subscripted with a [column
expression](#expressions) matching one of the columns returned.
```swift
for user in try db.prepare(users) {
print("id: \(user[id]), email: \(user[email]), name: \(user[name])")
// id: 1, email: alice@mac.com, name: Optional("Alice")
}
// SELECT * FROM "users"
```
`Expression` column values are _automatically unwrapped_ (we’ve made a
promise to the compiler that they’ll never be `NULL`), while `Expression`
values remain wrapped.
⚠ Column subscripts on `Row` will force try and abort execution in error cases.
If you want to handle this yourself, use `Row.get(_ column: Expression)`:
```swift
for user in try db.prepare(users) {
do {
print("name: \(try user.get(name))")
} catch {
// handle
}
}
```
Note that the iterator can throw *undeclared* database errors at any point during
iteration:
```swift
let query = try db.prepare(users)
for user in query {
// 💥 can throw an error here
}
```
#### Failable iteration
It is therefore recommended using the `RowIterator` API instead,
which has explicit error handling:
```swift
// option 1: convert results into an Array of rows
let rowIterator = try db.prepareRowIterator(users)
for user in try Array(rowIterator) {
print("id: \(user[id]), email: \(user[email])")
}
/// option 2: transform results using `map()`
let mapRowIterator = try db.prepareRowIterator(users)
let userIds = try mapRowIterator.map { $0[id] }
/// option 3: handle each row individually with `failableNext()`
do {
while let row = try rowIterator.failableNext() {
// Handle row
}
} catch {
// Handle error
}
```
### Plucking Rows
We can pluck the first row by passing a query to the `pluck` function on a
database connection.
```swift
if let user = try db.pluck(users) { /* ... */ } // Row
// SELECT * FROM "users" LIMIT 1
```
To collect all rows into an array, we can simply wrap the sequence (though
this is not always the most memory-efficient idea).
```swift
let all = Array(try db.prepare(users))
// SELECT * FROM "users"
```
### Building Complex Queries
[Queries](#queries) have a number of chainable functions that can be used
(with [expressions](#expressions)) to add and modify [a number of
clauses](https://www.sqlite.org/lang_select.html) to the underlying
statement.
```swift
let query = users.select(email) // SELECT "email" FROM "users"
.filter(name != nil) // WHERE "name" IS NOT NULL
.order(email.desc, name) // ORDER BY "email" DESC, "name"
.limit(5, offset: 1) // LIMIT 5 OFFSET 1
```
#### Selecting Columns
By default, [queries](#queries) select every column of the result set (using
`SELECT *`). We can use the `select` function with a list of
[expressions](#expressions) to return specific columns instead.
```swift
for user in try db.prepare(users.select(id, email)) {
print("id: \(user[id]), email: \(user[email])")
// id: 1, email: alice@mac.com
}
// SELECT "id", "email" FROM "users"
```
We can access the results of more complex expressions by holding onto a
reference of the expression itself.
```swift
let sentence = name + " is " + cast(age) as Expression + " years old!"
for user in users.select(sentence) {
print(user[sentence])
// Optional("Alice is 30 years old!")
}
// SELECT ((("name" || ' is ') || CAST ("age" AS TEXT)) || ' years old!') FROM "users"
```
#### Joining Other Tables
We can join tables using a [query’s](#queries) `join` function.
```swift
users.join(posts, on: user_id == users[id])
// SELECT * FROM "users" INNER JOIN "posts" ON ("user_id" = "users"."id")
```
The `join` function takes a [query](#queries) object (for the table being
joined on), a join condition (`on`), and is prefixed with an optional join
type (default: `.inner`). Join conditions can be built using [filter
operators and functions](#filter-operators-and-functions), generally require
[namespacing](#column-namespacing), and sometimes require
[aliasing](#table-aliasing).
##### Column Namespacing
When joining tables, column names can become ambiguous. _E.g._, both tables
may have an `id` column.
```swift
let query = users.join(posts, on: user_id == id)
// assertion failure: ambiguous column 'id'
```
We can disambiguate by namespacing `id`.
```swift
let query = users.join(posts, on: user_id == users[id])
// SELECT * FROM "users" INNER JOIN "posts" ON ("user_id" = "users"."id")
```
Namespacing is achieved by subscripting a [query](#queries) with a [column
expression](#expressions) (_e.g._, `users[id]` above becomes `users.id`).
> _Note:_ We can namespace all of a table’s columns using `*`.
>
> ```swift
> let query = users.select(users[*])
> // SELECT "users".* FROM "users"
> ```
##### Table Aliasing
Occasionally, we need to join a table to itself, in which case we must alias
the table with another name. We can achieve this using the
[query’s](#queries) `alias` function.
```swift
let managers = users.alias("managers")
let query = users.join(managers, on: managers[id] == users[managerId])
// SELECT * FROM "users"
// INNER JOIN ("users") AS "managers" ON ("managers"."id" = "users"."manager_id")
```
If query results can have ambiguous column names, row values should be
accessed with namespaced [column expressions](#expressions). In the above
case, `SELECT *` immediately namespaces all columns of the result set.
```swift
let user = try db.pluck(query)
user[id] // fatal error: ambiguous column 'id'
// (please disambiguate: ["users"."id", "managers"."id"])
user[users[id]] // returns "users"."id"
user[managers[id]] // returns "managers"."id"
```
#### Filtering Rows
SQLite.swift filters rows using a [query’s](#queries) `filter` function with
a boolean [expression](#expressions) (`Expression`).
```swift
users.filter(id == 1)
// SELECT * FROM "users" WHERE ("id" = 1)
users.filter([1, 2, 3, 4, 5].contains(id))
// SELECT * FROM "users" WHERE ("id" IN (1, 2, 3, 4, 5))
users.filter(email.like("%@mac.com"))
// SELECT * FROM "users" WHERE ("email" LIKE '%@mac.com')
users.filter(verified && name.lowercaseString == "alice")
// SELECT * FROM "users" WHERE ("verified" AND (lower("name") == 'alice'))
users.filter(verified || balance >= 10_000)
// SELECT * FROM "users" WHERE ("verified" OR ("balance" >= 10000.0))
```
We can build our own boolean expressions by using one of the many [filter
operators and functions](#filter-operators-and-functions).
Instead of `filter` we can also use the `where` function which is an alias:
```swift
users.where(id == 1)
// SELECT * FROM "users" WHERE ("id" = 1)
```
##### Filter Operators and Functions
SQLite.swift defines a number of operators for building filtering predicates.
Operators and functions work together in a type-safe manner, so attempting to
equate or compare different types will prevent compilation.
###### Infix Filter Operators
| Swift | Types | SQLite |
| ----- | -------------------------------- | -------------- |
| `==` | `Equatable -> Bool` | `=`/`IS`* |
| `!=` | `Equatable -> Bool` | `!=`/`IS NOT`* |
| `>` | `Comparable -> Bool` | `>` |
| `>=` | `Comparable -> Bool` | `>=` |
| `<` | `Comparable -> Bool` | `<` |
| `<=` | `Comparable -> Bool` | `<=` |
| `~=` | `(Interval, Comparable) -> Bool` | `BETWEEN` |
| `&&` | `Bool -> Bool` | `AND` |
| `\|\|`| `Bool -> Bool` | `OR` |
| `===` | `Equatable -> Bool` | `IS` |
| `!==` | `Equatable -> Bool` | `IS NOT` |
> * When comparing against `nil`, SQLite.swift will use `IS` and `IS NOT`
> accordingly.
###### Prefix Filter Operators
| Swift | Types | SQLite |
| ----- | ------------------ | ------ |
| `!` | `Bool -> Bool` | `NOT` |
###### Filtering Functions
| Swift | Types | SQLite |
| ---------- | ----------------------- | ------- |
| `like` | `String -> Bool` | `LIKE` |
| `glob` | `String -> Bool` | `GLOB` |
| `match` | `String -> Bool` | `MATCH` |
| `contains` | `(Array, T) -> Bool` | `IN` |
#### Sorting Rows
We can pre-sort returned rows using the [query’s](#queries) `order` function.
_E.g._, to return users sorted by `email`, then `name`, in ascending order:
```swift
users.order(email, name)
// SELECT * FROM "users" ORDER BY "email", "name"
```
The `order` function takes a list of [column expressions](#expressions).
`Expression` objects have two computed properties to assist sorting: `asc`
and `desc`. These properties append the expression with `ASC` and `DESC` to
mark ascending and descending order respectively.
```swift
users.order(email.desc, name.asc)
// SELECT * FROM "users" ORDER BY "email" DESC, "name" ASC
```
#### Limiting and Paging Results
We can limit and skip returned rows using a [query’s](#queries) `limit`
function (and its optional `offset` parameter).
```swift
users.limit(5)
// SELECT * FROM "users" LIMIT 5
users.limit(5, offset: 5)
// SELECT * FROM "users" LIMIT 5 OFFSET 5
```
#### Recursive and Hierarchical Queries
We can perform a recursive or hierarchical query using a [query's](#queries)
[`WITH`](https://sqlite.org/lang_with.html) function.
```swift
// Get the management chain for the manager with id == 8
let chain = Table("chain")
let id = Expression("id")
let managerId = Expression("manager_id")
let query = managers
.where(id == 8)
.union(chain.join(managers, on: chain[managerId] == managers[id])
chain.with(chain, recursive: true, as: query)
// WITH RECURSIVE
// "chain" AS (
// SELECT * FROM "managers" WHERE "id" = 8
// UNION
// SELECT * from "chain"
// JOIN "managers" ON "chain"."manager_id" = "managers"."id"
// )
// SELECT * FROM "chain"
```
Column names and a materialization hint can optionally be provided.
```swift
// Add a "level" column to the query representing manager's position in the chain
let level = Expression("level")
let queryWithLevel =
managers
.select(id, managerId, 0)
.where(id == 8)
.union(
chain
.select(managers[id], managers[manager_id], level + 1)
.join(managers, on: chain[managerId] == managers[id])
)
chain.with(chain,
columns: [id, managerId, level],
recursive: true,
hint: .materialize,
as: queryWithLevel)
// WITH RECURSIVE
// "chain" ("id", "manager_id", "level") AS MATERIALIZED (
// SELECT ("id", "manager_id", 0) FROM "managers" WHERE "id" = 8
// UNION
// SELECT ("manager"."id", "manager"."manager_id", "level" + 1) FROM "chain"
// JOIN "managers" ON "chain"."manager_id" = "managers"."id"
// )
// SELECT * FROM "chain"
```
#### Aggregation
[Queries](#queries) come with a number of functions that quickly return
aggregate scalar values from the table. These mirror the [core aggregate
functions](#aggregate-sqlite-functions) and are executed immediately against
the query.
```swift
let count = try db.scalar(users.count)
// SELECT count(*) FROM "users"
```
Filtered queries will appropriately filter aggregate values.
```swift
let count = try db.scalar(users.filter(name != nil).count)
// SELECT count(*) FROM "users" WHERE "name" IS NOT NULL
```
- `count` as a computed property on a query (see examples above) returns
the total number of rows matching the query.
`count` as a computed property on a column expression returns the total
number of rows where that column is not `NULL`.
```swift
let count = try db.scalar(users.select(name.count)) // -> Int
// SELECT count("name") FROM "users"
```
- `max` takes a comparable column expression and returns the largest value
if any exists.
```swift
let max = try db.scalar(users.select(id.max)) // -> Int64?
// SELECT max("id") FROM "users"
```
- `min` takes a comparable column expression and returns the smallest value
if any exists.
```swift
let min = try db.scalar(users.select(id.min)) // -> Int64?
// SELECT min("id") FROM "users"
```
- `average` takes a numeric column expression and returns the average row
value (as a `Double`) if any exists.
```swift
let average = try db.scalar(users.select(balance.average)) // -> Double?
// SELECT avg("balance") FROM "users"
```
- `sum` takes a numeric column expression and returns the sum total of all
rows if any exist.
```swift
let sum = try db.scalar(users.select(balance.sum)) // -> Double?
// SELECT sum("balance") FROM "users"
```
- `total`, like `sum`, takes a numeric column expression and returns the
sum total of all rows, but in this case always returns a `Double`, and
returns `0.0` for an empty query.
```swift
let total = try db.scalar(users.select(balance.total)) // -> Double
// SELECT total("balance") FROM "users"
```
> _Note:_ Expressions can be prefixed with a `DISTINCT` clause by calling the
> `distinct` computed property.
>
> ```swift
> let count = try db.scalar(users.select(name.distinct.count) // -> Int
> // SELECT count(DISTINCT "name") FROM "users"
> ```
## Upserting Rows
We can upsert rows into a table by calling a [query’s](#queries) `upsert`
function with a list of [setters](#setters)—typically [typed column
expressions](#expressions) and values (which can also be expressions)—each
joined by the `<-` operator. Upserting is like inserting, except if there is a
conflict on the specified column value, SQLite will perform an update on the row instead.
```swift
try db.run(users.upsert(email <- "alice@mac.com", name <- "Alice", onConflictOf: email))
// INSERT INTO "users" ("email", "name") VALUES ('alice@mac.com', 'Alice') ON CONFLICT (\"email\") DO UPDATE SET \"name\" = \"excluded\".\"name\"
```
The `upsert` function, when run successfully, returns an `Int64` representing
the inserted row’s [`ROWID`][ROWID].
```swift
do {
let rowid = try db.run(users.upsert(email <- "alice@mac.com", name <- "Alice", onConflictOf: email))
print("inserted id: \(rowid)")
} catch {
print("insertion failed: \(error)")
}
```
The [`insert`](#inserting-rows), [`update`](#updating-rows), and [`delete`](#deleting-rows) functions
follow similar patterns.
## Updating Rows
We can update a table’s rows by calling a [query’s](#queries) `update`
function with a list of [setters](#setters)—typically [typed column
expressions](#expressions) and values (which can also be expressions)—each
joined by the `<-` operator.
When an unscoped query calls `update`, it will update _every_ row in the
table.
```swift
try db.run(users.update(email <- "alice@me.com"))
// UPDATE "users" SET "email" = 'alice@me.com'
```
Be sure to scope `UPDATE` statements beforehand using [the `filter` function
](#filtering-rows).
```swift
let alice = users.filter(id == 1)
try db.run(alice.update(email <- "alice@me.com"))
// UPDATE "users" SET "email" = 'alice@me.com' WHERE ("id" = 1)
```
The `update` function returns an `Int` representing the number of updated
rows.
```swift
do {
if try db.run(alice.update(email <- "alice@me.com")) > 0 {
print("updated alice")
} else {
print("alice not found")
}
} catch {
print("update failed: \(error)")
}
```
## Deleting Rows
We can delete rows from a table by calling a [query’s](#queries) `delete`
function.
When an unscoped query calls `delete`, it will delete _every_ row in the
table.
```swift
try db.run(users.delete())
// DELETE FROM "users"
```
Be sure to scope `DELETE` statements beforehand using
[the `filter` function](#filtering-rows).
```swift
let alice = users.filter(id == 1)
try db.run(alice.delete())
// DELETE FROM "users" WHERE ("id" = 1)
```
The `delete` function returns an `Int` representing the number of deleted
rows.
```swift
do {
if try db.run(alice.delete()) > 0 {
print("deleted alice")
} else {
print("alice not found")
}
} catch {
print("delete failed: \(error)")
}
```
## Transactions and Savepoints
Using the `transaction` and `savepoint` functions, we can run a series of
statements in a transaction. If a single statement fails or the block throws
an error, the changes will be rolled back.
```swift
try db.transaction {
let rowid = try db.run(users.insert(email <- "betty@icloud.com"))
try db.run(users.insert(email <- "cathy@icloud.com", managerId <- rowid))
}
// BEGIN DEFERRED TRANSACTION
// INSERT INTO "users" ("email") VALUES ('betty@icloud.com')
// INSERT INTO "users" ("email", "manager_id") VALUES ('cathy@icloud.com', 2)
// COMMIT TRANSACTION
```
> _Note:_ Transactions run in a serial queue.
## Querying the Schema
We can obtain generic information about objects in the current schema with a `SchemaReader`:
```swift
let schema = db.schema
```
To query the data:
```swift
let indexes = try schema.objectDefinitions(type: .index)
let tables = try schema.objectDefinitions(type: .table)
let triggers = try schema.objectDefinitions(type: .trigger)
```
### Indexes and Columns
Specialized methods are available to get more detailed information:
```swift
let indexes = try schema.indexDefinitions("users")
let columns = try schema.columnDefinitions("users")
for index in indexes {
print("\(index.name) columns:\(index.columns))")
}
for column in columns {
print("\(column.name) pk:\(column.primaryKey) nullable: \(column.nullable)")
}
```
## Altering the Schema
SQLite.swift comes with several functions (in addition to `Table.create`) for
altering a database schema in a type-safe manner.
### Renaming Tables
We can build an `ALTER TABLE … RENAME TO` statement by calling the `rename`
function on a `Table` or `VirtualTable`.
```swift
try db.run(users.rename(Table("users_old")))
// ALTER TABLE "users" RENAME TO "users_old"
```
### Dropping Tables
We can build
[`DROP TABLE` statements](https://www.sqlite.org/lang_droptable.html)
by calling the `dropTable` function on a `SchemaType`.
```swift
try db.run(users.drop())
// DROP TABLE "users"
```
The `drop` function has one additional parameter, `ifExists`, which (when
`true`) adds an `IF EXISTS` clause to the statement.
```swift
try db.run(users.drop(ifExists: true))
// DROP TABLE IF EXISTS "users"
```
### Adding Columns
We can add columns to a table by calling `addColumn` function on a `Table`.
SQLite.swift enforces
[the same limited subset](https://www.sqlite.org/lang_altertable.html) of
`ALTER TABLE` that SQLite supports.
```swift
try db.run(users.addColumn(suffix))
// ALTER TABLE "users" ADD COLUMN "suffix" TEXT
```
#### Added Column Constraints
The `addColumn` function shares several of the same [`column` function
parameters](#column-constraints) used when [creating
tables](#creating-a-table).
- `check` attaches a `CHECK` constraint to a column definition in the form
of a boolean expression (`Expression`). (See also the `check`
function under [Table Constraints](#table-constraints).)
```swift
try db.run(users.addColumn(suffix, check: ["JR", "SR"].contains(suffix)))
// ALTER TABLE "users" ADD COLUMN "suffix" TEXT CHECK ("suffix" IN ('JR', 'SR'))
```
- `defaultValue` adds a `DEFAULT` clause to a column definition and _only_
accepts a value matching the column’s type. This value is used if none is
explicitly provided during [an `INSERT`](#inserting-rows).
```swift
try db.run(users.addColumn(suffix, defaultValue: "SR"))
// ALTER TABLE "users" ADD COLUMN "suffix" TEXT DEFAULT 'SR'
```
> _Note:_ Unlike the [`CREATE TABLE` constraint](#table-constraints),
> default values may not be expression structures (including
> `CURRENT_TIME`, `CURRENT_DATE`, or `CURRENT_TIMESTAMP`).
- `collate` adds a `COLLATE` clause to `Expression` (and
`Expression`) column definitions with [a collating
sequence](https://www.sqlite.org/datatype3.html#collation) defined in the
`Collation` enumeration.
```swift
try db.run(users.addColumn(email, collate: .nocase))
// ALTER TABLE "users" ADD COLUMN "email" TEXT NOT NULL COLLATE "NOCASE"
try db.run(users.addColumn(name, collate: .rtrim))
// ALTER TABLE "users" ADD COLUMN "name" TEXT COLLATE "RTRIM"
```
- `references` adds a `REFERENCES` clause to `Int64` (and `Int64?`) column
definitions and accepts a table or namespaced column expression. (See the
`foreignKey` function under [Table Constraints](#table-constraints) for
non-integer foreign key support.)
```swift
try db.run(posts.addColumn(userId, references: users, id)
// ALTER TABLE "posts" ADD COLUMN "user_id" INTEGER REFERENCES "users" ("id")
```
### SchemaChanger
Version 0.14.0 introduces `SchemaChanger`, an alternative API to perform more complex
migrations such as renaming columns. These operations work with all versions of
SQLite but use SQL statements such as `ALTER TABLE RENAME COLUMN` when available.
#### Adding Columns
```swift
let newColumn = ColumnDefinition(
name: "new_text_column",
type: .TEXT,
nullable: true,
defaultValue: .stringLiteral("foo")
)
let schemaChanger = SchemaChanger(connection: db)
try schemaChanger.alter(table: "users") { table in
table.add(column: newColumn)
}
```
#### Renaming Columns
```swift
let schemaChanger = SchemaChanger(connection: db)
try schemaChanger.alter(table: "users") { table in
table.rename(column: "old_name", to: "new_name")
}
```
#### Dropping Columns
```swift
let schemaChanger = SchemaChanger(connection: db)
try schemaChanger.alter(table: "users") { table in
table.drop(column: "email")
}
```
#### Renaming/Dropping Tables
```swift
let schemaChanger = SchemaChanger(connection: db)
try schemaChanger.rename(table: "users", to: "users_new")
try schemaChanger.drop(table: "emails", ifExists: false)
```
#### Creating Tables
```swift
let schemaChanger = SchemaChanger(connection: db)
try schemaChanger.create(table: "users") { table in
table.add(column: .init(name: "id", primaryKey: .init(autoIncrement: true), type: .INTEGER))
table.add(column: .init(name: "name", type: .TEXT, nullable: false))
}
```
### Indexes
#### Creating Indexes
We can build
[`CREATE INDEX` statements](https://www.sqlite.org/lang_createindex.html)
by calling the `createIndex` function on a `SchemaType`.
```swift
try db.run(users.createIndex(email))
// CREATE INDEX "index_users_on_email" ON "users" ("email")
```
The index name is generated automatically based on the table and column
names.
The `createIndex` function has a couple default parameters we can override.
- `unique` adds a `UNIQUE` constraint to the index. Default: `false`.
```swift
try db.run(users.createIndex(email, unique: true))
// CREATE UNIQUE INDEX "index_users_on_email" ON "users" ("email")
```
- `ifNotExists` adds an `IF NOT EXISTS` clause to the `CREATE TABLE`
statement (which will bail out gracefully if the table already exists).
Default: `false`.
```swift
try db.run(users.createIndex(email, ifNotExists: true))
// CREATE INDEX IF NOT EXISTS "index_users_on_email" ON "users" ("email")
```
#### Dropping Indexes
We can build
[`DROP INDEX` statements](https://www.sqlite.org/lang_dropindex.html) by
calling the `dropIndex` function on a `SchemaType`.
```swift
try db.run(users.dropIndex(email))
// DROP INDEX "index_users_on_email"
```
The `dropIndex` function has one additional parameter, `ifExists`, which
(when `true`) adds an `IF EXISTS` clause to the statement.
```swift
try db.run(users.dropIndex(email, ifExists: true))
// DROP INDEX IF EXISTS "index_users_on_email"
```
### Migrations and Schema Versioning
You can use the convenience property on `Connection` to query and set the
[`PRAGMA user_version`](https://sqlite.org/pragma.html#pragma_user_version).
This is a great way to manage your schema’s version over migrations.
You can conditionally run your migrations along the lines of:
```swift
if db.userVersion == 0 {
// handle first migration
db.userVersion = 1
}
if db.userVersion == 1 {
// handle second migration
db.userVersion = 2
}
```
For more complex migration requirements check out the schema management
system [SQLiteMigrationManager.swift][].
## Custom Types
SQLite.swift supports serializing and deserializing any custom type as long
as it conforms to the `Value` protocol.
```swift
protocol Value {
typealias Datatype: Binding
class var declaredDatatype: String { get }
class func fromDatatypeValue(datatypeValue: Datatype) -> Self
var datatypeValue: Datatype { get }
}
```
The `Datatype` must be one of the basic Swift types that values are bridged
through before serialization and deserialization (see [Building Type-Safe SQL
](#building-type-safe-sql) for a list of types).
> ⚠ _Note:_ `Binding` is a protocol that SQLite.swift uses internally to
> directly map SQLite types to Swift types. **Do _not_** conform custom types
> to the `Binding` protocol.
### Date-Time Values
In SQLite, `DATETIME` columns can be treated as strings or numbers, so we can
transparently bridge `Date` objects through Swift’s `String` types.
We can use these types directly in SQLite statements.
```swift
let published_at = Expression("published_at")
let published = posts.filter(published_at <= Date())
// SELECT * FROM "posts" WHERE "published_at" <= '2014-11-18T12:45:30.000'
let startDate = Date(timeIntervalSince1970: 0)
let published = posts.filter(startDate...Date() ~= published_at)
// SELECT * FROM "posts" WHERE "published_at" BETWEEN '1970-01-01T00:00:00.000' AND '2014-11-18T12:45:30.000'
```
### Binary Data
We can bridge any type that can be initialized from and encoded to `Data`.
```swift
extension UIImage: Value {
public class var declaredDatatype: String {
return Blob.declaredDatatype
}
public class func fromDatatypeValue(blobValue: Blob) -> UIImage {
return UIImage(data: Data.fromDatatypeValue(blobValue))!
}
public var datatypeValue: Blob {
return UIImagePNGRepresentation(self)!.datatypeValue
}
}
```
> _Note:_ See the [Archives and Serializations Programming Guide][] for more
> information on encoding and decoding custom types.
[Archives and Serializations Programming Guide]: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Archiving/Archiving.html
## Codable Types
[Codable types][Encoding and Decoding Custom Types] were introduced as a part
of Swift 4 to allow serializing and deserializing types. SQLite.swift supports
the insertion, updating, and retrieval of basic Codable types.
[Encoding and Decoding Custom Types]: https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types
### Inserting Codable Types
Queries have a method to allow inserting an [Encodable][] type.
```swift
struct User: Encodable {
let name: String
}
try db.run(users.insert(User(name: "test")))
```
There are two other parameters also available to this method:
- `userInfo` is a dictionary that is passed to the encoder and made available
to encodable types to allow customizing their behavior.
- `otherSetters` allows you to specify additional setters on top of those
that are generated from the encodable types themselves.
[Encodable]: https://developer.apple.com/documentation/swift/encodable
### Updating Codable Types
Queries have a method to allow updating an Encodable type.
```swift
try db.run(users.filter(id == userId).update(user))
```
> ⚠ Unless filtered, using the update method on an instance of a Codable
> type updates all table rows.
There are two other parameters also available to this method:
- `userInfo` is a dictionary that is passed to the encoder and made available
to encodable types to allow customizing their behavior.
- `otherSetters` allows you to specify additional setters on top of those
that are generated from the encodable types themselves.
### Retrieving Codable Types
Rows have a method to decode a [Decodable][] type.
```swift
let loadedUsers: [User] = try db.prepare(users).map { row in
return try row.decode()
}
```
You can also create a decoder to use manually yourself. This can be useful
for example if you are using the
[Facade pattern](https://en.wikipedia.org/wiki/Facade_pattern) to hide
subclasses behind a super class. For example, you may want to encode an Image
type that can be multiple different formats such as PNGImage, JPGImage, or
HEIFImage. You will need to determine the correct subclass before you know
which type to decode.
```swift
enum ImageCodingKeys: String, CodingKey {
case kind
}
enum ImageKind: Int, Codable {
case png, jpg, heif
}
let loadedImages: [Image] = try db.prepare(images).map { row in
let decoder = row.decoder()
let container = try decoder.container(keyedBy: ImageCodingKeys.self)
switch try container.decode(ImageKind.self, forKey: .kind) {
case .png:
return try PNGImage(from: decoder)
case .jpg:
return try JPGImage(from: decoder)
case .heif:
return try HEIFImage(from: decoder)
}
}
```
Both of the above methods also have the following optional parameter:
- `userInfo` is a dictionary that is passed to the decoder and made available
to decodable types to allow customizing their behavior.
[Decodable]: https://developer.apple.com/documentation/swift/decodable
### Restrictions
There are a few restrictions on using Codable types:
- The encodable and decodable objects can only use the following types:
- Int, Bool, Float, Double, String, Date
- Nested Codable types that will be encoded as JSON to a single column
- These methods will not handle object relationships for you. You must write
your own Codable and Decodable implementations if you wish to support this.
- The Codable types may not try to access nested containers or nested unkeyed
containers
- The Codable types may not access single value containers or unkeyed
containers
- The Codable types may not access super decoders or encoders
## Other Operators
In addition to [filter operators](#filtering-infix-operators), SQLite.swift
defines a number of operators that can modify expression values with
arithmetic, bitwise operations, and concatenation.
###### Other Infix Operators
| Swift | Types | SQLite |
| ----- | -------------------------------- | -------- |
| `+` | `Number -> Number` | `+` |
| `-` | `Number -> Number` | `-` |
| `*` | `Number -> Number` | `*` |
| `/` | `Number -> Number` | `/` |
| `%` | `Int -> Int` | `%` |
| `<<` | `Int -> Int` | `<<` |
| `>>` | `Int -> Int` | `>>` |
| `&` | `Int -> Int` | `&` |
| `\|` | `Int -> Int` | `\|` |
| `+` | `String -> String` | `\|\|` |
> _Note:_ SQLite.swift also defines a bitwise XOR operator, `^`, which
> expands the expression `lhs ^ rhs` to `~(lhs & rhs) & (lhs | rhs)`.
###### Other Prefix Operators
| Swift | Types | SQLite |
| ----- | ------------------ | ------ |
| `~` | `Int -> Int` | `~` |
| `-` | `Number -> Number` | `-` |
## Core SQLite Functions
Many of SQLite’s [core functions](https://www.sqlite.org/lang_corefunc.html)
have been surfaced in and type-audited for SQLite.swift.
> _Note:_ SQLite.swift aliases the `??` operator to the `ifnull` function.
>
> ```swift
> name ?? email // ifnull("name", "email")
> ```
## Aggregate SQLite Functions
Most of SQLite’s
[aggregate functions](https://www.sqlite.org/lang_aggfunc.html) have been
surfaced in and type-audited for SQLite.swift.
## Window SQLite Functions
Most of SQLite's [window functions](https://www.sqlite.org/windowfunctions.html) have been
surfaced in and type-audited for SQLite.swift. Currently only `OVER (ORDER BY ...)` windowing is possible.
## Date and Time functions
SQLite's [date and time](https://www.sqlite.org/lang_datefunc.html)
functions are available:
```swift
DateFunctions.date("now")
// date('now')
Date().date
// date('2007-01-09T09:41:00.000')
Expression("date").date
// date("date")
```
## Custom SQL Functions
We can create custom SQL functions by calling `createFunction` on a database
connection.
For example, to give queries access to
[`MobileCoreServices.UTTypeConformsTo`][UTTypeConformsTo], we can
write the following:
```swift
import MobileCoreServices
let typeConformsTo: (Expression, Expression) -> Expression = (
try db.createFunction("typeConformsTo", deterministic: true) { UTI, conformsToUTI in
return UTTypeConformsTo(UTI, conformsToUTI)
}
)
```
> _Note:_ The optional `deterministic` parameter is an optimization that
> causes the function to be created with
> [`SQLITE_DETERMINISTIC`](https://www.sqlite.org/c3ref/c_deterministic.html).
Note `typeConformsTo`’s signature:
```swift
(Expression, Expression) -> Expression
```
Because of this, `createFunction` expects a block with the following
signature:
```swift
(String, String) -> Bool
```
Once assigned, the closure can be called wherever boolean expressions are
accepted.
```swift
let attachments = Table("attachments")
let UTI = Expression("UTI")
let images = attachments.filter(typeConformsTo(UTI, kUTTypeImage))
// SELECT * FROM "attachments" WHERE "typeConformsTo"("UTI", 'public.image')
```
> _Note:_ The return type of a function must be
> [a core SQL type](#building-type-safe-sql) or [conform to `Value`](#custom-types).
We can create loosely-typed functions by handling an array of raw arguments,
instead.
```swift
db.createFunction("typeConformsTo", deterministic: true) { args in
guard let UTI = args[0] as? String, conformsToUTI = args[1] as? String else { return nil }
return UTTypeConformsTo(UTI, conformsToUTI)
}
```
Creating a loosely-typed function cannot return a closure and instead must be
wrapped manually or executed [using raw SQL](#executing-arbitrary-sql).
```swift
let stmt = try db.prepare("SELECT * FROM attachments WHERE typeConformsTo(UTI, ?)")
for row in stmt.bind(kUTTypeImage) { /* ... */ }
```
> _Note:_ Prepared queries can be reused, and long lived prepared queries should be `reset()` after each use. Otherwise, the transaction (either [implicit or explicit](https://www.sqlite.org/lang_transaction.html#implicit_versus_explicit_transactions)) will be held open until the query is reset or finalized. This can affect performance. Statements are reset automatically during `deinit`.
>
> ```swift
> someObj.statement = try db.prepare("SELECT * FROM attachments WHERE typeConformsTo(UTI, ?)")
> for row in someObj.statement.bind(kUTTypeImage) { /* ... */ }
> someObj.statement.reset()
> ```
[UTTypeConformsTo]: https://developer.apple.com/documentation/coreservices/1444079-uttypeconformsto
## Custom Aggregations
We can create custom aggregation functions by calling `createAggregation`:
```swift
let reduce: (String, [Binding?]) -> String = { (last, bindings) in
last + " " + (bindings.first as? String ?? "")
}
db.createAggregation("customConcat", initialValue: "", reduce: reduce, result: { $0 })
let result = db.prepare("SELECT customConcat(email) FROM users").scalar() as! String
```
## Custom Collations
We can create custom collating sequences by calling `createCollation` on a
database connection.
```swift
try db.createCollation("NODIACRITIC") { lhs, rhs in
return lhs.compare(rhs, options: .diacriticInsensitiveSearch)
}
```
We can reference a custom collation using the `Custom` member of the
`Collation` enumeration.
```swift
restaurants.order(collate(.custom("NODIACRITIC"), name))
// SELECT * FROM "restaurants" ORDER BY "name" COLLATE "NODIACRITIC"
```
## Full-text Search
We can create a virtual table using the [FTS4
module](http://www.sqlite.org/fts3.html) by calling `create` on a
`VirtualTable`.
```swift
let emails = VirtualTable("emails")
let subject = Expression("subject")
let body = Expression("body")
try db.run(emails.create(.FTS4(subject, body)))
// CREATE VIRTUAL TABLE "emails" USING fts4("subject", "body")
```
We can specify a [tokenizer](http://www.sqlite.org/fts3.html#tokenizer) using the `tokenize` parameter.
```swift
try db.run(emails.create(.FTS4([subject, body], tokenize: .Porter)))
// CREATE VIRTUAL TABLE "emails" USING fts4("subject", "body", tokenize=porter)
```
We can set the full range of parameters by creating a `FTS4Config` object.
```swift
let emails = VirtualTable("emails")
let subject = Expression("subject")
let body = Expression("body")
let config = FTS4Config()
.column(subject)
.column(body, [.unindexed])
.languageId("lid")
.order(.desc)
try db.run(emails.create(.FTS4(config))
// CREATE VIRTUAL TABLE "emails" USING fts4("subject", "body", notindexed="body", languageid="lid", order="desc")
```
Once we insert a few rows, we can search using the `match` function, which
takes a table or column as its first argument and a query string as its
second.
```swift
try db.run(emails.insert(
subject <- "Just Checking In",
body <- "Hey, I was just wondering...did you get my last email?"
))
let wonderfulEmails: QueryType = emails.match("wonder*")
// SELECT * FROM "emails" WHERE "emails" MATCH 'wonder*'
let replies = emails.filter(subject.match("Re:*"))
// SELECT * FROM "emails" WHERE "subject" MATCH 'Re:*'
```
### FTS5
When linking against a version of SQLite with
[FTS5](http://www.sqlite.org/fts5.html) enabled we can create the virtual
table in a similar fashion.
```swift
let emails = VirtualTable("emails")
let subject = Expression("subject")
let body = Expression("body")
let config = FTS5Config()
.column(subject)
.column(body, [.unindexed])
try db.run(emails.create(.FTS5(config)))
// CREATE VIRTUAL TABLE "emails" USING fts5("subject", "body" UNINDEXED)
// Note that FTS5 uses a different syntax to select columns, so we need to rewrite
// the last FTS4 query above as:
let replies = emails.filter(emails.match("subject:\"Re:\"*"))
// SELECT * FROM "emails" WHERE "emails" MATCH 'subject:"Re:"*'
```
## Executing Arbitrary SQL
Though we recommend you stick with SQLite.swift’s
[type-safe system](#building-type-safe-sql) whenever possible, it is possible
to simply and safely prepare and execute raw SQL statements via a `Database` connection
using the following functions.
- `execute` runs an arbitrary number of SQL statements as a convenience.
```swift
try db.execute("""
BEGIN TRANSACTION;
CREATE TABLE users (
id INTEGER PRIMARY KEY NOT NULL,
email TEXT UNIQUE NOT NULL,
name TEXT
);
CREATE TABLE posts (
id INTEGER PRIMARY KEY NOT NULL,
title TEXT NOT NULL,
body TEXT NOT NULL,
published_at DATETIME
);
PRAGMA user_version = 1;
COMMIT TRANSACTION;
"""
)
```
- `prepare` prepares a single `Statement` object from a SQL string,
optionally binds values to it (using the statement’s `bind` function),
and returns the statement for deferred execution.
```swift
let stmt = try db.prepare("INSERT INTO users (email) VALUES (?)")
```
Once prepared, statements may be executed using `run`, binding any
unbound parameters.
```swift
try stmt.run("alice@mac.com")
db.changes // -> {Some 1}
```
Statements with results may be iterated over, using the columnNames if
useful.
```swift
let stmt = try db.prepare("SELECT id, email FROM users")
for row in stmt {
for (index, name) in stmt.columnNames.enumerated() {
print ("\(name):\(row[index]!)")
// id: Optional(1), email: Optional("alice@mac.com")
}
}
```
- `run` prepares a single `Statement` object from a SQL string, optionally
binds values to it (using the statement’s `bind` function), executes,
and returns the statement.
```swift
try db.run("INSERT INTO users (email) VALUES (?)", "alice@mac.com")
```
- `scalar` prepares a single `Statement` object from a SQL string,
optionally binds values to it (using the statement’s `bind` function),
executes, and returns the first value of the first row.
```swift
let count = try db.scalar("SELECT count(*) FROM users") as! Int64
```
Statements also have a `scalar` function, which can optionally re-bind
values at execution.
```swift
let stmt = try db.prepare("SELECT count (*) FROM users")
let count = try stmt.scalar() as! Int64
```
## Online Database Backup
To copy a database to another using the
[SQLite Online Backup API](https://sqlite.org/backup.html):
```swift
// creates an in-memory copy of db.sqlite
let db = try Connection("db.sqlite")
let target = try Connection(.inMemory)
let backup = try db.backup(usingConnection: target)
try backup.step()
```
## Attaching and detaching databases
We can [ATTACH](https://www3.sqlite.org/lang_attach.html) and [DETACH](https://www3.sqlite.org/lang_detach.html)
databases to an existing connection:
```swift
let db = try Connection("db.sqlite")
try db.attach(.uri("external.sqlite", parameters: [.mode(.readOnly)]), as: "external")
// ATTACH DATABASE 'file:external.sqlite?mode=ro' AS 'external'
let table = Table("table", database: "external")
let count = try db.scalar(table.count)
// SELECT count(*) FROM 'external.table'
try db.detach("external")
// DETACH DATABASE 'external'
```
When compiled for SQLCipher, we can additionally pass a `key` parameter to `attach`:
```swift
try db.attach(.uri("encrypted.sqlite"), as: "encrypted", key: "secret")
// ATTACH DATABASE 'encrypted.sqlite' AS 'encrypted' KEY 'secret'
```
## Logging
We can log SQL using the database’s `trace` function.
```swift
#if DEBUG
db.trace { print($0) }
#endif
```
## Vacuum
To run the [vacuum](https://www.sqlite.org/lang_vacuum.html) command:
```swift
try db.vacuum()
```
[ROWID]: https://sqlite.org/lang_createtable.html#rowid
[SQLiteMigrationManager.swift]: https://github.com/garriguv/SQLiteMigrationManager.swift
================================================
FILE: Documentation/Linux.md
================================================
# Linux
## Limitations
* Custom functions/aggregations are currently not supported and crash, caused by a bug in Swift.
See [#1071](https://github.com/stephencelis/SQLite.swift/issues/1071).
## Installation
On Linux you should enable the `SQLiteSwiftCSQLite` trait to automatically
embed SQLite:
```swift
dependencies: [
.package(url: "https://github.com/stephencelis/SQLite.swift.git",
from: "0.16.0",
traits: ["SQLiteSwiftCSQLite"])
]
```
See the [main documentation](Index.md#available-traits) for a list of all available traits.
## Debugging
### Create and launch docker container
```shell
$ docker container create swift:focal
$ docker run --cap-add=SYS_PTRACE \
--security-opt seccomp=unconfined \
--security-opt apparmor=unconfined \
-i -t swift:focal bash
```
### Compile and run tests in debugger
```shell
$ apt-get update && apt-get install libsqlite3-dev
$ git clone https://github.com/stephencelis/SQLite.swift.git
$ swift test
$ lldb .build/x86_64-unknown-linux-gnu/debug/SQLite.swiftPackageTests.xctest
(lldb) target create ".build/x86_64-unknown-linux-gnu/debug/SQLite.swiftPackageTests.xctest"
(lldb) run
```
================================================
FILE: Documentation/Planning.md
================================================
# SQLite.swift Planning
This document captures both near term steps (aka Roadmap) and feature
requests. The goal is to add some visibility and guidance for future
additions and Pull Requests, as well as to keep the Issues list clear of
enhancement requests so that bugs are more visible.
> ⚠ This document is currently not actively maintained. See
> the [0.14.1 milestone](https://github.com/stephencelis/SQLite.swift/issues?q=is%3Aopen+is%3Aissue+milestone%3A0.14.1)
> on Github for additional information about planned features for the next release.
## Roadmap
_Lists agreed upon next steps in approximate priority order._
## Feature Requests
_A gathering point for ideas for new features. In general, the corresponding
issue will be closed once it is added here, with the assumption that it will
be referred to when it comes time to add the corresponding feature._
### Features
* provide separate threads for update vs read, so updates don't block reads,
per [#236](https://github.com/stephencelis/SQLite.swift/issues/236)
* expose triggers, per
[#164](https://github.com/stephencelis/SQLite.swift/issues/164)
## Suspended Feature Requests
_Features that are not actively being considered, perhaps because of no clean
type-safe way to implement them with the current Swift, or bugs, or just
general uncertainty._
================================================
FILE: Documentation/Release.md
================================================
# SQLite.swift Release checklist
* [ ] Make sure current master branch has a green build
* [ ] Make sure `SQLite.playground` runs without errors
* [ ] Make sure `CHANGELOG.md` is up-to-date
* [ ] Add content to `Documentation/Upgrading.md` if needed
* [ ] Update the version number in `SQLite.swift.podspec`
* [ ] Run `pod lib lint` locally
* [ ] Update the version numbers mentioned in `README.md`, `Documentation/Index.md`
* [ ] Update `MARKETING_VERSION` in `SQLite.xcodeproj/project.pbxproj`
* [ ] Create a tag with the version number (`x.y.z`)
* [ ] Publish to CocoaPods: `pod trunk push`
* [ ] Update the release information on GitHub
================================================
FILE: Documentation/Upgrading.md
================================================
# Upgrading
## 0.13 → 0.14
- `Expression.asSQL()` is no longer available. Expressions now implement `CustomStringConvertible`,
where `description` returns the SQL.
- `Statement.prepareRowIterator()` is no longer available. Instead, use the methods
of the same name on `Connection`.
- `Connection.registerTokenizer` is no longer available to register custom FTS4 tokenizers.
- `Setter.asSQL()` is no longer available. Instead, Setter now implement `CustomStringConvertible`,
where `description` returns the SQL.
================================================
FILE: Gemfile
================================================
source "https://rubygems.org"
# https://github.com/CocoaPods/CocoaPods/pull/12816
gem 'cocoapods', :git => 'https://github.com/jberkel/CocoaPods.git', branch: 'watchos-fourflusher'
================================================
FILE: LICENSE.txt
================================================
(The MIT License)
Copyright (c) 2014-2015 Stephen Celis ()
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Makefile
================================================
XCODEBUILD = xcodebuild
BUILD_SCHEME = SQLite Mac
IOS_SIMULATOR = iPhone 14
IOS_VERSION = 16.4
# tool settings
SWIFTLINT_VERSION=0.63.1
SWIFTLINT=bin/swiftlint-$(SWIFTLINT_VERSION)
SWIFTLINT_URL=https://github.com/realm/SwiftLint/releases/download/$(SWIFTLINT_VERSION)/portable_swiftlint.zip
XCBEAUTIFY_VERSION=3.1.2
XCBEAUTIFY=bin/xcbeautify-$(XCBEAUTIFY_VERSION)
ifeq ($(shell uname), Linux)
XCBEAUTIFY_PLATFORM=x86_64-unknown-linux-gnu.tar.xz
else
XCBEAUTIFY_PLATFORM=universal-apple-macosx.zip
endif
XCBEAUTIFY_URL=https://github.com/cpisciotta/xcbeautify/releases/download/$(XCBEAUTIFY_VERSION)/xcbeautify-$(XCBEAUTIFY_VERSION)-$(XCBEAUTIFY_PLATFORM)
CURL_OPTS=--fail --silent -L --retry 3
ifeq ($(BUILD_SCHEME),SQLite iOS)
BUILD_ARGUMENTS = -scheme "$(BUILD_SCHEME)" -destination "platform=iOS Simulator,name=$(IOS_SIMULATOR),OS=$(IOS_VERSION)"
else
BUILD_ARGUMENTS = -scheme "$(BUILD_SCHEME)"
endif
test: $(XCBEAUTIFY)
set -o pipefail; \
$(XCODEBUILD) $(BUILD_ARGUMENTS) test | $(XCBEAUTIFY)
build: $(XCBEAUTIFY)
set -o pipefail; \
$(XCODEBUILD) $(BUILD_ARGUMENTS) | $(XCBEAUTIFY)
lint: $(SWIFTLINT)
$< --strict
lint-fix: $(SWIFTLINT)
$< --fix
clean:
$(XCODEBUILD) $(BUILD_ARGUMENTS) clean
repl:
@$(XCODEBUILD) $(BUILD_ARGUMENTS) -derivedDataPath $(TMPDIR)/SQLite.swift > /dev/null && \
swift repl -F '$(TMPDIR)/SQLite.swift/Build/Products/Debug'
sloc:
@zsh -c "grep -vE '^ *//|^$$' Sources/**/*.{swift,h} | wc -l"
$(SWIFTLINT):
set -e ; \
curl $(CURL_OPTS) $(SWIFTLINT_URL) -o swiftlint.zip; \
unzip -o swiftlint.zip swiftlint; \
mkdir -p bin; \
mv swiftlint $@ && rm -f swiftlint.zip
$(XCBEAUTIFY):
set -e; \
FILE=$(XCBEAUTIFY_PLATFORM); \
curl $(CURL_OPTS) $(XCBEAUTIFY_URL) -o $$FILE; \
case "$${FILE#*.}" in \
"zip") \
unzip -o $$FILE release/xcbeautify; \
;; \
"tar.xz") \
tar -xvf $$FILE release/xcbeautify; \
;; \
*) \
echo "unknown extension $${FILE#*.}!"; \
exit 1; \
;; \
esac; \
mkdir -p bin; \
mv release/xcbeautify $@ && rm -f $$FILE;
.PHONY: test clean repl sloc
================================================
FILE: Package.swift
================================================
// swift-tools-version: 6.1
import PackageDescription
let applePlatforms: [PackageDescription.Platform] = [.iOS, .macOS, .watchOS, .tvOS, .visionOS]
let target: Target = .target(
name: "SQLite",
dependencies: [
.product(name: "SQLiteSwiftCSQLite",
package: "CSQLite",
condition: .when(traits: ["SQLiteSwiftCSQLite"])),
.product(name: "SQLCipher",
package: "SQLCipher.swift",
condition: .when(platforms: applePlatforms, traits: ["SQLCipher"]))
],
exclude: ["Info.plist"],
resources: [.copy("PrivacyInfo.xcprivacy")],
cSettings: [
.define("SQLITE_HAS_CODEC", .when(platforms: applePlatforms, traits: ["SQLCipher"]))
]
)
let testTarget: Target = .testTarget(
name: "SQLiteTests",
dependencies: ["SQLite"],
exclude: ["Info.plist"],
resources: [.copy("Resources")]
)
let defaultTraits: Set
#if os(Linux)
defaultTraits = ["SQLiteSwiftCSQLite"]
#else
defaultTraits = ["SystemSQLite"]
#endif
let package = Package(
name: "SQLite.swift",
platforms: [
.iOS(.v12),
.macOS(.v10_13),
.watchOS(.v4),
.tvOS(.v12),
.visionOS(.v1)
],
products: [
.library(name: "SQLite", targets: ["SQLite"]),
.library(name: "SQLite-Dynamic", type: .dynamic, targets: ["SQLite"])
],
traits: [
.trait(name: "SystemSQLite",
description: "Uses the system-provided SQLite (on Apple platforms)"),
.trait(name: "SQLiteSwiftCSQLite",
description: "Include SQLite from SQLite.swift, based on the toolchain version"),
// this will note compile, just included for sake of completeness
.trait(name: "StandaloneSQLite",
description: "Assumes SQLite to be already available as 'sqlite3'"),
.trait(name: "SQLCipher",
description: "Enables SQLCipher encryption when a key is supplied to Connection"),
.trait(name: "FTS5",
description: "Enables FTS5 in the embedded SQLite (only supported by SQLiteSwiftCSQLite)"),
.default(enabledTraits: defaultTraits)
],
dependencies: [
.package(url: "https://github.com/stephencelis/CSQLite", from: "3.50.4", traits: [.trait(name: "FTS5", condition: .when(traits: ["FTS5"]))]),
.package(url: "https://github.com/sqlcipher/SQLCipher.swift", from: "4.11.0")
],
targets: [target, testTarget],
swiftLanguageModes: [.v5],
)
================================================
FILE: README.md
================================================
# SQLite.swift
![Build Status][GitHubActionBadge] [![CocoaPods Version][CocoaPodsVersionBadge]][CocoaPodsVersionLink] [![Swift5 compatible][Swift5Badge]][Swift5Link] [![Platform][PlatformBadge]][PlatformLink] [![Carthage compatible][CartagheBadge]][CarthageLink] [![Join the chat at https://gitter.im/stephencelis/SQLite.swift][GitterBadge]][GitterLink]
A type-safe, [Swift][]-language layer over [SQLite3][].
[SQLite.swift][] provides compile-time confidence in SQL statement
syntax _and_ intent.
## Features
- A pure-Swift interface
- A type-safe, optional-aware SQL expression builder
- A flexible, chainable, lazy-executing query layer
- Automatically-typed data access
- A lightweight, uncomplicated query and parameter binding interface
- Developer-friendly error handling and debugging
- [Full-text search][] support
- [Well-documented][See Documentation]
- Extensively tested
- [SQLCipher][] support via Swift Package Manager
- [Schema query/migration][]
- Works on [Linux](Documentation/Linux.md) (with some limitations)
- Active support at
[StackOverflow](https://stackoverflow.com/questions/tagged/sqlite.swift),
and [Gitter Chat Room](https://gitter.im/stephencelis/SQLite.swift)
(_experimental_)
[SQLCipher]: https://www.zetetic.net/sqlcipher/
[Full-text search]: Documentation/Index.md#full-text-search
[Schema query/migration]: Documentation/Index.md#querying-the-schema
[See Documentation]: Documentation/Index.md#sqliteswift-documentation
## Usage
```swift
import SQLite
// Wrap everything in a do...catch to handle errors
do {
let db = try Connection("path/to/db.sqlite3")
let users = Table("users")
let id = SQLite.Expression("id")
let name = SQLite.Expression("name")
let email = SQLite.Expression("email")
try db.run(users.create { t in
t.column(id, primaryKey: true)
t.column(name)
t.column(email, unique: true)
})
// CREATE TABLE "users" (
// "id" INTEGER PRIMARY KEY NOT NULL,
// "name" TEXT,
// "email" TEXT NOT NULL UNIQUE
// )
let insert = users.insert(name <- "Alice", email <- "alice@mac.com")
let rowid = try db.run(insert)
// INSERT INTO "users" ("name", "email") VALUES ('Alice', 'alice@mac.com')
for user in try db.prepare(users) {
print("id: \(user[id]), name: \(user[name]), email: \(user[email])")
// id: 1, name: Optional("Alice"), email: alice@mac.com
}
// SELECT * FROM "users"
let alice = users.filter(id == rowid)
try db.run(alice.update(email <- email.replace("mac.com", with: "me.com")))
// UPDATE "users" SET "email" = replace("email", 'mac.com', 'me.com')
// WHERE ("id" = 1)
try db.run(alice.delete())
// DELETE FROM "users" WHERE ("id" = 1)
try db.scalar(users.count) // 0
// SELECT count(*) FROM "users"
} catch {
print (error)
}
```
Note that `Expression` should be written as `SQLite.Expression` to avoid
conflicts with the `SwiftUI.Expression` if you are using SwiftUI too.
SQLite.swift also works as a lightweight, Swift-friendly wrapper over the C
API.
```swift
// Wrap everything in a do...catch to handle errors
do {
// ...
let stmt = try db.prepare("INSERT INTO users (email) VALUES (?)")
for email in ["betty@icloud.com", "cathy@icloud.com"] {
try stmt.run(email)
}
db.totalChanges // 3
db.changes // 1
db.lastInsertRowid // 3
for row in try db.prepare("SELECT id, email FROM users") {
print("id: \(row[0]), email: \(row[1])")
// id: Optional(2), email: Optional("betty@icloud.com")
// id: Optional(3), email: Optional("cathy@icloud.com")
}
try db.scalar("SELECT count(*) FROM users") // 2
} catch {
print (error)
}
```
[Read the documentation][See Documentation] or explore more,
interactively, from the Xcode project’s playground.

## Installation
### Swift Package Manager
The [Swift Package Manager][] is a tool for managing the distribution of
Swift code.
1. Add the following to your `Package.swift` file:
```swift
dependencies: [
.package(url: "https://github.com/stephencelis/SQLite.swift.git", from: "0.16.0")
]
```
2. Build your project:
```sh
$ swift build
```
See the [Tests/SPM](https://github.com/stephencelis/SQLite.swift/tree/master/Tests/SPM) folder for a small demo project which uses SPM.
[Swift Package Manager]: https://swift.org/package-manager
### Carthage
[Carthage][] is a simple, decentralized dependency manager for Cocoa. To
install SQLite.swift with Carthage:
1. Make sure Carthage is [installed][Carthage Installation].
2. Update your Cartfile to include the following:
```ruby
github "stephencelis/SQLite.swift" ~> 0.16.0
```
3. Run `carthage update` and
[add the appropriate framework][Carthage Usage].
[Carthage]: https://github.com/Carthage/Carthage
[Carthage Installation]: https://github.com/Carthage/Carthage#installing-carthage
[Carthage Usage]: https://github.com/Carthage/Carthage#adding-frameworks-to-an-application
### CocoaPods
[CocoaPods][] is a dependency manager for Cocoa projects. To install
SQLite.swift with CocoaPods:
1. Make sure CocoaPods is [installed][CocoaPods Installation].
```sh
# Using the default Ruby install will require you to use sudo when
# installing and updating gems.
[sudo] gem install cocoapods
```
2. Update your Podfile to include the following:
```ruby
use_frameworks!
target 'YourAppTargetName' do
pod 'SQLite.swift', '~> 0.15.0'
end
```
3. Run `pod install --repo-update`.
[CocoaPods]: https://cocoapods.org
[CocoaPods Installation]: https://guides.cocoapods.org/using/getting-started.html#getting-started
### Manual
To install SQLite.swift as an Xcode sub-project:
1. Drag the **SQLite.xcodeproj** file into your own project.
([Submodule][], clone, or [download][] the project first.)

2. In your target’s **General** tab, click the **+** button under **Linked
Frameworks and Libraries**.
3. Select the appropriate **SQLite.framework** for your platform.
4. **Add**.
Some additional steps are required to install the application on an actual
device:
5. In the **General** tab, click the **+** button under **Embedded
Binaries**.
6. Select the appropriate **SQLite.framework** for your platform.
7. **Add**.
[Xcode]: https://developer.apple.com/xcode/downloads/
[Submodule]: https://git-scm.com/book/en/Git-Tools-Submodules
[download]: https://github.com/stephencelis/SQLite.swift/archive/master.zip
## Communication
[Read the contributing guidelines][]. The _TL;DR_ (but please; _R_):
- Need **help** or have a **general question**? [Ask on Stack
Overflow][] (tag `sqlite.swift`).
- Found a **bug** or have a **feature request**? [Open an issue][].
- Want to **contribute**? [Submit a pull request][].
[Read the contributing guidelines]: ./CONTRIBUTING.md#contributing
[Ask on Stack Overflow]: https://stackoverflow.com/questions/tagged/sqlite.swift
[Open an issue]: https://github.com/stephencelis/SQLite.swift/issues/new
[Submit a pull request]: https://github.com/stephencelis/SQLite.swift/fork
## Original author
- [Stephen Celis](mailto:stephen@stephencelis.com)
([@stephencelis](https://twitter.com/stephencelis))
## License
SQLite.swift is available under the MIT license. See [the LICENSE
file](./LICENSE.txt) for more information.
## Related
These projects enhance or use SQLite.swift:
- [SQLiteMigrationManager.swift][] (inspired by
[FMDBMigrationManager][])
## Alternatives
Looking for something else? Try another Swift wrapper (or [FMDB][]):
- [GRDB](https://github.com/groue/GRDB.swift)
- [SQLiteDB](https://github.com/FahimF/SQLiteDB)
[Swift]: https://swift.org/
[SQLite3]: https://www.sqlite.org
[SQLite.swift]: https://github.com/stephencelis/SQLite.swift
[GitHubActionBadge]: https://img.shields.io/github/actions/workflow/status/stephencelis/SQLite.swift/build.yml?branch=master
[CocoaPodsVersionBadge]: https://img.shields.io/cocoapods/v/SQLite.swift.svg?style=flat
[CocoaPodsVersionLink]: https://cocoapods.org/pods/SQLite.swift
[PlatformBadge]: https://img.shields.io/cocoapods/p/SQLite.swift.svg?style=flat
[PlatformLink]: https://cocoapods.org/pods/SQLite.swift
[CartagheBadge]: https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat
[CarthageLink]: https://github.com/Carthage/Carthage
[GitterBadge]: https://badges.gitter.im/stephencelis/SQLite.swift.svg
[GitterLink]: https://gitter.im/stephencelis/SQLite.swift
[Swift5Badge]: https://img.shields.io/badge/swift-5-orange.svg?style=flat
[Swift5Link]: https://developer.apple.com/swift/
[SQLiteMigrationManager.swift]: https://github.com/garriguv/SQLiteMigrationManager.swift
[FMDB]: https://github.com/ccgus/fmdb
[FMDBMigrationManager]: https://github.com/layerhq/FMDBMigrationManager
================================================
FILE: SQLite.playground/Contents.swift
================================================
import SQLite
/// Create an in-memory database
let db = try Connection(.inMemory)
/// enable statement logging
db.trace { print($0) }
/// define a "users" table with some fields
let users = Table("users")
let id = Expression("id")
let email = Expression("email") // non-null
let name = Expression("name") // nullable
/// prepare the query
let statement = users.create { t in
t.column(id, primaryKey: true)
t.column(email, unique: true, check: email.like("%@%"))
t.column(name)
}
/// …and run it
try db.run(statement)
/// insert "alice"
let rowid = try db.run(users.insert(email <- "alice@mac.com"))
/// insert multiple rows using `insertMany`
let lastRowid = try db.run(users.insertMany([
[email <- "bob@mac.com"],
[email <- "mallory@evil.com"]
]))
let query = try db.prepare(users)
for user in query {
print("id: \(user[id]), email: \(user[email])")
}
// re-requery just rowid of Alice
let alice = try db.prepare(users.filter(id == rowid))
for user in alice {
print("id: \(user[id]), email: \(user[email])")
}
/// using the `RowIterator` API
let rowIterator = try db.prepareRowIterator(users)
for user in try Array(rowIterator) {
print("id: \(user[id]), email: \(user[email])")
}
/// also with `map()`
let mapRowIterator = try db.prepareRowIterator(users)
let userIds = try mapRowIterator.map { $0[id] }
/// using `failableNext()` on `RowIterator`
let iterator = try db.prepareRowIterator(users)
do {
while let row = try rowIterator.failableNext() {
print(row)
}
} catch {
// Handle error
}
/// define a virtual table for the FTS index
let emails = VirtualTable("emails")
let subject = Expression("subject")
let body = Expression("body")
/// create the index
try db.run(emails.create(.FTS5(
FTS5Config()
.column(subject)
.column(body)
)))
/// populate with data
try db.run(emails.insert(
subject <- "Hello, world!",
body <- "This is a hello world message."
))
/// run a query
let ftsQuery = try db.prepare(emails.match("hello"))
for row in ftsQuery {
print(row[subject])
}
/// custom aggregations
let reduce: (String, [Binding?]) -> String = { (last, bindings) in
last + " " + (bindings.first as? String ?? "")
}
db.createAggregation("customConcat",
initialValue: "users:",
reduce: reduce,
result: { $0 })
let result = try db.prepare("SELECT customConcat(email) FROM users").scalar() as! String
print(result)
/// schema queries
let schema = db.schema
let objects = try schema.objectDefinitions()
print(objects)
let columns = try schema.columnDefinitions(table: "users")
print(columns)
/// schema alteration
let schemaChanger = SchemaChanger(connection: db)
try schemaChanger.alter(table: "users") { table in
table.add(column: ColumnDefinition(name: "age", type: .INTEGER))
table.rename(column: "email", to: "electronic_mail")
table.drop(column: "name")
}
let changedColumns = try schema.columnDefinitions(table: "users")
print(changedColumns)
let age = Expression("age")
let electronicMail = Expression("electronic_mail")
let newRowid = try db.run(users.insert(
electronicMail <- "carol@mac.com",
age <- 33
))
================================================
FILE: SQLite.playground/contents.xcplayground
================================================
================================================
FILE: SQLite.playground/playground.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: SQLite.swift.podspec
================================================
Pod::Spec.new do |s|
s.name = "SQLite.swift"
s.version = "0.16.0"
s.summary = "A type-safe, Swift-language layer over SQLite3."
s.description = <<-DESC
SQLite.swift provides compile-time confidence in SQL statement syntax and
intent.
DESC
s.homepage = "https://github.com/stephencelis/SQLite.swift"
s.license = 'MIT'
s.author = { "Stephen Celis" => "stephen@stephencelis.com" }
s.source = { :git => "https://github.com/stephencelis/SQLite.swift.git", :tag => s.version.to_s }
s.social_media_url = 'https://twitter.com/stephencelis'
s.module_name = 'SQLite'
s.default_subspec = 'standard'
s.swift_versions = ['5']
s.ios.deployment_target = '12.0'
s.tvos.deployment_target = '12.0'
s.osx.deployment_target = '10.13'
s.watchos.deployment_target = '4.0'
s.visionos.deployment_target = '1.0'
# uses the built-in sqlite3 library
s.subspec 'standard' do |ss|
ss.library = 'sqlite3'
ss.source_files = 'Sources/SQLite/**/*.{c,h,m,swift}'
ss.exclude_files = 'Sources/**/Cipher.swift'
ss.resource_bundle = { 'SQLite.swift' => 'Sources/SQLite/PrivacyInfo.xcprivacy' }
ss.xcconfig = {
'OTHER_SWIFT_FLAGS' => '$(inherited) -DSystemSQLite'
}
ss.test_spec 'tests' do |test_spec|
test_spec.resources = 'Tests/SQLiteTests/Resources/*'
test_spec.source_files = 'Tests/SQLiteTests/**/*.swift'
end
end
# uses SQLite from https://github.com/clemensg/sqlite3pod
s.subspec 'standalone' do |ss|
ss.dependency 'sqlite3'
ss.source_files = 'Sources/SQLite/**/*.{c,h,m,swift}'
ss.exclude_files = 'Sources/**/Cipher.swift'
ss.resource_bundle = { 'SQLite.swift' => 'Sources/SQLite/PrivacyInfo.xcprivacy' }
ss.xcconfig = {
'OTHER_SWIFT_FLAGS' => '$(inherited) -DStandaloneSQLite'
}
ss.test_spec 'tests' do |test_spec|
test_spec.resources = 'Tests/SQLiteTests/Resources/*'
test_spec.source_files = 'Tests/SQLiteTests/**/*.swift'
end
end
# uses SQLCipher from https://github.com/sqlcipher/sqlcipher
s.subspec 'SQLCipher' do |ss|
ss.dependency 'SQLCipher', '>= 4.0.0'
# Disable unsupported visionOS
# https://github.com/sqlcipher/sqlcipher/issues/483
ss.ios.deployment_target = s.deployment_target(:ios)
ss.tvos.deployment_target = s.deployment_target(:tvos)
ss.osx.deployment_target = s.deployment_target(:osx)
ss.watchos.deployment_target = s.deployment_target(:watchos)
ss.source_files = 'Sources/SQLite/**/*.{c,h,m,swift}'
ss.resource_bundle = { 'SQLite.swift' => 'Sources/SQLite/PrivacyInfo.xcprivacy' }
ss.xcconfig = {
'OTHER_SWIFT_FLAGS' => '$(inherited) -DSQLCipher',
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SQLITE_HAS_CODEC=1'
}
ss.test_spec 'tests' do |test_spec|
test_spec.resources = 'Tests/SQLiteTests/Resources/*'
test_spec.source_files = 'Tests/SQLiteTests/**/*.swift'
end
end
end
================================================
FILE: SQLite.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
02A43A9822738CF100FEC494 /* Backup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02A43A9722738CF100FEC494 /* Backup.swift */; };
02A43A9922738CF100FEC494 /* Backup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02A43A9722738CF100FEC494 /* Backup.swift */; };
02A43A9A22738CF100FEC494 /* Backup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02A43A9722738CF100FEC494 /* Backup.swift */; };
02A43A9B22738CF100FEC494 /* Backup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02A43A9722738CF100FEC494 /* Backup.swift */; };
03A65E641C6BB0F60062603F /* SQLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03A65E5A1C6BB0F50062603F /* SQLite.framework */; };
03A65E721C6BB2D30062603F /* SQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AD61C3F04ED00AE3E12 /* SQLite.h */; settings = {ATTRIBUTES = (Public, ); }; };
03A65E731C6BB2D80062603F /* Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF71C3F06E900AE3E12 /* Foundation.swift */; };
03A65E741C6BB2DA0062603F /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF81C3F06E900AE3E12 /* Helpers.swift */; };
03A65E761C6BB2E60062603F /* Blob.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEE1C3F06E900AE3E12 /* Blob.swift */; };
03A65E771C6BB2E60062603F /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEF1C3F06E900AE3E12 /* Connection.swift */; };
03A65E7A1C6BB2F70062603F /* Statement.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF21C3F06E900AE3E12 /* Statement.swift */; };
03A65E7B1C6BB2F70062603F /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF31C3F06E900AE3E12 /* Value.swift */; };
03A65E7C1C6BB2F70062603F /* FTS4.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF51C3F06E900AE3E12 /* FTS4.swift */; };
03A65E7D1C6BB2F70062603F /* RTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF61C3F06E900AE3E12 /* RTree.swift */; };
03A65E7E1C6BB2FB0062603F /* AggregateFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */; };
03A65E7F1C6BB2FB0062603F /* Collation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFB1C3F06E900AE3E12 /* Collation.swift */; };
03A65E801C6BB2FB0062603F /* CoreFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */; };
03A65E811C6BB2FB0062603F /* CustomFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */; };
03A65E821C6BB2FB0062603F /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFE1C3F06E900AE3E12 /* Expression.swift */; };
03A65E831C6BB2FB0062603F /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFF1C3F06E900AE3E12 /* Operators.swift */; };
03A65E841C6BB2FB0062603F /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B001C3F06E900AE3E12 /* Query.swift */; };
03A65E851C6BB2FB0062603F /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B011C3F06E900AE3E12 /* Schema.swift */; };
03A65E861C6BB2FB0062603F /* Setter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B021C3F06E900AE3E12 /* Setter.swift */; };
03A65E951C6BB3030062603F /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B161C3F127200AE3E12 /* TestHelpers.swift */; };
03A65E971C6BB3210062603F /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 03A65E961C6BB3210062603F /* libsqlite3.tbd */; };
19A17018F250343BD0F9F4B0 /* Connection+Pragmas.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17F285B767BFACD96714B /* Connection+Pragmas.swift */; };
19A17021286A4D8D6C2EF12D /* ConnectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17855BD524FF888265B3C /* ConnectionTests.swift */; };
19A17026DCDCDA405B09A229 /* Connection+AttachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A170C08525D3D27CB5F83C /* Connection+AttachTests.swift */; };
19A17073552293CA063BEA66 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17E723300E5ED3771DCB5 /* Result.swift */; };
19A1708D3D58D7BC1168E55F /* CipherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1787E16C8562C09C076F5 /* CipherTests.swift */; };
19A1709C3E7A406E62293B2A /* Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17B93B48B5560E6E51791 /* Fixtures.swift */; };
19A170ACC97B19730FB7BA4D /* Connection+Aggregation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A175A9CB446640AE6F2200 /* Connection+Aggregation.swift */; };
19A170AEBAA56DC3355A73B3 /* DateAndTimeFunctionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A178AEF32ABC8BF2993FB5 /* DateAndTimeFunctionTests.swift */; };
19A170C56745F9D722A73D77 /* AggregateFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17613F00A3F4D4A257A04 /* AggregateFunctionsTests.swift */; };
19A170D938343E30119EDFB3 /* RowTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A174FE5B47A97937A27276 /* RowTests.swift */; };
19A1714F7CF964D568AB14E0 /* BlobTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A171A2ED4E2640F197F48C /* BlobTests.swift */; };
19A17152E32A9585831E3FE0 /* DateAndTimeFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17BA55DABB480F9020C8A /* DateAndTimeFunctions.swift */; };
19A1716BF8E15F91A6B5CB7A /* CustomFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17F2B5959B212A33C383F /* CustomFunctionsTests.swift */; };
19A1717B10CC941ACB5533D6 /* FTS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1730E4390C775C25677D1 /* FTS5.swift */; };
19A17188B4D96636F9C0C209 /* Connection+SchemaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17CA1DF7D0F7C9A94C51C /* Connection+SchemaTests.swift */; };
19A171F12AB8B07F2FD7201A /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A178A39ACA9667A62663CC /* Cipher.swift */; };
19A171F243A589C5EBC47937 /* OperatorsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17475DCA068453F787613 /* OperatorsTests.swift */; };
19A1725658E480B9B378F28B /* Connection+SchemaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17CA1DF7D0F7C9A94C51C /* Connection+SchemaTests.swift */; };
19A1726002D24C14F876C8FE /* ValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17AE284BB1DF31D1B753E /* ValueTests.swift */; };
19A172F71EFD65342072D8D2 /* SchemaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A171A7714C6524093255C5 /* SchemaTests.swift */; };
19A173088B85A7E18E8582A7 /* FTS5IntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17BE1CC4AD4036BAB8EE0 /* FTS5IntegrationTests.swift */; };
19A173389E53CB24DFA8CEDD /* QueryIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17CAE60446607E99C22A6 /* QueryIntegrationTests.swift */; };
19A173465F23C64DF3DF469B /* ConnectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17855BD524FF888265B3C /* ConnectionTests.swift */; };
19A173668D948AD4DF1F5352 /* DateAndTimeFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17BA55DABB480F9020C8A /* DateAndTimeFunctions.swift */; };
19A1737286A74F3CF7412906 /* DateAndTimeFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17BA55DABB480F9020C8A /* DateAndTimeFunctions.swift */; };
19A173EFEF0B3BD0B3ED406C /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17E723300E5ED3771DCB5 /* Result.swift */; };
19A173F25449876761347072 /* Connection+AttachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A170C08525D3D27CB5F83C /* Connection+AttachTests.swift */; };
19A173F429D7E46289EB2167 /* ResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1745BE8623D8C6808DB3C /* ResultTests.swift */; };
19A17408007B182F884E3A53 /* Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17B93B48B5560E6E51791 /* Fixtures.swift */; };
19A1740EACD47904AA24B8DC /* SchemaDefinitions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17268AE67B746B96AC125 /* SchemaDefinitions.swift */; };
19A17411403D60640467209E /* ExpressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A170F141BF21946D159083 /* ExpressionTests.swift */; };
19A174118D11B93DA5DAAF79 /* DateAndTimeFunctionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A178AEF32ABC8BF2993FB5 /* DateAndTimeFunctionTests.swift */; };
19A17437659BD7FD787D94A6 /* CustomAggregationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A177EF5E2D91BA86DA4480 /* CustomAggregationTests.swift */; };
19A17444861E1443143DEB44 /* FTS4Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1715904F7B6851FCB5EF6 /* FTS4Tests.swift */; };
19A174506543905D71BF0518 /* Connection+Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A170A97B51DC5EE365F3C5 /* Connection+Schema.swift */; };
19A17457B0461F484AF6BE40 /* CustomFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17F2B5959B212A33C383F /* CustomFunctionsTests.swift */; };
19A17482E6FC5E563F3E6A47 /* OperatorsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17475DCA068453F787613 /* OperatorsTests.swift */; };
19A17490543609FCED53CACC /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1710E73A46D5AC721CDA9 /* Errors.swift */; };
19A1750CEE9B05267995CF3D /* FTS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1730E4390C775C25677D1 /* FTS5.swift */; };
19A1750EF4A5F92954A451FF /* Connection+Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A170A97B51DC5EE365F3C5 /* Connection+Schema.swift */; };
19A1755C49154C87304C9146 /* FTS5IntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17BE1CC4AD4036BAB8EE0 /* FTS5IntegrationTests.swift */; };
19A1760CE25615CA015E2E5F /* Connection+Pragmas.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17F285B767BFACD96714B /* Connection+Pragmas.swift */; };
19A176376CB6A94759F7980A /* Connection+Aggregation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A175A9CB446640AE6F2200 /* Connection+Aggregation.swift */; };
19A1766135CE9786B1878603 /* ValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17AE284BB1DF31D1B753E /* ValueTests.swift */; };
19A1766AC10D13C4EFF349AD /* SchemaChangerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17FDB0B0CFB8987906FD0 /* SchemaChangerTests.swift */; };
19A176B3316281F004F92276 /* RowTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A174FE5B47A97937A27276 /* RowTests.swift */; };
19A177290558991BCC60E4E3 /* SchemaChanger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A171B262DDE8718513CFDA /* SchemaChanger.swift */; };
19A1772EBE65173EDFB1AFCA /* CustomAggregationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A177EF5E2D91BA86DA4480 /* CustomAggregationTests.swift */; };
19A1773155AC2BF2CA86A473 /* SetterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1709D5BDD2691BA160012 /* SetterTests.swift */; };
19A1773A335CAB9D0AE14E8E /* SchemaChanger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A171B262DDE8718513CFDA /* SchemaChanger.swift */; };
19A17746150A815944A6820B /* SelectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17EC0C43015063945D32E /* SelectTests.swift */; };
19A1776BD5127DFDF847FF1F /* FTS5Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17B96EBD42C878E609CDC /* FTS5Tests.swift */; };
19A177909023B7B940C5805E /* FTS5IntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17BE1CC4AD4036BAB8EE0 /* FTS5IntegrationTests.swift */; };
19A177AA5922527BBDC77CF9 /* QueryIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17CAE60446607E99C22A6 /* QueryIntegrationTests.swift */; };
19A177C25834473FAB32CF3B /* SchemaChangerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17FDB0B0CFB8987906FD0 /* SchemaChangerTests.swift */; };
19A177D5C6542E2D572162E5 /* QueryIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17CAE60446607E99C22A6 /* QueryIntegrationTests.swift */; };
19A178072B371489E6A1E839 /* FoundationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1794CC4D7827E997E32A7 /* FoundationTests.swift */; };
19A1781CBA8968ABD3E00877 /* ExpressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A170F141BF21946D159083 /* ExpressionTests.swift */; };
19A1782444437C7FC6B75CBC /* BlobTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A171A2ED4E2640F197F48C /* BlobTests.swift */; };
19A17835FD5886FDC5A3228F /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A178A39ACA9667A62663CC /* Cipher.swift */; };
19A178767223229E61C5066F /* FTS4Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1715904F7B6851FCB5EF6 /* FTS4Tests.swift */; };
19A17885B646CB0201BE4BD5 /* QueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A171ED017645C8B04DF9F2 /* QueryTests.swift */; };
19A178A8B2A34FB6B565DEDA /* Connection+Pragmas.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17F285B767BFACD96714B /* Connection+Pragmas.swift */; };
19A178C041DDCF80B533AD13 /* BlobTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A171A2ED4E2640F197F48C /* BlobTests.swift */; };
19A178DA2BB5970778CCAF13 /* FTS5Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17B96EBD42C878E609CDC /* FTS5Tests.swift */; };
19A178DF5A96CFEFF1E271F6 /* AggregateFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17613F00A3F4D4A257A04 /* AggregateFunctionsTests.swift */; };
19A178F9008614B8A8425635 /* Connection+PragmaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17C60D3464461057E4D63 /* Connection+PragmaTests.swift */; };
19A17900387FDCF578B31E3E /* OperatorsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17475DCA068453F787613 /* OperatorsTests.swift */; };
19A17912DB9D3AC8FECF948B /* ResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1745BE8623D8C6808DB3C /* ResultTests.swift */; };
19A17923494236793893BF72 /* StatementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1756EB81E9F7F45B12A78 /* StatementTests.swift */; };
19A1792C0520D4E83C2EB075 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1710E73A46D5AC721CDA9 /* Errors.swift */; };
19A1793972BDDDB027C113BB /* CustomAggregationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A177EF5E2D91BA86DA4480 /* CustomAggregationTests.swift */; };
19A179786A6826D58A70F8BC /* AggregateFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17613F00A3F4D4A257A04 /* AggregateFunctionsTests.swift */; };
19A17986405D9A875698408F /* Connection+Pragmas.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17F285B767BFACD96714B /* Connection+Pragmas.swift */; };
19A1799AF6643CF5081BFA15 /* DateAndTimeFunctionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A178AEF32ABC8BF2993FB5 /* DateAndTimeFunctionTests.swift */; };
19A179B59450FE7C4811AB8A /* Connection+Aggregation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A175A9CB446640AE6F2200 /* Connection+Aggregation.swift */; };
19A179BB9A6665B2B99DA546 /* CoreFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17B55F2409B7031443495 /* CoreFunctionsTests.swift */; };
19A179BCD483DEA21661FD37 /* Connection+AttachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A170C08525D3D27CB5F83C /* Connection+AttachTests.swift */; };
19A179CCF9671E345E5A9811 /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A178A39ACA9667A62663CC /* Cipher.swift */; };
19A179E76EA6207669B60C1B /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A178A39ACA9667A62663CC /* Cipher.swift */; };
19A17A33EA026C2E2CEBAF36 /* Connection+Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A170A97B51DC5EE365F3C5 /* Connection+Schema.swift */; };
19A17A391BF056E3D729E70A /* SchemaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A171A7714C6524093255C5 /* SchemaTests.swift */; };
19A17A52BF29D27C9AA229E7 /* QueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A171ED017645C8B04DF9F2 /* QueryTests.swift */; };
19A17A7B3E3B7E76364A2AEE /* CipherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1787E16C8562C09C076F5 /* CipherTests.swift */; };
19A17A7DF99B0379FD3396B1 /* CustomFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17F2B5959B212A33C383F /* CustomFunctionsTests.swift */; };
19A17A9520802ACF45907970 /* RTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17162C9861E5C4900455D /* RTreeTests.swift */; };
19A17ABCF0EB4808BDC5B5FF /* RowTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A174FE5B47A97937A27276 /* RowTests.swift */; };
19A17B0DF1DDB6BBC9C95D64 /* SchemaDefinitions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17268AE67B746B96AC125 /* SchemaDefinitions.swift */; };
19A17B1D9B5CEBE9CE09280C /* RTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17162C9861E5C4900455D /* RTreeTests.swift */; };
19A17B36ABC6006AB80F693C /* Connection+SchemaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17CA1DF7D0F7C9A94C51C /* Connection+SchemaTests.swift */; };
19A17B62A4125AF4F6014CF5 /* SchemaDefinitionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A176174862D0F0139B3987 /* SchemaDefinitionsTests.swift */; };
19A17BA13FD35F058787B7D3 /* SchemaDefinitions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17268AE67B746B96AC125 /* SchemaDefinitions.swift */; };
19A17BACF4C032513DE1F879 /* Connection+PragmaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17C60D3464461057E4D63 /* Connection+PragmaTests.swift */; };
19A17C74233AFC2EDAFA23DC /* ResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1745BE8623D8C6808DB3C /* ResultTests.swift */; };
19A17CA4D7B63D845428A9C5 /* StatementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1756EB81E9F7F45B12A78 /* StatementTests.swift */; };
19A17CA6ADB78A2E545BF836 /* CipherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1787E16C8562C09C076F5 /* CipherTests.swift */; };
19A17CF65C0196E03BC64519 /* ConnectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17855BD524FF888265B3C /* ConnectionTests.swift */; };
19A17D1BEABA610ABF003D67 /* SchemaDefinitions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17268AE67B746B96AC125 /* SchemaDefinitions.swift */; };
19A17D6EC40BC35A5DC81BA8 /* StatementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1756EB81E9F7F45B12A78 /* StatementTests.swift */; };
19A17D993398B8215B73E1EA /* CoreFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17B55F2409B7031443495 /* CoreFunctionsTests.swift */; };
19A17DAD5975D9367EAA46E2 /* RTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17162C9861E5C4900455D /* RTreeTests.swift */; };
19A17DC282E36C4F41AA440B /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1710E73A46D5AC721CDA9 /* Errors.swift */; };
19A17DD33C2E43DD6EE05A60 /* ExpressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A170F141BF21946D159083 /* ExpressionTests.swift */; };
19A17DE1FCDB5695702AD24D /* SelectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17EC0C43015063945D32E /* SelectTests.swift */; };
19A17DE34C477232592A8F6B /* CoreFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17B55F2409B7031443495 /* CoreFunctionsTests.swift */; };
19A17DF8D4F13A20F5D2269E /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17E723300E5ED3771DCB5 /* Result.swift */; };
19A17DFE05ED8B1F7C45F7EE /* SchemaChanger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A171B262DDE8718513CFDA /* SchemaChanger.swift */; };
19A17E04C4C0956715C5676A /* FoundationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1794CC4D7827E997E32A7 /* FoundationTests.swift */; };
19A17E0ABA6C415F014CD51C /* SetterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1709D5BDD2691BA160012 /* SetterTests.swift */; };
19A17E1DD976D5CE80018749 /* FTS4Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1715904F7B6851FCB5EF6 /* FTS4Tests.swift */; };
19A17E29278A12BC4F542506 /* DateAndTimeFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17BA55DABB480F9020C8A /* DateAndTimeFunctions.swift */; };
19A17E3F47DA087E2B76D087 /* QueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A171ED017645C8B04DF9F2 /* QueryTests.swift */; };
19A17E80F736EEE8EE2AA4CE /* SchemaDefinitionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A176174862D0F0139B3987 /* SchemaDefinitionsTests.swift */; };
19A17EC0D68BA8C03288ADF7 /* FTS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1730E4390C775C25677D1 /* FTS5.swift */; };
19A17F0BF02896E1664F4090 /* Connection+Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A170A97B51DC5EE365F3C5 /* Connection+Schema.swift */; };
19A17F1B3F0A3C96B5ED6D64 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17E723300E5ED3771DCB5 /* Result.swift */; };
19A17F2096E83A3181E03317 /* SchemaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A171A7714C6524093255C5 /* SchemaTests.swift */; };
19A17F60B685636D1F83C2DD /* Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17B93B48B5560E6E51791 /* Fixtures.swift */; };
19A17F7977364EC8CD33C3C3 /* SelectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17EC0C43015063945D32E /* SelectTests.swift */; };
19A17F907258E524B3CA2FAE /* SetterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1709D5BDD2691BA160012 /* SetterTests.swift */; };
19A17FACE8E4D54A50BA934E /* FTS5Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17B96EBD42C878E609CDC /* FTS5Tests.swift */; };
19A17FB80B94E882050AA908 /* FoundationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1794CC4D7827E997E32A7 /* FoundationTests.swift */; };
19A17FBAA26953EB854E790D /* Connection+PragmaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17C60D3464461057E4D63 /* Connection+PragmaTests.swift */; };
19A17FC04708C6ED637DDFD4 /* SchemaChangerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17FDB0B0CFB8987906FD0 /* SchemaChangerTests.swift */; };
19A17FC07731779C1B8506FA /* SchemaChanger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A171B262DDE8718513CFDA /* SchemaChanger.swift */; };
19A17FD22EF43DF428DD93BA /* ValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17AE284BB1DF31D1B753E /* ValueTests.swift */; };
19A17FE78A39E86F330420EC /* SchemaDefinitionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A176174862D0F0139B3987 /* SchemaDefinitionsTests.swift */; };
19A17FF4A10B44D3937C8CAC /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1710E73A46D5AC721CDA9 /* Errors.swift */; };
3D67B3E61DB2469200A4F4C6 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D67B3E51DB2469200A4F4C6 /* libsqlite3.tbd */; };
3D67B3E71DB246BA00A4F4C6 /* Blob.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEE1C3F06E900AE3E12 /* Blob.swift */; };
3D67B3E81DB246BA00A4F4C6 /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEF1C3F06E900AE3E12 /* Connection.swift */; };
3D67B3E91DB246D100A4F4C6 /* Statement.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF21C3F06E900AE3E12 /* Statement.swift */; };
3D67B3EA1DB246D100A4F4C6 /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF31C3F06E900AE3E12 /* Value.swift */; };
3D67B3EB1DB246D100A4F4C6 /* FTS4.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF51C3F06E900AE3E12 /* FTS4.swift */; };
3D67B3EC1DB246D100A4F4C6 /* RTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF61C3F06E900AE3E12 /* RTree.swift */; };
3D67B3ED1DB246D100A4F4C6 /* FTS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1730E4390C775C25677D1 /* FTS5.swift */; };
3D67B3EE1DB246D100A4F4C6 /* AggregateFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */; };
3D67B3EF1DB246D100A4F4C6 /* Collation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFB1C3F06E900AE3E12 /* Collation.swift */; };
3D67B3F01DB246D100A4F4C6 /* CoreFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */; };
3D67B3F11DB246D100A4F4C6 /* CustomFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */; };
3D67B3F21DB246D100A4F4C6 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFE1C3F06E900AE3E12 /* Expression.swift */; };
3D67B3F31DB246D100A4F4C6 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFF1C3F06E900AE3E12 /* Operators.swift */; };
3D67B3F41DB246D100A4F4C6 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B001C3F06E900AE3E12 /* Query.swift */; };
3D67B3F51DB246D100A4F4C6 /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B011C3F06E900AE3E12 /* Schema.swift */; };
3D67B3F61DB246D100A4F4C6 /* Setter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B021C3F06E900AE3E12 /* Setter.swift */; };
3D67B3F71DB246D700A4F4C6 /* Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF71C3F06E900AE3E12 /* Foundation.swift */; };
3D67B3F81DB246D700A4F4C6 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF81C3F06E900AE3E12 /* Helpers.swift */; };
3D67B3FC1DB2471B00A4F4C6 /* SQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AD61C3F04ED00AE3E12 /* SQLite.h */; settings = {ATTRIBUTES = (Public, ); }; };
3DF7B78828842972005DD8CA /* Connection+Attach.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF7B78728842972005DD8CA /* Connection+Attach.swift */; };
3DF7B78928842972005DD8CA /* Connection+Attach.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF7B78728842972005DD8CA /* Connection+Attach.swift */; };
3DF7B78A28842972005DD8CA /* Connection+Attach.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF7B78728842972005DD8CA /* Connection+Attach.swift */; };
3DF7B78B28842972005DD8CA /* Connection+Attach.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF7B78728842972005DD8CA /* Connection+Attach.swift */; };
3DF7B791288449BA005DD8CA /* URIQueryParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF7B790288449BA005DD8CA /* URIQueryParameter.swift */; };
3DF7B792288449BA005DD8CA /* URIQueryParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF7B790288449BA005DD8CA /* URIQueryParameter.swift */; };
3DF7B793288449BA005DD8CA /* URIQueryParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF7B790288449BA005DD8CA /* URIQueryParameter.swift */; };
3DF7B794288449BA005DD8CA /* URIQueryParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF7B790288449BA005DD8CA /* URIQueryParameter.swift */; };
3DF7B79628846FCC005DD8CA /* Resources in Resources */ = {isa = PBXBuildFile; fileRef = 3DF7B79528846FCC005DD8CA /* Resources */; };
3DF7B79828846FED005DD8CA /* Resources in Resources */ = {isa = PBXBuildFile; fileRef = 3DF7B79528846FCC005DD8CA /* Resources */; };
3DF7B79928847055005DD8CA /* Resources in Resources */ = {isa = PBXBuildFile; fileRef = 3DF7B79528846FCC005DD8CA /* Resources */; };
49EB68C41F7B3CB400D89D40 /* Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49EB68C31F7B3CB400D89D40 /* Coding.swift */; };
49EB68C51F7B3CB400D89D40 /* Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49EB68C31F7B3CB400D89D40 /* Coding.swift */; };
49EB68C61F7B3CB400D89D40 /* Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49EB68C31F7B3CB400D89D40 /* Coding.swift */; };
49EB68C71F7B3CB400D89D40 /* Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49EB68C31F7B3CB400D89D40 /* Coding.swift */; };
64A8EE432B095FBB00F583F7 /* WindowFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A8EE422B095FBB00F583F7 /* WindowFunctions.swift */; };
64A8EE442B095FBB00F583F7 /* WindowFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A8EE422B095FBB00F583F7 /* WindowFunctions.swift */; };
64A8EE452B095FBB00F583F7 /* WindowFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A8EE422B095FBB00F583F7 /* WindowFunctions.swift */; };
64A8EE462B095FBB00F583F7 /* WindowFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A8EE422B095FBB00F583F7 /* WindowFunctions.swift */; };
64B8E1702B09748000545AFB /* WindowFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64B8E16F2B09748000545AFB /* WindowFunctionsTests.swift */; };
64B8E1712B09748000545AFB /* WindowFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64B8E16F2B09748000545AFB /* WindowFunctionsTests.swift */; };
64B8E1722B09748000545AFB /* WindowFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64B8E16F2B09748000545AFB /* WindowFunctionsTests.swift */; };
997DF2AE287FC06D00F8DF95 /* Query+with.swift in Sources */ = {isa = PBXBuildFile; fileRef = 997DF2AD287FC06D00F8DF95 /* Query+with.swift */; };
997DF2AF287FC06D00F8DF95 /* Query+with.swift in Sources */ = {isa = PBXBuildFile; fileRef = 997DF2AD287FC06D00F8DF95 /* Query+with.swift */; };
997DF2B0287FC06D00F8DF95 /* Query+with.swift in Sources */ = {isa = PBXBuildFile; fileRef = 997DF2AD287FC06D00F8DF95 /* Query+with.swift */; };
997DF2B1287FC06D00F8DF95 /* Query+with.swift in Sources */ = {isa = PBXBuildFile; fileRef = 997DF2AD287FC06D00F8DF95 /* Query+with.swift */; };
DB58B21128FB864300F8EEA4 /* SchemaReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB58B21028FB864300F8EEA4 /* SchemaReader.swift */; };
DB58B21228FB864300F8EEA4 /* SchemaReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB58B21028FB864300F8EEA4 /* SchemaReader.swift */; };
DB58B21328FB864300F8EEA4 /* SchemaReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB58B21028FB864300F8EEA4 /* SchemaReader.swift */; };
DB58B21428FB864300F8EEA4 /* SchemaReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB58B21028FB864300F8EEA4 /* SchemaReader.swift */; };
DB58B21628FC7C4600F8EEA4 /* SQLiteFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB58B21528FC7C4600F8EEA4 /* SQLiteFeature.swift */; };
DB58B21728FC7C4600F8EEA4 /* SQLiteFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB58B21528FC7C4600F8EEA4 /* SQLiteFeature.swift */; };
DB58B21828FC7C4600F8EEA4 /* SQLiteFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB58B21528FC7C4600F8EEA4 /* SQLiteFeature.swift */; };
DB58B21928FC7C4600F8EEA4 /* SQLiteFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB58B21528FC7C4600F8EEA4 /* SQLiteFeature.swift */; };
DB7C5DA628D7C9B6006395CF /* SQLiteVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB7C5DA528D7C9B6006395CF /* SQLiteVersion.swift */; };
DB7C5DA728D7C9B6006395CF /* SQLiteVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB7C5DA528D7C9B6006395CF /* SQLiteVersion.swift */; };
DB7C5DA828D7C9B6006395CF /* SQLiteVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB7C5DA528D7C9B6006395CF /* SQLiteVersion.swift */; };
DB7C5DA928D7C9B6006395CF /* SQLiteVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB7C5DA528D7C9B6006395CF /* SQLiteVersion.swift */; };
DBB93D5A2A22A373009BB96E /* SchemaReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB93D592A22A373009BB96E /* SchemaReaderTests.swift */; };
DBB93D5B2A22A373009BB96E /* SchemaReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB93D592A22A373009BB96E /* SchemaReaderTests.swift */; };
DBB93D5C2A22A373009BB96E /* SchemaReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB93D592A22A373009BB96E /* SchemaReaderTests.swift */; };
DEB306BA2B61CEF500F9D46B /* SQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AD61C3F04ED00AE3E12 /* SQLite.h */; settings = {ATTRIBUTES = (Public, ); }; };
DEB306BC2B61CEF500F9D46B /* CoreFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */; };
DEB306BD2B61CEF500F9D46B /* Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49EB68C31F7B3CB400D89D40 /* Coding.swift */; };
DEB306BE2B61CEF500F9D46B /* RTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF61C3F06E900AE3E12 /* RTree.swift */; };
DEB306BF2B61CEF500F9D46B /* Blob.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEE1C3F06E900AE3E12 /* Blob.swift */; };
DEB306C02B61CEF500F9D46B /* URIQueryParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF7B790288449BA005DD8CA /* URIQueryParameter.swift */; };
DEB306C12B61CEF500F9D46B /* Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF71C3F06E900AE3E12 /* Foundation.swift */; };
DEB306C22B61CEF500F9D46B /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEF1C3F06E900AE3E12 /* Connection.swift */; };
DEB306C32B61CEF500F9D46B /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFE1C3F06E900AE3E12 /* Expression.swift */; };
DEB306C42B61CEF500F9D46B /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF81C3F06E900AE3E12 /* Helpers.swift */; };
DEB306C52B61CEF500F9D46B /* Collation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFB1C3F06E900AE3E12 /* Collation.swift */; };
DEB306C62B61CEF500F9D46B /* Setter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B021C3F06E900AE3E12 /* Setter.swift */; };
DEB306C72B61CEF500F9D46B /* Connection+Attach.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF7B78728842972005DD8CA /* Connection+Attach.swift */; };
DEB306C82B61CEF500F9D46B /* CustomFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */; };
DEB306C92B61CEF500F9D46B /* FTS4.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF51C3F06E900AE3E12 /* FTS4.swift */; };
DEB306CA2B61CEF500F9D46B /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF31C3F06E900AE3E12 /* Value.swift */; };
DEB306CB2B61CEF500F9D46B /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFF1C3F06E900AE3E12 /* Operators.swift */; };
DEB306CC2B61CEF500F9D46B /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B011C3F06E900AE3E12 /* Schema.swift */; };
DEB306CD2B61CEF500F9D46B /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B001C3F06E900AE3E12 /* Query.swift */; };
DEB306CE2B61CEF500F9D46B /* Statement.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF21C3F06E900AE3E12 /* Statement.swift */; };
DEB306CF2B61CEF500F9D46B /* AggregateFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */; };
DEB306D02B61CEF500F9D46B /* FTS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1730E4390C775C25677D1 /* FTS5.swift */; };
DEB306D12B61CEF500F9D46B /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A178A39ACA9667A62663CC /* Cipher.swift */; };
DEB306D22B61CEF500F9D46B /* Backup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02A43A9722738CF100FEC494 /* Backup.swift */; };
DEB306D32B61CEF500F9D46B /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1710E73A46D5AC721CDA9 /* Errors.swift */; };
DEB306D42B61CEF500F9D46B /* DateAndTimeFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17BA55DABB480F9020C8A /* DateAndTimeFunctions.swift */; };
DEB306D52B61CEF500F9D46B /* SQLiteVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB7C5DA528D7C9B6006395CF /* SQLiteVersion.swift */; };
DEB306D62B61CEF500F9D46B /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17E723300E5ED3771DCB5 /* Result.swift */; };
DEB306D72B61CEF500F9D46B /* Query+with.swift in Sources */ = {isa = PBXBuildFile; fileRef = 997DF2AD287FC06D00F8DF95 /* Query+with.swift */; };
DEB306D82B61CEF500F9D46B /* Connection+Aggregation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A175A9CB446640AE6F2200 /* Connection+Aggregation.swift */; };
DEB306D92B61CEF500F9D46B /* SQLiteFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB58B21528FC7C4600F8EEA4 /* SQLiteFeature.swift */; };
DEB306DA2B61CEF500F9D46B /* SchemaChanger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A171B262DDE8718513CFDA /* SchemaChanger.swift */; };
DEB306DB2B61CEF500F9D46B /* SchemaDefinitions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17268AE67B746B96AC125 /* SchemaDefinitions.swift */; };
DEB306DC2B61CEF500F9D46B /* Connection+Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A170A97B51DC5EE365F3C5 /* Connection+Schema.swift */; };
DEB306DD2B61CEF500F9D46B /* Connection+Pragmas.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17F285B767BFACD96714B /* Connection+Pragmas.swift */; };
DEB306DE2B61CEF500F9D46B /* SchemaReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB58B21028FB864300F8EEA4 /* SchemaReader.swift */; };
DEB306E02B61CEF500F9D46B /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = EE9180931C46EA210038162A /* libsqlite3.tbd */; };
DEB306EB2B61CF9500F9D46B /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B161C3F127200AE3E12 /* TestHelpers.swift */; };
DEB306EC2B61CF9500F9D46B /* FoundationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1794CC4D7827E997E32A7 /* FoundationTests.swift */; };
DEB306ED2B61CF9500F9D46B /* Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17B93B48B5560E6E51791 /* Fixtures.swift */; };
DEB306EE2B61CF9500F9D46B /* SchemaDefinitionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A176174862D0F0139B3987 /* SchemaDefinitionsTests.swift */; };
DEB306EF2B61CF9500F9D46B /* SchemaChangerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17FDB0B0CFB8987906FD0 /* SchemaChangerTests.swift */; };
DEB306F02B61CF9500F9D46B /* Connection+SchemaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17CA1DF7D0F7C9A94C51C /* Connection+SchemaTests.swift */; };
DEB306F12B61CF9500F9D46B /* FTS5Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17B96EBD42C878E609CDC /* FTS5Tests.swift */; };
DEB306F22B61CF9500F9D46B /* FTS5IntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17BE1CC4AD4036BAB8EE0 /* FTS5IntegrationTests.swift */; };
DEB306F32B61CF9500F9D46B /* FTS4Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1715904F7B6851FCB5EF6 /* FTS4Tests.swift */; };
DEB306F42B61CF9500F9D46B /* ExpressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A170F141BF21946D159083 /* ExpressionTests.swift */; };
DEB306F52B61CF9500F9D46B /* StatementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1756EB81E9F7F45B12A78 /* StatementTests.swift */; };
DEB306F62B61CF9500F9D46B /* QueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A171ED017645C8B04DF9F2 /* QueryTests.swift */; };
DEB306F72B61CF9500F9D46B /* CipherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1787E16C8562C09C076F5 /* CipherTests.swift */; };
DEB306F82B61CF9500F9D46B /* BlobTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A171A2ED4E2640F197F48C /* BlobTests.swift */; };
DEB306F92B61CF9500F9D46B /* ConnectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17855BD524FF888265B3C /* ConnectionTests.swift */; };
DEB306FA2B61CF9500F9D46B /* CoreFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17B55F2409B7031443495 /* CoreFunctionsTests.swift */; };
DEB306FB2B61CF9500F9D46B /* DateAndTimeFunctionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A178AEF32ABC8BF2993FB5 /* DateAndTimeFunctionTests.swift */; };
DEB306FC2B61CF9500F9D46B /* CustomFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17F2B5959B212A33C383F /* CustomFunctionsTests.swift */; };
DEB306FD2B61CF9500F9D46B /* OperatorsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17475DCA068453F787613 /* OperatorsTests.swift */; };
DEB306FE2B61CF9500F9D46B /* ResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1745BE8623D8C6808DB3C /* ResultTests.swift */; };
DEB306FF2B61CF9500F9D46B /* RTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17162C9861E5C4900455D /* RTreeTests.swift */; };
DEB307002B61CF9500F9D46B /* SchemaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A171A7714C6524093255C5 /* SchemaTests.swift */; };
DEB307012B61CF9500F9D46B /* SelectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17EC0C43015063945D32E /* SelectTests.swift */; };
DEB307022B61CF9500F9D46B /* ValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17AE284BB1DF31D1B753E /* ValueTests.swift */; };
DEB307032B61CF9500F9D46B /* QueryIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17CAE60446607E99C22A6 /* QueryIntegrationTests.swift */; };
DEB307042B61CF9500F9D46B /* AggregateFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17613F00A3F4D4A257A04 /* AggregateFunctionsTests.swift */; };
DEB307052B61CF9500F9D46B /* CustomAggregationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A177EF5E2D91BA86DA4480 /* CustomAggregationTests.swift */; };
DEB307062B61CF9500F9D46B /* SetterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A1709D5BDD2691BA160012 /* SetterTests.swift */; };
DEB307072B61CF9500F9D46B /* RowTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A174FE5B47A97937A27276 /* RowTests.swift */; };
DEB307082B61CF9500F9D46B /* Connection+PragmaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A17C60D3464461057E4D63 /* Connection+PragmaTests.swift */; };
DEB307092B61CF9500F9D46B /* Connection+AttachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A170C08525D3D27CB5F83C /* Connection+AttachTests.swift */; };
DEB3070B2B61CF9500F9D46B /* SQLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03A65E5A1C6BB0F50062603F /* SQLite.framework */; };
DEB3070D2B61CF9500F9D46B /* Resources in Resources */ = {isa = PBXBuildFile; fileRef = 3DF7B79528846FCC005DD8CA /* Resources */; };
EAE5A0372B893C43007C7EA4 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = EAE5A0362B893C43007C7EA4 /* PrivacyInfo.xcprivacy */; };
EAE5A0382B893C43007C7EA4 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = EAE5A0362B893C43007C7EA4 /* PrivacyInfo.xcprivacy */; };
EAE5A0392B893C43007C7EA4 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = EAE5A0362B893C43007C7EA4 /* PrivacyInfo.xcprivacy */; };
EAE5A03A2B893C43007C7EA4 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = EAE5A0362B893C43007C7EA4 /* PrivacyInfo.xcprivacy */; };
EE247AD71C3F04ED00AE3E12 /* SQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AD61C3F04ED00AE3E12 /* SQLite.h */; settings = {ATTRIBUTES = (Public, ); }; };
EE247ADE1C3F04ED00AE3E12 /* SQLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EE247AD31C3F04ED00AE3E12 /* SQLite.framework */; };
EE247B031C3F06E900AE3E12 /* Blob.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEE1C3F06E900AE3E12 /* Blob.swift */; };
EE247B041C3F06E900AE3E12 /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEF1C3F06E900AE3E12 /* Connection.swift */; };
EE247B071C3F06E900AE3E12 /* Statement.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF21C3F06E900AE3E12 /* Statement.swift */; };
EE247B081C3F06E900AE3E12 /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF31C3F06E900AE3E12 /* Value.swift */; };
EE247B091C3F06E900AE3E12 /* FTS4.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF51C3F06E900AE3E12 /* FTS4.swift */; };
EE247B0A1C3F06E900AE3E12 /* RTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF61C3F06E900AE3E12 /* RTree.swift */; };
EE247B0B1C3F06E900AE3E12 /* Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF71C3F06E900AE3E12 /* Foundation.swift */; };
EE247B0C1C3F06E900AE3E12 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF81C3F06E900AE3E12 /* Helpers.swift */; };
EE247B0D1C3F06E900AE3E12 /* AggregateFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */; };
EE247B0E1C3F06E900AE3E12 /* Collation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFB1C3F06E900AE3E12 /* Collation.swift */; };
EE247B0F1C3F06E900AE3E12 /* CoreFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */; };
EE247B101C3F06E900AE3E12 /* CustomFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */; };
EE247B111C3F06E900AE3E12 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFE1C3F06E900AE3E12 /* Expression.swift */; };
EE247B121C3F06E900AE3E12 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFF1C3F06E900AE3E12 /* Operators.swift */; };
EE247B131C3F06E900AE3E12 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B001C3F06E900AE3E12 /* Query.swift */; };
EE247B141C3F06E900AE3E12 /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B011C3F06E900AE3E12 /* Schema.swift */; };
EE247B151C3F06E900AE3E12 /* Setter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B021C3F06E900AE3E12 /* Setter.swift */; };
EE247B171C3F127200AE3E12 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B161C3F127200AE3E12 /* TestHelpers.swift */; };
EE247B461C3F3ED000AE3E12 /* SQLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EE247B3C1C3F3ED000AE3E12 /* SQLite.framework */; };
EE247B611C3F3FC700AE3E12 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B161C3F127200AE3E12 /* TestHelpers.swift */; };
EE247B621C3F3FDB00AE3E12 /* SQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = EE247AD61C3F04ED00AE3E12 /* SQLite.h */; settings = {ATTRIBUTES = (Public, ); }; };
EE247B631C3F3FDB00AE3E12 /* Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF71C3F06E900AE3E12 /* Foundation.swift */; };
EE247B641C3F3FDB00AE3E12 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF81C3F06E900AE3E12 /* Helpers.swift */; };
EE247B651C3F3FEC00AE3E12 /* Blob.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEE1C3F06E900AE3E12 /* Blob.swift */; };
EE247B661C3F3FEC00AE3E12 /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AEF1C3F06E900AE3E12 /* Connection.swift */; };
EE247B691C3F3FEC00AE3E12 /* Statement.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF21C3F06E900AE3E12 /* Statement.swift */; };
EE247B6A1C3F3FEC00AE3E12 /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF31C3F06E900AE3E12 /* Value.swift */; };
EE247B6B1C3F3FEC00AE3E12 /* FTS4.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF51C3F06E900AE3E12 /* FTS4.swift */; };
EE247B6C1C3F3FEC00AE3E12 /* RTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AF61C3F06E900AE3E12 /* RTree.swift */; };
EE247B6D1C3F3FEC00AE3E12 /* AggregateFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */; };
EE247B6E1C3F3FEC00AE3E12 /* Collation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFB1C3F06E900AE3E12 /* Collation.swift */; };
EE247B6F1C3F3FEC00AE3E12 /* CoreFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */; };
EE247B701C3F3FEC00AE3E12 /* CustomFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */; };
EE247B711C3F3FEC00AE3E12 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFE1C3F06E900AE3E12 /* Expression.swift */; };
EE247B721C3F3FEC00AE3E12 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247AFF1C3F06E900AE3E12 /* Operators.swift */; };
EE247B731C3F3FEC00AE3E12 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B001C3F06E900AE3E12 /* Query.swift */; };
EE247B741C3F3FEC00AE3E12 /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B011C3F06E900AE3E12 /* Schema.swift */; };
EE247B751C3F3FEC00AE3E12 /* Setter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE247B021C3F06E900AE3E12 /* Setter.swift */; };
EE9180941C46EA210038162A /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = EE9180931C46EA210038162A /* libsqlite3.tbd */; };
EE9180951C46EBCC0038162A /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = EE9180911C46E9D30038162A /* libsqlite3.tbd */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
03A65E651C6BB0F60062603F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = EE247ACA1C3F04ED00AE3E12 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 03A65E591C6BB0F50062603F;
remoteInfo = "SQLite tvOS";
};
DEB307142B61D07F00F9D46B /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = EE247ACA1C3F04ED00AE3E12 /* Project object */;
proxyType = 1;
remoteGlobalIDString = DEB306B82B61CEF500F9D46B;
remoteInfo = "SQLite visionOS";
};
EE247ADF1C3F04ED00AE3E12 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = EE247ACA1C3F04ED00AE3E12 /* Project object */;
proxyType = 1;
remoteGlobalIDString = EE247AD21C3F04ED00AE3E12;
remoteInfo = SQLite;
};
EE247B471C3F3ED000AE3E12 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = EE247ACA1C3F04ED00AE3E12 /* Project object */;
proxyType = 1;
remoteGlobalIDString = EE247B3B1C3F3ED000AE3E12;
remoteInfo = SQLite;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
02A43A9722738CF100FEC494 /* Backup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Backup.swift; sourceTree = ""; };
03A65E5A1C6BB0F50062603F /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; };
03A65E631C6BB0F60062603F /* SQLiteTests tvOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SQLiteTests tvOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
03A65E961C6BB3210062603F /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS.sdk/usr/lib/libsqlite3.tbd; sourceTree = DEVELOPER_DIR; };
19A1709D5BDD2691BA160012 /* SetterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetterTests.swift; sourceTree = ""; };
19A170A97B51DC5EE365F3C5 /* Connection+Schema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Connection+Schema.swift"; sourceTree = ""; };
19A170C08525D3D27CB5F83C /* Connection+AttachTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Connection+AttachTests.swift"; sourceTree = ""; };
19A170F141BF21946D159083 /* ExpressionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExpressionTests.swift; sourceTree = ""; };
19A1710E73A46D5AC721CDA9 /* Errors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Errors.swift; sourceTree = ""; };
19A1715904F7B6851FCB5EF6 /* FTS4Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FTS4Tests.swift; sourceTree = ""; };
19A17162C9861E5C4900455D /* RTreeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RTreeTests.swift; sourceTree = ""; };
19A171A2ED4E2640F197F48C /* BlobTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlobTests.swift; sourceTree = ""; };
19A171A7714C6524093255C5 /* SchemaTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaTests.swift; sourceTree = ""; };
19A171B262DDE8718513CFDA /* SchemaChanger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaChanger.swift; sourceTree = ""; };
19A171ED017645C8B04DF9F2 /* QueryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryTests.swift; sourceTree = ""; };
19A17268AE67B746B96AC125 /* SchemaDefinitions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaDefinitions.swift; sourceTree = ""; };
19A1730E4390C775C25677D1 /* FTS5.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FTS5.swift; sourceTree = ""; };
19A1745BE8623D8C6808DB3C /* ResultTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultTests.swift; sourceTree = ""; };
19A17475DCA068453F787613 /* OperatorsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperatorsTests.swift; sourceTree = ""; };
19A174FE5B47A97937A27276 /* RowTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowTests.swift; sourceTree = ""; };
19A1756EB81E9F7F45B12A78 /* StatementTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatementTests.swift; sourceTree = ""; };
19A175A9CB446640AE6F2200 /* Connection+Aggregation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Connection+Aggregation.swift"; sourceTree = ""; };
19A17613F00A3F4D4A257A04 /* AggregateFunctionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AggregateFunctionsTests.swift; sourceTree = ""; };
19A176174862D0F0139B3987 /* SchemaDefinitionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaDefinitionsTests.swift; sourceTree = ""; };
19A177EF5E2D91BA86DA4480 /* CustomAggregationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomAggregationTests.swift; sourceTree = ""; };
19A17855BD524FF888265B3C /* ConnectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionTests.swift; sourceTree = ""; };
19A1787E16C8562C09C076F5 /* CipherTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CipherTests.swift; sourceTree = ""; };
19A178A39ACA9667A62663CC /* Cipher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cipher.swift; sourceTree = ""; };
19A178AEF32ABC8BF2993FB5 /* DateAndTimeFunctionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateAndTimeFunctionTests.swift; sourceTree = ""; };
19A1794B7972D14330A65BBD /* Linux.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Linux.md; sourceTree = ""; };
19A1794CC4D7827E997E32A7 /* FoundationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FoundationTests.swift; sourceTree = ""; };
19A17AE284BB1DF31D1B753E /* ValueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValueTests.swift; sourceTree = ""; };
19A17B55F2409B7031443495 /* CoreFunctionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreFunctionsTests.swift; sourceTree = ""; };
19A17B93B48B5560E6E51791 /* Fixtures.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fixtures.swift; sourceTree = ""; };
19A17B96EBD42C878E609CDC /* FTS5Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FTS5Tests.swift; sourceTree = ""; };
19A17BA55DABB480F9020C8A /* DateAndTimeFunctions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateAndTimeFunctions.swift; sourceTree = ""; };
19A17BE1CC4AD4036BAB8EE0 /* FTS5IntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FTS5IntegrationTests.swift; sourceTree = ""; };
19A17C60D3464461057E4D63 /* Connection+PragmaTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Connection+PragmaTests.swift"; sourceTree = ""; };
19A17CA1DF7D0F7C9A94C51C /* Connection+SchemaTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Connection+SchemaTests.swift"; sourceTree = ""; };
19A17CAE60446607E99C22A6 /* QueryIntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryIntegrationTests.swift; sourceTree = ""; };
19A17E723300E5ED3771DCB5 /* Result.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Result.swift; sourceTree = ""; };
19A17EA3A313F129011B3FA0 /* Release.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Release.md; sourceTree = ""; };
19A17EC0C43015063945D32E /* SelectTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectTests.swift; sourceTree = ""; };
19A17F285B767BFACD96714B /* Connection+Pragmas.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Connection+Pragmas.swift"; sourceTree = ""; };
19A17F2B5959B212A33C383F /* CustomFunctionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomFunctionsTests.swift; sourceTree = ""; };
19A17FDB0B0CFB8987906FD0 /* SchemaChangerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaChangerTests.swift; sourceTree = ""; };
3D3C3CCB26E5568800759140 /* SQLite.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = SQLite.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
3D67B3E51DB2469200A4F4C6 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS3.0.sdk/usr/lib/libsqlite3.tbd; sourceTree = DEVELOPER_DIR; };
3DF7B78728842972005DD8CA /* Connection+Attach.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Connection+Attach.swift"; sourceTree = ""; };
3DF7B790288449BA005DD8CA /* URIQueryParameter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URIQueryParameter.swift; sourceTree = ""; };
3DF7B79528846FCC005DD8CA /* Resources */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Resources; sourceTree = ""; };
3DF7B79A2884C353005DD8CA /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = ""; };
3DF7B79B2884C901005DD8CA /* Planning.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Planning.md; sourceTree = ""; };
3DFC0B862886C239001C8FC9 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; };
49EB68C31F7B3CB400D89D40 /* Coding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coding.swift; sourceTree = ""; };
64A8EE422B095FBB00F583F7 /* WindowFunctions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowFunctions.swift; sourceTree = ""; };
64B8E16F2B09748000545AFB /* WindowFunctionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowFunctionsTests.swift; sourceTree = ""; };
997DF2AD287FC06D00F8DF95 /* Query+with.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Query+with.swift"; sourceTree = ""; };
A121AC451CA35C79005A31D1 /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; };
DB58B21028FB864300F8EEA4 /* SchemaReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaReader.swift; sourceTree = ""; };
DB58B21528FC7C4600F8EEA4 /* SQLiteFeature.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteFeature.swift; sourceTree = ""; };
DB7C5DA528D7C9B6006395CF /* SQLiteVersion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteVersion.swift; sourceTree = ""; };
DBB93D592A22A373009BB96E /* SchemaReaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchemaReaderTests.swift; sourceTree = ""; };
DEB306E52B61CEF500F9D46B /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; };
DEB307112B61CF9500F9D46B /* SQLiteTests visionOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SQLiteTests visionOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
DEB307132B61D04500F9D46B /* SQLite visionOS.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; name = "SQLite visionOS.xctestplan"; path = "Tests/SQLite visionOS.xctestplan"; sourceTree = ""; };
EAE5A0362B893C43007C7EA4 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; };
EE247AD31C3F04ED00AE3E12 /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; };
EE247AD61C3F04ED00AE3E12 /* SQLite.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SQLite.h; sourceTree = ""; };
EE247AD81C3F04ED00AE3E12 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
EE247ADD1C3F04ED00AE3E12 /* SQLiteTests iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SQLiteTests iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
EE247AE41C3F04ED00AE3E12 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
EE247AEE1C3F06E900AE3E12 /* Blob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Blob.swift; sourceTree = ""; };
EE247AEF1C3F06E900AE3E12 /* Connection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Connection.swift; sourceTree = ""; };
EE247AF21C3F06E900AE3E12 /* Statement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Statement.swift; sourceTree = ""; };
EE247AF31C3F06E900AE3E12 /* Value.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Value.swift; sourceTree = ""; };
EE247AF51C3F06E900AE3E12 /* FTS4.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FTS4.swift; sourceTree = ""; };
EE247AF61C3F06E900AE3E12 /* RTree.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RTree.swift; sourceTree = ""; };
EE247AF71C3F06E900AE3E12 /* Foundation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Foundation.swift; sourceTree = ""; };
EE247AF81C3F06E900AE3E12 /* Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = ""; };
EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AggregateFunctions.swift; sourceTree = ""; };
EE247AFB1C3F06E900AE3E12 /* Collation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Collation.swift; sourceTree = ""; };
EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreFunctions.swift; sourceTree = ""; };
EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomFunctions.swift; sourceTree = ""; };
EE247AFE1C3F06E900AE3E12 /* Expression.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Expression.swift; sourceTree = ""; };
EE247AFF1C3F06E900AE3E12 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; };
EE247B001C3F06E900AE3E12 /* Query.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Query.swift; sourceTree = ""; };
EE247B011C3F06E900AE3E12 /* Schema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Schema.swift; sourceTree = ""; };
EE247B021C3F06E900AE3E12 /* Setter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Setter.swift; sourceTree = ""; };
EE247B161C3F127200AE3E12 /* TestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestHelpers.swift; sourceTree = ""; };
EE247B3C1C3F3ED000AE3E12 /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; };
EE247B451C3F3ED000AE3E12 /* SQLiteTests Mac.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SQLiteTests Mac.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
EE247B771C3F40D700AE3E12 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
EE247B8B1C3F820300AE3E12 /* CONTRIBUTING.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CONTRIBUTING.md; sourceTree = ""; };
EE247B8D1C3F821200AE3E12 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; };
EE247B8F1C3F822500AE3E12 /* Index.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Index.md; sourceTree = ""; };
EE247B911C3F822500AE3E12 /* installation@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "installation@2x.png"; sourceTree = ""; };
EE247B921C3F822600AE3E12 /* playground@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "playground@2x.png"; sourceTree = ""; };
EE247B931C3F826100AE3E12 /* SQLite.swift.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = SQLite.swift.podspec; sourceTree = ""; };
EE9180911C46E9D30038162A /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/libsqlite3.tbd; sourceTree = DEVELOPER_DIR; };
EE9180931C46EA210038162A /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
03A65E561C6BB0F50062603F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
03A65E971C6BB3210062603F /* libsqlite3.tbd in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
03A65E601C6BB0F60062603F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
03A65E641C6BB0F60062603F /* SQLite.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A121AC411CA35C79005A31D1 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
3D67B3E61DB2469200A4F4C6 /* libsqlite3.tbd in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DEB306DF2B61CEF500F9D46B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
DEB306E02B61CEF500F9D46B /* libsqlite3.tbd in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DEB3070A2B61CF9500F9D46B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
DEB3070B2B61CF9500F9D46B /* SQLite.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
EE247ACF1C3F04ED00AE3E12 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
EE9180941C46EA210038162A /* libsqlite3.tbd in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
EE247ADA1C3F04ED00AE3E12 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
EE247ADE1C3F04ED00AE3E12 /* SQLite.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
EE247B381C3F3ED000AE3E12 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
EE9180951C46EBCC0038162A /* libsqlite3.tbd in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
EE247B421C3F3ED000AE3E12 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
EE247B461C3F3ED000AE3E12 /* SQLite.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
19A1792D261C689FC988A90A /* Schema */ = {
isa = PBXGroup;
children = (
DB58B21028FB864300F8EEA4 /* SchemaReader.swift */,
19A171B262DDE8718513CFDA /* SchemaChanger.swift */,
19A17268AE67B746B96AC125 /* SchemaDefinitions.swift */,
19A170A97B51DC5EE365F3C5 /* Connection+Schema.swift */,
);
path = Schema;
sourceTree = "";
};
19A1798E3459573BEE50FA34 /* Core */ = {
isa = PBXGroup;
children = (
19A1756EB81E9F7F45B12A78 /* StatementTests.swift */,
19A171A2ED4E2640F197F48C /* BlobTests.swift */,
19A17855BD524FF888265B3C /* ConnectionTests.swift */,
19A17B55F2409B7031443495 /* CoreFunctionsTests.swift */,
19A1745BE8623D8C6808DB3C /* ResultTests.swift */,
19A17AE284BB1DF31D1B753E /* ValueTests.swift */,
19A17C60D3464461057E4D63 /* Connection+PragmaTests.swift */,
19A170C08525D3D27CB5F83C /* Connection+AttachTests.swift */,
);
path = Core;
sourceTree = "";
};
19A17AECBF878B1DAE0AE3DD /* Typed */ = {
isa = PBXGroup;
children = (
19A170F141BF21946D159083 /* ExpressionTests.swift */,
19A171ED017645C8B04DF9F2 /* QueryTests.swift */,
19A178AEF32ABC8BF2993FB5 /* DateAndTimeFunctionTests.swift */,
19A17F2B5959B212A33C383F /* CustomFunctionsTests.swift */,
19A17475DCA068453F787613 /* OperatorsTests.swift */,
19A17EC0C43015063945D32E /* SelectTests.swift */,
19A17CAE60446607E99C22A6 /* QueryIntegrationTests.swift */,
19A17613F00A3F4D4A257A04 /* AggregateFunctionsTests.swift */,
19A177EF5E2D91BA86DA4480 /* CustomAggregationTests.swift */,
19A1709D5BDD2691BA160012 /* SetterTests.swift */,
19A174FE5B47A97937A27276 /* RowTests.swift */,
64B8E16F2B09748000545AFB /* WindowFunctionsTests.swift */,
);
path = Typed;
sourceTree = "";
};
19A17B56FBA20E7245BC8AC0 /* Schema */ = {
isa = PBXGroup;
children = (
DBB93D592A22A373009BB96E /* SchemaReaderTests.swift */,
19A176174862D0F0139B3987 /* SchemaDefinitionsTests.swift */,
19A17FDB0B0CFB8987906FD0 /* SchemaChangerTests.swift */,
19A17CA1DF7D0F7C9A94C51C /* Connection+SchemaTests.swift */,
19A171A7714C6524093255C5 /* SchemaTests.swift */,
);
path = Schema;
sourceTree = "";
};
19A17E470E4492D287C0D12F /* Extensions */ = {
isa = PBXGroup;
children = (
19A17B96EBD42C878E609CDC /* FTS5Tests.swift */,
19A17BE1CC4AD4036BAB8EE0 /* FTS5IntegrationTests.swift */,
19A1715904F7B6851FCB5EF6 /* FTS4Tests.swift */,
19A1787E16C8562C09C076F5 /* CipherTests.swift */,
19A17162C9861E5C4900455D /* RTreeTests.swift */,
);
path = Extensions;
sourceTree = "";
};
3D67B3E41DB2469200A4F4C6 /* Frameworks */ = {
isa = PBXGroup;
children = (
3D67B3E51DB2469200A4F4C6 /* libsqlite3.tbd */,
);
name = Frameworks;
sourceTree = "";
};
EE247AC91C3F04ED00AE3E12 = {
isa = PBXGroup;
children = (
3D3C3CCB26E5568800759140 /* SQLite.playground */,
EE247AD51C3F04ED00AE3E12 /* SQLite */,
EE247AE11C3F04ED00AE3E12 /* SQLiteTests */,
DEB307132B61D04500F9D46B /* SQLite visionOS.xctestplan */,
EE247B8A1C3F81D000AE3E12 /* Metadata */,
EE247AD41C3F04ED00AE3E12 /* Products */,
3D67B3E41DB2469200A4F4C6 /* Frameworks */,
);
indentWidth = 4;
sourceTree = "";
tabWidth = 4;
};
EE247AD41C3F04ED00AE3E12 /* Products */ = {
isa = PBXGroup;
children = (
EE247AD31C3F04ED00AE3E12 /* SQLite.framework */,
EE247ADD1C3F04ED00AE3E12 /* SQLiteTests iOS.xctest */,
EE247B3C1C3F3ED000AE3E12 /* SQLite.framework */,
EE247B451C3F3ED000AE3E12 /* SQLiteTests Mac.xctest */,
03A65E5A1C6BB0F50062603F /* SQLite.framework */,
03A65E631C6BB0F60062603F /* SQLiteTests tvOS.xctest */,
A121AC451CA35C79005A31D1 /* SQLite.framework */,
DEB306E52B61CEF500F9D46B /* SQLite.framework */,
DEB307112B61CF9500F9D46B /* SQLiteTests visionOS.xctest */,
);
name = Products;
sourceTree = "";
};
EE247AD51C3F04ED00AE3E12 /* SQLite */ = {
isa = PBXGroup;
children = (
EE247AD61C3F04ED00AE3E12 /* SQLite.h */,
EE247AF71C3F06E900AE3E12 /* Foundation.swift */,
EE247AF81C3F06E900AE3E12 /* Helpers.swift */,
EAE5A0362B893C43007C7EA4 /* PrivacyInfo.xcprivacy */,
EE247AD81C3F04ED00AE3E12 /* Info.plist */,
EE247AED1C3F06E900AE3E12 /* Core */,
EE247AF41C3F06E900AE3E12 /* Extensions */,
EE247AF91C3F06E900AE3E12 /* Typed */,
19A1792D261C689FC988A90A /* Schema */,
);
name = SQLite;
path = Sources/SQLite;
sourceTree = "";
};
EE247AE11C3F04ED00AE3E12 /* SQLiteTests */ = {
isa = PBXGroup;
children = (
3DF7B79528846FCC005DD8CA /* Resources */,
EE247B161C3F127200AE3E12 /* TestHelpers.swift */,
EE247AE41C3F04ED00AE3E12 /* Info.plist */,
19A1794CC4D7827E997E32A7 /* FoundationTests.swift */,
19A17B93B48B5560E6E51791 /* Fixtures.swift */,
19A17B56FBA20E7245BC8AC0 /* Schema */,
19A17E470E4492D287C0D12F /* Extensions */,
19A1798E3459573BEE50FA34 /* Core */,
19A17AECBF878B1DAE0AE3DD /* Typed */,
);
name = SQLiteTests;
path = Tests/SQLiteTests;
sourceTree = "";
};
EE247AED1C3F06E900AE3E12 /* Core */ = {
isa = PBXGroup;
children = (
EE247AEE1C3F06E900AE3E12 /* Blob.swift */,
EE247AEF1C3F06E900AE3E12 /* Connection.swift */,
EE247AF21C3F06E900AE3E12 /* Statement.swift */,
EE247AF31C3F06E900AE3E12 /* Value.swift */,
19A1710E73A46D5AC721CDA9 /* Errors.swift */,
02A43A9722738CF100FEC494 /* Backup.swift */,
19A17E723300E5ED3771DCB5 /* Result.swift */,
19A175A9CB446640AE6F2200 /* Connection+Aggregation.swift */,
3DF7B78728842972005DD8CA /* Connection+Attach.swift */,
3DF7B790288449BA005DD8CA /* URIQueryParameter.swift */,
DB58B21528FC7C4600F8EEA4 /* SQLiteFeature.swift */,
DB7C5DA528D7C9B6006395CF /* SQLiteVersion.swift */,
19A17F285B767BFACD96714B /* Connection+Pragmas.swift */,
);
path = Core;
sourceTree = "";
};
EE247AF41C3F06E900AE3E12 /* Extensions */ = {
isa = PBXGroup;
children = (
19A178A39ACA9667A62663CC /* Cipher.swift */,
EE247AF51C3F06E900AE3E12 /* FTS4.swift */,
19A1730E4390C775C25677D1 /* FTS5.swift */,
EE247AF61C3F06E900AE3E12 /* RTree.swift */,
);
path = Extensions;
sourceTree = "";
};
EE247AF91C3F06E900AE3E12 /* Typed */ = {
isa = PBXGroup;
children = (
EE247AFA1C3F06E900AE3E12 /* AggregateFunctions.swift */,
64A8EE422B095FBB00F583F7 /* WindowFunctions.swift */,
EE247AFB1C3F06E900AE3E12 /* Collation.swift */,
EE247AFC1C3F06E900AE3E12 /* CoreFunctions.swift */,
EE247AFD1C3F06E900AE3E12 /* CustomFunctions.swift */,
EE247AFE1C3F06E900AE3E12 /* Expression.swift */,
EE247AFF1C3F06E900AE3E12 /* Operators.swift */,
EE247B001C3F06E900AE3E12 /* Query.swift */,
997DF2AD287FC06D00F8DF95 /* Query+with.swift */,
EE247B011C3F06E900AE3E12 /* Schema.swift */,
EE247B021C3F06E900AE3E12 /* Setter.swift */,
49EB68C31F7B3CB400D89D40 /* Coding.swift */,
19A17BA55DABB480F9020C8A /* DateAndTimeFunctions.swift */,
);
path = Typed;
sourceTree = "";
};
EE247B8A1C3F81D000AE3E12 /* Metadata */ = {
isa = PBXGroup;
children = (
EE247B771C3F40D700AE3E12 /* README.md */,
3DF7B79A2884C353005DD8CA /* CHANGELOG.md */,
EE247B8B1C3F820300AE3E12 /* CONTRIBUTING.md */,
EE247B931C3F826100AE3E12 /* SQLite.swift.podspec */,
3DFC0B862886C239001C8FC9 /* Package.swift */,
EE247B8D1C3F821200AE3E12 /* Makefile */,
EE9180931C46EA210038162A /* libsqlite3.tbd */,
EE9180911C46E9D30038162A /* libsqlite3.tbd */,
03A65E961C6BB3210062603F /* libsqlite3.tbd */,
EE247B8E1C3F822500AE3E12 /* Documentation */,
);
name = Metadata;
sourceTree = "";
};
EE247B8E1C3F822500AE3E12 /* Documentation */ = {
isa = PBXGroup;
children = (
EE247B8F1C3F822500AE3E12 /* Index.md */,
3DF7B79B2884C901005DD8CA /* Planning.md */,
EE247B901C3F822500AE3E12 /* Resources */,
19A17EA3A313F129011B3FA0 /* Release.md */,
19A1794B7972D14330A65BBD /* Linux.md */,
);
path = Documentation;
sourceTree = "";
};
EE247B901C3F822500AE3E12 /* Resources */ = {
isa = PBXGroup;
children = (
EE247B911C3F822500AE3E12 /* installation@2x.png */,
EE247B921C3F822600AE3E12 /* playground@2x.png */,
);
path = Resources;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
03A65E571C6BB0F50062603F /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
03A65E721C6BB2D30062603F /* SQLite.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A121AC421CA35C79005A31D1 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
3D67B3FC1DB2471B00A4F4C6 /* SQLite.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DEB306B92B61CEF500F9D46B /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
DEB306BA2B61CEF500F9D46B /* SQLite.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
EE247AD01C3F04ED00AE3E12 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
EE247AD71C3F04ED00AE3E12 /* SQLite.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
EE247B391C3F3ED000AE3E12 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
EE247B621C3F3FDB00AE3E12 /* SQLite.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
03A65E591C6BB0F50062603F /* SQLite tvOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 03A65E6F1C6BB0F60062603F /* Build configuration list for PBXNativeTarget "SQLite tvOS" */;
buildPhases = (
03A65E571C6BB0F50062603F /* Headers */,
03A65E551C6BB0F50062603F /* Sources */,
03A65E561C6BB0F50062603F /* Frameworks */,
03A65E581C6BB0F50062603F /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "SQLite tvOS";
productName = "SQLite tvOS";
productReference = 03A65E5A1C6BB0F50062603F /* SQLite.framework */;
productType = "com.apple.product-type.framework";
};
03A65E621C6BB0F60062603F /* SQLiteTests tvOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 03A65E701C6BB0F60062603F /* Build configuration list for PBXNativeTarget "SQLiteTests tvOS" */;
buildPhases = (
03A65E5F1C6BB0F60062603F /* Sources */,
03A65E601C6BB0F60062603F /* Frameworks */,
03A65E611C6BB0F60062603F /* Resources */,
);
buildRules = (
);
dependencies = (
03A65E661C6BB0F60062603F /* PBXTargetDependency */,
);
name = "SQLiteTests tvOS";
productName = "SQLite tvOSTests";
productReference = 03A65E631C6BB0F60062603F /* SQLiteTests tvOS.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
A121AC441CA35C79005A31D1 /* SQLite watchOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = A121AC4C1CA35C79005A31D1 /* Build configuration list for PBXNativeTarget "SQLite watchOS" */;
buildPhases = (
A121AC421CA35C79005A31D1 /* Headers */,
A121AC401CA35C79005A31D1 /* Sources */,
A121AC411CA35C79005A31D1 /* Frameworks */,
A121AC431CA35C79005A31D1 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "SQLite watchOS";
productName = "SQLite watchOS";
productReference = A121AC451CA35C79005A31D1 /* SQLite.framework */;
productType = "com.apple.product-type.framework";
};
DEB306B82B61CEF500F9D46B /* SQLite visionOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = DEB306E22B61CEF500F9D46B /* Build configuration list for PBXNativeTarget "SQLite visionOS" */;
buildPhases = (
DEB306B92B61CEF500F9D46B /* Headers */,
DEB306BB2B61CEF500F9D46B /* Sources */,
DEB306DF2B61CEF500F9D46B /* Frameworks */,
DEB306E12B61CEF500F9D46B /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "SQLite visionOS";
productName = SQLite;
productReference = DEB306E52B61CEF500F9D46B /* SQLite.framework */;
productType = "com.apple.product-type.framework";
};
DEB306E72B61CF9500F9D46B /* SQLiteTests visionOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = DEB3070E2B61CF9500F9D46B /* Build configuration list for PBXNativeTarget "SQLiteTests visionOS" */;
buildPhases = (
DEB306EA2B61CF9500F9D46B /* Sources */,
DEB3070A2B61CF9500F9D46B /* Frameworks */,
DEB3070C2B61CF9500F9D46B /* Resources */,
);
buildRules = (
);
dependencies = (
DEB307152B61D07F00F9D46B /* PBXTargetDependency */,
);
name = "SQLiteTests visionOS";
productName = "SQLite tvOSTests";
productReference = DEB307112B61CF9500F9D46B /* SQLiteTests visionOS.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
EE247AD21C3F04ED00AE3E12 /* SQLite iOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = EE247AE71C3F04ED00AE3E12 /* Build configuration list for PBXNativeTarget "SQLite iOS" */;
buildPhases = (
EE247AD01C3F04ED00AE3E12 /* Headers */,
EE247ACE1C3F04ED00AE3E12 /* Sources */,
EE247ACF1C3F04ED00AE3E12 /* Frameworks */,
EE247AD11C3F04ED00AE3E12 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "SQLite iOS";
productName = SQLite;
productReference = EE247AD31C3F04ED00AE3E12 /* SQLite.framework */;
productType = "com.apple.product-type.framework";
};
EE247ADC1C3F04ED00AE3E12 /* SQLiteTests iOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = EE247AEA1C3F04ED00AE3E12 /* Build configuration list for PBXNativeTarget "SQLiteTests iOS" */;
buildPhases = (
EE247AD91C3F04ED00AE3E12 /* Sources */,
EE247ADA1C3F04ED00AE3E12 /* Frameworks */,
EE247ADB1C3F04ED00AE3E12 /* Resources */,
);
buildRules = (
);
dependencies = (
EE247AE01C3F04ED00AE3E12 /* PBXTargetDependency */,
);
name = "SQLiteTests iOS";
productName = SQLiteTests;
productReference = EE247ADD1C3F04ED00AE3E12 /* SQLiteTests iOS.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
EE247B3B1C3F3ED000AE3E12 /* SQLite Mac */ = {
isa = PBXNativeTarget;
buildConfigurationList = EE247B511C3F3ED000AE3E12 /* Build configuration list for PBXNativeTarget "SQLite Mac" */;
buildPhases = (
EE247B391C3F3ED000AE3E12 /* Headers */,
EE247B371C3F3ED000AE3E12 /* Sources */,
EE247B381C3F3ED000AE3E12 /* Frameworks */,
EE247B3A1C3F3ED000AE3E12 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "SQLite Mac";
productName = SQLite;
productReference = EE247B3C1C3F3ED000AE3E12 /* SQLite.framework */;
productType = "com.apple.product-type.framework";
};
EE247B441C3F3ED000AE3E12 /* SQLiteTests Mac */ = {
isa = PBXNativeTarget;
buildConfigurationList = EE247B521C3F3ED000AE3E12 /* Build configuration list for PBXNativeTarget "SQLiteTests Mac" */;
buildPhases = (
EE247B411C3F3ED000AE3E12 /* Sources */,
EE247B421C3F3ED000AE3E12 /* Frameworks */,
EE247B431C3F3ED000AE3E12 /* Resources */,
);
buildRules = (
);
dependencies = (
EE247B481C3F3ED000AE3E12 /* PBXTargetDependency */,
);
name = "SQLiteTests Mac";
productName = SQLiteTests;
productReference = EE247B451C3F3ED000AE3E12 /* SQLiteTests Mac.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
EE247ACA1C3F04ED00AE3E12 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0720;
LastUpgradeCheck = 1250;
TargetAttributes = {
03A65E591C6BB0F50062603F = {
CreatedOnToolsVersion = 7.2;
LastSwiftMigration = 0900;
};
03A65E621C6BB0F60062603F = {
CreatedOnToolsVersion = 7.2;
LastSwiftMigration = 0900;
};
A121AC441CA35C79005A31D1 = {
CreatedOnToolsVersion = 7.3;
LastSwiftMigration = 0900;
};
EE247AD21C3F04ED00AE3E12 = {
CreatedOnToolsVersion = 7.2;
LastSwiftMigration = 0900;
};
EE247ADC1C3F04ED00AE3E12 = {
CreatedOnToolsVersion = 7.2;
LastSwiftMigration = 1020;
};
EE247B3B1C3F3ED000AE3E12 = {
CreatedOnToolsVersion = 7.2;
LastSwiftMigration = 0900;
};
EE247B441C3F3ED000AE3E12 = {
CreatedOnToolsVersion = 7.2;
LastSwiftMigration = 0900;
};
};
};
buildConfigurationList = EE247ACD1C3F04ED00AE3E12 /* Build configuration list for PBXProject "SQLite" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = EE247AC91C3F04ED00AE3E12;
productRefGroup = EE247AD41C3F04ED00AE3E12 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
EE247AD21C3F04ED00AE3E12 /* SQLite iOS */,
EE247ADC1C3F04ED00AE3E12 /* SQLiteTests iOS */,
EE247B3B1C3F3ED000AE3E12 /* SQLite Mac */,
EE247B441C3F3ED000AE3E12 /* SQLiteTests Mac */,
03A65E591C6BB0F50062603F /* SQLite tvOS */,
03A65E621C6BB0F60062603F /* SQLiteTests tvOS */,
A121AC441CA35C79005A31D1 /* SQLite watchOS */,
DEB306B82B61CEF500F9D46B /* SQLite visionOS */,
DEB306E72B61CF9500F9D46B /* SQLiteTests visionOS */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
03A65E581C6BB0F50062603F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
EAE5A0392B893C43007C7EA4 /* PrivacyInfo.xcprivacy in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
03A65E611C6BB0F60062603F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3DF7B79828846FED005DD8CA /* Resources in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A121AC431CA35C79005A31D1 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
EAE5A03A2B893C43007C7EA4 /* PrivacyInfo.xcprivacy in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DEB306E12B61CEF500F9D46B /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
DEB3070C2B61CF9500F9D46B /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DEB3070D2B61CF9500F9D46B /* Resources in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
EE247AD11C3F04ED00AE3E12 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
EAE5A0372B893C43007C7EA4 /* PrivacyInfo.xcprivacy in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
EE247ADB1C3F04ED00AE3E12 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3DF7B79628846FCC005DD8CA /* Resources in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
EE247B3A1C3F3ED000AE3E12 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
EAE5A0382B893C43007C7EA4 /* PrivacyInfo.xcprivacy in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
EE247B431C3F3ED000AE3E12 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3DF7B79928847055005DD8CA /* Resources in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
03A65E551C6BB0F50062603F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
03A65E801C6BB2FB0062603F /* CoreFunctions.swift in Sources */,
49EB68C61F7B3CB400D89D40 /* Coding.swift in Sources */,
03A65E761C6BB2E60062603F /* Blob.swift in Sources */,
03A65E7D1C6BB2F70062603F /* RTree.swift in Sources */,
3DF7B793288449BA005DD8CA /* URIQueryParameter.swift in Sources */,
03A65E7B1C6BB2F70062603F /* Value.swift in Sources */,
03A65E821C6BB2FB0062603F /* Expression.swift in Sources */,
03A65E731C6BB2D80062603F /* Foundation.swift in Sources */,
03A65E7F1C6BB2FB0062603F /* Collation.swift in Sources */,
03A65E861C6BB2FB0062603F /* Setter.swift in Sources */,
3DF7B78A28842972005DD8CA /* Connection+Attach.swift in Sources */,
03A65E811C6BB2FB0062603F /* CustomFunctions.swift in Sources */,
03A65E7A1C6BB2F70062603F /* Statement.swift in Sources */,
64A8EE452B095FBB00F583F7 /* WindowFunctions.swift in Sources */,
03A65E741C6BB2DA0062603F /* Helpers.swift in Sources */,
03A65E831C6BB2FB0062603F /* Operators.swift in Sources */,
03A65E851C6BB2FB0062603F /* Schema.swift in Sources */,
03A65E841C6BB2FB0062603F /* Query.swift in Sources */,
03A65E7C1C6BB2F70062603F /* FTS4.swift in Sources */,
03A65E771C6BB2E60062603F /* Connection.swift in Sources */,
03A65E7E1C6BB2FB0062603F /* AggregateFunctions.swift in Sources */,
19A17EC0D68BA8C03288ADF7 /* FTS5.swift in Sources */,
19A179E76EA6207669B60C1B /* Cipher.swift in Sources */,
02A43A9A22738CF100FEC494 /* Backup.swift in Sources */,
19A17FF4A10B44D3937C8CAC /* Errors.swift in Sources */,
19A1737286A74F3CF7412906 /* DateAndTimeFunctions.swift in Sources */,
DB7C5DA828D7C9B6006395CF /* SQLiteVersion.swift in Sources */,
19A17073552293CA063BEA66 /* Result.swift in Sources */,
997DF2B0287FC06D00F8DF95 /* Query+with.swift in Sources */,
19A179B59450FE7C4811AB8A /* Connection+Aggregation.swift in Sources */,
DB58B21828FC7C4600F8EEA4 /* SQLiteFeature.swift in Sources */,
19A17FC07731779C1B8506FA /* SchemaChanger.swift in Sources */,
19A1740EACD47904AA24B8DC /* SchemaDefinitions.swift in Sources */,
19A1750EF4A5F92954A451FF /* Connection+Schema.swift in Sources */,
19A17986405D9A875698408F /* Connection+Pragmas.swift in Sources */,
DB58B21328FB864300F8EEA4 /* SchemaReader.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
03A65E5F1C6BB0F60062603F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
03A65E951C6BB3030062603F /* TestHelpers.swift in Sources */,
19A17E04C4C0956715C5676A /* FoundationTests.swift in Sources */,
19A17F60B685636D1F83C2DD /* Fixtures.swift in Sources */,
19A17B62A4125AF4F6014CF5 /* SchemaDefinitionsTests.swift in Sources */,
19A17FC04708C6ED637DDFD4 /* SchemaChangerTests.swift in Sources */,
19A17188B4D96636F9C0C209 /* Connection+SchemaTests.swift in Sources */,
19A17FACE8E4D54A50BA934E /* FTS5Tests.swift in Sources */,
19A177909023B7B940C5805E /* FTS5IntegrationTests.swift in Sources */,
19A17E1DD976D5CE80018749 /* FTS4Tests.swift in Sources */,
DBB93D5C2A22A373009BB96E /* SchemaReaderTests.swift in Sources */,
19A17411403D60640467209E /* ExpressionTests.swift in Sources */,
19A17CA4D7B63D845428A9C5 /* StatementTests.swift in Sources */,
19A17885B646CB0201BE4BD5 /* QueryTests.swift in Sources */,
19A1708D3D58D7BC1168E55F /* CipherTests.swift in Sources */,
19A178C041DDCF80B533AD13 /* BlobTests.swift in Sources */,
19A17021286A4D8D6C2EF12D /* ConnectionTests.swift in Sources */,
19A17DE34C477232592A8F6B /* CoreFunctionsTests.swift in Sources */,
19A1799AF6643CF5081BFA15 /* DateAndTimeFunctionTests.swift in Sources */,
19A17457B0461F484AF6BE40 /* CustomFunctionsTests.swift in Sources */,
19A17900387FDCF578B31E3E /* OperatorsTests.swift in Sources */,
19A17C74233AFC2EDAFA23DC /* ResultTests.swift in Sources */,
19A17A9520802ACF45907970 /* RTreeTests.swift in Sources */,
19A17A391BF056E3D729E70A /* SchemaTests.swift in Sources */,
19A17746150A815944A6820B /* SelectTests.swift in Sources */,
19A1766135CE9786B1878603 /* ValueTests.swift in Sources */,
19A177D5C6542E2D572162E5 /* QueryIntegrationTests.swift in Sources */,
64B8E1722B09748000545AFB /* WindowFunctionsTests.swift in Sources */,
19A178DF5A96CFEFF1E271F6 /* AggregateFunctionsTests.swift in Sources */,
19A17437659BD7FD787D94A6 /* CustomAggregationTests.swift in Sources */,
19A17F907258E524B3CA2FAE /* SetterTests.swift in Sources */,
19A17ABCF0EB4808BDC5B5FF /* RowTests.swift in Sources */,
19A17BACF4C032513DE1F879 /* Connection+PragmaTests.swift in Sources */,
19A173F25449876761347072 /* Connection+AttachTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A121AC401CA35C79005A31D1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3DF7B78B28842972005DD8CA /* Connection+Attach.swift in Sources */,
49EB68C71F7B3CB400D89D40 /* Coding.swift in Sources */,
997DF2B1287FC06D00F8DF95 /* Query+with.swift in Sources */,
3D67B3F71DB246D700A4F4C6 /* Foundation.swift in Sources */,
3D67B3F81DB246D700A4F4C6 /* Helpers.swift in Sources */,
DB58B21428FB864300F8EEA4 /* SchemaReader.swift in Sources */,
3D67B3E91DB246D100A4F4C6 /* Statement.swift in Sources */,
DB7C5DA928D7C9B6006395CF /* SQLiteVersion.swift in Sources */,
3D67B3EA1DB246D100A4F4C6 /* Value.swift in Sources */,
3D67B3EB1DB246D100A4F4C6 /* FTS4.swift in Sources */,
DB58B21928FC7C4600F8EEA4 /* SQLiteFeature.swift in Sources */,
3D67B3EC1DB246D100A4F4C6 /* RTree.swift in Sources */,
3D67B3ED1DB246D100A4F4C6 /* FTS5.swift in Sources */,
3D67B3EE1DB246D100A4F4C6 /* AggregateFunctions.swift in Sources */,
3D67B3EF1DB246D100A4F4C6 /* Collation.swift in Sources */,
3D67B3F01DB246D100A4F4C6 /* CoreFunctions.swift in Sources */,
3D67B3F11DB246D100A4F4C6 /* CustomFunctions.swift in Sources */,
3D67B3F21DB246D100A4F4C6 /* Expression.swift in Sources */,
3D67B3F31DB246D100A4F4C6 /* Operators.swift in Sources */,
3DF7B794288449BA005DD8CA /* URIQueryParameter.swift in Sources */,
3D67B3F41DB246D100A4F4C6 /* Query.swift in Sources */,
3D67B3F51DB246D100A4F4C6 /* Schema.swift in Sources */,
3D67B3F61DB246D100A4F4C6 /* Setter.swift in Sources */,
3D67B3E71DB246BA00A4F4C6 /* Blob.swift in Sources */,
3D67B3E81DB246BA00A4F4C6 /* Connection.swift in Sources */,
19A179CCF9671E345E5A9811 /* Cipher.swift in Sources */,
02A43A9B22738CF100FEC494 /* Backup.swift in Sources */,
19A17DC282E36C4F41AA440B /* Errors.swift in Sources */,
19A173668D948AD4DF1F5352 /* DateAndTimeFunctions.swift in Sources */,
19A17DF8D4F13A20F5D2269E /* Result.swift in Sources */,
64A8EE462B095FBB00F583F7 /* WindowFunctions.swift in Sources */,
19A17DFE05ED8B1F7C45F7EE /* SchemaChanger.swift in Sources */,
19A17D1BEABA610ABF003D67 /* SchemaDefinitions.swift in Sources */,
19A17A33EA026C2E2CEBAF36 /* Connection+Schema.swift in Sources */,
19A178A8B2A34FB6B565DEDA /* Connection+Pragmas.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DEB306BB2B61CEF500F9D46B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DEB306BC2B61CEF500F9D46B /* CoreFunctions.swift in Sources */,
DEB306BD2B61CEF500F9D46B /* Coding.swift in Sources */,
DEB306BE2B61CEF500F9D46B /* RTree.swift in Sources */,
DEB306BF2B61CEF500F9D46B /* Blob.swift in Sources */,
DEB306C02B61CEF500F9D46B /* URIQueryParameter.swift in Sources */,
DEB306C12B61CEF500F9D46B /* Foundation.swift in Sources */,
DEB306C22B61CEF500F9D46B /* Connection.swift in Sources */,
DEB306C32B61CEF500F9D46B /* Expression.swift in Sources */,
DEB306C42B61CEF500F9D46B /* Helpers.swift in Sources */,
DEB306C52B61CEF500F9D46B /* Collation.swift in Sources */,
DEB306C62B61CEF500F9D46B /* Setter.swift in Sources */,
DEB306C72B61CEF500F9D46B /* Connection+Attach.swift in Sources */,
DEB306C82B61CEF500F9D46B /* CustomFunctions.swift in Sources */,
DEB306C92B61CEF500F9D46B /* FTS4.swift in Sources */,
DEB306CA2B61CEF500F9D46B /* Value.swift in Sources */,
DEB306CB2B61CEF500F9D46B /* Operators.swift in Sources */,
DEB306CC2B61CEF500F9D46B /* Schema.swift in Sources */,
DEB306CD2B61CEF500F9D46B /* Query.swift in Sources */,
DEB306CE2B61CEF500F9D46B /* Statement.swift in Sources */,
DEB306CF2B61CEF500F9D46B /* AggregateFunctions.swift in Sources */,
DEB306D02B61CEF500F9D46B /* FTS5.swift in Sources */,
DEB306D12B61CEF500F9D46B /* Cipher.swift in Sources */,
DEB306D22B61CEF500F9D46B /* Backup.swift in Sources */,
DEB306D32B61CEF500F9D46B /* Errors.swift in Sources */,
DEB306D42B61CEF500F9D46B /* DateAndTimeFunctions.swift in Sources */,
DEB306D52B61CEF500F9D46B /* SQLiteVersion.swift in Sources */,
DEB306D62B61CEF500F9D46B /* Result.swift in Sources */,
DEB306D72B61CEF500F9D46B /* Query+with.swift in Sources */,
DEB306D82B61CEF500F9D46B /* Connection+Aggregation.swift in Sources */,
DEB306D92B61CEF500F9D46B /* SQLiteFeature.swift in Sources */,
DEB306DA2B61CEF500F9D46B /* SchemaChanger.swift in Sources */,
DEB306DB2B61CEF500F9D46B /* SchemaDefinitions.swift in Sources */,
DEB306DC2B61CEF500F9D46B /* Connection+Schema.swift in Sources */,
DEB306DD2B61CEF500F9D46B /* Connection+Pragmas.swift in Sources */,
DEB306DE2B61CEF500F9D46B /* SchemaReader.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DEB306EA2B61CF9500F9D46B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DEB306EB2B61CF9500F9D46B /* TestHelpers.swift in Sources */,
DEB306EC2B61CF9500F9D46B /* FoundationTests.swift in Sources */,
DEB306ED2B61CF9500F9D46B /* Fixtures.swift in Sources */,
DEB306EE2B61CF9500F9D46B /* SchemaDefinitionsTests.swift in Sources */,
DEB306EF2B61CF9500F9D46B /* SchemaChangerTests.swift in Sources */,
DEB306F02B61CF9500F9D46B /* Connection+SchemaTests.swift in Sources */,
DEB306F12B61CF9500F9D46B /* FTS5Tests.swift in Sources */,
DEB306F22B61CF9500F9D46B /* FTS5IntegrationTests.swift in Sources */,
DEB306F32B61CF9500F9D46B /* FTS4Tests.swift in Sources */,
DEB306F42B61CF9500F9D46B /* ExpressionTests.swift in Sources */,
DEB306F52B61CF9500F9D46B /* StatementTests.swift in Sources */,
DEB306F62B61CF9500F9D46B /* QueryTests.swift in Sources */,
DEB306F72B61CF9500F9D46B /* CipherTests.swift in Sources */,
DEB306F82B61CF9500F9D46B /* BlobTests.swift in Sources */,
DEB306F92B61CF9500F9D46B /* ConnectionTests.swift in Sources */,
DEB306FA2B61CF9500F9D46B /* CoreFunctionsTests.swift in Sources */,
DEB306FB2B61CF9500F9D46B /* DateAndTimeFunctionTests.swift in Sources */,
DEB306FC2B61CF9500F9D46B /* CustomFunctionsTests.swift in Sources */,
DEB306FD2B61CF9500F9D46B /* OperatorsTests.swift in Sources */,
DEB306FE2B61CF9500F9D46B /* ResultTests.swift in Sources */,
DEB306FF2B61CF9500F9D46B /* RTreeTests.swift in Sources */,
DEB307002B61CF9500F9D46B /* SchemaTests.swift in Sources */,
DEB307012B61CF9500F9D46B /* SelectTests.swift in Sources */,
DEB307022B61CF9500F9D46B /* ValueTests.swift in Sources */,
DEB307032B61CF9500F9D46B /* QueryIntegrationTests.swift in Sources */,
DEB307042B61CF9500F9D46B /* AggregateFunctionsTests.swift in Sources */,
DEB307052B61CF9500F9D46B /* CustomAggregationTests.swift in Sources */,
DEB307062B61CF9500F9D46B /* SetterTests.swift in Sources */,
DEB307072B61CF9500F9D46B /* RowTests.swift in Sources */,
DEB307082B61CF9500F9D46B /* Connection+PragmaTests.swift in Sources */,
DEB307092B61CF9500F9D46B /* Connection+AttachTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
EE247ACE1C3F04ED00AE3E12 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
EE247B0F1C3F06E900AE3E12 /* CoreFunctions.swift in Sources */,
49EB68C41F7B3CB400D89D40 /* Coding.swift in Sources */,
EE247B0A1C3F06E900AE3E12 /* RTree.swift in Sources */,
EE247B031C3F06E900AE3E12 /* Blob.swift in Sources */,
3DF7B791288449BA005DD8CA /* URIQueryParameter.swift in Sources */,
EE247B0B1C3F06E900AE3E12 /* Foundation.swift in Sources */,
EE247B041C3F06E900AE3E12 /* Connection.swift in Sources */,
EE247B111C3F06E900AE3E12 /* Expression.swift in Sources */,
EE247B0C1C3F06E900AE3E12 /* Helpers.swift in Sources */,
EE247B0E1C3F06E900AE3E12 /* Collation.swift in Sources */,
EE247B151C3F06E900AE3E12 /* Setter.swift in Sources */,
3DF7B78828842972005DD8CA /* Connection+Attach.swift in Sources */,
EE247B101C3F06E900AE3E12 /* CustomFunctions.swift in Sources */,
64A8EE432B095FBB00F583F7 /* WindowFunctions.swift in Sources */,
EE247B091C3F06E900AE3E12 /* FTS4.swift in Sources */,
EE247B081C3F06E900AE3E12 /* Value.swift in Sources */,
EE247B121C3F06E900AE3E12 /* Operators.swift in Sources */,
EE247B141C3F06E900AE3E12 /* Schema.swift in Sources */,
EE247B131C3F06E900AE3E12 /* Query.swift in Sources */,
EE247B071C3F06E900AE3E12 /* Statement.swift in Sources */,
EE247B0D1C3F06E900AE3E12 /* AggregateFunctions.swift in Sources */,
19A1717B10CC941ACB5533D6 /* FTS5.swift in Sources */,
19A171F12AB8B07F2FD7201A /* Cipher.swift in Sources */,
02A43A9822738CF100FEC494 /* Backup.swift in Sources */,
19A1792C0520D4E83C2EB075 /* Errors.swift in Sources */,
19A17E29278A12BC4F542506 /* DateAndTimeFunctions.swift in Sources */,
DB7C5DA628D7C9B6006395CF /* SQLiteVersion.swift in Sources */,
19A173EFEF0B3BD0B3ED406C /* Result.swift in Sources */,
997DF2AE287FC06D00F8DF95 /* Query+with.swift in Sources */,
19A176376CB6A94759F7980A /* Connection+Aggregation.swift in Sources */,
DB58B21628FC7C4600F8EEA4 /* SQLiteFeature.swift in Sources */,
19A1773A335CAB9D0AE14E8E /* SchemaChanger.swift in Sources */,
19A17BA13FD35F058787B7D3 /* SchemaDefinitions.swift in Sources */,
19A174506543905D71BF0518 /* Connection+Schema.swift in Sources */,
19A17018F250343BD0F9F4B0 /* Connection+Pragmas.swift in Sources */,
DB58B21128FB864300F8EEA4 /* SchemaReader.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
EE247AD91C3F04ED00AE3E12 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
EE247B171C3F127200AE3E12 /* TestHelpers.swift in Sources */,
19A17FB80B94E882050AA908 /* FoundationTests.swift in Sources */,
19A17408007B182F884E3A53 /* Fixtures.swift in Sources */,
19A17FE78A39E86F330420EC /* SchemaDefinitionsTests.swift in Sources */,
19A177C25834473FAB32CF3B /* SchemaChangerTests.swift in Sources */,
19A1725658E480B9B378F28B /* Connection+SchemaTests.swift in Sources */,
19A178DA2BB5970778CCAF13 /* FTS5Tests.swift in Sources */,
19A1755C49154C87304C9146 /* FTS5IntegrationTests.swift in Sources */,
19A17444861E1443143DEB44 /* FTS4Tests.swift in Sources */,
DBB93D5A2A22A373009BB96E /* SchemaReaderTests.swift in Sources */,
19A17DD33C2E43DD6EE05A60 /* ExpressionTests.swift in Sources */,
19A17D6EC40BC35A5DC81BA8 /* StatementTests.swift in Sources */,
19A17E3F47DA087E2B76D087 /* QueryTests.swift in Sources */,
19A17A7B3E3B7E76364A2AEE /* CipherTests.swift in Sources */,
19A1782444437C7FC6B75CBC /* BlobTests.swift in Sources */,
19A17CF65C0196E03BC64519 /* ConnectionTests.swift in Sources */,
19A179BB9A6665B2B99DA546 /* CoreFunctionsTests.swift in Sources */,
19A174118D11B93DA5DAAF79 /* DateAndTimeFunctionTests.swift in Sources */,
19A17A7DF99B0379FD3396B1 /* CustomFunctionsTests.swift in Sources */,
19A171F243A589C5EBC47937 /* OperatorsTests.swift in Sources */,
19A173F429D7E46289EB2167 /* ResultTests.swift in Sources */,
19A17B1D9B5CEBE9CE09280C /* RTreeTests.swift in Sources */,
19A172F71EFD65342072D8D2 /* SchemaTests.swift in Sources */,
19A17F7977364EC8CD33C3C3 /* SelectTests.swift in Sources */,
19A17FD22EF43DF428DD93BA /* ValueTests.swift in Sources */,
19A177AA5922527BBDC77CF9 /* QueryIntegrationTests.swift in Sources */,
64B8E1702B09748000545AFB /* WindowFunctionsTests.swift in Sources */,
19A179786A6826D58A70F8BC /* AggregateFunctionsTests.swift in Sources */,
19A1793972BDDDB027C113BB /* CustomAggregationTests.swift in Sources */,
19A1773155AC2BF2CA86A473 /* SetterTests.swift in Sources */,
19A176B3316281F004F92276 /* RowTests.swift in Sources */,
19A17FBAA26953EB854E790D /* Connection+PragmaTests.swift in Sources */,
19A17026DCDCDA405B09A229 /* Connection+AttachTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
EE247B371C3F3ED000AE3E12 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
EE247B6F1C3F3FEC00AE3E12 /* CoreFunctions.swift in Sources */,
49EB68C51F7B3CB400D89D40 /* Coding.swift in Sources */,
EE247B651C3F3FEC00AE3E12 /* Blob.swift in Sources */,
EE247B6C1C3F3FEC00AE3E12 /* RTree.swift in Sources */,
3DF7B792288449BA005DD8CA /* URIQueryParameter.swift in Sources */,
EE247B6A1C3F3FEC00AE3E12 /* Value.swift in Sources */,
EE247B711C3F3FEC00AE3E12 /* Expression.swift in Sources */,
EE247B631C3F3FDB00AE3E12 /* Foundation.swift in Sources */,
EE247B6E1C3F3FEC00AE3E12 /* Collation.swift in Sources */,
EE247B751C3F3FEC00AE3E12 /* Setter.swift in Sources */,
3DF7B78928842972005DD8CA /* Connection+Attach.swift in Sources */,
EE247B701C3F3FEC00AE3E12 /* CustomFunctions.swift in Sources */,
EE247B691C3F3FEC00AE3E12 /* Statement.swift in Sources */,
64A8EE442B095FBB00F583F7 /* WindowFunctions.swift in Sources */,
EE247B641C3F3FDB00AE3E12 /* Helpers.swift in Sources */,
EE247B721C3F3FEC00AE3E12 /* Operators.swift in Sources */,
EE247B741C3F3FEC00AE3E12 /* Schema.swift in Sources */,
EE247B731C3F3FEC00AE3E12 /* Query.swift in Sources */,
EE247B6B1C3F3FEC00AE3E12 /* FTS4.swift in Sources */,
EE247B661C3F3FEC00AE3E12 /* Connection.swift in Sources */,
EE247B6D1C3F3FEC00AE3E12 /* AggregateFunctions.swift in Sources */,
19A1750CEE9B05267995CF3D /* FTS5.swift in Sources */,
19A17835FD5886FDC5A3228F /* Cipher.swift in Sources */,
02A43A9922738CF100FEC494 /* Backup.swift in Sources */,
19A17490543609FCED53CACC /* Errors.swift in Sources */,
19A17152E32A9585831E3FE0 /* DateAndTimeFunctions.swift in Sources */,
DB7C5DA728D7C9B6006395CF /* SQLiteVersion.swift in Sources */,
19A17F1B3F0A3C96B5ED6D64 /* Result.swift in Sources */,
997DF2AF287FC06D00F8DF95 /* Query+with.swift in Sources */,
19A170ACC97B19730FB7BA4D /* Connection+Aggregation.swift in Sources */,
DB58B21728FC7C4600F8EEA4 /* SQLiteFeature.swift in Sources */,
19A177290558991BCC60E4E3 /* SchemaChanger.swift in Sources */,
19A17B0DF1DDB6BBC9C95D64 /* SchemaDefinitions.swift in Sources */,
19A17F0BF02896E1664F4090 /* Connection+Schema.swift in Sources */,
19A1760CE25615CA015E2E5F /* Connection+Pragmas.swift in Sources */,
DB58B21228FB864300F8EEA4 /* SchemaReader.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
EE247B411C3F3ED000AE3E12 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
EE247B611C3F3FC700AE3E12 /* TestHelpers.swift in Sources */,
19A178072B371489E6A1E839 /* FoundationTests.swift in Sources */,
19A1709C3E7A406E62293B2A /* Fixtures.swift in Sources */,
19A17E80F736EEE8EE2AA4CE /* SchemaDefinitionsTests.swift in Sources */,
19A1766AC10D13C4EFF349AD /* SchemaChangerTests.swift in Sources */,
19A17B36ABC6006AB80F693C /* Connection+SchemaTests.swift in Sources */,
19A1776BD5127DFDF847FF1F /* FTS5Tests.swift in Sources */,
19A173088B85A7E18E8582A7 /* FTS5IntegrationTests.swift in Sources */,
19A178767223229E61C5066F /* FTS4Tests.swift in Sources */,
DBB93D5B2A22A373009BB96E /* SchemaReaderTests.swift in Sources */,
19A1781CBA8968ABD3E00877 /* ExpressionTests.swift in Sources */,
19A17923494236793893BF72 /* StatementTests.swift in Sources */,
19A17A52BF29D27C9AA229E7 /* QueryTests.swift in Sources */,
19A17CA6ADB78A2E545BF836 /* CipherTests.swift in Sources */,
19A1714F7CF964D568AB14E0 /* BlobTests.swift in Sources */,
19A173465F23C64DF3DF469B /* ConnectionTests.swift in Sources */,
19A17D993398B8215B73E1EA /* CoreFunctionsTests.swift in Sources */,
19A170AEBAA56DC3355A73B3 /* DateAndTimeFunctionTests.swift in Sources */,
19A1716BF8E15F91A6B5CB7A /* CustomFunctionsTests.swift in Sources */,
19A17482E6FC5E563F3E6A47 /* OperatorsTests.swift in Sources */,
19A17912DB9D3AC8FECF948B /* ResultTests.swift in Sources */,
19A17DAD5975D9367EAA46E2 /* RTreeTests.swift in Sources */,
19A17F2096E83A3181E03317 /* SchemaTests.swift in Sources */,
19A17DE1FCDB5695702AD24D /* SelectTests.swift in Sources */,
19A1726002D24C14F876C8FE /* ValueTests.swift in Sources */,
19A173389E53CB24DFA8CEDD /* QueryIntegrationTests.swift in Sources */,
64B8E1712B09748000545AFB /* WindowFunctionsTests.swift in Sources */,
19A170C56745F9D722A73D77 /* AggregateFunctionsTests.swift in Sources */,
19A1772EBE65173EDFB1AFCA /* CustomAggregationTests.swift in Sources */,
19A17E0ABA6C415F014CD51C /* SetterTests.swift in Sources */,
19A170D938343E30119EDFB3 /* RowTests.swift in Sources */,
19A178F9008614B8A8425635 /* Connection+PragmaTests.swift in Sources */,
19A179BCD483DEA21661FD37 /* Connection+AttachTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
03A65E661C6BB0F60062603F /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 03A65E591C6BB0F50062603F /* SQLite tvOS */;
targetProxy = 03A65E651C6BB0F60062603F /* PBXContainerItemProxy */;
};
DEB307152B61D07F00F9D46B /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = DEB306B82B61CEF500F9D46B /* SQLite visionOS */;
targetProxy = DEB307142B61D07F00F9D46B /* PBXContainerItemProxy */;
};
EE247AE01C3F04ED00AE3E12 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = EE247AD21C3F04ED00AE3E12 /* SQLite iOS */;
targetProxy = EE247ADF1C3F04ED00AE3E12 /* PBXContainerItemProxy */;
};
EE247B481C3F3ED000AE3E12 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = EE247B3B1C3F3ED000AE3E12 /* SQLite Mac */;
targetProxy = EE247B471C3F3ED000AE3E12 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
03A65E6B1C6BB0F60062603F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite;
PRODUCT_NAME = SQLite;
SDKROOT = appletvos;
SKIP_INSTALL = YES;
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
TVOS_DEPLOYMENT_TARGET = 12.0;
};
name = Debug;
};
03A65E6C1C6BB0F60062603F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite;
PRODUCT_NAME = SQLite;
SDKROOT = appletvos;
SKIP_INSTALL = YES;
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
TVOS_DEPLOYMENT_TARGET = 12.0;
};
name = Release;
};
03A65E6D1C6BB0F60062603F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = Tests/SQLiteTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
TVOS_DEPLOYMENT_TARGET = 12.0;
};
name = Debug;
};
03A65E6E1C6BB0F60062603F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = Tests/SQLiteTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
TVOS_DEPLOYMENT_TARGET = 12.0;
};
name = Release;
};
A121AC4A1CA35C79005A31D1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ANALYZER_NONNULL = YES;
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite;
PRODUCT_NAME = SQLite;
SDKROOT = watchos;
SKIP_INSTALL = YES;
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 4.0;
};
name = Debug;
};
A121AC4B1CA35C79005A31D1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ANALYZER_NONNULL = YES;
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite;
PRODUCT_NAME = SQLite;
SDKROOT = watchos;
SKIP_INSTALL = YES;
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 4.0;
};
name = Release;
};
DEB306E32B61CEF500F9D46B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite;
PRODUCT_NAME = SQLite;
SDKROOT = xros;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
TARGETED_DEVICE_FAMILY = 7;
};
name = Debug;
};
DEB306E42B61CEF500F9D46B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite;
PRODUCT_NAME = SQLite;
SDKROOT = xros;
SKIP_INSTALL = YES;
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
TARGETED_DEVICE_FAMILY = 7;
};
name = Release;
};
DEB3070F2B61CF9500F9D46B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = Tests/SQLiteTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = xros;
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
TARGETED_DEVICE_FAMILY = 7;
};
name = Debug;
};
DEB307102B61CF9500F9D46B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = Tests/SQLiteTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = xros;
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
TARGETED_DEVICE_FAMILY = 7;
};
name = Release;
};
EE247AE51C3F04ED00AE3E12 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 0.16.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = "";
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2,3";
TVOS_DEPLOYMENT_TARGET = 12.0;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
WATCHOS_DEPLOYMENT_TARGET = 4.0;
};
name = Debug;
};
EE247AE61C3F04ED00AE3E12 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 0.16.0;
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_NAME = "";
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2,3";
TVOS_DEPLOYMENT_TARGET = 12.0;
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
WATCHOS_DEPLOYMENT_TARGET = 4.0;
};
name = Release;
};
EE247AE81C3F04ED00AE3E12 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite;
PRODUCT_NAME = SQLite;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
};
name = Debug;
};
EE247AE91C3F04ED00AE3E12 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite;
PRODUCT_NAME = SQLite;
SKIP_INSTALL = YES;
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
};
name = Release;
};
EE247AEB1C3F04ED00AE3E12 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = Tests/SQLiteTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
};
name = Debug;
};
EE247AEC1C3F04ED00AE3E12 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = Tests/SQLiteTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
};
name = Release;
};
EE247B4D1C3F3ED000AE3E12 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CODE_SIGN_IDENTITY = "";
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.13;
PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite;
PRODUCT_NAME = SQLite;
SDKROOT = macosx;
SKIP_INSTALL = YES;
SWIFT_INCLUDE_PATHS = "";
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
};
name = Debug;
};
EE247B4E1C3F3ED000AE3E12 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CODE_SIGN_IDENTITY = "";
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = "$(SRCROOT)/Sources/SQLite/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.13;
PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLite;
PRODUCT_NAME = SQLite;
SDKROOT = macosx;
SKIP_INSTALL = YES;
SWIFT_INCLUDE_PATHS = "";
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
};
name = Release;
};
EE247B4F1C3F3ED000AE3E12 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
COMBINE_HIDPI_IMAGES = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = Tests/SQLiteTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.13;
PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
};
name = Debug;
};
EE247B501C3F3ED000AE3E12 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
COMBINE_HIDPI_IMAGES = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INFOPLIST_FILE = Tests/SQLiteTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.13;
PRODUCT_BUNDLE_IDENTIFIER = com.stephencelis.SQLiteTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
03A65E6F1C6BB0F60062603F /* Build configuration list for PBXNativeTarget "SQLite tvOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
03A65E6B1C6BB0F60062603F /* Debug */,
03A65E6C1C6BB0F60062603F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
03A65E701C6BB0F60062603F /* Build configuration list for PBXNativeTarget "SQLiteTests tvOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
03A65E6D1C6BB0F60062603F /* Debug */,
03A65E6E1C6BB0F60062603F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
A121AC4C1CA35C79005A31D1 /* Build configuration list for PBXNativeTarget "SQLite watchOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A121AC4A1CA35C79005A31D1 /* Debug */,
A121AC4B1CA35C79005A31D1 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
DEB306E22B61CEF500F9D46B /* Build configuration list for PBXNativeTarget "SQLite visionOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DEB306E32B61CEF500F9D46B /* Debug */,
DEB306E42B61CEF500F9D46B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
DEB3070E2B61CF9500F9D46B /* Build configuration list for PBXNativeTarget "SQLiteTests visionOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DEB3070F2B61CF9500F9D46B /* Debug */,
DEB307102B61CF9500F9D46B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
EE247ACD1C3F04ED00AE3E12 /* Build configuration list for PBXProject "SQLite" */ = {
isa = XCConfigurationList;
buildConfigurations = (
EE247AE51C3F04ED00AE3E12 /* Debug */,
EE247AE61C3F04ED00AE3E12 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
EE247AE71C3F04ED00AE3E12 /* Build configuration list for PBXNativeTarget "SQLite iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
EE247AE81C3F04ED00AE3E12 /* Debug */,
EE247AE91C3F04ED00AE3E12 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
EE247AEA1C3F04ED00AE3E12 /* Build configuration list for PBXNativeTarget "SQLiteTests iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
EE247AEB1C3F04ED00AE3E12 /* Debug */,
EE247AEC1C3F04ED00AE3E12 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
EE247B511C3F3ED000AE3E12 /* Build configuration list for PBXNativeTarget "SQLite Mac" */ = {
isa = XCConfigurationList;
buildConfigurations = (
EE247B4D1C3F3ED000AE3E12 /* Debug */,
EE247B4E1C3F3ED000AE3E12 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
EE247B521C3F3ED000AE3E12 /* Build configuration list for PBXNativeTarget "SQLiteTests Mac" */ = {
isa = XCConfigurationList;
buildConfigurations = (
EE247B4F1C3F3ED000AE3E12 /* Debug */,
EE247B501C3F3ED000AE3E12 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = EE247ACA1C3F04ED00AE3E12 /* Project object */;
}
================================================
FILE: SQLite.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: SQLite.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
IDEDidComputeMac32BitWarning
================================================
FILE: SQLite.xcodeproj/xcshareddata/xcschemes/SQLite Mac.xcscheme
================================================
================================================
FILE: SQLite.xcodeproj/xcshareddata/xcschemes/SQLite iOS.xcscheme
================================================
================================================
FILE: SQLite.xcodeproj/xcshareddata/xcschemes/SQLite tvOS.xcscheme
================================================
================================================
FILE: SQLite.xcodeproj/xcshareddata/xcschemes/SQLite visionOS.xcscheme
================================================
================================================
FILE: SQLite.xcodeproj/xcshareddata/xcschemes/SQLite watchOS.xcscheme
================================================
================================================
FILE: Sources/SQLite/Core/Backup.swift
================================================
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import Foundation
import Dispatch
#if StandaloneSQLite
import sqlite3
#elseif SQLCipher
import SQLCipher
#elseif SQLiteSwiftCSQLite
import SQLiteSwiftCSQLite
#else
import SQLite3 // SystemSQLite
#endif
/// An object representing database backup.
///
/// See:
public final class Backup {
/// The name of the database to backup
public enum DatabaseName {
/// The main database
case main
/// The temporary database
case temp
/// A database added to the connection with ATTACH statement
case attached(name: String)
var name: String {
switch self {
case .main:
return "main"
case .temp:
return "temp"
case .attached(let name):
return name
}
}
}
/// Number of pages to copy while performing a backup step
public enum Pages {
/// Indicates all remaining pages should be copied
case all
/// Indicates the maximal number of pages to be copied in single step
case limited(number: Int32)
var number: Int32 {
switch self {
case .all:
return -1
case .limited(let number):
return number
}
}
}
/// Total number of pages to copy
///
/// See:
public var pageCount: Int32 {
return handle.map { sqlite3_backup_pagecount($0) } ?? 0
}
/// Number of remaining pages to copy.
///
/// See:
public var remainingPages: Int32 {
return handle.map { sqlite3_backup_remaining($0) } ?? 0
}
private let targetConnection: Connection
private let sourceConnection: Connection
private var handle: OpaquePointer?
/// Initializes a new SQLite backup.
///
/// - Parameters:
///
/// - sourceConnection: The connection to the database to backup.
/// - sourceName: The name of the database to backup.
/// Default: `.main`.
///
/// - targetConnection: The connection to the database to save backup into.
/// - targetName: The name of the database to save backup into.
/// Default: `.main`.
///
/// - Returns: A new database backup.
///
/// See:
public init(sourceConnection: Connection,
sourceName: DatabaseName = .main,
targetConnection: Connection,
targetName: DatabaseName = .main) throws {
self.targetConnection = targetConnection
self.sourceConnection = sourceConnection
self.handle = sqlite3_backup_init(targetConnection.handle,
targetName.name,
sourceConnection.handle,
sourceName.name)
if handle == nil, let error = Result(errorCode: sqlite3_errcode(targetConnection.handle),
connection: targetConnection) {
throw error
}
}
/// Performs a backup step.
///
/// - Parameter pagesToCopy: The maximal number of pages to copy in one step
///
/// - Throws: `Result.Error` if step fails.
///
/// See:
public func step(pagesToCopy pages: Pages = .all) throws {
let status = sqlite3_backup_step(handle, pages.number)
guard status != SQLITE_DONE else {
finish()
return
}
if let error = Result(errorCode: status, connection: targetConnection) {
throw error
}
}
/// Finalizes backup.
///
/// See:
public func finish() {
guard let handle = self.handle else {
return
}
sqlite3_backup_finish(handle)
self.handle = nil
}
deinit {
finish()
}
}
================================================
FILE: Sources/SQLite/Core/Blob.swift
================================================
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
public struct Blob: Sendable {
public let bytes: [UInt8]
public init(bytes: [UInt8]) {
self.bytes = bytes
}
public init(bytes: UnsafeRawPointer, length: Int) {
let i8bufptr = UnsafeBufferPointer(start: bytes.assumingMemoryBound(to: UInt8.self), count: length)
self.init(bytes: [UInt8](i8bufptr))
}
public func toHex() -> String {
bytes.map {
($0 < 16 ? "0" : "") + String($0, radix: 16, uppercase: false)
}.joined(separator: "")
}
}
extension Blob: CustomStringConvertible {
public var description: String {
"x'\(toHex())'"
}
}
extension Blob: Equatable {
}
public func ==(lhs: Blob, rhs: Blob) -> Bool {
lhs.bytes == rhs.bytes
}
================================================
FILE: Sources/SQLite/Core/Connection+Aggregation.swift
================================================
import Foundation
#if StandaloneSQLite
import sqlite3
#elseif SQLCipher
import SQLCipher
#elseif SQLiteSwiftCSQLite
import SQLiteSwiftCSQLite
#else
import SQLite3 // SystemSQLite
#endif
extension Connection {
private typealias Aggregate = @convention(block) (Int, Context, Int32, Argv) -> Void
/// Creates or redefines a custom SQL aggregate.
///
/// - Parameters:
///
/// - aggregate: The name of the aggregate to create or redefine.
///
/// - argumentCount: The number of arguments that the aggregate takes. If
/// `nil`, the aggregate may take any number of arguments.
///
/// Default: `nil`
///
/// - deterministic: Whether or not the aggregate is deterministic (_i.e._
/// the aggregate always returns the same result for a given input).
///
/// Default: `false`
///
/// - step: A block of code to run for each row of an aggregation group.
/// The block is called with an array of raw SQL values mapped to the
/// aggregate’s parameters, and an UnsafeMutablePointer to a state
/// variable.
///
/// - final: A block of code to run after each row of an aggregation group
/// is processed. The block is called with an UnsafeMutablePointer to a
/// state variable, and should return a raw SQL value (or nil).
///
/// - state: A block of code to run to produce a fresh state variable for
/// each aggregation group. The block should return an
/// UnsafeMutablePointer to the fresh state variable.
public func createAggregation(
_ functionName: String,
argumentCount: UInt? = nil,
deterministic: Bool = false,
step: @escaping ([Binding?], UnsafeMutablePointer) -> Void,
final: @escaping (UnsafeMutablePointer) -> Binding?,
state: @escaping () -> UnsafeMutablePointer) {
let argc = argumentCount.map { Int($0) } ?? -1
let box: Aggregate = { (stepFlag: Int, context: Context, argc: Int32, argv: Argv) in
let nBytes = Int32(MemoryLayout>.size)
guard let aggregateContext = sqlite3_aggregate_context(context, nBytes) else {
fatalError("Could not get aggregate context")
}
let mutablePointer = aggregateContext.assumingMemoryBound(to: UnsafeMutableRawPointer.self)
if stepFlag > 0 {
let arguments = argv.getBindings(argc: argc)
if aggregateContext.assumingMemoryBound(to: Int64.self).pointee == 0 {
mutablePointer.pointee = UnsafeMutableRawPointer(mutating: state())
}
step(arguments, mutablePointer.pointee.assumingMemoryBound(to: T.self))
} else {
let result = final(mutablePointer.pointee.assumingMemoryBound(to: T.self))
context.set(result: result)
}
}
func xStep(context: Context, argc: Int32, value: Argv) {
unsafeBitCast(sqlite3_user_data(context), to: Aggregate.self)(1, context, argc, value)
}
func xFinal(context: Context) {
unsafeBitCast(sqlite3_user_data(context), to: Aggregate.self)(0, context, 0, nil)
}
let flags = SQLITE_UTF8 | (deterministic ? SQLITE_DETERMINISTIC : 0)
let resultCode = sqlite3_create_function_v2(
handle,
functionName,
Int32(argc),
flags,
/* pApp */ unsafeBitCast(box, to: UnsafeMutableRawPointer.self),
/* xFunc */ nil, xStep, xFinal, /* xDestroy */ nil
)
if let result = Result(errorCode: resultCode, connection: self) {
fatalError("Error creating function: \(result)")
}
register(functionName, argc: argc, value: box)
}
public func createAggregation(
_ aggregate: String,
argumentCount: UInt? = nil,
deterministic: Bool = false,
initialValue: T,
reduce: @escaping (T, [Binding?]) -> T,
result: @escaping (T) -> Binding?
) {
let step: ([Binding?], UnsafeMutablePointer) -> Void = { (bindings, ptr) in
let pointer = ptr.pointee.assumingMemoryBound(to: T.self)
let current = Unmanaged.fromOpaque(pointer).takeRetainedValue()
let next = reduce(current, bindings)
ptr.pointee = Unmanaged.passRetained(next).toOpaque()
}
let final: (UnsafeMutablePointer) -> Binding? = { ptr in
let pointer = ptr.pointee.assumingMemoryBound(to: T.self)
let obj = Unmanaged.fromOpaque(pointer).takeRetainedValue()
let value = result(obj)
ptr.deallocate()
return value
}
let state: () -> UnsafeMutablePointer = {
let pointer = UnsafeMutablePointer.allocate(capacity: 1)
pointer.pointee = Unmanaged.passRetained(initialValue).toOpaque()
return pointer
}
createAggregation(aggregate, step: step, final: final, state: state)
}
public func createAggregation(
_ aggregate: String,
argumentCount: UInt? = nil,
deterministic: Bool = false,
initialValue: T,
reduce: @escaping (T, [Binding?]) -> T,
result: @escaping (T) -> Binding?
) {
let step: ([Binding?], UnsafeMutablePointer) -> Void = { (bindings, pointer) in
let current = pointer.pointee
let next = reduce(current, bindings)
pointer.pointee = next
}
let final: (UnsafeMutablePointer) -> Binding? = { pointer in
let value = result(pointer.pointee)
pointer.deallocate()
return value
}
let state: () -> UnsafeMutablePointer = {
let pointer = UnsafeMutablePointer.allocate(capacity: 1)
pointer.initialize(to: initialValue)
return pointer
}
createAggregation(aggregate, step: step, final: final, state: state)
}
}
================================================
FILE: Sources/SQLite/Core/Connection+Attach.swift
================================================
import Foundation
extension Connection {
#if SQLCipher
/// See https://www.zetetic.net/sqlcipher/sqlcipher-api/#attach
public func attach(_ location: Location, as schemaName: String, key: String? = nil) throws {
if let key {
try run("ATTACH DATABASE ? AS ? KEY ?", location.description, schemaName, key)
} else {
try run("ATTACH DATABASE ? AS ?", location.description, schemaName)
}
}
#else
/// See https://www3.sqlite.org/lang_attach.html
public func attach(_ location: Location, as schemaName: String) throws {
try run("ATTACH DATABASE ? AS ?", location.description, schemaName)
}
#endif
/// See https://www3.sqlite.org/lang_detach.html
public func detach(_ schemaName: String) throws {
try run("DETACH DATABASE ?", schemaName)
}
}
================================================
FILE: Sources/SQLite/Core/Connection+Pragmas.swift
================================================
import Foundation
public typealias UserVersion = Int32
public extension Connection {
/// The user version of the database.
/// See SQLite [PRAGMA user_version](https://sqlite.org/pragma.html#pragma_user_version)
var userVersion: UserVersion? {
get {
(try? scalar("PRAGMA user_version") as? Int64)?.map(Int32.init)
}
set {
_ = try? run("PRAGMA user_version = \(newValue ?? 0)")
}
}
/// The version of SQLite.
/// See SQLite [sqlite_version()](https://sqlite.org/lang_corefunc.html#sqlite_version)
var sqliteVersion: SQLiteVersion {
guard let version = (try? scalar("SELECT sqlite_version()")) as? String,
let splits = .some(version.split(separator: ".", maxSplits: 3)), splits.count == 3,
let major = Int(splits[0]), let minor = Int(splits[1]), let point = Int(splits[2]) else {
return .zero
}
return .init(major: major, minor: minor, point: point)
}
// Changing the foreign_keys setting affects the execution of all statements prepared using the database
// connection, including those prepared before the setting was changed.
//
// https://sqlite.org/pragma.html#pragma_foreign_keys
var foreignKeys: Bool {
get { getBoolPragma("foreign_keys") }
set { setBoolPragma("foreign_keys", newValue) }
}
var deferForeignKeys: Bool {
get { getBoolPragma("defer_foreign_keys") }
set { setBoolPragma("defer_foreign_keys", newValue) }
}
private func getBoolPragma(_ key: String) -> Bool {
guard let binding = try? scalar("PRAGMA \(key)"),
let intBinding = binding as? Int64 else { return false }
return intBinding == 1
}
private func setBoolPragma(_ key: String, _ newValue: Bool) {
_ = try? run("PRAGMA \(key) = \(newValue ? "1" : "0")")
}
}
================================================
FILE: Sources/SQLite/Core/Connection.swift
================================================
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import Foundation
import Dispatch
#if StandaloneSQLite
import sqlite3
#elseif SQLCipher
import SQLCipher
#elseif SQLiteSwiftCSQLite
import SQLiteSwiftCSQLite
#else
import SQLite3 // SystemSQLite
#endif
/// A connection to SQLite.
public final class Connection {
/// The location of a SQLite database.
public enum Location {
/// An in-memory database (equivalent to `.uri(":memory:")`).
///
/// See:
case inMemory
/// A temporary, file-backed database (equivalent to `.uri("")`).
///
/// See:
case temporary
/// A database located at the given URI filename (or path).
///
/// See:
///
/// - Parameter filename: A URI filename
/// - Parameter parameters: optional query parameters
case uri(String, parameters: [URIQueryParameter] = [])
}
/// An SQL operation passed to update callbacks.
public enum Operation {
/// An INSERT operation.
case insert
/// An UPDATE operation.
case update
/// A DELETE operation.
case delete
fileprivate init(rawValue: Int32) {
switch rawValue {
case SQLITE_INSERT:
self = .insert
case SQLITE_UPDATE:
self = .update
case SQLITE_DELETE:
self = .delete
default:
fatalError("unhandled operation code: \(rawValue)")
}
}
}
public var handle: OpaquePointer { _handle! }
fileprivate var _handle: OpaquePointer?
/// Initializes a new SQLite connection.
///
/// - Parameters:
///
/// - location: The location of the database. Creates a new database if it
/// doesn’t already exist (unless in read-only mode).
///
/// Default: `.inMemory`.
///
/// - readonly: Whether or not to open the database in a read-only state.
///
/// Default: `false`.
///
/// - Returns: A new database connection.
public init(_ location: Location = .inMemory, readonly: Bool = false) throws {
let flags = readonly ? SQLITE_OPEN_READONLY : (SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE)
try check(sqlite3_open_v2(location.description,
&_handle,
flags | SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_URI,
nil))
queue.setSpecific(key: Connection.queueKey, value: queueContext)
}
/// Initializes a new connection to a database.
///
/// - Parameters:
///
/// - filename: The location of the database. Creates a new database if
/// it doesn’t already exist (unless in read-only mode).
///
/// - readonly: Whether or not to open the database in a read-only state.
///
/// Default: `false`.
///
/// - Throws: `Result.Error` iff a connection cannot be established.
///
/// - Returns: A new database connection.
public convenience init(_ filename: String, readonly: Bool = false) throws {
try self.init(.uri(filename), readonly: readonly)
}
deinit {
sqlite3_close(handle)
}
// MARK: -
/// Whether or not the database was opened in a read-only state.
public var readonly: Bool { sqlite3_db_readonly(handle, nil) == 1 }
/// The last rowid inserted into the database via this connection.
public var lastInsertRowid: Int64 {
sqlite3_last_insert_rowid(handle)
}
/// The last number of changes (inserts, updates, or deletes) made to the
/// database via this connection.
public var changes: Int {
Int(sqlite3_changes(handle))
}
/// The total number of changes (inserts, updates, or deletes) made to the
/// database via this connection.
public var totalChanges: Int {
Int(sqlite3_total_changes(handle))
}
/// Whether or not the database will return extended error codes when errors are handled.
public var usesExtendedErrorCodes: Bool = false {
didSet {
sqlite3_extended_result_codes(handle, usesExtendedErrorCodes ? 1 : 0)
}
}
// MARK: - Execute
/// Executes a batch of SQL statements.
///
/// - Parameter SQL: A batch of zero or more semicolon-separated SQL
/// statements.
///
/// - Throws: `Result.Error` if query execution fails.
public func execute(_ SQL: String) throws {
_ = try sync { try check(sqlite3_exec(handle, SQL, nil, nil, nil)) }
}
// MARK: - Prepare
/// Prepares a single SQL statement (with optional parameter bindings).
///
/// - Parameters:
///
/// - statement: A single SQL statement.
///
/// - bindings: A list of parameters to bind to the statement.
///
/// - Returns: A prepared statement.
public func prepare(_ statement: String, _ bindings: Binding?...) throws -> Statement {
if !bindings.isEmpty { return try prepare(statement, bindings) }
return try Statement(self, statement)
}
/// Prepares a single SQL statement and binds parameters to it.
///
/// - Parameters:
///
/// - statement: A single SQL statement.
///
/// - bindings: A list of parameters to bind to the statement.
///
/// - Returns: A prepared statement.
public func prepare(_ statement: String, _ bindings: [Binding?]) throws -> Statement {
try prepare(statement).bind(bindings)
}
/// Prepares a single SQL statement and binds parameters to it.
///
/// - Parameters:
///
/// - statement: A single SQL statement.
///
/// - bindings: A dictionary of named parameters to bind to the statement.
///
/// - Returns: A prepared statement.
public func prepare(_ statement: String, _ bindings: [String: Binding?]) throws -> Statement {
try prepare(statement).bind(bindings)
}
// MARK: - Run
/// Runs a single SQL statement (with optional parameter bindings).
///
/// - Parameters:
///
/// - statement: A single SQL statement.
///
/// - bindings: A list of parameters to bind to the statement.
///
/// - Throws: `Result.Error` if query execution fails.
///
/// - Returns: The statement.
@discardableResult public func run(_ statement: String, _ bindings: Binding?...) throws -> Statement {
try run(statement, bindings)
}
/// Prepares, binds, and runs a single SQL statement.
///
/// - Parameters:
///
/// - statement: A single SQL statement.
///
/// - bindings: A list of parameters to bind to the statement.
///
/// - Throws: `Result.Error` if query execution fails.
///
/// - Returns: The statement.
@discardableResult public func run(_ statement: String, _ bindings: [Binding?]) throws -> Statement {
try prepare(statement).run(bindings)
}
/// Prepares, binds, and runs a single SQL statement.
///
/// - Parameters:
///
/// - statement: A single SQL statement.
///
/// - bindings: A dictionary of named parameters to bind to the statement.
///
/// - Throws: `Result.Error` if query execution fails.
///
/// - Returns: The statement.
@discardableResult public func run(_ statement: String, _ bindings: [String: Binding?]) throws -> Statement {
try prepare(statement).run(bindings)
}
// MARK: - VACUUM
/// Run a vacuum on the database
///
/// - Throws: `Result.Error` if query execution fails.
///
/// - Returns: The statement.
@discardableResult public func vacuum() throws -> Statement {
try run("VACUUM")
}
// MARK: - Scalar
/// Runs a single SQL statement (with optional parameter bindings),
/// returning the first value of the first row.
///
/// - Parameters:
///
/// - statement: A single SQL statement.
///
/// - bindings: A list of parameters to bind to the statement.
///
/// - Returns: The first value of the first row returned.
public func scalar(_ statement: String, _ bindings: Binding?...) throws -> Binding? {
try scalar(statement, bindings)
}
/// Runs a single SQL statement (with optional parameter bindings),
/// returning the first value of the first row.
///
/// - Parameters:
///
/// - statement: A single SQL statement.
///
/// - bindings: A list of parameters to bind to the statement.
///
/// - Returns: The first value of the first row returned.
public func scalar(_ statement: String, _ bindings: [Binding?]) throws -> Binding? {
try prepare(statement).scalar(bindings)
}
/// Runs a single SQL statement (with optional parameter bindings),
/// returning the first value of the first row.
///
/// - Parameters:
///
/// - statement: A single SQL statement.
///
/// - bindings: A dictionary of named parameters to bind to the statement.
///
/// - Returns: The first value of the first row returned.
public func scalar(_ statement: String, _ bindings: [String: Binding?]) throws -> Binding? {
try prepare(statement).scalar(bindings)
}
// MARK: - Transactions
/// The mode in which a transaction acquires a lock.
public enum TransactionMode: String {
/// Defers locking the database till the first read/write executes.
case deferred = "DEFERRED"
/// Immediately acquires a reserved lock on the database.
case immediate = "IMMEDIATE"
/// Immediately acquires an exclusive lock on all databases.
case exclusive = "EXCLUSIVE"
}
// TODO: Consider not requiring a throw to roll back?
/// Runs a transaction with the given mode.
///
/// - Note: Transactions cannot be nested. To nest transactions, see
/// `savepoint()`, instead.
///
/// - Parameters:
///
/// - mode: The mode in which a transaction acquires a lock.
///
/// Default: `.deferred`
///
/// - block: A closure to run SQL statements within the transaction.
/// The transaction will be committed when the block returns. The block
/// must throw to roll the transaction back.
///
/// - Throws: `Result.Error`, and rethrows.
public func transaction(_ mode: TransactionMode = .deferred, block: () throws -> Void) throws {
try transaction("BEGIN \(mode.rawValue) TRANSACTION", block, "COMMIT TRANSACTION", or: "ROLLBACK TRANSACTION")
}
// TODO: Consider not requiring a throw to roll back?
// TODO: Consider removing ability to set a name?
/// Runs a transaction with the given savepoint name (if omitted, it will
/// generate a UUID).
///
/// - SeeAlso: `transaction()`.
///
/// - Parameters:
///
/// - savepointName: A unique identifier for the savepoint (optional).
///
/// - block: A closure to run SQL statements within the transaction.
/// The savepoint will be released (committed) when the block returns.
/// The block must throw to roll the savepoint back.
///
/// - Throws: `SQLite.Result.Error`, and rethrows.
public func savepoint(_ name: String = UUID().uuidString, block: () throws -> Void) throws {
let name = name.quote("'")
let savepoint = "SAVEPOINT \(name)"
try transaction(savepoint, block, "RELEASE \(savepoint)", or: "ROLLBACK TO \(savepoint)")
}
fileprivate func transaction(_ begin: String, _ block: () throws -> Void, _ commit: String, or rollback: String) throws {
return try sync {
try self.run(begin)
do {
try block()
try self.run(commit)
} catch {
try self.run(rollback)
throw error
}
}
}
/// Interrupts any long-running queries.
public func interrupt() {
sqlite3_interrupt(handle)
}
// MARK: - Handlers
/// The number of seconds a connection will attempt to retry a statement
/// after encountering a busy signal (lock).
public var busyTimeout: Double = 0 {
didSet {
sqlite3_busy_timeout(handle, Int32(busyTimeout * 1_000))
}
}
/// Sets a handler to call after encountering a busy signal (lock).
///
/// - Parameter callback: This block is executed during a lock in which a
/// busy error would otherwise be returned. It’s passed the number of
/// times it’s been called for this lock. If it returns `true`, it will
/// try again. If it returns `false`, no further attempts will be made.
public func busyHandler(_ callback: ((_ tries: Int) -> Bool)?) {
guard let callback else {
sqlite3_busy_handler(handle, nil, nil)
busyHandler = nil
return
}
let box: BusyHandler = { callback(Int($0)) ? 1 : 0 }
sqlite3_busy_handler(handle, { callback, tries in
unsafeBitCast(callback, to: BusyHandler.self)(tries)
}, unsafeBitCast(box, to: UnsafeMutableRawPointer.self))
busyHandler = box
}
fileprivate typealias BusyHandler = @convention(block) (Int32) -> Int32
fileprivate var busyHandler: BusyHandler?
/// Sets a handler to call when a statement is executed with the compiled
/// SQL.
///
/// - Parameter callback: This block is invoked when a statement is executed
/// with the compiled SQL as its argument.
///
/// db.trace { SQL in print(SQL) }
public func trace(_ callback: ((String) -> Void)?) {
if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
trace_v2(callback)
} else {
trace_v1(callback)
}
}
@available(OSX, deprecated: 10.12)
@available(iOS, deprecated: 10.0)
@available(watchOS, deprecated: 3.0)
@available(tvOS, deprecated: 10.0)
fileprivate func trace_v1(_ callback: ((String) -> Void)?) {
guard let callback else {
sqlite3_trace(handle, nil /* xCallback */, nil /* pCtx */)
trace = nil
return
}
let box: Trace = { (pointer: UnsafeRawPointer) in
callback(String(cString: pointer.assumingMemoryBound(to: UInt8.self)))
}
sqlite3_trace(handle, { (context: UnsafeMutableRawPointer?, SQL: UnsafePointer?) in
if let context, let SQL {
unsafeBitCast(context, to: Trace.self)(SQL)
}
},
unsafeBitCast(box, to: UnsafeMutableRawPointer.self)
)
trace = box
}
@available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *)
fileprivate func trace_v2(_ callback: ((String) -> Void)?) {
guard let callback else {
// If the X callback is NULL or if the M mask is zero, then tracing is disabled.
sqlite3_trace_v2(handle, 0 /* mask */, nil /* xCallback */, nil /* pCtx */)
trace = nil
return
}
let box: Trace = { (pointer: UnsafeRawPointer) in
callback(String(cString: pointer.assumingMemoryBound(to: UInt8.self)))
}
sqlite3_trace_v2(handle, UInt32(SQLITE_TRACE_STMT) /* mask */, {
// 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.
(_: UInt32, context: UnsafeMutableRawPointer?, pointer: UnsafeMutableRawPointer?, _: UnsafeMutableRawPointer?) in
if let pointer,
let expandedSQL = sqlite3_expanded_sql(OpaquePointer(pointer)) {
unsafeBitCast(context, to: Trace.self)(expandedSQL)
sqlite3_free(expandedSQL)
}
return Int32(0) // currently ignored
},
unsafeBitCast(box, to: UnsafeMutableRawPointer.self) /* pCtx */
)
trace = box
}
fileprivate typealias Trace = @convention(block) (UnsafeRawPointer) -> Void
fileprivate var trace: Trace?
/// Registers a callback to be invoked whenever a row is inserted, updated,
/// or deleted in a rowid table.
///
/// - Parameter callback: A callback invoked with the `Operation` (one of
/// `.Insert`, `.Update`, or `.Delete`), database name, table name, and
/// rowid.
public func updateHook(_ callback: ((_ operation: Operation, _ db: String, _ table: String, _ rowid: Int64) -> Void)?) {
guard let callback else {
sqlite3_update_hook(handle, nil, nil)
updateHook = nil
return
}
let box: UpdateHook = {
callback(
Operation(rawValue: $0),
String(cString: $1),
String(cString: $2),
$3
)
}
sqlite3_update_hook(handle, { callback, operation, db, table, rowid in
unsafeBitCast(callback, to: UpdateHook.self)(operation, db!, table!, rowid)
}, unsafeBitCast(box, to: UnsafeMutableRawPointer.self))
updateHook = box
}
fileprivate typealias UpdateHook = @convention(block) (Int32, UnsafePointer, UnsafePointer, Int64) -> Void
fileprivate var updateHook: UpdateHook?
/// Registers a callback to be invoked whenever a transaction is committed.
///
/// - Parameter callback: A callback invoked whenever a transaction is
/// committed. If this callback throws, the transaction will be rolled
/// back.
public func commitHook(_ callback: (() throws -> Void)?) {
guard let callback else {
sqlite3_commit_hook(handle, nil, nil)
commitHook = nil
return
}
let box: CommitHook = {
do {
try callback()
} catch {
return 1
}
return 0
}
sqlite3_commit_hook(handle, { callback in
unsafeBitCast(callback, to: CommitHook.self)()
}, unsafeBitCast(box, to: UnsafeMutableRawPointer.self))
commitHook = box
}
fileprivate typealias CommitHook = @convention(block) () -> Int32
fileprivate var commitHook: CommitHook?
/// Registers a callback to be invoked whenever a transaction rolls back.
///
/// - Parameter callback: A callback invoked when a transaction is rolled
/// back.
public func rollbackHook(_ callback: (() -> Void)?) {
guard let callback else {
sqlite3_rollback_hook(handle, nil, nil)
rollbackHook = nil
return
}
let box: RollbackHook = { callback() }
sqlite3_rollback_hook(handle, { callback in
unsafeBitCast(callback, to: RollbackHook.self)()
}, unsafeBitCast(box, to: UnsafeMutableRawPointer.self))
rollbackHook = box
}
fileprivate typealias RollbackHook = @convention(block) () -> Void
fileprivate var rollbackHook: RollbackHook?
/// Creates or redefines a custom SQL function.
///
/// - Parameters:
///
/// - function: The name of the function to create or redefine.
///
/// - argumentCount: The number of arguments that the function takes. If
/// `nil`, the function may take any number of arguments.
///
/// Default: `nil`
///
/// - deterministic: Whether or not the function is deterministic (_i.e._
/// the function always returns the same result for a given input).
///
/// Default: `false`
///
/// - block: A block of code to run when the function is called. The block
/// is called with an array of raw SQL values mapped to the function’s
/// parameters and should return a raw SQL value (or nil).
public func createFunction(_ functionName: String,
argumentCount: UInt? = nil,
deterministic: Bool = false,
_ block: @escaping (_ args: [Binding?]) -> Binding?) {
let argc = argumentCount.map { Int($0) } ?? -1
let box: Function = { (context: Context, argc, argv: Argv) in
context.set(result: block(argv.getBindings(argc: argc)))
}
func xFunc(context: Context, argc: Int32, value: Argv) {
unsafeBitCast(sqlite3_user_data(context), to: Function.self)(context, argc, value)
}
let flags = SQLITE_UTF8 | (deterministic ? SQLITE_DETERMINISTIC : 0)
let resultCode = sqlite3_create_function_v2(
handle,
functionName,
Int32(argc),
flags,
/* pApp */ unsafeBitCast(box, to: UnsafeMutableRawPointer.self),
xFunc, /*xStep*/ nil, /*xFinal*/ nil, /*xDestroy*/ nil
)
if let result = Result(errorCode: resultCode, connection: self) {
fatalError("Error creating function: \(result)")
}
register(functionName, argc: argc, value: box)
}
func register(_ functionName: String, argc: Int, value: Any) {
if functions[functionName] == nil {
functions[functionName] = [:] // fails on Linux, https://github.com/stephencelis/SQLite.swift/issues/1071
}
functions[functionName]?[argc] = value
}
fileprivate typealias Function = @convention(block) (Context, Int32, Argv) -> Void
fileprivate var functions = [String: [Int: Any]]()
/// Defines a new collating sequence.
///
/// - Parameters:
///
/// - collation: The name of the collation added.
///
/// - block: A collation function that takes two strings and returns the
/// comparison result.
public func createCollation(_ collation: String, _ block: @escaping (_ lhs: String, _ rhs: String) -> ComparisonResult) throws {
let box: Collation = { (lhs: UnsafeRawPointer, rhs: UnsafeRawPointer) in
let lstr = String(cString: lhs.assumingMemoryBound(to: UInt8.self))
let rstr = String(cString: rhs.assumingMemoryBound(to: UInt8.self))
return Int32(block(lstr, rstr).rawValue)
}
try check(sqlite3_create_collation_v2(handle, collation, SQLITE_UTF8,
unsafeBitCast(box, to: UnsafeMutableRawPointer.self), { (callback: UnsafeMutableRawPointer?, _,
lhs: UnsafeRawPointer?, _, rhs: UnsafeRawPointer?) in /* xCompare */
if let lhs, let rhs {
return unsafeBitCast(callback, to: Collation.self)(lhs, rhs)
} else {
fatalError("sqlite3_create_collation_v2 callback called with NULL pointer")
}
}, nil /* xDestroy */))
collations[collation] = box
}
fileprivate typealias Collation = @convention(block) (UnsafeRawPointer, UnsafeRawPointer) -> Int32
fileprivate var collations = [String: Collation]()
// MARK: - Backup
/// Prepares a new backup for current connection.
///
/// - Parameters:
///
/// - databaseName: The name of the database to backup.
///
/// Default: `.main`
///
/// - targetConnection: The name of the database to save backup into.
///
/// - targetDatabaseName: The name of the database to save backup into.
///
/// Default: `.main`.
///
/// - Returns: A new database backup.
public func backup(databaseName: Backup.DatabaseName = .main,
usingConnection targetConnection: Connection,
andDatabaseName targetDatabaseName: Backup.DatabaseName = .main) throws -> Backup {
try Backup(sourceConnection: self, sourceName: databaseName, targetConnection: targetConnection,
targetName: targetDatabaseName)
}
// MARK: - Error Handling
func sync(_ block: () throws -> T) rethrows -> T {
if DispatchQueue.getSpecific(key: Connection.queueKey) == queueContext {
return try block()
} else {
return try queue.sync(execute: block)
}
}
@discardableResult func check(_ resultCode: Int32, statement: Statement? = nil) throws -> Int32 {
guard let error = Result(errorCode: resultCode, connection: self, statement: statement) else {
return resultCode
}
throw error
}
fileprivate var queue = DispatchQueue(label: "SQLite.Database", attributes: [])
fileprivate static let queueKey = DispatchSpecificKey()
fileprivate lazy var queueContext: Int = unsafeBitCast(self, to: Int.self)
}
extension Connection: CustomStringConvertible {
public var description: String {
String(cString: sqlite3_db_filename(handle, nil))
}
}
extension Connection.Location: CustomStringConvertible {
public var description: String {
switch self {
case .inMemory:
return ":memory:"
case .temporary:
return ""
case let .uri(URI, parameters):
guard parameters.count > 0,
var components = URLComponents(string: URI) else {
return URI
}
components.queryItems =
(components.queryItems ?? []) + parameters.map(\.queryItem)
if components.scheme == nil {
components.scheme = "file"
}
return components.description
}
}
}
typealias Context = OpaquePointer?
extension Context {
func set(result: Binding?) {
switch result {
case let blob as Blob:
sqlite3_result_blob(self, blob.bytes, Int32(blob.bytes.count), nil)
case let double as Double:
sqlite3_result_double(self, double)
case let int as Int64:
sqlite3_result_int64(self, int)
case let string as String:
sqlite3_result_text(self, string, Int32(string.lengthOfBytes(using: .utf8)), SQLITE_TRANSIENT)
case .none:
sqlite3_result_null(self)
default:
fatalError("unsupported result type: \(String(describing: result))")
}
}
}
typealias Argv = UnsafeMutablePointer?
extension Argv {
func getBindings(argc: Int32) -> [Binding?] {
(0.. sqlite_schema
case renameColumn // ALTER TABLE ... RENAME COLUMN
case dropColumn // ALTER TABLE ... DROP COLUMN
func isSupported(by version: SQLiteVersion) -> Bool {
switch self {
case .partialIntegrityCheck, .sqliteSchemaTable:
return version >= .init(major: 3, minor: 33)
case .renameColumn:
return version >= .init(major: 3, minor: 25)
case .dropColumn:
return version >= .init(major: 3, minor: 35)
}
}
}
extension Connection {
func supports(_ feature: SQLiteFeature) -> Bool {
feature.isSupported(by: sqliteVersion)
}
}
================================================
FILE: Sources/SQLite/Core/SQLiteVersion.swift
================================================
import Foundation
public struct SQLiteVersion: Comparable, CustomStringConvertible, Sendable {
public let major: Int
public let minor: Int
public var point: Int = 0
public var description: String {
"SQLite \(major).\(minor).\(point)"
}
public static func <(lhs: SQLiteVersion, rhs: SQLiteVersion) -> Bool {
lhs.tuple < rhs.tuple
}
public static func ==(lhs: SQLiteVersion, rhs: SQLiteVersion) -> Bool {
lhs.tuple == rhs.tuple
}
static let zero: SQLiteVersion = .init(major: 0, minor: 0)
private var tuple: (Int, Int, Int) { (major, minor, point) }
}
================================================
FILE: Sources/SQLite/Core/Statement.swift
================================================
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#if StandaloneSQLite
import sqlite3
#elseif SQLCipher
import SQLCipher
#elseif SQLiteSwiftCSQLite
import SQLiteSwiftCSQLite
#else
import SQLite3 // SystemSQLite
#endif
/// A single SQL statement.
public final class Statement {
fileprivate var handle: OpaquePointer?
fileprivate let connection: Connection
init(_ connection: Connection, _ SQL: String) throws {
self.connection = connection
try connection.check(sqlite3_prepare_v2(connection.handle, SQL, -1, &handle, nil))
}
deinit {
sqlite3_finalize(handle)
}
public lazy var columnCount: Int = Int(sqlite3_column_count(handle))
public lazy var columnNames: [String] = (0.. Statement {
bind(values)
}
/// Binds a list of parameters to a statement.
///
/// - Parameter values: A list of parameters to bind to the statement.
///
/// - Returns: The statement object (useful for chaining).
public func bind(_ values: [Binding?]) -> Statement {
if values.isEmpty { return self }
reset()
guard values.count == Int(sqlite3_bind_parameter_count(handle)) else {
fatalError("\(sqlite3_bind_parameter_count(handle)) values expected, \(values.count) passed")
}
for idx in 1...values.count { bind(values[idx - 1], atIndex: idx) }
return self
}
/// Binds a dictionary of named parameters to a statement.
///
/// - Parameter values: A dictionary of named parameters to bind to the
/// statement.
///
/// - Returns: The statement object (useful for chaining).
public func bind(_ values: [String: Binding?]) -> Statement {
reset()
for (name, value) in values {
let idx = sqlite3_bind_parameter_index(handle, name)
guard idx > 0 else {
fatalError("parameter not found: \(name)")
}
bind(value, atIndex: Int(idx))
}
return self
}
fileprivate func bind(_ value: Binding?, atIndex idx: Int) {
switch value {
case .none:
sqlite3_bind_null(handle, Int32(idx))
case let value as Blob where value.bytes.count == 0:
sqlite3_bind_zeroblob(handle, Int32(idx), 0)
case let value as Blob:
sqlite3_bind_blob(handle, Int32(idx), value.bytes, Int32(value.bytes.count), SQLITE_TRANSIENT)
case let value as Double:
sqlite3_bind_double(handle, Int32(idx), value)
case let value as Int64:
sqlite3_bind_int64(handle, Int32(idx), value)
case let value as String:
sqlite3_bind_text(handle, Int32(idx), value, -1, SQLITE_TRANSIENT)
case let value as Int:
self.bind(value.datatypeValue, atIndex: idx)
case let value as Bool:
self.bind(value.datatypeValue, atIndex: idx)
case .some(let value):
fatalError("tried to bind unexpected value \(value)")
}
}
/// - Parameter bindings: A list of parameters to bind to the statement.
///
/// - Throws: `Result.Error` if query execution fails.
///
/// - Returns: The statement object (useful for chaining).
@discardableResult public func run(_ bindings: Binding?...) throws -> Statement {
guard bindings.isEmpty else {
return try run(bindings)
}
reset(clearBindings: false)
repeat {} while try step()
return self
}
/// - Parameter bindings: A list of parameters to bind to the statement.
///
/// - Throws: `Result.Error` if query execution fails.
///
/// - Returns: The statement object (useful for chaining).
@discardableResult public func run(_ bindings: [Binding?]) throws -> Statement {
try bind(bindings).run()
}
/// - Parameter bindings: A dictionary of named parameters to bind to the
/// statement.
///
/// - Throws: `Result.Error` if query execution fails.
///
/// - Returns: The statement object (useful for chaining).
@discardableResult public func run(_ bindings: [String: Binding?]) throws -> Statement {
try bind(bindings).run()
}
/// - Parameter bindings: A list of parameters to bind to the statement.
///
/// - Returns: The first value of the first row returned.
public func scalar(_ bindings: Binding?...) throws -> Binding? {
guard bindings.isEmpty else {
return try scalar(bindings)
}
reset(clearBindings: false)
_ = try step()
return row[0]
}
/// - Parameter bindings: A list of parameters to bind to the statement.
///
/// - Returns: The first value of the first row returned.
public func scalar(_ bindings: [Binding?]) throws -> Binding? {
try bind(bindings).scalar()
}
/// - Parameter bindings: A dictionary of named parameters to bind to the
/// statement.
///
/// - Returns: The first value of the first row returned.
public func scalar(_ bindings: [String: Binding?]) throws -> Binding? {
try bind(bindings).scalar()
}
public func step() throws -> Bool {
try connection.sync { try connection.check(sqlite3_step(handle)) == SQLITE_ROW }
}
public func reset() {
reset(clearBindings: true)
}
fileprivate func reset(clearBindings shouldClear: Bool) {
sqlite3_reset(handle)
if shouldClear { sqlite3_clear_bindings(handle) }
}
}
extension Statement: Sequence {
public func makeIterator() -> Statement {
reset(clearBindings: false)
return self
}
}
public protocol FailableIterator: IteratorProtocol {
func failableNext() throws -> Self.Element?
}
extension FailableIterator {
public func next() -> Element? {
// swiftlint:disable:next force_try
try! failableNext()
}
}
extension Array {
public init(_ failableIterator: I) throws where I.Element == Element {
self.init()
while let row = try failableIterator.failableNext() {
append(row)
}
}
}
extension Statement: FailableIterator {
public typealias Element = [Binding?]
public func failableNext() throws -> [Binding?]? {
try step() ? Array(row) : nil
}
}
extension Statement {
func prepareRowIterator() -> RowIterator {
RowIterator(statement: self, columnNames: columnNameMap)
}
var columnNameMap: [String: Int] {
var result = [String: Int]()
for (index, name) in self.columnNames.enumerated() {
result[name.quote()] = index
}
return result
}
}
extension Statement: CustomStringConvertible {
public var description: String {
String(cString: sqlite3_sql(handle))
}
}
public struct Cursor {
fileprivate let handle: OpaquePointer
fileprivate let columnCount: Int
fileprivate init(_ statement: Statement) {
handle = statement.handle!
columnCount = statement.columnCount
}
public subscript(idx: Int) -> Double {
sqlite3_column_double(handle, Int32(idx))
}
public subscript(idx: Int) -> Int64 {
sqlite3_column_int64(handle, Int32(idx))
}
public subscript(idx: Int) -> String {
String(cString: UnsafePointer(sqlite3_column_text(handle, Int32(idx))))
}
public subscript(idx: Int) -> Blob {
if let pointer = sqlite3_column_blob(handle, Int32(idx)) {
let length = Int(sqlite3_column_bytes(handle, Int32(idx)))
return Blob(bytes: pointer, length: length)
} else {
// The return value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
// https://www.sqlite.org/c3ref/column_blob.html
return Blob(bytes: [])
}
}
// MARK: -
public subscript(idx: Int) -> Bool {
Bool.fromDatatypeValue(self[idx])
}
public subscript(idx: Int) -> Int {
Int.fromDatatypeValue(self[idx])
}
}
/// Cursors provide direct access to a statement’s current row.
extension Cursor: Sequence {
public subscript(idx: Int) -> Binding? {
switch sqlite3_column_type(handle, Int32(idx)) {
case SQLITE_BLOB:
return self[idx] as Blob
case SQLITE_FLOAT:
return self[idx] as Double
case SQLITE_INTEGER:
return self[idx] as Int64
case SQLITE_NULL:
return nil
case SQLITE_TEXT:
return self[idx] as String
case let type:
fatalError("unsupported column type: \(type)")
}
}
public func makeIterator() -> AnyIterator {
var idx = 0
return AnyIterator {
if idx >= columnCount {
return .none
} else {
idx += 1
return self[idx - 1]
}
}
}
}
================================================
FILE: Sources/SQLite/Core/URIQueryParameter.swift
================================================
import Foundation
/// See https://www.sqlite.org/uri.html
public enum URIQueryParameter: CustomStringConvertible {
public enum FileMode: String {
case readOnly = "ro", readWrite = "rw", readWriteCreate = "rwc", memory
}
public enum CacheMode: String {
case shared, `private`
}
/// The cache query parameter determines if the new database is opened using shared cache mode or with a private cache.
case cache(CacheMode)
/// The immutable query parameter is a boolean that signals to SQLite that the underlying database file is held on read-only media
/// and cannot be modified, even by another process with elevated privileges.
case immutable(Bool)
/// When creating a new database file during `sqlite3_open_v2()` on unix systems, SQLite will try to set the permissions of the new database
/// file to match the existing file "filename".
case modeOf(String)
/// The mode query parameter determines if the new database is opened read-only, read-write, read-write and created if it does not exist,
/// or that the database is a pure in-memory database that never interacts with disk, respectively.
case mode(FileMode)
/// The nolock query parameter is a boolean that disables all calls to the `xLock`, ` xUnlock`, and `xCheckReservedLock` methods
/// of the VFS when true.
case nolock(Bool)
/// The psow query parameter overrides the `powersafe_overwrite` property of the database file being opened.
case powersafeOverwrite(Bool)
/// The vfs query parameter causes the database connection to be opened using the VFS called NAME.
case vfs(String)
public var description: String {
queryItem.description
}
var queryItem: URLQueryItem {
switch self {
case .cache(let mode): return .init(name: "cache", value: mode.rawValue)
case .immutable(let bool): return .init(name: "immutable", value: NSNumber(value: bool).description)
case .modeOf(let filename): return .init(name: "modeOf", value: filename)
case .mode(let fileMode): return .init(name: "mode", value: fileMode.rawValue)
case .nolock(let bool): return .init(name: "nolock", value: NSNumber(value: bool).description)
case .powersafeOverwrite(let bool): return .init(name: "psow", value: NSNumber(value: bool).description)
case .vfs(let name): return .init(name: "vfs", value: name)
}
}
}
================================================
FILE: Sources/SQLite/Core/Value.swift
================================================
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
/// - Warning: `Binding` is a protocol that SQLite.swift uses internally to
/// directly map SQLite types to Swift types.
///
/// Do not conform custom types to the Binding protocol. See the `Value`
/// protocol, instead.
public protocol Binding: Sendable {}
public protocol Number: Binding {}
public protocol Value: Expressible { // extensions cannot have inheritance clauses
associatedtype ValueType = Self
associatedtype Datatype: Binding
static var declaredDatatype: String { get }
static func fromDatatypeValue(_ datatypeValue: Datatype) throws -> ValueType
var datatypeValue: Datatype { get }
}
extension Double: Number, Value {
public static let declaredDatatype = "REAL"
public static func fromDatatypeValue(_ datatypeValue: Double) -> Double {
datatypeValue
}
public var datatypeValue: Double {
self
}
}
extension Int64: Number, Value {
public static let declaredDatatype = "INTEGER"
public static func fromDatatypeValue(_ datatypeValue: Int64) -> Int64 {
datatypeValue
}
public var datatypeValue: Int64 {
self
}
}
extension String: Binding, Value {
public static let declaredDatatype = "TEXT"
public static func fromDatatypeValue(_ datatypeValue: String) -> String {
datatypeValue
}
public var datatypeValue: String {
self
}
}
extension Blob: Binding, Value {
public static let declaredDatatype = "BLOB"
public static func fromDatatypeValue(_ datatypeValue: Blob) -> Blob {
datatypeValue
}
public var datatypeValue: Blob {
self
}
}
// MARK: -
extension Bool: Binding, Value {
public static var declaredDatatype = Int64.declaredDatatype
public static func fromDatatypeValue(_ datatypeValue: Int64) -> Bool {
datatypeValue != 0
}
public var datatypeValue: Int64 {
self ? 1 : 0
}
}
extension Int: Number, Value {
public static var declaredDatatype = Int64.declaredDatatype
public static func fromDatatypeValue(_ datatypeValue: Int64) -> Int {
Int(datatypeValue)
}
public var datatypeValue: Int64 {
Int64(self)
}
}
================================================
FILE: Sources/SQLite/Extensions/Cipher.swift
================================================
#if SQLCipher
import SQLCipher
/// Extension methods for [SQLCipher](https://www.zetetic.net/sqlcipher/).
/// @see [sqlcipher api](https://www.zetetic.net/sqlcipher/sqlcipher-api/)
extension Connection {
/// Granularitly of SQLCipher log outputs
/// Each log level is more verbose than the last
///
/// See https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_log_level
public enum CipherLogLevel: String {
case none
case error
case warn
case info
case debug
case trace
}
/// - Returns: the SQLCipher version
///
/// See https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_version
public var cipherVersion: String? {
(try? scalar("PRAGMA cipher_version")) as? String
}
/// - Returns: the SQLCipher fips status: 1 for fips mode, 0 for non-fips mode
/// The FIPS status will not be initialized until the database connection has been keyed
/// See https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_fips_status
public var cipherFipsStatus: String? {
(try? scalar("PRAGMA cipher_fips_status")) as? String
}
/// - Returns: The compiled crypto provider.
/// The database must be keyed before requesting the name of the crypto provider.
///
/// See https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_provider
public var cipherProvider: String? {
(try? scalar("PRAGMA cipher_provider")) as? String
}
/// - Returns: the version number provided from the compiled crypto provider.
/// This value, if known, is available only after the database has been keyed.
///
/// See https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_provider_version
public var cipherProviderVersion: String? {
(try? scalar("PRAGMA cipher_provider_version")) as? String
}
/// Specify the key for an encrypted database. This routine should be
/// called right after sqlite3_open().
///
/// @param key The key to use.The key itself can be a passphrase, which is converted to a key
/// using [PBKDF2](https://en.wikipedia.org/wiki/PBKDF2) key derivation. The result
/// is used as the encryption key for the database.
///
/// Alternatively, it is possible to specify an exact byte sequence using a blob literal.
/// With this method, it is the calling application's responsibility to ensure that the data
/// provided is a 64 character hex string, which will be converted directly to 32 bytes (256 bits)
/// of key data.
/// e.g. x'2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99'
/// @param db name of the database, defaults to 'main'
///
/// See https://www.zetetic.net/sqlcipher/sqlcipher-api/#sqlite3_key
public func key(_ key: String, db: String = "main") throws {
try _key_v2(db: db, keyPointer: key, keySize: key.utf8.count)
}
public func key(_ key: Blob, db: String = "main") throws {
try _key_v2(db: db, keyPointer: key.bytes, keySize: key.bytes.count)
}
/// Same as `key(_ key: String, db: String = "main")`, running "PRAGMA cipher_migrate;"
/// immediately after calling `sqlite3_key_v2`, which performs the migration of
/// SQLCipher database created by older major version of SQLCipher, to be able to
/// open this database with new major version of SQLCipher
/// (e.g. to open database created by SQLCipher version 3.x.x with SQLCipher version 4.x.x).
/// As "PRAGMA cipher_migrate;" is time-consuming, it is recommended to use this function
/// only after failure of `key(_ key: String, db: String = "main")`, if older versions of
/// your app may ise older version of SQLCipher
///
/// See https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_migrate
/// and https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283
/// for more details regarding SQLCipher upgrade
public func keyAndMigrate(_ key: String, db: String = "main") throws {
try _key_v2(db: db, keyPointer: key, keySize: key.utf8.count, migrate: true)
}
/// Same as `[`keyAndMigrate(_ key: String, db: String = "main")` accepting byte array as key
public func keyAndMigrate(_ key: Blob, db: String = "main") throws {
try _key_v2(db: db, keyPointer: key.bytes, keySize: key.bytes.count, migrate: true)
}
/// Change the key on an open database. NB: only works if the database is already encrypted.
///
/// To change the key on an existing encrypted database, it must first be unlocked with the
/// current encryption key. Once the database is readable and writeable, rekey can be used
/// to re-encrypt every page in the database with a new key.
///
/// See https://www.zetetic.net/sqlcipher/sqlcipher-api/#sqlite3_rekey
public func rekey(_ key: String, db: String = "main") throws {
try _rekey_v2(db: db, keyPointer: key, keySize: key.utf8.count)
}
public func rekey(_ key: Blob, db: String = "main") throws {
try _rekey_v2(db: db, keyPointer: key.bytes, keySize: key.bytes.count)
}
/// Converts a non-encrypted database to an encrypted one.
///
/// See https://www.zetetic.net/sqlcipher/sqlcipher-api/#sqlcipher_export
public func sqlcipher_export(_ location: Location, key: String) throws {
let schemaName = "cipher_export"
try attach(location, as: schemaName, key: key)
try run("SELECT sqlcipher_export(?)", schemaName)
try detach(schemaName)
}
/// When using Commercial or Enterprise SQLCipher packages you must call
/// `PRAGMA cipher_license` with a valid license code prior to executing
/// cryptographic operations on an encrypted database.
/// Failure to provide a license code, or use of an expired trial code,
/// will result in an `SQLITE_AUTH (23)` error code reported from the SQLite API
/// License Codes will activate SQLCipher Commercial or Enterprise packages
/// from Zetetic: https://www.zetetic.net/sqlcipher/buy/
/// 15-day free trials are available by request: https://www.zetetic.net/sqlcipher/trial/
///
/// See https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_license
/// - Parameter license: base64 SQLCipher license code to activate SQLCipher commercial
public func applyLicense(_ license: String) throws {
try run("PRAGMA cipher_license = '\(license)'")
}
/// Instructs SQLCipher to log internal debugging and operational information
/// to the sepecified log target (device) using `os_log`
/// The supplied logLevel will determine the granularity of the logs output
/// Available logLevel options are: NONE, ERROR, WARN, INFO, DEBUG, TRACE
/// Note that each level is more verbose than the last,
/// and particularly with DEBUG and TRACE the logging system will generate
/// a significant log volume
///
/// See https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_log
/// - Parameter logLevel: CipherLogLevel The granularity to use for the logging system - defaults to `DEBUG`
public func enableCipherLogging(logLevel: CipherLogLevel = .debug) throws {
try run("PRAGMA cipher_log = device")
try run("PRAGMA cipher_log_level = \(logLevel.rawValue.uppercased())")
}
/// Instructs SQLCipher to disable logging internal debugging and operational information
///
/// See https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_log
public func disableCipherLogging() throws {
try run("PRAGMA cipher_log_level = \(CipherLogLevel.none.rawValue.uppercased())")
}
// MARK: - private
private func _key_v2(db: String,
keyPointer: UnsafePointer,
keySize: Int,
migrate: Bool = false) throws {
try check(sqlite3_key_v2(handle, db, keyPointer, Int32(keySize)))
if migrate {
// Run "PRAGMA cipher_migrate;" immediately after `sqlite3_key_v2`
// per recommendation of SQLCipher authors
let migrateResult = try scalar("PRAGMA cipher_migrate;")
if (migrateResult as? String) != "0" {
// "0" is the result of successful migration
throw Result.error(message: "Error in cipher migration, result \(migrateResult.debugDescription)", code: 1, statement: nil)
}
}
try cipher_key_check()
}
private func _rekey_v2(db: String, keyPointer: UnsafePointer, keySize: Int) throws {
try check(sqlite3_rekey_v2(handle, db, keyPointer, Int32(keySize)))
}
// When opening an existing database, sqlite3_key_v2 will not immediately throw an error if
// the key provided is incorrect. To test that the database can be successfully opened with the
// provided key, it is necessary to perform some operation on the database (i.e. read from it).
private func cipher_key_check() throws {
_ = try scalar("SELECT count(*) FROM sqlite_master;")
}
}
#endif
================================================
FILE: Sources/SQLite/Extensions/FTS4.swift
================================================
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
extension Module {
public static func FTS4(_ column: Expressible, _ more: Expressible...) -> Module {
FTS4([column] + more)
}
public static func FTS4(_ columns: [Expressible] = [], tokenize tokenizer: Tokenizer? = nil) -> Module {
FTS4(FTS4Config().columns(columns).tokenizer(tokenizer))
}
public static func FTS4(_ config: FTS4Config) -> Module {
Module(name: "fts4", arguments: config.arguments())
}
}
extension VirtualTable {
/// Builds an expression appended with a `MATCH` query against the given
/// pattern.
///
/// let emails = VirtualTable("emails")
///
/// emails.filter(emails.match("Hello"))
/// // SELECT * FROM "emails" WHERE "emails" MATCH 'Hello'
///
/// - Parameter pattern: A pattern to match.
///
/// - Returns: An expression appended with a `MATCH` query against the given
/// pattern.
public func match(_ pattern: String) -> Expression {
"MATCH".infix(tableName(), pattern)
}
public func match(_ pattern: Expression) -> Expression {
"MATCH".infix(tableName(), pattern)
}
public func match(_ pattern: Expression) -> Expression {
"MATCH".infix(tableName(), pattern)
}
/// Builds a copy of the query with a `WHERE … MATCH` clause.
///
/// let emails = VirtualTable("emails")
///
/// emails.match("Hello")
/// // SELECT * FROM "emails" WHERE "emails" MATCH 'Hello'
///
/// - Parameter pattern: A pattern to match.
///
/// - Returns: A query with the given `WHERE … MATCH` clause applied.
public func match(_ pattern: String) -> QueryType {
filter(match(pattern))
}
public func match(_ pattern: Expression) -> QueryType {
filter(match(pattern))
}
public func match(_ pattern: Expression) -> QueryType {
filter(match(pattern))
}
}
// swiftlint:disable identifier_name
public struct Tokenizer {
public static let Simple = Tokenizer("simple")
public static let Porter = Tokenizer("porter")
public static func Unicode61(removeDiacritics: Bool? = nil,
tokenchars: Set = [],
separators: Set = []) -> Tokenizer {
var arguments = [String]()
if let removeDiacritics {
arguments.append("remove_diacritics=\(removeDiacritics ? 1 : 0)")
}
if !tokenchars.isEmpty {
let joined = tokenchars.map { String($0) }.joined(separator: "")
arguments.append("tokenchars=\(joined)")
}
if !separators.isEmpty {
let joined = separators.map { String($0) }.joined(separator: "")
arguments.append("separators=\(joined)")
}
return Tokenizer("unicode61", arguments)
}
// https://sqlite.org/fts5.html#the_experimental_trigram_tokenizer
public static func Trigram(caseSensitive: Bool = false) -> Tokenizer {
Tokenizer("trigram", ["case_sensitive", caseSensitive ? "1" : "0"])
}
public static func Custom(_ name: String) -> Tokenizer {
Tokenizer(Tokenizer.moduleName.quote(), [name.quote()])
}
public let name: String
public let arguments: [String]
fileprivate init(_ name: String, _ arguments: [String] = []) {
self.name = name
self.arguments = arguments
}
fileprivate static let moduleName = "SQLite.swift"
}
extension Tokenizer: CustomStringConvertible {
public var description: String {
if arguments.isEmpty {
name
} else {
([name] + arguments).joined(separator: " ").quote()
}
}
}
/// Configuration options shared between the [FTS4](https://www.sqlite.org/fts3.html) and
/// [FTS5](https://www.sqlite.org/fts5.html) extensions.
open class FTSConfig {
public enum ColumnOption {
/// [The notindexed= option](https://www.sqlite.org/fts3.html#section_6_5)
case unindexed
}
typealias ColumnDefinition = (Expressible, options: [ColumnOption])
var columnDefinitions = [ColumnDefinition]()
var tokenizer: Tokenizer?
var prefixes = [Int]()
var externalContentSchema: SchemaType?
var isContentless: Bool = false
/// Adds a column definition
@discardableResult open func column(_ column: Expressible, _ options: [ColumnOption] = []) -> Self {
columnDefinitions.append((column, options))
return self
}
@discardableResult open func columns(_ columns: [Expressible]) -> Self {
for column in columns {
self.column(column)
}
return self
}
/// [Tokenizers](https://www.sqlite.org/fts3.html#tokenizer)
@discardableResult open func tokenizer(_ tokenizer: Tokenizer?) -> Self {
self.tokenizer = tokenizer
return self
}
/// [The prefix= option](https://www.sqlite.org/fts3.html#section_6_6)
@discardableResult open func prefix(_ prefix: [Int]) -> Self {
prefixes += prefix
return self
}
/// [The content= option](https://www.sqlite.org/fts3.html#section_6_2)
@discardableResult open func externalContent(_ schema: SchemaType) -> Self {
externalContentSchema = schema
return self
}
/// [Contentless FTS4 Tables](https://www.sqlite.org/fts3.html#section_6_2_1)
@discardableResult open func contentless() -> Self {
isContentless = true
return self
}
func formatColumnDefinitions() -> [Expressible] {
columnDefinitions.map { $0.0 }
}
func arguments() -> [Expressible] {
options().arguments
}
func options() -> Options {
var options = Options()
options.append(formatColumnDefinitions())
if let tokenizer {
options.append("tokenize", value: Expression(literal: tokenizer.description))
}
options.appendCommaSeparated("prefix", values: prefixes.sorted().map { String($0) })
if isContentless {
options.append("content", value: "")
} else if let externalContentSchema {
options.append("content", value: externalContentSchema.tableName())
}
return options
}
struct Options {
var arguments = [Expressible]()
@discardableResult mutating func append(_ columns: [Expressible]) -> Options {
arguments.append(contentsOf: columns)
return self
}
@discardableResult mutating func appendCommaSeparated(_ key: String, values: [String]) -> Options {
if values.isEmpty {
return self
} else {
return append(key, value: values.joined(separator: ","))
}
}
@discardableResult mutating func append(_ key: String, value: String) -> Options {
append(key, value: Expression(value))
}
@discardableResult mutating func append(_ key: String, value: Expressible) -> Options {
arguments.append("=".join([Expression(literal: key), value]))
return self
}
}
}
/// Configuration for the [FTS4](https://www.sqlite.org/fts3.html) extension.
open class FTS4Config: FTSConfig {
/// [The matchinfo= option](https://www.sqlite.org/fts3.html#section_6_4)
public enum MatchInfo: String {
case fts3
}
/// [FTS4 options](https://www.sqlite.org/fts3.html#fts4_options)
public enum Order: String {
/// Data structures are optimized for returning results in ascending order by docid (default)
case asc
/// FTS4 stores its data in such a way as to optimize returning results in descending order by docid.
case desc
}
var compressFunction: String?
var uncompressFunction: String?
var languageId: String?
var matchInfo: MatchInfo?
var order: Order?
override public init() {
}
/// [The compress= and uncompress= options](https://www.sqlite.org/fts3.html#section_6_1)
@discardableResult open func compress(_ functionName: String) -> Self {
compressFunction = functionName
return self
}
/// [The compress= and uncompress= options](https://www.sqlite.org/fts3.html#section_6_1)
@discardableResult open func uncompress(_ functionName: String) -> Self {
uncompressFunction = functionName
return self
}
/// [The languageid= option](https://www.sqlite.org/fts3.html#section_6_3)
@discardableResult open func languageId(_ columnName: String) -> Self {
languageId = columnName
return self
}
/// [The matchinfo= option](https://www.sqlite.org/fts3.html#section_6_4)
@discardableResult open func matchInfo(_ matchInfo: MatchInfo) -> Self {
self.matchInfo = matchInfo
return self
}
/// [FTS4 options](https://www.sqlite.org/fts3.html#fts4_options)
@discardableResult open func order(_ order: Order) -> Self {
self.order = order
return self
}
override func options() -> Options {
var options = super.options()
for (column, _) in (columnDefinitions.filter { $0.options.contains(.unindexed) }) {
options.append("notindexed", value: column)
}
if let languageId {
options.append("languageid", value: languageId)
}
if let compressFunction {
options.append("compress", value: compressFunction)
}
if let uncompressFunction {
options.append("uncompress", value: uncompressFunction)
}
if let matchInfo {
options.append("matchinfo", value: matchInfo.rawValue)
}
if let order {
options.append("order", value: order.rawValue)
}
return options
}
}
================================================
FILE: Sources/SQLite/Extensions/FTS5.swift
================================================
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
extension Module {
public static func FTS5(_ config: FTS5Config) -> Module {
Module(name: "fts5", arguments: config.arguments())
}
}
/// Configuration for the [FTS5](https://www.sqlite.org/fts5.html) extension.
///
/// **Note:** this is currently only applicable when using SQLite.swift together with a FTS5-enabled version
/// of SQLite.
open class FTS5Config: FTSConfig {
public enum Detail: String {
/// store rowid, column number, term offset
case full
/// store rowid, column number
case column
/// store rowid
case none
}
var detail: Detail?
var contentRowId: Expressible?
var columnSize: Int?
override public init() {
}
/// [External Content Tables](https://www.sqlite.org/fts5.html#section_4_4_2)
@discardableResult open func contentRowId(_ column: Expressible) -> Self {
contentRowId = column
return self
}
/// [The Columnsize Option](https://www.sqlite.org/fts5.html#section_4_5)
@discardableResult open func columnSize(_ size: Int) -> Self {
columnSize = size
return self
}
/// [The Detail Option](https://www.sqlite.org/fts5.html#section_4_6)
@discardableResult open func detail(_ detail: Detail) -> Self {
self.detail = detail
return self
}
override func options() -> Options {
var options = super.options()
if let contentRowId {
options.append("content_rowid", value: contentRowId)
}
if let columnSize {
options.append("columnsize", value: Expression(value: columnSize))
}
if let detail {
options.append("detail", value: detail.rawValue)
}
return options
}
override func formatColumnDefinitions() -> [Expressible] {
columnDefinitions.map { definition in
if definition.options.contains(.unindexed) {
return " ".join([definition.0, Expression(literal: "UNINDEXED")])
} else {
return definition.0
}
}
}
}
================================================
FILE: Sources/SQLite/Extensions/RTree.swift
================================================
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
extension Module {
public static func RTree(_ primaryKey: Expression,
_ pairs: (Expression, Expression)...)
-> Module where T.Datatype == Int64, U.Datatype == Double {
var arguments: [Expressible] = [primaryKey]
for pair in pairs {
arguments.append(contentsOf: [pair.0, pair.1] as [Expressible])
}
return Module(name: "rtree", arguments: arguments)
}
}
================================================
FILE: Sources/SQLite/Foundation.swift
================================================
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import Foundation
extension Data: Value {
public static var declaredDatatype: String {
Blob.declaredDatatype
}
public static func fromDatatypeValue(_ dataValue: Blob) -> Data {
Data(dataValue.bytes)
}
public var datatypeValue: Blob {
withUnsafeBytes { (pointer: UnsafeRawBufferPointer) -> Blob in
Blob(bytes: pointer.baseAddress!, length: count)
}
}
}
extension Date: Value {
public static var declaredDatatype: String {
String.declaredDatatype
}
public static func fromDatatypeValue(_ stringValue: String) -> Date {
dateFormatter.date(from: stringValue)!
}
public var datatypeValue: String {
dateFormatter.string(from: self)
}
}
/// A global date formatter used to serialize and deserialize `NSDate` objects.
/// If multiple date formats are used in an application’s database(s), use a
/// custom `Value` type per additional format.
public var dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
return formatter
}()
extension UUID: Value {
public static var declaredDatatype: String {
String.declaredDatatype
}
public static func fromDatatypeValue(_ stringValue: String) -> UUID {
UUID(uuidString: stringValue)!
}
public var datatypeValue: String {
uuidString
}
}
extension URL: Value {
public static var declaredDatatype: String {
String.declaredDatatype
}
public static func fromDatatypeValue(_ stringValue: String) -> URL {
URL(string: stringValue)!
}
public var datatypeValue: String {
absoluteString
}
}
================================================
FILE: Sources/SQLite/Helpers.swift
================================================
//
// SQLite.swift
// https://github.com/stephencelis/SQLite.swift
// Copyright © 2014-2015 Stephen Celis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#if StandaloneSQLite
import sqlite3
#elseif SQLCipher
import SQLCipher
#elseif SQLiteSwiftCSQLite
import SQLiteSwiftCSQLite
#else
import SQLite3 // SystemSQLite
#endif
public typealias Star = (Expression?, Expression?) -> Expression
public func *(_: Expression?, _: Expression?) -> Expression {
Expression(literal: "*")
}
// swiftlint:disable:next type_name
public protocol _OptionalType {
associatedtype WrappedType
}
extension Optional: _OptionalType {
public typealias WrappedType = Wrapped
}
// let SQLITE_STATIC = unsafeBitCast(0, sqlite3_destructor_type.self)
let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
extension String {
func quote(_ mark: Character = "\"") -> String {
var quoted = ""
quoted.append(mark)
for character in self {
quoted.append(character)
if character == mark {
quoted.append(character)
}
}
quoted.append(mark)
return quoted
}
func join(_ expressions: [Expressible]) -> Expressible {
var (template, bindings) = ([String](), [Binding?]())
for expressible in expressions {
let expression = expressible.expression
template.append(expression.template)
bindings.append(contentsOf: expression.bindings)
}
return Expression(template.joined(separator: self), bindings)
}
func infix(_ lhs: Expressible, _ rhs: Expressible, wrap: Bool = true) -> Expression {
infix([lhs, rhs], wrap: wrap)
}
func infix(_ terms: [Expressible], wrap: Bool = true) -> Expression {
let expression = Expression(" \(self) ".join(terms).expression)
guard wrap else {
return expression
}
return "".wrap(expression)
}
func prefix(_ expressions: Expressible) -> Expressible {
"\(self) ".wrap(expressions) as Expression
}
func prefix(_ expressions: [Expressible]) -> Expressible {
"\(self) ".wrap(expressions) as Expression
}
func wrap(_ expression: Expressible) -> Expression {
Expression("\(self)(\(expression.expression.template))", expression.expression.bindings)
}
func wrap(_ expressions: [Expressible]) -> Expression {
wrap(", ".join(expressions))
}
}
func transcode(_ literal: Binding?) -> String {
guard let literal else { return "NULL" }
switch literal {
case let blob as Blob:
return blob.description
case let string as String:
return string.quote("'")
case let binding:
return "\(binding)"
}
}
// swiftlint:disable force_cast force_try
func value(_ binding: Binding) -> A {
try! A.fromDatatypeValue(binding as! A.Datatype) as! A
}
func value(_ binding: Binding?) -> A {
value(binding!)
}
================================================
FILE: Sources/SQLite/Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
FMWK
CFBundleShortVersionString
$(MARKETING_VERSION)
CFBundleSignature
????
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
NSPrincipalClass
================================================
FILE: Sources/SQLite/PrivacyInfo.xcprivacy
================================================
NSPrivacyTrackingDomains
NSPrivacyCollectedDataTypes
NSPrivacyAccessedAPITypes
NSPrivacyTracking
================================================
FILE: Sources/SQLite/SQLite.h
================================================
@import Foundation;
FOUNDATION_EXPORT double SQLiteVersionNumber;
FOUNDATION_EXPORT const unsigned char SQLiteVersionString[];
================================================
FILE: Sources/SQLite/Schema/Connection+Schema.swift
================================================
import Foundation
public extension Connection {
var schema: SchemaReader { SchemaReader(connection: self) }
// There are four columns in each result row.
// The first column is the name of the table that
// contains the REFERENCES clause.
// The second column is the rowid of the row that contains the
// invalid REFERENCES clause, or NULL if the child table is a WITHOUT ROWID table.
// The third column is the name of the table that is referred to.
// The fourth column is the index of the specific foreign key constraint that failed.
//
// https://sqlite.org/pragma.html#pragma_foreign_key_check
func foreignKeyCheck(table: String? = nil) throws -> [ForeignKeyError] {
try run("PRAGMA foreign_key_check" + (table.map { "(\($0.quote()))" } ?? ""))
.compactMap { (row: [Binding?]) -> ForeignKeyError? in
guard let table = row[0] as? String,
let rowId = row[1] as? Int64,
let target = row[2] as? String else { return nil }
return ForeignKeyError(from: table, rowId: rowId, to: target)
}
}
// This pragma does a low-level formatting and consistency check of the database.
// https://sqlite.org/pragma.html#pragma_integrity_check
func integrityCheck(table: String? = nil) throws -> [String] {
precondition(table == nil || supports(.partialIntegrityCheck), "partial integrity check not supported")
return try run("PRAGMA integrity_check" + (table.map { "(\($0.quote()))" } ?? ""))
.compactMap { $0[0] as? String }
.filter { $0 != "ok" }
}
}
================================================
FILE: Sources/SQLite/Schema/SchemaChanger.swift
================================================
import Foundation
/*
https://www.sqlite.org/lang_altertable.html
The only schema altering commands directly supported by SQLite are the "rename table" and "add column"
commands shown above.
(SQLite 3.25.0: RENAME COLUMN)
(SQLite 3.35.0: DROP COLUMN)
However, applications can make other arbitrary changes to the format of a table using a
simple sequence of operations. The steps to make arbitrary changes to the schema design of some table X are as follows:
1. If foreign key constraints are enabled, disable them using PRAGMA foreign_keys=OFF.
2. Start a transaction.
3. Remember the format of all indexes and triggers associated with table X
(SELECT sql FROM sqlite_master WHERE tbl_name='X' AND type='index')
4. Use CREATE TABLE to construct a new table "new_X" that is in the desired revised format of table X.
5. Transfer content from X into new_X using a statement like: INSERT INTO new_X SELECT ... FROM X.
6. Drop the old table X: DROP TABLE X.
7. Change the name of new_X to X using: ALTER TABLE new_X RENAME TO X.
8. Use CREATE INDEX and CREATE TRIGGER to reconstruct indexes and triggers associated with table X.
9. If any views refer to table X in a way that is affected by the schema change, then drop those views using DROP VIEW
10. If foreign key constraints were originally enabled then run PRAGMA foreign_key_check
11. Commit the transaction started in step 2.
12. If foreign keys constraints were originally enabled, reenable them now.
*/
public class SchemaChanger: CustomStringConvertible {
public enum Error: LocalizedError {
case invalidColumnDefinition(String)
case foreignKeyError([ForeignKeyError])
public var errorDescription: String? {
switch self {
case .foreignKeyError(let errors):
return "Foreign key errors: \(errors)"
case .invalidColumnDefinition(let message):
return "Invalid column definition: \(message)"
}
}
}
public enum Operation {
case addColumn(ColumnDefinition)
case addIndex(IndexDefinition, ifNotExists: Bool)
case dropColumn(String)
case dropIndex(String, ifExists: Bool)
case renameColumn(String, String)
case renameTable(String)
case createTable(columns: [ColumnDefinition], ifNotExists: Bool)
/// Returns non-nil if the operation can be executed with a simple SQL statement
func toSQL(_ table: String, version: SQLiteVersion) -> String? {
switch self {
case .addColumn(let definition):
return "ALTER TABLE \(table.quote()) ADD COLUMN \(definition.toSQL())"
case .addIndex(let definition, let ifNotExists):
return definition.toSQL(ifNotExists: ifNotExists)
case .renameColumn(let from, let to) where SQLiteFeature.renameColumn.isSupported(by: version):
return "ALTER TABLE \(table.quote()) RENAME COLUMN \(from.quote()) TO \(to.quote())"
case .dropColumn(let column) where SQLiteFeature.dropColumn.isSupported(by: version):
return "ALTER TABLE \(table.quote()) DROP COLUMN \(column.quote())"
case .dropIndex(let name, let ifExists):
return "DROP INDEX \(ifExists ? " IF EXISTS " : "") \(name.quote())"
case .createTable(let columns, let ifNotExists):
return "CREATE TABLE \(ifNotExists ? " IF NOT EXISTS " : "") \(table.quote()) (" +
columns.map { $0.toSQL() }.joined(separator: ", ") +
")"
default: return nil
}
}
func validate() throws {
switch self {
case .addColumn(let definition):
// The new column may take any of the forms permissible in a CREATE TABLE statement, with the following restrictions:
// - The column may not have a PRIMARY KEY or UNIQUE constraint.
// - The column may not have a default value of CURRENT_TIME, CURRENT_DATE, CURRENT_TIMESTAMP, or an expression in parentheses
// - If a NOT NULL constraint is specified, then the column must have a default value other than NULL.
guard definition.primaryKey == nil else {
throw Error.invalidColumnDefinition("can not add primary key column")
}
let invalidValues: [LiteralValue] = [.CURRENT_TIME, .CURRENT_DATE, .CURRENT_TIMESTAMP]
if invalidValues.contains(definition.defaultValue) {
throw Error.invalidColumnDefinition("Invalid default value")
}
if !definition.nullable && definition.defaultValue == .NULL {
throw Error.invalidColumnDefinition("NOT NULL columns must have a default value other than NULL")
}
case .dropColumn:
// The DROP COLUMN command only works if the column is not referenced by any other parts of the schema
// and is not a PRIMARY KEY and does not have a UNIQUE constraint
break
default: break
}
}
}
public class AlterTableDefinition {
fileprivate var operations: [Operation] = []
public let name: String
init(name: String) {
self.name = name
}
public func add(column: ColumnDefinition) {
operations.append(.addColumn(column))
}
public func add(index: IndexDefinition, ifNotExists: Bool = false) {
operations.append(.addIndex(index, ifNotExists: ifNotExists))
}
public func drop(column: String) {
operations.append(.dropColumn(column))
}
public func drop(index: String, ifExists: Bool = false) {
operations.append(.dropIndex(index, ifExists: ifExists))
}
public func rename(column: String, to: String) {
operations.append(.renameColumn(column, to))
}
}
public class CreateTableDefinition {
fileprivate var columnDefinitions: [ColumnDefinition] = []
fileprivate var indexDefinitions: [IndexDefinition] = []
let name: String
let ifNotExists: Bool
init(name: String, ifNotExists: Bool) {
self.name = name
self.ifNotExists = ifNotExists
}
public func add(column: ColumnDefinition) {
columnDefinitions.append(column)
}
public func add(expression: Expression) where T: Value {
add(column: .init(name: columnName(for: expression), type: .init(expression: expression), nullable: false))
}
public func add(expression: Expression) where T: Value {
add(column: .init(name: columnName(for: expression), type: .init(expression: expression), nullable: true))
}
public func add(index: IndexDefinition) {
indexDefinitions.append(index)
}
var operations: [Operation] {
precondition(!columnDefinitions.isEmpty)
return [
.createTable(columns: columnDefinitions, ifNotExists: ifNotExists)
] + indexDefinitions.map { .addIndex($0, ifNotExists: ifNotExists) }
}
private func columnName(for expression: Expression) -> String {
switch LiteralValue(expression.template) {
case .stringLiteral(let string): return string
default: fatalError("expression is not a literal string value")
}
}
}
private let connection: Connection
private let schemaReader: SchemaReader
private let version: SQLiteVersion
static let tempPrefix = "tmp_"
typealias Block = () throws -> Void
public typealias AlterTableDefinitionBlock = (AlterTableDefinition) -> Void
public typealias CreateTableDefinitionBlock = (CreateTableDefinition) -> Void
struct Options: OptionSet {
let rawValue: Int
static let `default`: Options = []
static let temp = Options(rawValue: 1)
}
public convenience init(connection: Connection) {
self.init(connection: connection,
version: connection.sqliteVersion)
}
init(connection: Connection, version: SQLiteVersion) {
self.connection = connection
schemaReader = connection.schema
self.version = version
}
public func alter(table: String, block: AlterTableDefinitionBlock) throws {
let alterTableDefinition = AlterTableDefinition(name: table)
block(alterTableDefinition)
for operation in alterTableDefinition.operations {
try run(table: table, operation: operation)
}
}
public func create(table: String, ifNotExists: Bool = false, block: CreateTableDefinitionBlock) throws {
let createTableDefinition = CreateTableDefinition(name: table, ifNotExists: ifNotExists)
block(createTableDefinition)
for operation in createTableDefinition.operations {
try run(table: table, operation: operation)
}
}
public func drop(table: String, ifExists: Bool = true) throws {
try dropTable(table, ifExists: ifExists)
}
// Beginning with release 3.25.0 (2018-09-15), references to the table within trigger bodies and
// view definitions are also renamed.
public func rename(table: String, to: String) throws {
try connection.run("ALTER TABLE \(table.quote()) RENAME TO \(to.quote())")
}
// Runs arbitrary SQL. Should only be used if no predefined operations exist.
@discardableResult
public func run(_ sql: String, _ bindings: Binding?...) throws -> Statement {
return try connection.run(sql, bindings)
}
private func run(table: String, operation: Operation) throws {
try operation.validate()
if let sql = operation.toSQL(table, version: version) {
try connection.run(sql)
} else {
try doTheTableDance(table: table, operation: operation)
}
}
private func doTheTableDance(table: String, operation: Operation) throws {
try connection.transaction {
try disableRefIntegrity {
let tempTable = "\(SchemaChanger.tempPrefix)\(table)"
try moveTable(from: table, to: tempTable, options: [.temp], operation: operation)
try rename(table: tempTable, to: table)
let foreignKeyErrors = try connection.foreignKeyCheck()
if foreignKeyErrors.count > 0 {
throw Error.foreignKeyError(foreignKeyErrors)
}
}
}
}
private func disableRefIntegrity(block: Block) throws {
let oldForeignKeys = connection.foreignKeys
let oldDeferForeignKeys = connection.deferForeignKeys
connection.deferForeignKeys = true
connection.foreignKeys = false
defer {
connection.deferForeignKeys = oldDeferForeignKeys
connection.foreignKeys = oldForeignKeys
}
try block()
}
private func moveTable(from: String, to: String, options: Options = .default, operation: Operation? = nil) throws {
try copyTable(from: from, to: to, options: options, operation: operation)
try dropTable(from, ifExists: true)
}
private func copyTable(from: String, to: String, options: Options = .default, operation: Operation?) throws {
let fromDefinition = TableDefinition(
name: from,
columns: try schemaReader.columnDefinitions(table: from),
indexes: try schemaReader.indexDefinitions(table: from)
)
let toDefinition = fromDefinition
.apply(.renameTable(to))
.apply(operation)
try createTable(definition: toDefinition, options: options)
try createTableIndexes(definition: toDefinition)
if case .dropColumn = operation {
try copyTableContents(from: fromDefinition.apply(operation), to: toDefinition)
} else {
try copyTableContents(from: fromDefinition, to: toDefinition)
}
}
private func createTable(definition: TableDefinition, options: Options) throws {
try connection.run(definition.toSQL(temporary: options.contains(.temp)))
}
private func createTableIndexes(definition: TableDefinition) throws {
for index in definition.indexes {
try index.validate()
try connection.run(index.toSQL())
}
}
private func dropTable(_ table: String, ifExists: Bool) throws {
try connection.run("DROP TABLE \(ifExists ? "IF EXISTS" : "") \(table.quote())")
}
private func copyTableContents(from: TableDefinition, to: TableDefinition) throws {
try connection.run(from.copySQL(to: to))
}
public var description: String {
"SQLiteSchemaChanger: \(connection.description)"
}
}
extension IndexDefinition {
func renameTable(to: String) -> IndexDefinition {
func indexName() -> String {
if to.starts(with: SchemaChanger.tempPrefix) {
return "\(SchemaChanger.tempPrefix)\(name)"
} else if table.starts(with: SchemaChanger.tempPrefix) {
return name.replacingOccurrences(of: SchemaChanger.tempPrefix, with: "")
} else {
return name
}
}
return IndexDefinition(table: to, name: indexName(), unique: unique, columns: columns, where: `where`, orders: orders)
}
func renameColumn(from: String, to: String) -> IndexDefinition {
IndexDefinition(table: table, name: name, unique: unique, columns: columns.map {
$0 == from ? to : $0
}, where: `where`, orders: orders)
}
}
extension TableDefinition {
func apply(_ operation: SchemaChanger.Operation?) -> TableDefinition {
switch operation {
case .none: return self
case .createTable, .addIndex, .dropIndex: fatalError()
case .addColumn: fatalError("Use 'ALTER TABLE ADD COLUMN (...)'")
case .dropColumn(let column):
return TableDefinition(name: name,
columns: columns.filter { $0.name != column },
indexes: indexes.filter { !$0.columns.contains(column) }
)
case .renameColumn(let from, let to):
return TableDefinition(
name: name,
columns: columns.map { $0.rename(from: from, to: to) },
indexes: indexes.map { $0.renameColumn(from: from, to: to) }
)
case .renameTable(let to):
return TableDefinition(name: to, columns: columns, indexes: indexes.map { $0.renameTable(to: to) })
}
}
}
extension ColumnDefinition.Affinity {
init(expression: Expression) where T: Value {
self.init(T.declaredDatatype)
}
init(expression: Expression) where T: Value {
self.init(T.declaredDatatype)
}
}
================================================
FILE: Sources/SQLite/Schema/SchemaDefinitions.swift
================================================
import Foundation
struct TableDefinition: Equatable {
let name: String
let columns: [ColumnDefinition]
let indexes: [IndexDefinition]
var quotedColumnList: String {
columns.map { $0.name.quote() }.joined(separator: ", ")
}
}
// https://sqlite.org/schematab.html#interpretation_of_the_schema_table
public struct ObjectDefinition: Equatable {
public enum ObjectType: String {
case table, index, view, trigger
}
public let type: ObjectType
// The name of the object
public let name: String
// The name of a table or view that the object is associated with.
// * For a table or view, a copy of the name column.
// * For an index, the name of the table that is indexed
// * For a trigger, the column stores the name of the table or view that causes the trigger to fire.
public let tableName: String
// The page number of the root b-tree page for tables and indexes, otherwise 0 or NULL
public let rootpage: Int64
// SQL text that describes the object (NULL for the internal indexes)
public let sql: String?
public var isInternal: Bool {
name.starts(with: "sqlite_") || sql == nil
}
}
// https://sqlite.org/syntax/column-def.html
// column-name -> type-name -> column-constraint*
public struct ColumnDefinition: Equatable {
// The type affinity of a column is the recommended type for data stored in that column.
// The important idea here is that the type is recommended, not required. Any column can still
// store any type of data. It is just that some columns, given the choice, will prefer to use one
// storage class over another. The preferred storage class for a column is called its "affinity".
public enum Affinity: String, CustomStringConvertible, CaseIterable {
case INTEGER
case NUMERIC
case REAL
case TEXT
case BLOB
public var description: String {
rawValue
}
init(_ string: String) {
let test = string.uppercased()
// https://sqlite.org/datatype3.html#determination_of_column_affinity
if test.contains("INT") { // Rule 1
self = .INTEGER
} else if ["CHAR", "CLOB", "TEXT"].first(where: {test.contains($0)}) != nil { // Rule 2
self = .TEXT
} else if string.contains("BLOB") { // Rule 3
self = .BLOB
} else if ["REAL", "FLOA", "DOUB"].first(where: {test.contains($0)}) != nil { // Rule 4
self = .REAL
} else { // Rule 5
self = .NUMERIC
}
}
}
public enum OnConflict: String, CaseIterable {
case ROLLBACK
case ABORT
case FAIL
case IGNORE
case REPLACE
init?(_ string: String) {
guard let value = (OnConflict.allCases.first { $0.rawValue == string }) else { return nil }
self = value
}
}
public struct PrimaryKey: Equatable {
let autoIncrement: Bool
let onConflict: OnConflict?
// swiftlint:disable:next force_try
static let pattern = try! NSRegularExpression(pattern: "PRIMARY KEY\\s*(?:ASC|DESC)?\\s*(?:ON CONFLICT (\\w+)?)?\\s*(AUTOINCREMENT)?")
public init(autoIncrement: Bool = true, onConflict: OnConflict? = nil) {
self.autoIncrement = autoIncrement
self.onConflict = onConflict
}
init?(sql: String) {
guard let match = PrimaryKey.pattern.firstMatch(
in: sql,
range: NSRange(location: 0, length: sql.count)) else {
return nil
}
let conflict = match.range(at: 1)
let onConflict: ColumnDefinition.OnConflict?
if conflict.location != NSNotFound {
onConflict = OnConflict((sql as NSString).substring(with: conflict))
} else {
onConflict = nil
}
let autoIncrement = match.range(at: 2).location != NSNotFound
self.init(autoIncrement: autoIncrement, onConflict: onConflict)
}
}
public struct ForeignKey: Equatable {
let fromColumn: String
let toTable: String
// when null, use primary key of "toTable"
let toColumn: String?
let onUpdate: String?
let onDelete: String?
public init(toTable: String, toColumn: String? = nil, onUpdate: String? = nil, onDelete: String? = nil) {
self.init(fromColumn: "", toTable: toTable, toColumn: toColumn, onUpdate: onUpdate, onDelete: onDelete)
}
public init(fromColumn: String, toTable: String, toColumn: String? = nil, onUpdate: String? = nil, onDelete: String? = nil) {
self.fromColumn = fromColumn
self.toTable = toTable
self.toColumn = toColumn
self.onUpdate = onUpdate
self.onDelete = onDelete
}
}
public let name: String
public let primaryKey: PrimaryKey?
public let type: Affinity
public let nullable: Bool
public let unique: Bool
public let defaultValue: LiteralValue
public let references: ForeignKey?
public init(name: String,
primaryKey: PrimaryKey? = nil,
type: Affinity,
nullable: Bool = true,
unique: Bool = false,
defaultValue: LiteralValue = .NULL,
references: ForeignKey? = nil) {
self.name = name
self.primaryKey = primaryKey
self.type = type
self.nullable = nullable
self.unique = unique
self.defaultValue = defaultValue
self.references = references
}
func rename(from: String, to: String) -> ColumnDefinition {
guard from == name else { return self }
return ColumnDefinition(name: to, primaryKey: primaryKey, type: type, nullable: nullable, defaultValue: defaultValue, references: references)
}
}
public enum LiteralValue: Equatable, CustomStringConvertible {
// swiftlint:disable force_try
private static let singleQuote = try! NSRegularExpression(pattern: "^'(.*)'$")
private static let doubleQuote = try! NSRegularExpression(pattern: "^\"(.*)\"$")
private static let blob = try! NSRegularExpression(pattern: "^[xX]\'(.*)\'$")
// swiftlint:enable force_try
case numericLiteral(String)
case stringLiteral(String)
// BLOB literals are string literals containing hexadecimal data and preceded by a single "x" or "X"
// character. Example: X'53514C697465'
case blobLiteral(String)
// If there is no explicit DEFAULT clause attached to a column definition, then the default value of the
// column is NULL
case NULL
// Beginning with SQLite 3.23.0 (2018-04-02), SQLite recognizes the identifiers "TRUE" and
// "FALSE" as boolean literals, if and only if those identifiers are not already used for some other
// meaning.
//
// The boolean identifiers TRUE and FALSE are usually just aliases for the integer values 1 and 0, respectively.
case TRUE
case FALSE
// swiftlint:disable identifier_name
case CURRENT_TIME
case CURRENT_DATE
case CURRENT_TIMESTAMP
// swiftlint:enable identifier_name
init(_ string: String?) {
guard let string else {
self = .NULL
return
}
switch string {
case "NULL": self = .NULL
case "TRUE": self = .TRUE
case "FALSE": self = .FALSE
case "CURRENT_TIME": self = .CURRENT_TIME
case "CURRENT_TIMESTAMP": self = .CURRENT_TIMESTAMP
case "CURRENT_DATE": self = .CURRENT_DATE
default: self = LiteralValue.parse(string)
}
}
public var description: String {
switch self {
case .NULL: return "NULL"
case .TRUE: return "TRUE"
case .FALSE: return "FALSE"
case .CURRENT_TIMESTAMP: return "CURRENT_TIMESTAMP"
case .CURRENT_TIME: return "CURRENT_TIME"
case .CURRENT_DATE: return "CURRENT_DATE"
case .stringLiteral(let value): return value.quote("'")
case .blobLiteral(let value): return "X\(value.quote("'"))"
case .numericLiteral(let value): return value
}
}
func map(block: (LiteralValue) -> U) -> U? {
if self == .NULL {
return nil
} else {
return block(self)
}
}
private static func parse(_ string: String) -> LiteralValue {
if let match = LiteralValue.singleQuote.firstMatch(in: string, range: NSRange(location: 0, length: string.count)) {
return .stringLiteral((string as NSString).substring(with: match.range(at: 1)).replacingOccurrences(of: "''", with: "'"))
} else if let match = LiteralValue.doubleQuote.firstMatch(in: string, range: NSRange(location: 0, length: string.count)) {
return .stringLiteral((string as NSString).substring(with: match.range(at: 1)).replacingOccurrences(of: "\"\"", with: "\""))
} else if let match = LiteralValue.blob.firstMatch(in: string, range: NSRange(location: 0, length: string.count)) {
return .blobLiteral((string as NSString).substring(with: match.range(at: 1)))
} else {
return .numericLiteral(string)
}
}
}
// https://sqlite.org/lang_createindex.html
// schema-name.index-name ON table-name ( indexed-column+ ) WHERE expr
public struct IndexDefinition: Equatable {
// SQLite supports index names up to 64 characters.
static let maxIndexLength = 64
// swiftlint:disable force_try
static let whereRe = try! NSRegularExpression(pattern: "\\sWHERE\\s+(.+)$")
static let orderRe = try! NSRegularExpression(pattern: "\"?(\\w+)\"? DESC")
// swiftlint:enable force_try
public enum Order: String { case ASC, DESC }
public init(table: String, name: String, unique: Bool = false, columns: [String], `where`: String? = nil,
orders: [String: Order]? = nil, origin: Origin? = nil) {
self.table = table
self.name = name
self.unique = unique
self.columns = columns
self.where = `where`
self.orders = orders
self.origin = origin
}
init (table: String, name: String, unique: Bool, columns: [String], indexSQL: String?, origin: Origin? = nil) {
func wherePart(sql: String) -> String? {
IndexDefinition.whereRe.firstMatch(in: sql, options: [], range: NSRange(location: 0, length: sql.count)).map {
(sql as NSString).substring(with: $0.range(at: 1))
}
}
func orders(sql: String) -> [String: IndexDefinition.Order] {
IndexDefinition.orderRe
.matches(in: sql, range: NSRange(location: 0, length: sql.count))
.reduce([String: IndexDefinition.Order]()) { (memo, result) in
var memo2 = memo
let column = (sql as NSString).substring(with: result.range(at: 1))
memo2[column] = .DESC
return memo2
}
}
let orders = indexSQL.flatMap(orders)
self.init(table: table,
name: name,
unique: unique,
columns: columns,
where: indexSQL.flatMap(wherePart),
orders: (orders?.isEmpty ?? false) ? nil : orders,
origin: origin)
}
public let table: String
public let name: String
public let unique: Bool
public let columns: [String]
public let `where`: String?
public let orders: [String: Order]?
public let origin: Origin?
public enum Origin: String {
case uniqueConstraint = "u" // index created from a "CREATE TABLE (... UNIQUE)" column constraint
case createIndex = "c" // index created explicitly via "CREATE INDEX ..."
case primaryKey = "pk" // index created from a "CREATE TABLE PRIMARY KEY" column constraint
}
enum IndexError: LocalizedError {
case tooLong(String, String)
var errorDescription: String? {
switch self {
case .tooLong(let name, let table):
return "Index name '\(name)' on table '\(table)' is too long; the limit is " +
"\(IndexDefinition.maxIndexLength) characters"
}
}
}
// Indices with names of the form "sqlite_autoindex_TABLE_N" that are used to implement UNIQUE and PRIMARY KEY
// constraints on ordinary tables.
// https://sqlite.org/fileformat2.html#intschema
var isInternal: Bool {
name.starts(with: "sqlite_autoindex_")
}
func validate() throws {
if name.count > IndexDefinition.maxIndexLength {
throw IndexError.tooLong(name, table)
}
}
}
public struct ForeignKeyError: CustomStringConvertible {
public let from: String
public let rowId: Int64
public let to: String
public var description: String {
"\(from) [\(rowId)] => \(to)"
}
}
extension TableDefinition {
func toSQL(temporary: Bool = false) -> String {
precondition(columns.count > 0, "no columns to create")
return ([
"CREATE",
temporary ? "TEMPORARY" : nil,
"TABLE",
name,
"(",
columns.map { $0.toSQL() }.joined(separator: ",\n"),
")"
] as [String?]).compactMap { $0 }
.joined(separator: " ")
}
func copySQL(to: TableDefinition) -> String {
precondition(columns.count > 0)
precondition(columns.count == to.columns.count, "column counts don't match")
return "INSERT INTO \(to.name.quote()) (\(to.quotedColumnList)) SELECT \(quotedColumnList) FROM \(name.quote())"
}
}
extension ColumnDefinition {
func toSQL() -> String {
[
name.quote(),
type.rawValue,
defaultValue.map { "DEFAULT \($0)" },
primaryKey.map { $0.toSQL() },
nullable ? nil : "NOT NULL",
unique ? "UNIQUE" : nil,
references.map { $0.toSQL() }
].compactMap { $0 }
.joined(separator: " ")
}
}
extension IndexDefinition {
public func toSQL(ifNotExists: Bool = false) -> String {
let commaSeparatedColumns = columns.map { (column: String) -> String in
column.quote() + (orders?[column].map { " \($0.rawValue)" } ?? "")
}.joined(separator: ", ")
return ([
"CREATE",
unique ? "UNIQUE" : nil,
"INDEX",
ifNotExists ? "IF NOT EXISTS" : nil,
name.quote(),
"ON",
table.quote(),
"(\(commaSeparatedColumns))",
`where`.map { "WHERE \($0)" }
] as [String?]).compactMap { $0 }
.joined(separator: " ")
}
}
extension ColumnDefinition.ForeignKey {
func toSQL() -> String {
([
"REFERENCES",
toTable.quote(),
toColumn.map { "(\($0.quote()))" },
onUpdate.map { "ON UPDATE \($0)" },
onDelete.map { "ON DELETE \($0)" }
] as [String?]).compactMap { $0 }
.joined(separator: " ")
}
}
extension ColumnDefinition.PrimaryKey {
func toSQL() -> String {
[
"PRIMARY KEY",
autoIncrement ? "AUTOINCREMENT" : nil,
onConflict.map { "ON CONFLICT \($0.rawValue)" }
].compactMap { $0 }.joined(separator: " ")
}
}
================================================
FILE: Sources/SQLite/Schema/SchemaReader.swift
================================================
import Foundation
public class SchemaReader {
private let connection: Connection
init(connection: Connection) {
self.connection = connection
}
// https://sqlite.org/pragma.html#pragma_table_info
//
// This pragma returns one row for each column in the named table. Columns in the result set include the
// column name, data type, whether or not the column can be NULL, and the default value for the column. The
// "pk" column in the result set is zero for columns that are not part of the primary key, and is the
// index of the column in the primary key for columns that are part of the primary key.
public func columnDefinitions(table: String) throws -> [ColumnDefinition] {
func parsePrimaryKey(column: String) throws -> ColumnDefinition.PrimaryKey? {
try createTableSQL(name: table).flatMap { .init(sql: $0) }
}
let foreignKeys: [String: [ColumnDefinition.ForeignKey]] =
Dictionary(grouping: try foreignKeys(table: table), by: { $0.fromColumn })
let columnDefinitions = try connection.prepareRowIterator("PRAGMA table_info(\(table.quote()))")
.map { (row: Row) -> ColumnDefinition in
ColumnDefinition(
name: row[TableInfoTable.nameColumn],
primaryKey: (row[TableInfoTable.primaryKeyColumn] ?? 0) > 0 ?
try parsePrimaryKey(column: row[TableInfoTable.nameColumn]) : nil,
type: ColumnDefinition.Affinity(row[TableInfoTable.typeColumn]),
nullable: row[TableInfoTable.notNullColumn] == 0,
unique: false,
defaultValue: LiteralValue(row[TableInfoTable.defaultValueColumn]),
references: foreignKeys[row[TableInfoTable.nameColumn]]?.first
)
}
let internalIndexes = try indexDefinitions(table: table).filter { $0.isInternal }
return columnDefinitions.map { definition in
if let index = internalIndexes.first(where: { $0.columns.contains(definition.name) }), index.origin == .uniqueConstraint {
ColumnDefinition(name: definition.name,
primaryKey: definition.primaryKey,
type: definition.type,
nullable: definition.nullable,
unique: true,
defaultValue: definition.defaultValue,
references: definition.references)
} else {
definition
}
}
}
public func objectDefinitions(name: String? = nil,
type: ObjectDefinition.ObjectType? = nil,
temp: Bool = false) throws -> [ObjectDefinition] {
var query: QueryType = SchemaTable.get(for: connection, temp: temp)
if let name {
query = query.where(SchemaTable.nameColumn == name)
}
if let type {
query = query.where(SchemaTable.typeColumn == type.rawValue)
}
return try connection.prepare(query).map { row -> ObjectDefinition in
guard let type = ObjectDefinition.ObjectType(rawValue: row[SchemaTable.typeColumn]) else {
fatalError("unexpected type")
}
return ObjectDefinition(
type: type,
name: row[SchemaTable.nameColumn],
tableName: row[SchemaTable.tableNameColumn],
rootpage: row[SchemaTable.rootPageColumn] ?? 0,
sql: row[SchemaTable.sqlColumn]
)
}
}
public func indexDefinitions(table: String) throws -> [IndexDefinition] {
func indexSQL(name: String) throws -> String? {
try objectDefinitions(name: name, type: .index)
.compactMap(\.sql)
.first
}
func indexInfos(name: String) throws -> [IndexInfo] {
try connection.prepareRowIterator("PRAGMA index_info(\(name.quote()))")
.compactMap { row in
IndexInfo(name: row[IndexInfoTable.nameColumn],
columnRank: row[IndexInfoTable.seqnoColumn],
columnRankWithinTable: row[IndexInfoTable.cidColumn])
}
}
return try connection.prepareRowIterator("PRAGMA index_list(\(table.quote()))")
.compactMap { row -> IndexDefinition? in
let name = row[IndexListTable.nameColumn]
return IndexDefinition(
table: table,
name: name,
unique: row[IndexListTable.uniqueColumn] == 1,
columns: try indexInfos(name: name).compactMap { $0.name },
indexSQL: try indexSQL(name: name),
origin: IndexDefinition.Origin(rawValue: row[IndexListTable.originColumn])
)
}
}
func foreignKeys(table: String) throws -> [ColumnDefinition.ForeignKey] {
try connection.prepareRowIterator("PRAGMA foreign_key_list(\(table.quote()))")
.map { row in
ColumnDefinition.ForeignKey(
fromColumn: row[ForeignKeyListTable.fromColumn],
toTable: row[ForeignKeyListTable.tableColumn],
toColumn: row[ForeignKeyListTable.toColumn],
onUpdate: row[ForeignKeyListTable.onUpdateColumn] == TableBuilder.Dependency.noAction.rawValue
? nil : row[ForeignKeyListTable.onUpdateColumn],
onDelete: row[ForeignKeyListTable.onDeleteColumn] == TableBuilder.Dependency.noAction.rawValue
? nil : row[ForeignKeyListTable.onDeleteColumn]
)
}
}
func tableDefinitions() throws -> [TableDefinition] {
try objectDefinitions(type: .table)
.map { table in
TableDefinition(
name: table.name,
columns: try columnDefinitions(table: table.name),
indexes: try indexDefinitions(table: table.name)
)
}
}
private func createTableSQL(name: String) throws -> String? {
try (
objectDefinitions(name: name, type: .table) +
objectDefinitions(name: name, type: .table, temp: true)
).compactMap(\.sql).first
}
struct IndexInfo {
let name: String?
// The rank of the column within the index. (0 means left-most.)
let columnRank: Int
// The rank of the column within the table being indexed.
// A value of -1 means rowid and a value of -2 means that an expression is being used
let columnRankWithinTable: Int
}
}
private enum SchemaTable {
private static let name = Table("sqlite_schema", database: "main")
private static let tempName = Table("sqlite_schema", database: "temp")
// legacy names (< 3.33.0)
private static let masterName = Table("sqlite_master")
private static let tempMasterName = Table("sqlite_temp_master")
static func get(for connection: Connection, temp: Bool = false) -> Table {
if connection.supports(.sqliteSchemaTable) {
return temp ? SchemaTable.tempName : SchemaTable.name
} else {
return temp ? SchemaTable.tempMasterName : SchemaTable.masterName
}
}
// columns
static let typeColumn = Expression("type")
static let nameColumn = Expression("name")
static let tableNameColumn = Expression("tbl_name")
static let rootPageColumn = Expression("rootpage")
static let sqlColumn = Expression("sql")
}
private enum TableInfoTable {
static let idColumn = Expression("cid")
static let nameColumn = Expression("name")
static let typeColumn = Expression("type")
static let notNullColumn = Expression("notnull")
static let defaultValueColumn = Expression("dflt_value")
static let primaryKeyColumn = Expression