├── .cproject
├── .editorconfig
├── .gitbugtraq
├── .github
├── dependabot.yml
└── workflows
│ ├── cmake.yml
│ ├── cmake_builtin_lib.yml
│ ├── cmake_subdir_example.yml
│ └── meson.yml
├── .gitignore
├── .gitmodules
├── .project
├── .travis.yml
├── CHANGELOG.md
├── CMakeLists.txt
├── Doxyfile
├── LICENSE.txt
├── README.md
├── TODO.txt
├── _config.yml
├── appveyor.yml
├── build.bat
├── build.sh
├── cmake
├── FindSQLite3.cmake
└── SQLiteCppConfig.cmake.in
├── cpplint.py
├── docs
└── README.md
├── examples
├── example1
│ ├── README.md
│ ├── example.db3
│ ├── logo.png
│ ├── main.cpp
│ └── meson.build
├── example2
│ ├── CMakeLists.txt
│ ├── README.md
│ ├── build.bat
│ ├── build.sh
│ ├── meson.build
│ └── src
│ │ └── main.cpp
└── meson.build
├── include
└── SQLiteCpp
│ ├── Assertion.h
│ ├── Backup.h
│ ├── Column.h
│ ├── Database.h
│ ├── Exception.h
│ ├── ExecuteMany.h
│ ├── SQLiteCpp.h
│ ├── SQLiteCppExport.h
│ ├── Savepoint.h
│ ├── Statement.h
│ ├── Transaction.h
│ ├── Utils.h
│ └── VariadicBind.h
├── meson.build
├── meson_options.txt
├── package.xml
├── sqlite3
├── CMakeLists.txt
├── README.md
├── sqlite3.c
└── sqlite3.h
├── src
├── Backup.cpp
├── Column.cpp
├── Database.cpp
├── Exception.cpp
├── Savepoint.cpp
├── Statement.cpp
└── Transaction.cpp
├── subprojects
├── .gitignore
├── gtest.wrap
└── sqlite3.wrap
└── tests
├── Backup_test.cpp
├── Column_test.cpp
├── Database_test.cpp
├── Exception_test.cpp
├── ExecuteMany_test.cpp
├── Savepoint_test.cpp
├── Statement_test.cpp
├── Transaction_test.cpp
└── VariadicBind_test.cpp
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | # 4 space indentation
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 4
8 | insert_final_newline = true
9 | end_of_line = lf
10 |
11 | # 2 space indentation for CI configuration
12 | [*.yml]
13 | indent_style = space
14 | indent_size = 2
15 |
--------------------------------------------------------------------------------
/.gitbugtraq:
--------------------------------------------------------------------------------
1 | # .gitbugtraq for Git GUIs (SmartGit/TortoiseGit) to show links to the Github issue tracker.
2 | # Instead of the repository root directory, it could be added as an additional section to $GIT_DIR/config.
3 | # (note that '\' need to be escaped).
4 | [bugtraq]
5 | url = https://github.com/SRombauts/SQLiteCpp/issues/%BUGID%
6 | loglinkregex = "#\\d+"
7 | logregex = \\d+
8 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
2 | version: 2
3 | updates:
4 | - package-ecosystem: "github-actions"
5 | directory: "/" # Location of package manifests
6 | schedule:
7 | interval: "monthly"
8 |
--------------------------------------------------------------------------------
/.github/workflows/cmake.yml:
--------------------------------------------------------------------------------
1 | name: CMake build
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 | name: ${{ matrix.config.name }}
8 | runs-on: ${{ matrix.config.os }}
9 | strategy:
10 | fail-fast: false
11 | matrix:
12 | config:
13 | - {
14 | name: "Windows Latest MSVC",
15 | os: windows-latest,
16 | generator: "Visual Studio 17 2022",
17 | build_type: "Debug",
18 | cc: "cl", cxx: "cl",
19 | extra_path: "",
20 | }
21 | - {
22 | name: "Windows Latest MinGW",
23 | os: windows-latest,
24 | generator: "MinGW Makefiles",
25 | build_type: "Debug",
26 | cc: "gcc", cxx: "g++",
27 | extra_path: "C:\\ProgramData\\chocolatey\\lib\\mingw\\tools\\install\\mingw64\\bin",
28 | }
29 | - {
30 | name: "Ubuntu 24.04 GCC",
31 | os: ubuntu-24.04,
32 | generator: "Unix Makefiles",
33 | build_type: "Debug",
34 | cc: "gcc", cxx: "g++",
35 | extra_path: "",
36 | }
37 | - {
38 | name: "Ubuntu 22.04 GCC",
39 | os: ubuntu-22.04,
40 | generator: "Unix Makefiles",
41 | build_type: "Debug",
42 | cc: "gcc", cxx: "g++",
43 | extra_path: "",
44 | }
45 | - {
46 | name: "macOS Latest Clang",
47 | os: macos-latest,
48 | generator: "Unix Makefiles",
49 | build_type: "Debug",
50 | cc: "clang", cxx: "clang++",
51 | extra_path: "",
52 | }
53 |
54 | steps:
55 | - name: Checkout ${{ github.ref_name }}
56 | uses: actions/checkout@v4
57 | - run: git submodule update --init --recursive
58 | - name: set extra GITHUB_PATH ${{ matrix.config.extra_path }} (for MinGW)
59 | shell: bash
60 | run: echo "${{ matrix.config.extra_path }}" >> $GITHUB_PATH
61 | - name: set env CXX=${{ matrix.config.cxx }}
62 | shell: cmake -P {0}
63 | run: |
64 | set(ENV{CC} ${{ matrix.config.cc }})
65 | set(ENV{CXX} ${{ matrix.config.cxx }})
66 | - run: mkdir build
67 | - run: cmake -G "${{ matrix.config.generator }}" -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} -DBUILD_SHARED_LIBS=ON -DSQLITECPP_BUILD_TESTS=ON -DSQLITECPP_BUILD_EXAMPLES=ON -DSQLITECPP_RUN_CPPCHECK=OFF -DSQLITECPP_RUN_CPPLINT=OFF ..
68 | working-directory: build
69 | - run: cmake --build build --config ${{ matrix.config.build_type }}
70 | - run: ctest --verbose --output-on-failure --test-dir build
71 |
--------------------------------------------------------------------------------
/.github/workflows/cmake_builtin_lib.yml:
--------------------------------------------------------------------------------
1 | name: CMake SQLite3 builtin library
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 | name: ${{ matrix.config.name }}
8 | runs-on: ${{ matrix.config.os }}
9 | strategy:
10 | fail-fast: false
11 | matrix:
12 | config:
13 | - {
14 | name: "Ubuntu Latest GCC",
15 | os: ubuntu-latest,
16 | generator: "Unix Makefiles",
17 | }
18 | - {
19 | name: "macOS Latest Clang",
20 | os: macos-latest,
21 | generator: "Unix Makefiles",
22 | }
23 |
24 | steps:
25 | - name: Checkout ${{ github.ref_name }}
26 | uses: actions/checkout@v4
27 | - run: git submodule update --init --recursive
28 | - run: mkdir build
29 | - run: cmake -G "Unix Makefiles" -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=Debug -DSQLITECPP_INTERNAL_SQLITE=OFF -DSQLITE_OMIT_LOAD_EXTENSION=ON -DSQLITECPP_BUILD_TESTS=ON -DSQLITECPP_BUILD_EXAMPLES=ON -DSQLITECPP_RUN_CPPCHECK=OFF -DSQLITECPP_RUN_CPPLINT=OFF ..
30 | working-directory: build
31 | - run: cmake --build build --config Debug
32 | - run: ctest --verbose --output-on-failure --test-dir build
33 |
--------------------------------------------------------------------------------
/.github/workflows/cmake_subdir_example.yml:
--------------------------------------------------------------------------------
1 | name: CMake build of example in subdirectory
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 | name: ${{ matrix.config.name }}
8 | runs-on: ${{ matrix.config.os }}
9 | strategy:
10 | fail-fast: false
11 | matrix:
12 | config:
13 | - {
14 | name: "Windows Latest MSVC",
15 | os: windows-latest,
16 | build_type: "Debug", cc: "cl", cxx: "cl",
17 | }
18 | - {
19 | name: "Ubuntu Latest GCC",
20 | os: ubuntu-latest,
21 | build_type: "Debug", cc: "gcc", cxx: "g++"
22 | }
23 | - {
24 | name: "macOS Latest Clang",
25 | os: macos-latest,
26 | build_type: "Debug", cc: "clang", cxx: "clang++"
27 | }
28 |
29 | steps:
30 | - uses: actions/checkout@v4
31 | - name: configure
32 | shell: cmake -P {0}
33 | run: |
34 | set(ENV{CC} ${{matrix.config.cc}})
35 | set(ENV{CXX} ${{matrix.config.cxx}})
36 | - name: generate
37 | run: |
38 | cd examples/example2
39 | mkdir build
40 | cd build
41 | cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=${{matrix.config.build_type}} ..
42 | - name: build
43 | run: cmake --build examples/example2/build --config ${{matrix.config.build_type}}
44 |
--------------------------------------------------------------------------------
/.github/workflows/meson.yml:
--------------------------------------------------------------------------------
1 | name: Meson build
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 | name: (Meson) ${{ matrix.config.name }}
8 | runs-on: ${{ matrix.config.os }}
9 | strategy:
10 | fail-fast: false
11 | matrix:
12 | config:
13 | - {
14 | name: "Windows Latest MSVC",
15 | os: windows-latest,
16 | cc: "cl", cxx: "cl",
17 | extra_path: "",
18 | requires_msvc: true,
19 | }
20 | - {
21 | name: "Windows Latest MinGW",
22 | os: windows-latest,
23 | cc: "gcc", cxx: "g++",
24 | extra_path: "C:\\ProgramData\\chocolatey\\lib\\mingw\\tools\\install\\mingw64\\bin",
25 | }
26 | - {
27 | name: "Windows Latest Clang",
28 | os: windows-latest,
29 | cc: "clang", cxx: "clang++", c_ld: "lld-link", cxx_ld: "lld-link",
30 | extra_path: "",
31 | }
32 | - {
33 | name: "Ubuntu Latest GCC",
34 | os: ubuntu-latest,
35 | cc: "gcc", cxx: "g++",
36 | extra_path: ""
37 | }
38 | - {
39 | name: "Ubuntu Latest Clang",
40 | os: ubuntu-latest,
41 | cc: "clang", cxx: "clang++", c_ld: "lld", cxx_ld: "lld",
42 | extra_path: ""
43 | }
44 | - {
45 | name: "macOS Latest Clang",
46 | os: macos-latest,
47 | cc: "clang", cxx: "clang++",
48 | extra_path: ""
49 | }
50 |
51 | steps:
52 | - uses: actions/checkout@v4
53 | # use msvc-dev-cmd to setup the environment for MSVC if needed
54 | - name: setup MSVC
55 | if: matrix.config.requires_msvc
56 | uses: ilammy/msvc-dev-cmd@v1
57 | - name: extra_path
58 | shell: bash
59 | run: echo "${{matrix.config.extra_path}}" >> $GITHUB_PATH
60 | - name: install prerequisites
61 | run: |
62 | # asuming that python and pipx are already installed
63 | pipx install meson ninja
64 | - name: setup meson project
65 | env: # set proper compilers and linkers for meson
66 | CC: ${{matrix.config.cc}}
67 | CXX: ${{matrix.config.cxx}}
68 | C_LD: ${{matrix.config.c_ld}}
69 | CXX_LD: ${{matrix.config.cxx_ld}}
70 | run: |
71 | # setup the build directory with tests and examples enabled
72 | meson setup builddir -DSQLITECPP_BUILD_TESTS=true -DSQLITECPP_BUILD_EXAMPLES=true --force-fallback-for=sqlite3
73 | - name: build meson project
74 | run: |
75 | # build the project
76 | meson compile -C builddir
77 | - name: test
78 | run: |
79 | # run the tests
80 | meson test -C builddir
81 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Debug
2 | Release
3 | build
4 | *.a
5 |
6 | # ignore clangd cache directory
7 | .cache
8 | .vs/
9 | .vscode/
10 | .vsconfig
11 | *.sln
12 | *.ncb
13 | *.suo
14 | *.user
15 | *sdf
16 | *.vc*
17 | *~
18 | doc
19 | core
20 | *ipch
21 | .settings/
22 |
23 | # do not track Visual Studio CMake settings
24 | CMakeSettings.json
25 | CMakeCache.txt
26 | CMakeFiles
27 | *.dir
28 | Testing
29 | Win32
30 |
31 | SQLiteCpp_example1
32 | SQLiteCpp_tests
33 |
34 | !FindSQLiteCpp.cmake
35 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "googletest"]
2 | path = googletest
3 | url = https://github.com/google/googletest.git
4 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | SQLiteC++
4 |
5 |
6 |
7 |
8 |
9 | org.python.pydev.PyDevBuilder
10 |
11 |
12 |
13 |
14 | org.eclipse.cdt.managedbuilder.core.genmakebuilder
15 | clean,full,incremental,
16 |
17 |
18 | ?name?
19 |
20 |
21 |
22 | org.eclipse.cdt.make.core.append_environment
23 | true
24 |
25 |
26 | org.eclipse.cdt.make.core.autoBuildTarget
27 | all
28 |
29 |
30 | org.eclipse.cdt.make.core.buildArguments
31 | -j
32 |
33 |
34 | org.eclipse.cdt.make.core.buildCommand
35 | make
36 |
37 |
38 | org.eclipse.cdt.make.core.cleanBuildTarget
39 | clean
40 |
41 |
42 | org.eclipse.cdt.make.core.contents
43 | org.eclipse.cdt.make.core.activeConfigSettings
44 |
45 |
46 | org.eclipse.cdt.make.core.enableAutoBuild
47 | false
48 |
49 |
50 | org.eclipse.cdt.make.core.enableCleanBuild
51 | true
52 |
53 |
54 | org.eclipse.cdt.make.core.enableFullBuild
55 | true
56 |
57 |
58 | org.eclipse.cdt.make.core.fullBuildTarget
59 | all
60 |
61 |
62 | org.eclipse.cdt.make.core.stopOnError
63 | true
64 |
65 |
66 | org.eclipse.cdt.make.core.useDefaultBuildCmd
67 | true
68 |
69 |
70 |
71 |
72 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
73 | full,incremental,
74 |
75 |
76 |
77 |
78 |
79 | org.eclipse.cdt.core.cnature
80 | org.eclipse.cdt.core.ccnature
81 | org.eclipse.cdt.managedbuilder.core.managedBuildNature
82 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
83 | org.python.pydev.pythonNature
84 |
85 |
86 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2012-2023 Sebastien Rombauts (sebastien.rombauts@gmail.com)
2 |
3 | language: cpp
4 |
5 | # Use Linux unless specified otherwise
6 | os: linux
7 |
8 | cache:
9 | apt: true
10 |
11 | env:
12 | global:
13 | - BUILD_TYPE=Debug
14 | - ASAN=ON
15 | - INTERNAL_SQLITE=ON
16 | - VALGRIND=OFF
17 | - TESTS=ON
18 | - SHARED_LIBS=OFF
19 |
20 | # Build variants (should test a reasonable number of combination of CMake options)
21 | jobs:
22 | include:
23 |
24 | ##########################################################################
25 | # GCC on Linux
26 | ##########################################################################
27 |
28 | # GCC 11.2.0 (Ubuntu Jammy 22.04)
29 | - dist: jammy
30 | env:
31 | - cc=gcc cxx=g++
32 |
33 | # Clang 9.3.0 (Ubuntu Focal 20.04)
34 | - dist: focal
35 | env:
36 | - cc=gcc cxx=g++
37 |
38 | # Coverity static code analysis (Ubuntu Bionic 18.04)
39 | - dist: bionic
40 | env:
41 | - COVERITY_SCAN_PROJECT_NAME=SRombauts/SQLiteCpp
42 | - COVERITY_SCAN_BRANCH_PATTERN=master
43 | - COVERITY_SCAN_NOTIFICATION_EMAIL=sebastien.rombauts@gmail.com
44 | - COVERITY_SCAN_BUILD_COMMAND_PREPEND="cmake ."
45 | - COVERITY_SCAN_BUILD_COMMAND="make -j8"
46 | # Encrypted COVERITY_SCAN_TOKEN, created via the "travis encrypt" command using the project repo's public key
47 | - secure: "Qm4d8NEDPBtYZCYav46uPEvDCtaRsjLXlkVS+C+WCJAPcwXCGkrr96wEi7RWcq2xD86QCh0XiqaPT+xdUmlohOYIovRhaaBmZ1lwIJ4GsG/ZR6xoFr3DYsZ3o4GyXk2vNXNxEl82AC+Xs6e6gkLOV9XRkBcjpVIvoIXgNlKWeGY="
48 |
49 | # GCC 7.4.0 Debug build with GCov for coverage build (Ubuntu Bionic 18.04)
50 | - dist: bionic
51 | env:
52 | - cc=gcc cxx=g++
53 | - GCOV=ON
54 | - COVERALLS=ON
55 |
56 | # GCC 7.4.0 Debug build with Valgrind instead of Address Sanitizer (Ubuntu Bionic 18.04)
57 | - dist: bionic
58 | env:
59 | - cc=gcc cxx=g++
60 | - ASAN=OFF
61 | - VALGRIND=ON
62 |
63 | # GCC 7.4.0 Release build (Ubuntu Bionic 18.04)
64 | - dist: bionic
65 | env:
66 | - cc=gcc cxx=g++
67 | - BUILD_TYPE=Release
68 |
69 | # GCC 7.4.0 Shared Libs (Ubuntu Bionic 18.04)
70 | - dist: bionic
71 | env:
72 | - cc=gcc cxx=g++
73 | - SHARED_LIBS=ON
74 |
75 | # GCC 7.4.0 test linking with libsqlite3-dev package (Ubuntu Bionic 18.04)
76 | - dist: bionic
77 | env:
78 | - cc=gcc cxx=g++
79 | - INTERNAL_SQLITE=OFF
80 |
81 | # GCC 5.4.0 (Ubuntu Xenial 16.04)
82 | - dist: xenial # Default
83 | env:
84 | - cc=gcc cxx=g++
85 |
86 | # GCC 4.8.4 (Ubuntu Trusty 14.04)
87 | - dist: trusty
88 | env:
89 | - cc=gcc cxx=g++
90 | - TESTS=OFF
91 |
92 | ##########################################################################
93 | # Clang on Linux
94 | ##########################################################################
95 |
96 | # Clang 7.0.0 (Ubuntu Jammy 22.04)
97 | - dist: jammy
98 | env:
99 | - cc=clang cxx=clang++
100 |
101 | # Clang 7.0.0 (Ubuntu Focal 20.04)
102 | - dist: focal
103 | env:
104 | - cc=clang cxx=clang++
105 |
106 | # Clang 7.0.0 (Ubuntu Bionic 18.04)
107 | - dist: bionic
108 | env:
109 | - cc=clang cxx=clang++
110 |
111 | # Clang 7.0.0 (Ubuntu Xenial 16.04)
112 | - dist: xenial # Default
113 | env:
114 | - cc=clang cxx=clang++
115 |
116 | # Clang 5.0.0 (Ubuntu Trusty 14.04)
117 | - dist: trusty
118 | env:
119 | - cc=clang cxx=clang++
120 | - TESTS=OFF
121 |
122 | ##########################################################################
123 | # Clang on OSX
124 | ##########################################################################
125 |
126 | # XCode 14.2 - Apple clang 14.0.0 - macOS 12.6
127 | - os: osx
128 | osx_image: xcode14.2
129 | env:
130 | - cc=clang cxx=clang++
131 |
132 | # Default XCode - Apple clang 9.1.0 - macOS 10.13
133 | - os: osx
134 | osx_image: xcode9.4 # Default
135 | env:
136 | - cc=clang cxx=clang++
137 |
138 | # XCode 8.3 - Applec lang 8.1.0 - macOS 10.12
139 | - os: osx
140 | osx_image: xcode8.3
141 | env:
142 | - cc=clang cxx=clang++
143 | - TESTS=OFF
144 |
145 | before_install:
146 | # Coverity: don't use addons.coverity_scan since it run on every job of the build matrix, which waste resources and exhausts quotas
147 | # Note: the job dedicated to Coverity need to only run the shell script and then exit (to not try to build and run unit tests etc.)
148 | - if [[ -n "$COVERITY_SCAN_PROJECT_NAME" ]] ; then curl -s https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh | bash ; exit 0 ; fi
149 |
150 | - if [[ "$INTERNAL_SQLITE" == "OFF" ]]; then sudo apt-get install libsqlite3-dev ; fi
151 | - if [[ "$VALGRIND" == "ON" ]]; then sudo apt-get install valgrind ; fi
152 | - if [[ "$COVERALLS" == "ON" ]]; then pip install --user cpp-coveralls ; fi
153 |
154 | # Set the compiler environment variables properly
155 | - export CC=${cc}
156 | - export CXX=${cxx}
157 |
158 | # scripts to run before build
159 | before_script:
160 | - mkdir build
161 | - cd build
162 | - cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_SHARED_LIBS=$SHARED_LIBS -DSQLITECPP_INTERNAL_SQLITE=$INTERNAL_SQLITE -DSQLITECPP_USE_ASAN=$ASAN -DSQLITECPP_USE_GCOV=$GCOV -DSQLITECPP_BUILD_EXAMPLES=$TESTS -DSQLITECPP_BUILD_TESTS=$TESTS ..
163 |
164 | # build examples, and run tests (ie make & make test)
165 | script:
166 | - cmake --build .
167 | - export ASAN_OPTIONS=verbosity=1:debug=1
168 | - if [[ "$TESTS" == "ON" ]]; then ctest --verbose --output-on-failure ; fi
169 | - if [[ "$VALGRIND" == "ON" ]]; then valgrind --leak-check=full --error-exitcode=1 bin/SQLiteCpp_example1 ; fi
170 | - if [[ "$VALGRIND" == "ON" ]]; then valgrind --leak-check=full --error-exitcode=1 bin/SQLiteCpp_tests ; fi
171 |
172 | # generate and publish GCov coveralls results
173 | after_success:
174 | - if [[ "$COVERALLS" == "ON" ]]; then coveralls --root .. -e examples -e googletest -e sqlite3 -e tests -E ".*feature_tests.*" -E ".*CompilerId.*" --gcov-options '\-lp' ; fi
175 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | 2012 Mar 30
2 | - Start of a new thin C++ SQLite wrapper
3 |
4 | 2012 Apr 2
5 | - The wrapper is functional
6 | - Added documentation and examples
7 | - Publication on GitHub
8 |
9 | Version 0.1.0 - 2012 Apr 4
10 | - Added a Database::exec() method to execute simple SQL statement
11 | - Added a version number like in sqlite3.h, starting with 0.1.0
12 |
13 | Version 0.2.0 - 2012 Apr 11
14 | - Added getLastInsertId() and setBusyTimout()
15 | - Added bind() by name methods
16 |
17 | Version 0.3.0 - 2012 Apr 16
18 | - Added an easy wrapper Database::execAngGet()
19 |
20 | Version 0.4.0 - 2012 Apr 23
21 | - Added a Database::tableExists() easy to use function
22 |
23 | Dec 10 2012
24 | - Added a Statement::exec() method to execute a one-step query with no expected result
25 |
26 | Version 0.5.0 - 2013 March 9
27 | - Added assert() on errors on destructors
28 | - Added getBytes()
29 | - Added getBlob(), getType() and isInteger/isFloat/isText/isBlob/isNull
30 | - Added bind() for binary blob data
31 |
32 | Version 0.5.1 - 2013 April 7
33 | - Added Column::getName()
34 |
35 | Version 0.6.0 - 2013 November 22
36 | - Renamed Column::getName() to Column::getOriginName()
37 | - Added Column::getName()
38 |
39 | Version 0.7.0 - 2014 January 9
40 | - Added Database::createFunction()
41 | - Added std::string version of existing APIs
42 | - Improved CMake with more build options and Doxygen auto-detection
43 |
44 | Version 0.8.0 - 2014 February 26
45 | - Database constructor support opening a database with a custom VFS (default to NULL)
46 | - Changed Column::getText() to return empty string "" by default instead of NULL pointer (to handle std::string conversion)
47 |
48 | Version 1.0.0 - 2015 May 3
49 | - Public headers file moved to include/ dir
50 | - Added support to biicode in CMakeLists.txt
51 | - Added Unit Tests
52 | - Added aBusyTimeoutMs parameter to Database() constructors
53 | - Added Database::getTotalChanges()
54 | - Added Database::getErrorCode()
55 | - Added Statement::clearBindings()
56 | - Added Statement::getColumn(aName)
57 | - Added Statement::getErrorCode()
58 | - Added Statement::getColumnName(aIndex)
59 | - Added Statement::getColumnOriginName(aIndex)
60 |
61 | Version 1.1.0 - 2015 May 18
62 | - Fixed valgrind error on Database destructor
63 | - Added Database::loadExtension
64 |
65 | Version 1.2.0 - 2015 September 9
66 | - Fixed build with GCC 5.1.0
67 | - Fixed MSVC release build warning
68 | - Fixed CppDepends warnings
69 | - Updated documentation on installation
70 | - Added Database::getHandle()
71 |
72 | Version 1.3.0 - 2015 November 1
73 | - Fixed build with Visual Studio 2015
74 | - Further improvements to README
75 | - Added Backup class
76 |
77 | Version 1.3.1 - 2016 February 10
78 | - Switch Linux/Mac build to the provided SQLite3 C library
79 | - Update SQLite3 from 3.8.8.3 to latest 3.10.2 (2016-01-20)
80 | - Remove warnings
81 | - Remove biicode support (defunct service, servers will shutdown the 16th of February 2016)
82 |
83 | Version 2.0.0 - 2016 July 25
84 | - Update SQLite3 from 3.10.2 to latest 3.13 (2016-05-18)
85 | - Move #include from headers to .cpp files only using forward declarations
86 | - Add Database::VERSION to reach SQLITE_VERSION without including sqlite3.h in application code
87 | - Add getLibVersion() and getLibVersionNumber() to get runtime version of the library
88 | - Better exception messages when Statements fail PR #84
89 | - Variadic templates for bind() (C++14) PR #85
90 | - Add Statement::bindNoCopy() methods for strings, using SQLITE_STATIC to avoid internal copy by SQLite3 PR #86
91 | - Add Statement::bind() overload for uint32_t, and Column::getUint() and cast operator to uint32_t PR #86
92 | - Use the new SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION from SQLite 3.13 for security reason
93 | - Rename Backup::remainingPageCount()/totalPageCount() to Backup::getRemainingPageCount()/getTotalPageCount()
94 | - Remove Column::errmsg() method : use Database or Statement equivalents
95 | - More unit tests, with code coverage status on the GitHub page
96 | - Do not force MSVC to use static runtime if unit-tests are not build
97 |
98 | Version 2.1.0 - 2017 July 18
99 | - Update SQLite3 from 3.13 to latest 3.19.3 (2017-06-08)
100 | - Fixed Incompatibility in 3.19.0 (to use older SQLite version set the CMake variable SQLITE_USE_LEGACY_STRUCT) #125
101 | - Fixed link error (inline in cpp) and compiler warnings (unused variable...) #96
102 | - Added ability to open encrypted databases (using SQLCipher, eg. libsqlcipher-dev) #107
103 | - Added convenience functions for constructing objects from a row #114
104 | - Added CMake install step #118
105 | - Fix warnings #119
106 | - Make cpplint.py Python-3 compatible #120
107 | - Link libssp when targeted #100
108 | - Removed redundant const #102
109 |
110 | Version 2.2.0 - 2017 Sept 19
111 | - Update SQLite3 from 3.19.3 to latest 3.20.1 (2017-08-24) #143
112 | - Added tryExecuteStep and tryReset #142
113 | - Removed virtual keywords from destructors #140
114 | - Removed misplaced noexcept keyword #139
115 | - Improved Exception class C++ conformance #138
116 | - Fix warnings #134
117 | - Deprecated Statement::isOk() to Statement::hasRow()
118 |
119 | Version 2.3.0 - 2019 March 3
120 | - Update SQLite3 from 3.20.1 to latest 3.27.2 (2019-02-25) #183 #187
121 | - Add Statement binding for long int values #147
122 | - Allows long int for bind when used with name #148
123 | - More cmake instructions for Linux #151
124 | - Add comparison with sqlite_orm #141
125 | - Fix Statement::bind truncates long integer to 32 bits on x86_64 Linux #155
126 | - Add a move constructor to Database #157
127 | - Added tests for all MSVC compilers available on AppVeyor (2013, 2015, 2017) #169
128 | - Update VariadicBind.h #172
129 | - Better CMake compatibility #170
130 | - Add implicit cast operator to char and short types #179 #180
131 |
132 | Version 2.4.0 - 2019 August 25
133 | - Update SQLite3 from 3.27.2 to 3.29.0 (2019-07-10) #217
134 | - #191 CMake Warning line 299
135 | - #190 Implement move constructors
136 | - #192 Add wrapper for bind parameter count
137 | - #197 Add tuple_bind and execute_many (requested by #24)
138 | - #199 Fix #156 misleading error message in exception from Statement::exec
139 | - #201 Add Statement::getExpandedSQL() to get the SQL text of prepared statement with bound parameters expanded
140 | - #211 Implement Database::backup()
141 | - #215 Disable implicit fallthrough warning when building internal sqlite3
142 | - #216 Set PROJECT_VERSION to fix CMP0048 Policy warnings
143 |
144 | Version 2.5.0 - 2019 December 31
145 | - Update SQLite3 from 3.29.0 to 3.30.1 (2019-10-10)
146 | - 100% Unit Test coverage
147 | - #212 fix sqlite3 compile properties (jzt)
148 | - #219 Disable cast-function-type warning when building internal sqlite (zxey)
149 | - #230 Fixed installation on other than Ubuntu GNU/Linux distributions (xvitaly)
150 | - #228 use transitive compile definitions via cmake (BioDataAnalysis/emmenlau)
151 | - #232 Added support of packaged GTest for running unit tests (xvitaly)
152 | - #231 Added SOVERSION field for shared library (xvitaly)
153 | - #229 Explicitly find and link against system sqlite library (xvitaly)
154 | - #235 Added support for cmake dependencies and version information (BioDataAnalysis/emmenlau)
155 | - #249 Added SQLite header parsing functionality and associated tests (patrick--)
156 |
157 | - #251 Added example for getHeaderInfo()
158 |
159 | Version 3.0.0 - 2020 January 31
160 | - C++11 is now required
161 | - CMake 3.1 minimum
162 | - Visual Studio 2015 minimum
163 | - Update Googletest to latest release 1.10
164 | - Add Github Actions continuous integration solution
165 | - Add Valgrind memcheck tool to Travis CI
166 | - Remove Statement::isOk() deprecated in 2.2.0 when renamed to Statement::hasRow()
167 | - Replace Database::backup() "C" implementation by calling the Backup class
168 | - #252 Run Valgrind memcheck on Travis CI
169 | - #253 Keep inline functions for GCov code coverage
170 | - #254 Re-enable Coverity static analysis
171 | - #256 Fix linking with system library (libsqlite3)
172 | - #242 Added a `getIndex` method and used it (KOLANICH)
173 | - #257 Improve Statement unit tests coverage (bind by name with a std::string)
174 | - #234 support for external sqlite3 (BioDataAnalysis/emmenlau)
175 | - #243 adding a pure attribute to getIndex() (KOLANICH)
176 |
177 | Version 3.1.0 - 2020 August 11
178 | - Update SQLite3 from 3.30.1 to 3.32.3 (2020-06-18)
179 | - #274 Install both cmake files into same lib directory from tcraigtyler
180 | - #275 Add a method on Statement to get the declared type of a column. from daniel-schmidt
181 | - #284 Add SQLITE_OPEN_FULLMUTEX flag from rwrx
182 | - #286 Add CMake option to toggle stack protection from chrisdalke
183 | - #287 Fixed installation on other than Ubuntu distributions from xvitaly
184 | - #288 Allow building of sqlite JSON1 extension when building internal sqlite library from zxey
185 |
186 | Version 3.1.1 - 2020 August 19
187 | - #292 Fix compilation if using SQLITE_HAS_CODEC from sum01
188 | - #293 Remove FindSQLiteCpp.cmake from sum01
189 |
190 | Version 3.2.0 - 2022 Septembre 18
191 | - #300 #316 #362 #368 Updated SQLite3 from 3.32.3 to 3.39.3 (2022-09-05)
192 | - #236 Disable explicit setting of MSVC runtime from BioDataAnalysis/emmenlau
193 | - #308 Fix build warning due to string truncation from stauffer-garmin
194 | - #311 Add Database::tryExec() from kcowolf
195 | - #313 [CMake] Add SQLITECPP_INCLUDE_SCRIPT option from past-due
196 | - #314 Add Database constructor for filesystem::path (#296) from ptrks
197 | - #295 Compile internal SQLite library with -ffunction-sections from smichaku
198 | - #299 Added Savepoint support from catalogm
199 | - #333 Added Database and Statement getChanges()
200 | - #305 Add other constants that work with sqlite3_open_v2 from LuAPi/more-flags
201 | - #333 Added Database and Statement method getChanges() from SRombauts/get-changes
202 | - #334 fix link for HAS_CODEC from linux-fan-dave/master
203 | - #338 fix load extension from paulo-coutinho/fix-load-extension
204 | - #335 from jagerman/older-macos-avoid-std-filesystem
205 | - #337 Add catkin configuration from ardabbour/master
206 | - #339 Allow specifying transaction behaviors DEFERRED, IMMEDIATE, and EXCLUSIVE from jjenkins278/transaction_behavior
207 | - #340 add HTML keywords and properly link up the links in docs/README.md from phoebe-leong/patch-1
208 | - #341 Install the package.xml file from ardabbour/patch-1
209 | - #352 add basic meson support from ninjaoflight/meson-support
210 | - #349 Refactoring of Statement and Column classes from Kacperos155/refactoring-Statement&Column
211 | - #359 Fix compilation issues earlier than iOS 13
212 | - #354 Windows improved support (meson) from ninjaoflight/windows-migration
213 | - #361 Fix Statement unit test using long from SRombauts/fix-statement-unit-tests-long-long-type
214 | - #346 Add compatible definition for std::experimental::filesystem from guoh27/master
215 | - #364 Removal of remaining long APIs from SRombauts/convert-remaining-long-types
216 | - #366 Add vcpkg installation instructions from FrankXie05/vcpkg-instructions
217 | - #360 Small improvements and code cleaning from Kacperos155/small_improvements
218 |
219 | Versions 3.2.1 - 2022 Decembre 12
220 | - #383 Update SQLite from 3.39.3 to 3.40.0 (2022-11-16) from SRombauts/update-sqlite-340
221 | - #370 Don't link anymore with Visual Studio's static runtime by default from SRombauts/dont-enforce-static-linking
222 | - #371 from SRombauts/appveyor-vs-2022
223 | - #277 from cuberite/cmake-scoping
224 | - #374 Update googletest from vuhailongkl97/master
225 | - #377 Some documentation fixes from cbielow/fix_doc
226 | - #380 [Meson] fixes for meson project from ninjaoflight/windows-support
227 | - #387 Ensure that TEXT column is UTF-8 encoded before using sqlite3_column_blob() from dougnazar
228 | - #385 disable SQLITECPP_USE_STACK_PROTECTION when on MinGW from SRombauts/mingw-disable-stack-protection
229 | - #386 [meson] Update SQLite from 3.39.3 to 3.40.0 from ninjaoflight/sqlite-meson-update
230 | - #389 [meson] add missing compile options from ninjaoflight/meson-fixes
231 |
232 | Version 3.3.0 - 2023 May 24
233 | - #393 Fix preprocessor issues from jowr/fix_preprocessor_issues
234 | - #394 check if SQLITE_OPEN_NOFOLLOW is defined from ninjaoflight/macos-11-fix
235 | - #391 meson project changes based on wrap submission review from ninjaoflight/meson-macos-fix
236 | - #390 fix incorrect work of savepoint from spoyler/save_point Sébastien Rombauts 12/15/2022 01:12 PM
237 | - #396 Rename Savepoint RollbackTo() and fix class comments and formatting from SRombauts/rename-savepoint-rollback-to
238 | - #384 Add Mingw GitHub actions from SRombauts/mingw-github-actions
239 | - #397 Add a Transaction::rollback() method from SRombauts/add-transaction-rollback
240 | - #395 add meson usage guide from ninjaoflight/meson-readme-guide
241 | - #401 Fix meson installation from dougnazar/fix_meson_install
242 | - #400 CMakr/meson Lint corrections from ninjaoflight/lint-corrections
243 | - #404 Add documentation for prepared statements in transactions from ewarchul/query_transactions_example
244 | - #399 add disable option for sqlite3_expanded_sql from ninjaoflight/optional-sqlite3_expanded_sql
245 | - #408 correct executable name in meson from ninjaoflight/patch-2
246 | - #407 Create Meson CI from ninjaoflight/patch-1
247 | - #409 Update package.xml from poshul/patch-1
248 | - #410 use checkout@v3 in CMake CI from ninjaoflight/fix-nodejs-warnings
249 | - #406 DLL export/import using BUILD_SHARED_LIBS from pierre-aimi/dllexport_import
250 | - #415 Remove mismatched else condition in CMakeLists.txt from Timmmm/patch-1
251 | - #413 Fix compiler warnings from ninjaoflight/fix-visibility-warning
252 | - #423 Update SQLite from 3.40.0 to 3.42.0 (2023-05-16) from SRombauts/update-sqlite
253 |
254 | Version 3.3.1 - 2023 Aug 27
255 |
256 | - #428 Add CMake option SQLITE_ENABLE_DBSTAT_VTAB and SQLITE_ENABLE_RTREE from SRombauts/cmake-sqlite-enable-dbstat-vtab
257 | - #434 Define SQLITECPP_COMPILE_DLL as PUBLIC from calumr/fix-dll-import
258 | - #439 Update CMake minimum version to 3.5 to get rid of a new deprecation warning with CMake 3.27 from SRombauts/cmake-update-minimum-version
259 | - #441 Cleanup of the Github "build" workflow from SRombauts/github-actions-improvements
260 | - Update usage of SQLITECPP_USE_STATIC_RUNTIME (#438)
261 | - Don't build the googlemock subproject, only the main googletest library
262 | - Declare BUILD_SHARED_LIBS option for discoverability (#440)
263 | - Set -DBUILD_SHARED_LIBS=ON by default on scripts and CI/CD (#442)
264 | - Update SQLite from 3.42.0 to 3.43.0 (2023-08-24) (#443)
265 | - Rename the original build.yml to cmake.yml vs meson.yml (#444)
266 |
267 | Version 3.3.2 - 2024 Aug 16
268 |
269 | - Fix and update Travis CI workflow (#450)
270 | - Update Googletest to v1.15.2 (#451) and (#478)
271 | - [Meson] update meson dependencies (#448)
272 | - Macos ci fix (#476)
273 | - Update meson dependencies [Meson only] (#475)
274 | - Update SQLite from 3.43.0 to 3.46.1 (2024-08-13) (#461) and (#477)
275 | - Explicitly =delete; Statement::bindNoCopy(..., std::string&&) (#469)
276 |
277 | Version 3.3.3 - 2025 May 20
278 |
279 | - Update SQLite from 3.46.1 to 3.49.2 (2025-05-07) (#505)
280 | - SQLiteCpp/Statement.h: add missing `` include (#488)
281 | - sqlite3: set SQLITE_OMIT_LOAD_EXTENSION (#496)
282 | - tests/Database_test.cpp: fix a warning around `#endif` (#489)
283 | - Add a Github Dependabot config file (#480)
284 | - Bump actions/checkout from 3 to 4 in (#482)
285 | - Replace all double-quoted string literals in unit test (#483)
286 | - Use explicit versions of Ubuntu images instead of latest (#484)
287 | - Test linking with builtin libsqlite3-dev package on Ubuntu (#485)
288 | - Add logic to use different FindPackage for python if cmake is above 3.12 (#454)
289 | - Update googletest to v1.16.0 (#506)
290 | - update meson dependencies (#508)
291 |
292 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2012-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is furnished
10 | to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
20 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/TODO.txt:
--------------------------------------------------------------------------------
1 | Add a Tutorial for SQLite newbies
2 | Add a real example in the form of a small interactive console application
3 |
4 | Improve Github Wiki pages with the FAQ: Installation, Examples, Tutorial, How to contribute
5 | Publish the Doxygen Documentation in the Github Pages (gh-pages branch)
6 |
7 | Missing features in v2.0.0:
8 | - #34: Better type for getColumn
9 |
10 | Missing documentation in v2.0.0:
11 | - explain the non-copyable property for RAII design
12 | - comment on returning error code instead of exception that shall not be thrown when expected (!?)
13 |
14 | Missing unit tests in v2.0.0:
15 | - Load Extension (not practicable, and easy to verify by code review)
16 |
17 | Advanced missing features:
18 | - Add optional usage of experimental sqlite3_trace() function to enable statistics
19 | - Aggregate ?
20 |
21 | - support for different transaction mode ? NO: too specific
22 | - operator<< binding ? NO: redundant with bind()
23 | - ATTACH Database ? NO: can already be done by "ATTACH" Statement
24 |
25 | Post an article to CodeProject: Is there a license issue ?
26 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-slate
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2012-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
2 |
3 | # build format
4 | version: "{build}"
5 |
6 | # scripts that run after cloning repository
7 | install:
8 | - git submodule update --init --recursive
9 |
10 | image:
11 | # Note: reduced the number of images to test on AppVeyor, to speed up the build
12 | - Visual Studio 2022
13 | # - Visual Studio 2019
14 | # - Visual Studio 2017
15 | - Visual Studio 2015
16 |
17 | # configurations to add to build matrix
18 | configuration:
19 | - Debug
20 | - Release
21 |
22 | environment:
23 | matrix:
24 | - arch: Win32
25 | - arch: x64
26 |
27 | init:
28 | - echo %APPVEYOR_BUILD_WORKER_IMAGE% - %configuration% - %arch%
29 | - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (set vs=Visual Studio 15 2017)
30 | - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" (set vs=Visual Studio 14 2015)
31 | - if "%arch%"=="x64" (set generator="%vs% Win64") else (set generator="%vs%")
32 | # CMake uses a different grammar for Visual Studio 2019, with -A to specify architecture:
33 | - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2019" (set generator="Visual Studio 16 2019" -A %arch%)
34 | - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2022" (set generator="Visual Studio 17 2022" -A %arch%)
35 | - echo %generator%
36 |
37 | # scripts to run before build
38 | before_build:
39 | - mkdir build
40 | - cd build
41 | - cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DSQLITECPP_BUILD_EXAMPLES=ON -DSQLITECPP_BUILD_TESTS=ON -DSQLITECPP_RUN_CPPCHECK=OFF .. -G %generator%
42 |
43 | # build examples, and run tests (ie make & make test)
44 | build_script:
45 | - cmake --build . --config %configuration%
46 | - ctest --output-on-failure
47 |
--------------------------------------------------------------------------------
/build.bat:
--------------------------------------------------------------------------------
1 | @REM Copyright (c) 2012-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
2 | @REM
3 | @REM Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
4 | @REM or copy at http://opensource.org/licenses/MIT)
5 | mkdir build
6 | cd build
7 |
8 | @REM Generate a Visual Studio solution for latest version found
9 | REM -DPYTHON_EXECUTABLE=D:\workspace\Corvus\UnrealEngine\Engine\Binaries\ThirdParty\Python\Win64\python.exe
10 | cmake -DBUILD_SHARED_LIBS=ON -DSQLITECPP_BUILD_TESTS=ON -DSQLITECPP_BUILD_EXAMPLES=ON -DSQLITECPP_RUN_CPPLINT=OFF ..
11 | @if ERRORLEVEL 1 goto onError
12 |
13 | @REM Build default configuration (ie 'Debug')
14 | cmake --build .
15 | @if ERRORLEVEL 1 goto onError
16 |
17 | @REM Build and run tests
18 | ctest --output-on-failure
19 | @if ERRORLEVEL 1 goto onError
20 |
21 | @goto onSuccess
22 |
23 | :onError
24 | @echo An error occured!
25 | :onSuccess
26 | @cd ..
27 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # Copyright (c) 2012-2025 Sébastien Rombauts (sebastien.rombauts@gmail.com)
3 | #
4 | # Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
5 | # or copy at http://opensource.org/licenses/MIT)
6 |
7 | # exit on first error
8 | set -e
9 |
10 | mkdir -p build
11 | cd build
12 |
13 | # Generate a Makefile for GCC (or Clang, depending on CC/CXX envvar)
14 | cmake -DCMAKE_BUILD_TYPE=Debug -DSQLITECPP_USE_ASAN=ON -DSQLITECPP_USE_GCOV=OFF -DBUILD_SHARED_LIBS=ON -DSQLITECPP_BUILD_TESTS=ON -DSQLITECPP_BUILD_EXAMPLES=ON ..
15 |
16 | # Build (ie 'make')
17 | cmake --build .
18 |
19 | # Build and run unit-tests (ie 'make test')
20 | ctest --output-on-failure
21 |
22 | # And with Valgrind
23 | echo "Note: uncomment to run valgrind memcheck"
24 | #valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --error-exitcode=1 ./SQLiteCpp_example1
25 | #valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --error-exitcode=1 ./SQLiteCpp_tests
26 |
--------------------------------------------------------------------------------
/cmake/FindSQLite3.cmake:
--------------------------------------------------------------------------------
1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 | # file Copyright.txt or https://cmake.org/licensing for details.
3 |
4 | #[=======================================================================[.rst:
5 | FindSQLite3
6 | -----------
7 |
8 | Find the SQLite libraries, v3
9 |
10 | IMPORTED targets
11 | ^^^^^^^^^^^^^^^^
12 |
13 | This module defines the following :prop_tgt:`IMPORTED` target:
14 |
15 | ``SQLite::SQLite3``
16 |
17 | Result variables
18 | ^^^^^^^^^^^^^^^^
19 |
20 | This module will set the following variables if found:
21 |
22 | ``SQLite3_INCLUDE_DIRS``
23 | where to find sqlite3.h, etc.
24 | ``SQLite3_LIBRARIES``
25 | the libraries to link against to use SQLite3.
26 | ``SQLite3_VERSION``
27 | version of the SQLite3 library found
28 | ``SQLite3_FOUND``
29 | TRUE if found
30 |
31 | #]=======================================================================]
32 |
33 | # Look for the necessary header
34 | find_path(SQLite3_INCLUDE_DIR NAMES sqlite3.h)
35 | mark_as_advanced(SQLite3_INCLUDE_DIR)
36 |
37 | # Look for the necessary library
38 | find_library(SQLite3_LIBRARY NAMES sqlite3 sqlite)
39 | mark_as_advanced(SQLite3_LIBRARY)
40 |
41 | # Extract version information from the header file
42 | if(SQLite3_INCLUDE_DIR)
43 | file(STRINGS ${SQLite3_INCLUDE_DIR}/sqlite3.h _ver_line
44 | REGEX "^#define SQLITE_VERSION *\"[0-9]+\\.[0-9]+\\.[0-9]+\""
45 | LIMIT_COUNT 1)
46 | string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+"
47 | SQLite3_VERSION "${_ver_line}")
48 | unset(_ver_line)
49 | endif()
50 |
51 | include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
52 | find_package_handle_standard_args(SQLite3
53 | REQUIRED_VARS SQLite3_INCLUDE_DIR SQLite3_LIBRARY
54 | VERSION_VAR SQLite3_VERSION)
55 |
56 | # Create the imported target
57 | if(SQLite3_FOUND)
58 | set(SQLite3_INCLUDE_DIRS ${SQLite3_INCLUDE_DIR})
59 | set(SQLite3_LIBRARIES ${SQLite3_LIBRARY})
60 | if(NOT TARGET SQLite::SQLite3)
61 | add_library(SQLite::SQLite3 UNKNOWN IMPORTED)
62 | set_target_properties(SQLite::SQLite3 PROPERTIES
63 | IMPORTED_LOCATION "${SQLite3_LIBRARY}"
64 | INTERFACE_INCLUDE_DIRECTORIES "${SQLite3_INCLUDE_DIR}")
65 | endif()
66 | endif()
67 |
--------------------------------------------------------------------------------
/cmake/SQLiteCppConfig.cmake.in:
--------------------------------------------------------------------------------
1 | include(CMakeFindDependencyMacro)
2 | if(NOT @SQLITECPP_INTERNAL_SQLITE@)
3 | find_dependency(SQLite3 REQUIRED)
4 | endif()
5 | if(@UNIX@)
6 | set(THREADS_PREFER_PTHREAD_FLAG @THREADS_PREFER_PTHREAD_FLAG@)
7 | find_dependency(Threads REQUIRED)
8 | endif()
9 |
10 | @PACKAGE_INIT@
11 |
12 | include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
13 | check_required_components("@PROJECT_NAME@")
14 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | SQLiteC++
2 | ---------
3 |
4 | [](https://github.com/SRombauts/SQLiteCpp/releases)
5 | [](https://github.com/SRombauts/SQLiteCpp/blob/master/LICENSE.txt)
6 | [](https://travis-ci.org/SRombauts/SQLiteCpp "Travis CI Linux Build Status")
7 | [](https://ci.appveyor.com/project/SbastienRombauts/SQLiteCpp "AppVeyor Windows Build status")
8 | [](https://github.com/SRombauts/SQLiteCpp/actions "GitHhub Actions Build status")
9 | [](https://coveralls.io/github/SRombauts/SQLiteCpp "Coveralls test coverage")
10 | [](https://scan.coverity.com/projects/srombauts-sqlitecpp "Coverity Scan Build Status")
11 | [](https://gitter.im/SRombauts/SQLiteCpp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
12 |
13 | SQLiteC++ (SQLiteCpp) is a lean and easy to use C++ SQLite3 wrapper.
14 |
15 |
16 |
17 |
18 | ## About SQLiteC++:
19 |
20 | SQLiteC++ offers an encapsulation around the native C APIs of SQLite,
21 | with a few intuitive and well documented C++ classes.
22 |
23 | ### License:
24 |
25 | Copyright (c) 2012-2023 Sébastien Rombauts (sebastien.rombauts@gmail.com)
26 |
27 |
28 | Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
29 | or copy at http://opensource.org/licenses/MIT)
30 |
31 | #### Note on redistribution of SQLite source files
32 |
33 | As stated by the MIT License, you are welcome to reuse, modify, and redistribute the SQLiteCpp source code
34 | the way you want it to, be it a git submodule, a subdirectory, or a selection of some source files.
35 |
36 | I would love a mention in your README, a web link to the SQLite repository, and a mention of the author,
37 | but none of those are mandatory.
38 |
39 | ### About SQLite underlying library:
40 |
41 | SQLite is a library that implements a serverless transactional SQL database engine.
42 | It is the most widely deployed SQL database engine in the world.
43 | All of the code and documentation in SQLite has been dedicated to the public domain by the authors.
44 | [http://www.sqlite.org/about.html](http://www.sqlite.org/about.html)
45 |
46 | ### The goals of SQLiteC++ are:
47 |
48 | - to offer the best of the existing simple C++ SQLite wrappers
49 | - to be elegantly written with good C++11 design, STL, exceptions and RAII idiom
50 | - to keep dependencies to a minimum (C++11 STL and SQLite3)
51 | - to be portable
52 | - to be light and fast
53 | - to be thread-safe only as much as SQLite "Multi-thread" mode (see below)
54 | - to have a good unit test coverage
55 | - to use API names sticking with those of the SQLite library
56 | - to be well documented with Doxygen tags, and with some good examples
57 | - to be well maintained
58 | - to use a permissive MIT license, similar to BSD or Boost, for proprietary/commercial usage
59 |
60 | It is designed using the Resource Acquisition Is Initialization (RAII) idiom
61 | (see [http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization](http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization)),
62 | and throwing exceptions in case of SQLite errors (except in destructors,
63 | where assert() are used instead).
64 | Each SQLiteC++ object must be constructed with a valid SQLite database connection,
65 | and then is always valid until destroyed.
66 |
67 | ### Supported platforms:
68 |
69 | Now requires a C++11 compiler. Use branch [sqlitecpp-2.x](https://github.com/SRombauts/SQLiteCpp/tree/sqlitecpp-2.x) for latest pre-C++11 developments.
70 |
71 | Developments and tests are done under the following OSs:
72 | - Ubuntu 14.04, 16.04 and 18.04 (Travis CI and Github Actions)
73 | - Windows 10, and Windows Server 2012 R2, Windows Server 2016, Windows Server 2022 (AppVeyor and Github Actions)
74 | - MacOS 10.11 and 11.7 (Travis CI and Github Actions)
75 | - Valgrind memcheck tool
76 |
77 | And the following IDEs/Compilers
78 | - GCC 4.8.4, 5.3.0, 7.1.1 and latest eg 9.4 (C++11, C++14, C++17)
79 | - Clang 5 and 7 (Travis CI)
80 | - AppleClang 8, 9 and 13 (Travis CI and Github Actions)
81 | - Xcode 8 & 9 (Travis CI)
82 | - Visual Studio Community/Entreprise 2022, 2019, 2017, and 2015 (AppVeyor and Github Actions)
83 |
84 | ### Dependencies
85 |
86 | - a modern C++11 STL implementation with GCC, Clang, or Visual Studio 2015
87 | - exception support (the class Exception inherits from std::runtime_error)
88 | - the SQLite library (3.7.15 minimum from 2012-12-12) either by linking to it dynamically or statically (install the libsqlite3-dev package under Debian/Ubuntu/Mint Linux),
89 | or by adding its source file in your project code base (source code provided in src/sqlite3 for Windows),
90 | with the `SQLITE_ENABLE_COLUMN_METADATA` macro defined (see http://www.sqlite.org/compile.html#enable_column_metadata).
91 |
92 | ## Getting started
93 | ### Installation
94 |
95 | To use this wrapper, you need to add the SQLiteC++ source files from the src/ directory
96 | in your project code base, and compile/link against the sqlite library.
97 |
98 | The easiest way to do this is to add the wrapper as a library.
99 | The "CMakeLists.txt" file defining the static library is provided in the root directory,
100 | so you simply have to add_subdirectory(SQLiteCpp) to you main CMakeLists.txt
101 | and link to the "SQLiteCpp" wrapper library.
102 |
103 | Example for Linux:
104 | ```cmake
105 | add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/thirdparty/SQLiteCpp)
106 |
107 | add_executable(main src/main.cpp)
108 | target_link_libraries(main
109 | SQLiteCpp
110 | sqlite3
111 | pthread
112 | dl
113 | )
114 | ```
115 | Thus this SQLiteCpp repository can be directly used as a Git submodule.
116 | See the [SQLiteCpp_Example](https://github.com/SRombauts/SQLiteCpp_Example) side repository for a standalone "from scratch" example.
117 |
118 | Under Debian/Ubuntu/Mint Linux, you can install the libsqlite3-dev package if you don't want to use the embedded sqlite3 library.
119 |
120 | ### Building example and unit-tests:
121 |
122 | Use git to clone the repository. Then init and update submodule "googletest".
123 |
124 | ```Shell
125 | git clone https://github.com/SRombauts/SQLiteCpp.git
126 | cd SQLiteCpp
127 | git submodule init
128 | git submodule update
129 | ```
130 |
131 | ### Installing SQLiteCpp (vcpkg)
132 |
133 | Alternatively, you can build and install SQLiteCpp using [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager:
134 |
135 | ```bash or powershell
136 | git clone https://github.com/Microsoft/vcpkg.git
137 | cd vcpkg
138 | ./bootstrap-vcpkg.sh
139 | ./vcpkg integrate install
140 | ./vcpkg install sqlitecpp
141 | ```
142 |
143 | The SQLiteCpp port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
144 |
145 |
146 | #### Using SQLiteCpp on a system-wide installation
147 |
148 | If you installed this package to your system, a `SQLiteCppConfig.cmake` file will be generated & installed to your system.
149 | This file lets you link against the SQLiteCpp library for use in your Cmake project.
150 |
151 | Here's an example of using this in your CMakeLists.txt
152 | ```cmake
153 | # You can optionally define a minimum version in this call
154 | find_package(SQLiteCpp REQUIRED)
155 | # For this example, lets say you created an target with add_executable (or add_library) called "my_target"
156 | # You can optionally declare PUBLIC or PRIVATE linkage here, depending on your needs.
157 | target_link_libraries(my_target PRIVATE SQLiteCpp)
158 | ```
159 |
160 | #### CMake and tests
161 | A CMake configuration file is also provided for multi-platform support and testing.
162 |
163 | Typical generic build for MS Visual Studio under Windows (from [build.bat](build.bat)):
164 |
165 | ```Batchfile
166 | mkdir build
167 | cd build
168 |
169 | cmake .. # cmake .. -G "Visual Studio 16 2019" # for Visual Studio 2019
170 | @REM Generate a Visual Studio solution for latest version found
171 | cmake -DSQLITECPP_BUILD_EXAMPLES=ON -DSQLITECPP_BUILD_TESTS=ON ..
172 |
173 | @REM Build default configuration (ie 'Debug')
174 | cmake --build .
175 |
176 | @REM Build and run tests
177 | ctest --output-on-failure
178 | ```
179 |
180 | Generating the Linux Makefile, building in Debug and executing the tests (from [build.sh](build.sh)):
181 |
182 | ```Shell
183 | mkdir Debug
184 | cd Debug
185 |
186 | # Generate a Makefile for GCC (or Clang, depanding on CC/CXX envvar)
187 | cmake -DSQLITECPP_BUILD_EXAMPLES=ON -DSQLITECPP_BUILD_TESTS=ON ..
188 |
189 | # Build (ie 'make')
190 | cmake --build .
191 |
192 | # Build and run unit-tests (ie 'make test')
193 | ctest --output-on-failure
194 | ```
195 |
196 | #### CMake options
197 |
198 | * For more options on customizing the build, see the [CMakeLists.txt](https://github.com/SRombauts/SQLiteCpp/blob/master/CMakeLists.txt) file.
199 |
200 | #### Troubleshooting
201 |
202 | Under Linux, if you get multiple linker errors like "undefined reference to sqlite3_xxx",
203 | it's that you lack the "sqlite3" library: install the libsqlite3-dev package.
204 |
205 | If you get a single linker error "Column.cpp: undefined reference to sqlite3_column_origin_name",
206 | it's that your "sqlite3" library was not compiled with
207 | the `SQLITE_ENABLE_COLUMN_METADATA` macro defined (see [http://www.sqlite.org/compile.html#enable_column_metadata](http://www.sqlite.org/compile.html#enable_column_metadata)).
208 | You can:
209 | - either recompile the sqlite3 library provided by your distribution yourself (seek help online)
210 | - or turn off the `option(SQLITE_ENABLE_COLUMN_METADATA "Enable Column::getColumnOriginName(). Require support from sqlite3 library." ON)` in [CMakeFiles.txt](CMakeFiles.txt) (or other build system scripts)
211 | - or turn on the `option(SQLITECPP_INTERNAL_SQLITE "Add the internal SQLite3 source to the project." ON)` in [CMakeFiles.txt](CMakeFiles.txt)
212 |
213 | ### Continuous Integration
214 |
215 | This project is continuously tested under Ubuntu Linux with the gcc and clang compilers
216 | using the Travis CI community service with the above CMake building and testing procedure.
217 | It is also tested in the same way under Windows Server 2012 R2 with Visual Studio 2013 compiler
218 | using the AppVeyor continuous integration service.
219 |
220 | Detailed results can be seen online:
221 | - [https://travis-ci.org/SRombauts/SQLiteCpp](https://travis-ci.org/SRombauts/SQLiteCpp)
222 | - [https://ci.appveyor.com/project/SbastienRombauts/SQLiteCpp](https://ci.appveyor.com/project/SbastienRombauts/SQLiteCpp)
223 |
224 | ### Thread-safety
225 |
226 | SQLite supports three modes of thread safety, as describe in "SQLite And Multiple Threads":
227 | see [http://www.sqlite.org/threadsafe.html](http://www.sqlite.org/threadsafe.html)
228 |
229 | This SQLiteC++ wrapper does no add any locks (no mutexes) nor any other thread-safety mechanism
230 | above the SQLite library itself, by design, for lightness and speed.
231 |
232 | Thus, SQLiteC++ naturally supports the "Multi Thread" mode of SQLite:
233 | "In this mode, SQLite can be safely used by multiple threads
234 | provided that no single database connection is used simultaneously in two or more threads."
235 |
236 | But SQLiteC++ does not support the fully thread-safe "Serialized" mode of SQLite,
237 | because of the way it shares the underlying SQLite precompiled statement
238 | in a custom shared pointer (See the inner class "Statement::Ptr").
239 |
240 | ### Valgrind memcheck
241 |
242 | Run valgrind to search for memory leaks in your application, the SQLiteCpp wrapper, or the sqlite3 library.
243 | Execute the following command under Unix like OS (Linux, MacOS or WSL2/Ubuntu under Windows Subsystem for Linux):
244 |
245 | ```Shell
246 | valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose build/SQLiteCpp_example1
247 | ```
248 |
249 | or uncoment the line at the end of [build.sh](build.sh)
250 |
251 | ## Examples
252 | ### The first sample demonstrates how to query a database and get results:
253 |
254 | ```C++
255 | try
256 | {
257 | // Open a database file
258 | SQLite::Database db("example.db3");
259 |
260 | // Compile a SQL query, containing one parameter (index 1)
261 | SQLite::Statement query(db, "SELECT * FROM test WHERE size > ?");
262 |
263 | // Bind the integer value 6 to the first parameter of the SQL query
264 | query.bind(1, 6);
265 |
266 | // Loop to execute the query step by step, to get rows of result
267 | while (query.executeStep())
268 | {
269 | // Demonstrate how to get some typed column value
270 | int id = query.getColumn(0);
271 | const char* value = query.getColumn(1);
272 | int size = query.getColumn(2);
273 |
274 | std::cout << "row: " << id << ", " << value << ", " << size << std::endl;
275 | }
276 | }
277 | catch (std::exception& e)
278 | {
279 | std::cout << "exception: " << e.what() << std::endl;
280 | }
281 | ```
282 |
283 | ### The second sample shows how to manage a transaction:
284 |
285 | ```C++
286 | try
287 | {
288 | SQLite::Database db("transaction.db3", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE);
289 |
290 | db.exec("DROP TABLE IF EXISTS test");
291 |
292 | // Begin transaction
293 | SQLite::Transaction transaction(db);
294 |
295 | db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)");
296 |
297 | int nb = db.exec("INSERT INTO test VALUES (NULL, \"test\")");
298 | std::cout << "INSERT INTO test VALUES (NULL, \"test\")\", returned " << nb << std::endl;
299 |
300 | // Commit transaction
301 | transaction.commit();
302 | }
303 | catch (std::exception& e)
304 | {
305 | std::cout << "exception: " << e.what() << std::endl;
306 | }
307 | ```
308 |
309 | ### How to handle assertion in SQLiteC++:
310 | Exceptions shall not be used in destructors, so SQLiteC++ uses SQLITECPP_ASSERT() to check for errors in destructors.
311 | If you don't want assert() to be called, you have to enable and define an assert handler as shown below,
312 | and by setting the flag SQLITECPP_ENABLE_ASSERT_HANDLER when compiling the lib.
313 |
314 | ```C++
315 | #ifdef SQLITECPP_ENABLE_ASSERT_HANDLER
316 | namespace SQLite
317 | {
318 | /// definition of the assertion handler enabled when SQLITECPP_ENABLE_ASSERT_HANDLER is defined in the project (CMakeList.txt)
319 | void assertion_failed(const char* apFile, const long apLine, const char* apFunc, const char* apExpr, const char* apMsg)
320 | {
321 | // Print a message to the standard error output stream, and abort the program.
322 | std::cerr << apFile << ":" << apLine << ":" << " error: assertion failed (" << apExpr << ") in " << apFunc << "() with message \"" << apMsg << "\"\n";
323 | std::abort();
324 | }
325 | }
326 | #endif
327 | ```
328 |
329 | ## How to contribute
330 | ### GitHub website
331 | The most efficient way to help and contribute to this wrapper project is to
332 | use the tools provided by GitHub:
333 | - please fill bug reports and feature requests here: [https://github.com/SRombauts/SQLiteCpp/issues](https://github.com/SRombauts/SQLiteCpp/issues)
334 | - fork the repository, make some small changes and submit them with pull-request
335 |
336 | ### Contact
337 | You can also email me directly, I will try to answer questions and requests whenever I get the time for it.
338 |
339 | ### Coding Style Guidelines
340 | The source code use the CamelCase naming style variant where:
341 | - type names (class, struct, typedef, enums...) begin with a capital letter
342 | - files (.cpp/.h) are named like the class they contain
343 | - function and variable names begin with a lower case letter
344 | - member variables begin with a 'm', function arguments begin with a 'a', booleans with a 'b', pointers with a 'p'
345 | - each file, class, method and member variable is documented using Doxygen tags
346 | - braces on their own line
347 | See also [http://www.appinf.com/download/CppCodingStyleGuide.pdf](http://www.appinf.com/download/CppCodingStyleGuide.pdf) for good guidelines
348 |
349 | ## See also - Some other simple C++ SQLite wrappers:
350 |
351 | See bellow a short comparison of other wrappers done at the time of writing:
352 | - [sqdbcpp](http://code.google.com/p/sqdbcpp/): RAII design, simple, no dependencies, UTF-8/UTF-16, new BSD license
353 | - [sqlite3cc](http://ed.am/dev/sqlite3cc): uses boost, modern design, LPGPL
354 | - [sqlite3pp](https://github.com/iwongu/sqlite3pp): modern design inspired by boost, MIT License
355 | - [SQLite++](http://sqlitepp.berlios.de/): uses boost build system, Boost License 1.0
356 | - [CppSQLite](http://www.codeproject.com/Articles/6343/CppSQLite-C-Wrapper-for-SQLite/): famous Code Project but old design, BSD License
357 | - [easySQLite](http://code.google.com/p/easysqlite/): manages table as structured objects, complex
358 | - [sqlite_modern_cpp](https://github.com/keramer/sqlite_modern_cpp): modern C++11, all in one file, MIT license
359 | - [sqlite_orm](https://github.com/fnc12/sqlite_orm): modern C++14, header only all in one file, no raw string queries, BSD-3 license
360 |
--------------------------------------------------------------------------------
/examples/example1/README.md:
--------------------------------------------------------------------------------
1 | examples/example1 - main example
2 | --------------------------------
3 |
4 | SQLiteCpp_Example demonstrates how to use SQLiteCpp as a subdirectory of a CMake project.
5 |
6 | See also examples/example2 on how to use SQLiteCpp as a subdirectory of a CMake project
--------------------------------------------------------------------------------
/examples/example1/example.db3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SRombauts/SQLiteCpp/1df768817e68529fe47870f8e9913a47343a822d/examples/example1/example.db3
--------------------------------------------------------------------------------
/examples/example1/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SRombauts/SQLiteCpp/1df768817e68529fe47870f8e9913a47343a822d/examples/example1/logo.png
--------------------------------------------------------------------------------
/examples/example1/meson.build:
--------------------------------------------------------------------------------
1 |
2 | example1_sources = files('main.cpp')
3 |
4 | example1_args = []
5 |
6 | ## under windows define _CRT_SECURE_NO_WARNINGS
7 | if host_machine.system() == 'windows'
8 | example1_args += ['-D_CRT_SECURE_NO_WARNINGS']
9 | endif
10 |
11 | executable(
12 | 'SQLITECPP_sample_demo1',
13 | sources: example1_sources,
14 | dependencies: sqlitecpp_dep,
15 | # inherit the default options from sqlitecpp
16 | override_options: sqlitecpp_opts,
17 | cpp_args: example1_args,
18 | )
19 |
--------------------------------------------------------------------------------
/examples/example2/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Example CMake file for compiling & linking a project with the the SQLiteCpp wrapper
2 | #
3 | # Copyright (c) 2012-2023 Sebastien Rombauts (sebastien.rombauts@gmail.com)
4 | #
5 | # Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
6 | # or copy at http://opensource.org/licenses/MIT)
7 | cmake_minimum_required(VERSION 3.1) # for "CMAKE_CXX_STANDARD" version
8 | project(SQLiteCpp_Example VERSION 2.0)
9 |
10 | # SQLiteC++ 3.x now requires C++11 compiler
11 | set(CMAKE_CXX_STANDARD 11)
12 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
13 |
14 | # Add SQLite3 C++ wrapper around sqlite3 library (and sqlite3 itself provided for ease of use)
15 | # Here you can set CMake variables to avoid building Example, as well as cpplint, cppcheck...
16 | # or set them in the cmake command line (see for instance provided build.bat/build.sh scripts)
17 | set(SQLITECPP_RUN_CPPCHECK OFF CACHE BOOL "" FORCE)
18 | set(SQLITECPP_RUN_CPPLINT OFF CACHE BOOL "" FORCE)
19 | set(SQLITECPP_USE_STATIC_RUNTIME OFF CACHE BOOL "" FORCE)
20 | add_subdirectory(../.. SQLiteCpp) # out-of-source build requires explicit subdir name for compilation artifacts
21 |
22 | # Add main.cpp example source code to the executable
23 | add_executable(SQLiteCpp_Example src/main.cpp)
24 |
25 | # Link SQLiteCpp_example1 with SQLiteCpp
26 | target_link_libraries(SQLiteCpp_Example SQLiteCpp)
27 |
--------------------------------------------------------------------------------
/examples/example2/README.md:
--------------------------------------------------------------------------------
1 | examples/example2 - SQLiteCpp_Example
2 | -------------------------------------
3 |
4 | SQLiteCpp_Example demonstrates how to use SQLiteCpp as a subdirectory of a CMake project.
5 |
6 | See https://github.com/SRombauts/SQLiteCpp_Example
7 |
8 | See also examples/example1 for the main example on how to use SQLiteCpp in a C++ project
--------------------------------------------------------------------------------
/examples/example2/build.bat:
--------------------------------------------------------------------------------
1 | @REM Copyright (c) 2012-2023 Sebastien Rombauts (sebastien.rombauts@gmail.com)
2 | @REM
3 | @REM Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
4 | @REM or copy at http://opensource.org/licenses/MIT)
5 | mkdir build
6 | cd build
7 |
8 | @REM Generate a Visual Studio solution for latest version found
9 | cmake ..
10 | @if ERRORLEVEL 1 goto onError
11 |
12 | @REM Build default configuration (ie 'Debug')
13 | cmake --build .
14 | @if ERRORLEVEL 1 goto onError
15 |
16 | goto onSuccess
17 |
18 | :onError
19 | @echo An error occured!
20 | :onSuccess
21 | cd ..
22 |
--------------------------------------------------------------------------------
/examples/example2/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # Copyright (c) 2012-2023 Sébastien Rombauts (sebastien.rombauts@gmail.com)
3 | #
4 | # Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
5 | # or copy at http://opensource.org/licenses/MIT)
6 |
7 | # exit on first error
8 | set -e
9 |
10 | mkdir -p build
11 | cd build
12 |
13 | # Generate a Makefile for GCC (or Clang, depanding on CC/CXX envvar)
14 | cmake -DCMAKE_BUILD_TYPE=Debug ..
15 |
16 | # Build (ie 'make')
17 | cmake --build .
18 |
19 |
--------------------------------------------------------------------------------
/examples/example2/meson.build:
--------------------------------------------------------------------------------
1 | example2_srcs = files('src/main.cpp')
2 |
3 | # if running on windows define _CRT_SECURE_NO_WARNINGS
4 | example2_args = []
5 |
6 | executable(
7 | 'SQLITECPP_sample_demo2',
8 | example2_srcs,
9 | dependencies: sqlitecpp_dep,
10 | # inherit the default options from sqlitecpp
11 | override_options: sqlitecpp_opts,
12 | cpp_args: example2_args,
13 | )
14 |
--------------------------------------------------------------------------------
/examples/example2/src/main.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file main.cpp
3 | * @brief A few short examples in a row.
4 | *
5 | * Demonstrates how-to use the SQLite++ wrapper
6 | *
7 | * Copyright (c) 2012-2023 Sebastien Rombauts (sebastien.rombauts@gmail.com)
8 | *
9 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
10 | * or copy at http://opensource.org/licenses/MIT)
11 | */
12 |
13 | #include
14 | #include
15 | #include
16 |
17 | #include
18 |
19 |
20 | #ifdef SQLITECPP_ENABLE_ASSERT_HANDLER
21 | namespace SQLite
22 | {
23 | /// definition of the assertion handler enabled when SQLITECPP_ENABLE_ASSERT_HANDLER is defined in the project (CMakeList.txt)
24 | void assertion_failed(const char* apFile, const long apLine, const char* apFunc, const char* apExpr, const char* apMsg)
25 | {
26 | // Print a message to the standard error output stream, and abort the program.
27 | std::cerr << apFile << ":" << apLine << ":" << " error: assertion failed (" << apExpr << ") in " << apFunc << "() with message \"" << apMsg << "\"\n";
28 | std::abort();
29 | }
30 | }
31 | #endif
32 |
33 | int main ()
34 | {
35 | // Using SQLITE_VERSION would require #include which we want to avoid: use SQLite::VERSION if possible.
36 | // std::cout << "SQlite3 version " << SQLITE_VERSION << std::endl;
37 | std::cout << "SQlite3 version " << SQLite::VERSION << " (" << SQLite::getLibVersion() << ")" << std::endl;
38 | std::cout << "SQliteC++ version " << SQLITECPP_VERSION << std::endl;
39 |
40 | ////////////////////////////////////////////////////////////////////////////
41 | // Simple batch queries example :
42 | try
43 | {
44 | // Open a database file in create/write mode
45 | SQLite::Database db("test.db3", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE);
46 | std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n";
47 |
48 | // Create a new table with an explicit "id" column aliasing the underlying rowid
49 | db.exec("DROP TABLE IF EXISTS test");
50 | db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)");
51 |
52 | // first row
53 | int nb = db.exec("INSERT INTO test VALUES (NULL, \"test\")");
54 | std::cout << "INSERT INTO test VALUES (NULL, \"test\")\", returned " << nb << std::endl;
55 |
56 | // second row
57 | nb = db.exec("INSERT INTO test VALUES (NULL, \"second\")");
58 | std::cout << "INSERT INTO test VALUES (NULL, \"second\")\", returned " << nb << std::endl;
59 |
60 | // update the second row
61 | nb = db.exec("UPDATE test SET value=\"second-updated\" WHERE id='2'");
62 | std::cout << "UPDATE test SET value=\"second-updated\" WHERE id='2', returned " << nb << std::endl;
63 |
64 | // Check the results : expect two row of result
65 | SQLite::Statement query(db, "SELECT * FROM test");
66 | std::cout << "SELECT * FROM test :\n";
67 | while (query.executeStep())
68 | {
69 | std::cout << "row (" << query.getColumn(0) << ", \"" << query.getColumn(1) << "\")\n";
70 | }
71 |
72 | db.exec("DROP TABLE test");
73 | }
74 | catch (std::exception& e)
75 | {
76 | std::cout << "SQLite exception: " << e.what() << std::endl;
77 | return EXIT_FAILURE; // unexpected error : exit the example program
78 | }
79 | remove("test.db3");
80 |
81 | std::cout << "everything ok, quitting\n";
82 |
83 | return EXIT_SUCCESS;
84 | }
85 |
--------------------------------------------------------------------------------
/examples/meson.build:
--------------------------------------------------------------------------------
1 | subdir('example1')
2 | subdir('example2')
--------------------------------------------------------------------------------
/include/SQLiteCpp/Assertion.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Assertion.h
3 | * @ingroup SQLiteCpp
4 | * @brief Definition of the SQLITECPP_ASSERT() macro.
5 | *
6 | * Copyright (c) 2012-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
7 | *
8 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
9 | * or copy at http://opensource.org/licenses/MIT)
10 | */
11 | #pragma once
12 |
13 | #include
14 |
15 | /**
16 | * SQLITECPP_ASSERT SQLITECPP_ASSERT() is used in destructors, where exceptions shall not be thrown
17 | *
18 | * Define SQLITECPP_ENABLE_ASSERT_HANDLER at the project level
19 | * and define a SQLite::assertion_failed() assertion handler
20 | * to tell SQLiteC++ to use it instead of assert() when an assertion fail.
21 | */
22 | #ifdef SQLITECPP_ENABLE_ASSERT_HANDLER
23 |
24 | // if an assert handler is provided by user code, use it instead of assert()
25 | namespace SQLite
26 | {
27 |
28 | // declaration of the assert handler to define in user code
29 | void assertion_failed(const char* apFile, const int apLine, const char* apFunc,
30 | const char* apExpr, const char* apMsg);
31 |
32 | #ifdef _MSC_VER
33 | #define __func__ __FUNCTION__
34 | #endif
35 | // call the assert handler provided by user code
36 | #define SQLITECPP_ASSERT(expression, message) \
37 | if (!(expression)) SQLite::assertion_failed(__FILE__, __LINE__, __func__, #expression, message)
38 |
39 | } // namespace SQLite
40 |
41 | #else
42 |
43 | // if no assert handler provided by user code, use standard assert()
44 | // (note: in release mode assert() does nothing)
45 | #define SQLITECPP_ASSERT(expression, message) assert(expression && message)
46 |
47 | #endif
48 |
--------------------------------------------------------------------------------
/include/SQLiteCpp/Backup.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Backup.h
3 | * @ingroup SQLiteCpp
4 | * @brief Backup is used to backup a database file in a safe and online way.
5 | *
6 | * Copyright (c) 2015 Shibao HONG (shibaohong@outlook.com)
7 | * Copyright (c) 2015-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
8 | *
9 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
10 | * or copy at http://opensource.org/licenses/MIT)
11 | */
12 | #pragma once
13 |
14 | #include
15 | #include
16 |
17 | #include
18 | #include
19 |
20 | // Forward declaration to avoid inclusion of in a header
21 | struct sqlite3_backup;
22 |
23 | namespace SQLite
24 | {
25 |
26 | /**
27 | * @brief RAII encapsulation of a SQLite Database Backup process.
28 | *
29 | * A Backup object is used to backup a source database file to a destination database file
30 | * in a safe and online way.
31 | *
32 | * See also the a reference implementation of live backup taken from the official site:
33 | * https://www.sqlite.org/backup.html
34 | */
35 | class SQLITECPP_API Backup
36 | {
37 | public:
38 | /**
39 | * @brief Initialize a SQLite Backup object.
40 | *
41 | * Initialize a SQLite Backup object for the source database and destination database.
42 | * The database name is "main" for the main database, "temp" for the temporary database,
43 | * or the name specified after the AS keyword in an ATTACH statement for an attached database.
44 | *
45 | * Exception is thrown in case of error, then the Backup object is NOT constructed.
46 | *
47 | * @param[in] aDestDatabase Destination database connection
48 | * @param[in] apDestDatabaseName Destination database name
49 | * @param[in] aSrcDatabase Source database connection
50 | * @param[in] apSrcDatabaseName Source database name
51 | *
52 | * @throw SQLite::Exception in case of error
53 | */
54 | Backup(Database& aDestDatabase,
55 | const char* apDestDatabaseName,
56 | Database& aSrcDatabase,
57 | const char* apSrcDatabaseName);
58 |
59 | /**
60 | * @brief Initialize a SQLite Backup object.
61 | *
62 | * Initialize a SQLite Backup object for source database and destination database.
63 | * The database name is "main" for the main database, "temp" for the temporary database,
64 | * or the name specified after the AS keyword in an ATTACH statement for an attached database.
65 | *
66 | * Exception is thrown in case of error, then the Backup object is NOT constructed.
67 | *
68 | * @param[in] aDestDatabase Destination database connection
69 | * @param[in] aDestDatabaseName Destination database name
70 | * @param[in] aSrcDatabase Source database connection
71 | * @param[in] aSrcDatabaseName Source database name
72 | *
73 | * @throw SQLite::Exception in case of error
74 | */
75 | Backup(Database& aDestDatabase,
76 | const std::string& aDestDatabaseName,
77 | Database& aSrcDatabase,
78 | const std::string& aSrcDatabaseName);
79 |
80 | /**
81 | * @brief Initialize a SQLite Backup object for main databases.
82 | *
83 | * Initialize a SQLite Backup object for source database and destination database.
84 | * Backup the main databases between the source and the destination.
85 | *
86 | * Exception is thrown in case of error, then the Backup object is NOT constructed.
87 | *
88 | * @param[in] aDestDatabase Destination database connection
89 | * @param[in] aSrcDatabase Source database connection
90 | *
91 | * @throw SQLite::Exception in case of error
92 | */
93 | Backup(Database& aDestDatabase,
94 | Database& aSrcDatabase);
95 |
96 | // Backup is non-copyable
97 | Backup(const Backup&) = delete;
98 | Backup& operator=(const Backup&) = delete;
99 |
100 | /**
101 | * @brief Execute a step of backup with a given number of source pages to be copied
102 | *
103 | * Exception is thrown when SQLITE_IOERR_XXX, SQLITE_NOMEM, or SQLITE_READONLY is returned
104 | * in sqlite3_backup_step(). These errors are considered fatal, so there is no point
105 | * in retrying the call to executeStep().
106 | *
107 | * @param[in] aNumPage The number of source pages to be copied, with a negative value meaning all remaining source pages
108 | *
109 | * @return SQLITE_OK/SQLITE_DONE/SQLITE_BUSY/SQLITE_LOCKED
110 | *
111 | * @throw SQLite::Exception in case of error
112 | */
113 | int executeStep(const int aNumPage = -1);
114 |
115 | /// Return the number of source pages still to be backed up as of the most recent call to executeStep().
116 | int getRemainingPageCount() const;
117 |
118 | /// Return the total number of pages in the source database as of the most recent call to executeStep().
119 | int getTotalPageCount() const;
120 |
121 | private:
122 | // Deleter functor to use with smart pointers to close the SQLite database backup in an RAII fashion.
123 | struct Deleter
124 | {
125 | void operator()(sqlite3_backup* apBackup);
126 | };
127 |
128 | std::unique_ptr mpSQLiteBackup; ///< Pointer to SQLite Database Backup Handle
129 | };
130 |
131 | } // namespace SQLite
132 |
--------------------------------------------------------------------------------
/include/SQLiteCpp/Column.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Column.h
3 | * @ingroup SQLiteCpp
4 | * @brief Encapsulation of a Column in a row of the result pointed by the prepared SQLite::Statement.
5 | *
6 | * Copyright (c) 2012-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
7 | *
8 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
9 | * or copy at http://opensource.org/licenses/MIT)
10 | */
11 | #pragma once
12 |
13 | #include
14 | #include
15 | #include
16 |
17 | #include
18 | #include
19 |
20 | // Forward declarations to avoid inclusion of in a header
21 | struct sqlite3_stmt;
22 |
23 | namespace SQLite
24 | {
25 |
26 | SQLITECPP_API extern const int INTEGER; ///< SQLITE_INTEGER
27 | SQLITECPP_API extern const int FLOAT; ///< SQLITE_FLOAT
28 | SQLITECPP_API extern const int TEXT; ///< SQLITE_TEXT
29 | SQLITECPP_API extern const int BLOB; ///< SQLITE_BLOB
30 | SQLITECPP_API extern const int Null; ///< SQLITE_NULL
31 |
32 | /**
33 | * @brief Encapsulation of a Column in a row of the result pointed by the prepared Statement.
34 | *
35 | * A Column is a particular field of SQLite data in the current row of result
36 | * of the Statement : it points to a single cell.
37 | *
38 | * Its value can be expressed as a text, and, when applicable, as a numeric
39 | * (integer or floating point) or a binary blob.
40 | *
41 | * Thread-safety: a Column object shall not be shared by multiple threads, because :
42 | * 1) in the SQLite "Thread Safe" mode, "SQLite can be safely used by multiple threads
43 | * provided that no single database connection is used simultaneously in two or more threads."
44 | * 2) the SQLite "Serialized" mode is not supported by SQLiteC++,
45 | * because of the way it shares the underling SQLite precompiled statement
46 | * in a custom shared pointer (See the inner class "Statement::Ptr").
47 | */
48 | class SQLITECPP_API Column
49 | {
50 | public:
51 | /**
52 | * @brief Encapsulation of a Column in a Row of the result.
53 | *
54 | * @param[in] aStmtPtr Shared pointer to the prepared SQLite Statement Object.
55 | * @param[in] aIndex Index of the column in the row of result, starting at 0
56 | */
57 | explicit Column(const Statement::TStatementPtr& aStmtPtr, int aIndex);
58 |
59 | /**
60 | * @brief Return a pointer to the named assigned to this result column (potentially aliased)
61 | *
62 | * @see getOriginName() to get original column name (not aliased)
63 | */
64 | const char* getName() const noexcept;
65 |
66 | #ifdef SQLITE_ENABLE_COLUMN_METADATA
67 | /**
68 | * @brief Return a pointer to the table column name that is the origin of this result column
69 | *
70 | * Require definition of the SQLITE_ENABLE_COLUMN_METADATA preprocessor macro :
71 | * - when building the SQLite library itself (which is the case for the Debian libsqlite3 binary for instance),
72 | * - and also when compiling this wrapper.
73 | */
74 | const char* getOriginName() const noexcept;
75 | #endif
76 |
77 | /// Return the integer value of the column.
78 | int32_t getInt() const noexcept;
79 | /// Return the 32bits unsigned integer value of the column (note that SQLite3 does not support unsigned 64bits).
80 | uint32_t getUInt() const noexcept;
81 | /// Return the 64bits integer value of the column (note that SQLite3 does not support unsigned 64bits).
82 | int64_t getInt64() const noexcept;
83 | /// Return the double (64bits float) value of the column
84 | double getDouble() const noexcept;
85 | /**
86 | * @brief Return a pointer to the text value (NULL terminated string) of the column.
87 | *
88 | * @warning The value pointed at is only valid while the statement is valid (ie. not finalized),
89 | * thus you must copy it before using it beyond its scope (to a std::string for instance).
90 | */
91 | const char* getText(const char* apDefaultValue = "") const noexcept;
92 | /**
93 | * @brief Return a pointer to the binary blob value of the column.
94 | *
95 | * @warning The value pointed at is only valid while the statement is valid (ie. not finalized),
96 | * thus you must copy it before using it beyond its scope (to a std::string for instance).
97 | */
98 | const void* getBlob() const noexcept;
99 | /**
100 | * @brief Return a std::string for a TEXT or BLOB column.
101 | *
102 | * Note this correctly handles strings that contain null bytes.
103 | */
104 | std::string getString() const;
105 |
106 | /**
107 | * @brief Return the type of the value of the column using sqlite3_column_type()
108 | *
109 | * Return either SQLite::INTEGER, SQLite::FLOAT, SQLite::TEXT, SQLite::BLOB, or SQLite::Null.
110 | * This type may change from one row to the next, since
111 | * SQLite stores data types dynamically for each value and not per column.
112 | * Use Statement::getColumnDeclaredType() to retrieve the declared column type from a SELECT statement.
113 | *
114 | * @warning After a type conversion (by a call to a getXxx on a Column of a Yyy type),
115 | * the value returned by sqlite3_column_type() is undefined.
116 | */
117 | int getType() const noexcept;
118 |
119 | /// Test if the column is an integer type value (meaningful only before any conversion)
120 | bool isInteger() const noexcept
121 | {
122 | return (SQLite::INTEGER == getType());
123 | }
124 | /// Test if the column is a floating point type value (meaningful only before any conversion)
125 | bool isFloat() const noexcept
126 | {
127 | return (SQLite::FLOAT == getType());
128 | }
129 | /// Test if the column is a text type value (meaningful only before any conversion)
130 | bool isText() const noexcept
131 | {
132 | return (SQLite::TEXT == getType());
133 | }
134 | /// Test if the column is a binary blob type value (meaningful only before any conversion)
135 | bool isBlob() const noexcept
136 | {
137 | return (SQLite::BLOB == getType());
138 | }
139 | /// Test if the column is NULL (meaningful only before any conversion)
140 | bool isNull() const noexcept
141 | {
142 | return (SQLite::Null == getType());
143 | }
144 |
145 | /**
146 | * @brief Return the number of bytes used by the text (or blob) value of the column
147 | *
148 | * Return either :
149 | * - size in bytes (not in characters) of the string returned by getText() without the '\0' terminator
150 | * - size in bytes of the string representation of the numerical value (integer or double)
151 | * - size in bytes of the binary blob returned by getBlob()
152 | * - 0 for a NULL value
153 | */
154 | int getBytes() const noexcept;
155 |
156 | /// Alias returning the number of bytes used by the text (or blob) value of the column
157 | int size() const noexcept
158 | {
159 | return getBytes ();
160 | }
161 |
162 | /// Inline cast operators to basic types
163 | operator char() const
164 | {
165 | return static_cast(getInt());
166 | }
167 | operator int8_t() const
168 | {
169 | return static_cast(getInt());
170 | }
171 | operator uint8_t() const
172 | {
173 | return static_cast(getInt());
174 | }
175 | operator int16_t() const
176 | {
177 | return static_cast(getInt());
178 | }
179 | operator uint16_t() const
180 | {
181 | return static_cast(getInt());
182 | }
183 | operator int32_t() const
184 | {
185 | return getInt();
186 | }
187 | operator uint32_t() const
188 | {
189 | return getUInt();
190 | }
191 | operator int64_t() const
192 | {
193 | return getInt64();
194 | }
195 | operator double() const
196 | {
197 | return getDouble();
198 | }
199 | /**
200 | * @brief Inline cast operator to char*
201 | *
202 | * @see getText
203 | */
204 | operator const char*() const
205 | {
206 | return getText();
207 | }
208 | /**
209 | * @brief Inline cast operator to void*
210 | *
211 | * @see getBlob
212 | */
213 | operator const void*() const
214 | {
215 | return getBlob();
216 | }
217 |
218 | /**
219 | * @brief Inline cast operator to std::string
220 | *
221 | * Handles BLOB or TEXT, which may contain null bytes within
222 | *
223 | * @see getString
224 | */
225 | operator std::string() const
226 | {
227 | return getString();
228 | }
229 |
230 | private:
231 | Statement::TStatementPtr mStmtPtr; ///< Shared Pointer to the prepared SQLite Statement Object
232 | int mIndex; ///< Index of the column in the row of result, starting at 0
233 | };
234 |
235 | /**
236 | * @brief Standard std::ostream text inserter
237 | *
238 | * Insert the text value of the Column object, using getText(), into the provided stream.
239 | *
240 | * @param[in] aStream Stream to use
241 | * @param[in] aColumn Column object to insert into the provided stream
242 | *
243 | * @return Reference to the stream used
244 | */
245 | SQLITECPP_API std::ostream& operator<<(std::ostream& aStream, const Column& aColumn);
246 |
247 | #if __cplusplus >= 201402L || (defined(_MSC_VER) && _MSC_VER >= 1900) // c++14: Visual Studio 2015
248 |
249 | // Create an instance of T from the first N columns, see declaration in Statement.h for full details
250 | template
251 | T Statement::getColumns()
252 | {
253 | checkRow();
254 | checkIndex(N - 1);
255 | return getColumns(std::make_integer_sequence{});
256 | }
257 |
258 | // Helper function called by getColums
259 | template
260 | T Statement::getColumns(const std::integer_sequence)
261 | {
262 | return T{Column(mpPreparedStatement, Is)...};
263 | }
264 |
265 | #endif
266 |
267 | } // namespace SQLite
268 |
--------------------------------------------------------------------------------
/include/SQLiteCpp/Exception.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Exception.h
3 | * @ingroup SQLiteCpp
4 | * @brief Encapsulation of the error message from SQLite3 on a std::runtime_error.
5 | *
6 | * Copyright (c) 2012-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
7 | *
8 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
9 | * or copy at http://opensource.org/licenses/MIT)
10 | */
11 | #pragma once
12 |
13 | #include
14 | #include
15 | #include
16 |
17 | // Forward declaration to avoid inclusion of in a header
18 | struct sqlite3;
19 |
20 | namespace SQLite
21 | {
22 |
23 | /**
24 | * @brief Encapsulation of the error message from SQLite3, based on std::runtime_error.
25 | */
26 | class SQLITECPP_API Exception : public std::runtime_error
27 | {
28 | public:
29 | /**
30 | * @brief Encapsulation of the error message from SQLite3, based on std::runtime_error.
31 | *
32 | * @param[in] aErrorMessage The string message describing the SQLite error
33 | * @param[in] ret Return value from function call that failed.
34 | */
35 | Exception(const char* aErrorMessage, int ret);
36 |
37 | Exception(const std::string& aErrorMessage, int ret) :
38 | Exception(aErrorMessage.c_str(), ret)
39 | {
40 | }
41 |
42 | /**
43 | * @brief Encapsulation of the error message from SQLite3, based on std::runtime_error.
44 | *
45 | * @param[in] aErrorMessage The string message describing the SQLite error
46 | */
47 | explicit Exception(const char* aErrorMessage) :
48 | Exception(aErrorMessage, -1) // 0 would be SQLITE_OK, which doesn't make sense
49 | {
50 | }
51 | explicit Exception(const std::string& aErrorMessage) :
52 | Exception(aErrorMessage.c_str(), -1) // 0 would be SQLITE_OK, which doesn't make sense
53 | {
54 | }
55 |
56 | /**
57 | * @brief Encapsulation of the error message from SQLite3, based on std::runtime_error.
58 | *
59 | * @param[in] apSQLite The SQLite object, to obtain detailed error messages from.
60 | */
61 | explicit Exception(sqlite3* apSQLite);
62 |
63 | /**
64 | * @brief Encapsulation of the error message from SQLite3, based on std::runtime_error.
65 | *
66 | * @param[in] apSQLite The SQLite object, to obtain detailed error messages from.
67 | * @param[in] ret Return value from function call that failed.
68 | */
69 | Exception(sqlite3* apSQLite, int ret);
70 |
71 | /// Return the result code (if any, otherwise -1).
72 | int getErrorCode() const noexcept
73 | {
74 | return mErrcode;
75 | }
76 |
77 | /// Return the extended numeric result code (if any, otherwise -1).
78 | int getExtendedErrorCode() const noexcept
79 | {
80 | return mExtendedErrcode;
81 | }
82 |
83 | /// Return a string, solely based on the error code
84 | const char* getErrorStr() const noexcept;
85 |
86 | private:
87 | int mErrcode; ///< Error code value
88 | int mExtendedErrcode; ///< Detailed error code if any
89 | };
90 |
91 | } // namespace SQLite
92 |
--------------------------------------------------------------------------------
/include/SQLiteCpp/ExecuteMany.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file ExecuteMany.h
3 | * @ingroup SQLiteCpp
4 | * @brief Convenience function to execute a Statement with multiple Parameter sets
5 | *
6 | * Copyright (c) 2019 Maximilian Bachmann (contact@maxbachmann.de)
7 | * Copyright (c) 2019-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
8 | *
9 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
10 | * or copy at http://opensource.org/licenses/MIT)
11 | */
12 | #pragma once
13 |
14 | #if (__cplusplus >= 201402L) || ( defined(_MSC_VER) && (_MSC_VER >= 1900) ) // c++14: Visual Studio 2015
15 |
16 | #include
17 | #include
18 |
19 | /// @cond
20 | #include
21 | #include
22 | #include
23 |
24 | namespace SQLite
25 | {
26 |
27 | /// @endcond
28 |
29 | /**
30 | * \brief Convenience function to execute a Statement with multiple Parameter sets once for each parameter set given.
31 | *
32 | *
33 | * This feature requires a c++14 capable compiler.
34 | *
35 | * \code{.cpp}
36 | * execute_many(db, "INSERT INTO test VALUES (?, ?)",
37 | * 1,
38 | * std::make_tuple(2),
39 | * std::make_tuple(3, "three")
40 | * );
41 | * \endcode
42 | * @param aDatabase Database to use
43 | * @param apQuery Query to use with all parameter sets
44 | * @param aArg first tuple with parameters
45 | * @param aParams the following tuples with parameters
46 | */
47 | template
48 | void execute_many(Database& aDatabase, const char* apQuery, Arg&& aArg, Types&&... aParams)
49 | {
50 | SQLite::Statement query(aDatabase, apQuery);
51 | bind_exec(query, std::forward(aArg));
52 | (void)std::initializer_list
53 | {
54 | ((void)reset_bind_exec(query, std::forward(aParams)), 0)...
55 | };
56 | }
57 |
58 | /**
59 | * \brief Convenience function to reset a statement and call bind_exec to
60 | * bind new values to the statement and execute it
61 | *
62 | * This feature requires a c++14 capable compiler.
63 | *
64 | * @param apQuery Query to use
65 | * @param aTuple Tuple to bind
66 | */
67 | template
68 | void reset_bind_exec(Statement& apQuery, TupleT&& aTuple)
69 | {
70 | apQuery.reset();
71 | bind_exec(apQuery, std::forward(aTuple));
72 | }
73 |
74 | /**
75 | * \brief Convenience function to bind values a the statement and execute it
76 | *
77 | * This feature requires a c++14 capable compiler.
78 | *
79 | * @param apQuery Query to use
80 | * @param aTuple Tuple to bind
81 | */
82 | template
83 | void bind_exec(Statement& apQuery, TupleT&& aTuple)
84 | {
85 | SQLite::bind(apQuery, std::forward(aTuple));
86 | while (apQuery.executeStep()) {}
87 | }
88 |
89 | } // namespace SQLite
90 |
91 | #endif // c++14
92 |
--------------------------------------------------------------------------------
/include/SQLiteCpp/SQLiteCpp.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file SQLiteCpp.h
3 | * @ingroup SQLiteCpp
4 | * @brief SQLiteC++ is a smart and simple C++ SQLite3 wrapper. This file is only "easy include" for other files.
5 | *
6 | * Include this main header file in your project to gain access to all functionality provided by the wrapper.
7 | *
8 | * Copyright (c) 2012-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
9 | *
10 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
11 | * or copy at http://opensource.org/licenses/MIT)
12 | */
13 | /**
14 | * @defgroup SQLiteCpp SQLiteC++
15 | * @brief SQLiteC++ is a smart and simple C++ SQLite3 wrapper. This file is only "easy include" for other files.
16 | */
17 | #pragma once
18 |
19 |
20 | // Include useful headers of SQLiteC++
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 |
30 | /**
31 | * @brief Version numbers for SQLiteC++ are provided in the same way as sqlite3.h
32 | *
33 | * The [SQLITECPP_VERSION] C preprocessor macro in the SQLiteC++.h header
34 | * evaluates to a string literal that is the SQLite version in the
35 | * format "X.Y.Z" where X is the major version number
36 | * and Y is the minor version number and Z is the release number.
37 | *
38 | * The [SQLITECPP_VERSION_NUMBER] C preprocessor macro resolves to an integer
39 | * with the value (X*1000000 + Y*1000 + Z) where X, Y, and Z are the same
40 | * numbers used in [SQLITECPP_VERSION].
41 | *
42 | * WARNING: shall always be updated in sync with PROJECT_VERSION in CMakeLists.txt
43 | */
44 | #define SQLITECPP_VERSION "3.03.03" // 3.3.3
45 | #define SQLITECPP_VERSION_NUMBER 3003003 // 3.3.3
46 |
47 |
--------------------------------------------------------------------------------
/include/SQLiteCpp/SQLiteCppExport.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file SQLiteCppExport.h
3 | * @ingroup SQLiteCpp
4 | * @brief File with macros needed in the generation of Windows DLLs
5 | *
6 | *
7 | * Copyright (c) 2012-2023 Sebastien Rombauts (sebastien.rombauts@gmail.com)
8 | *
9 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
10 | * or copy at http://opensource.org/licenses/MIT)
11 | */
12 |
13 | #pragma once
14 |
15 | /*
16 | * #define SQLITECPP_COMPILE_DLL to compile a DLL under Windows
17 | * #define SQLITECPP_EXPORT to export symbols when creating the DLL, otherwise it defaults to importing symbols
18 | */
19 |
20 | /* Windows DLL export/import */
21 | #if defined(_WIN32)&& !defined(__GNUC__) && defined(SQLITECPP_COMPILE_DLL)
22 | #if SQLITECPP_DLL_EXPORT
23 | #define SQLITECPP_API __declspec(dllexport)
24 | #else
25 | #define SQLITECPP_API __declspec(dllimport)
26 | #endif
27 | #else
28 | #if __GNUC__ >= 4
29 | #define SQLITECPP_API __attribute__ ((visibility ("default")))
30 | #else
31 | #define SQLITECPP_API
32 | #endif
33 | #endif
34 |
35 | #if defined(WIN32) && defined(SQLITECPP_COMPILE_DLL)
36 | #pragma warning( disable : 4251 )
37 | #pragma warning( disable : 4275 )
38 | #endif
39 |
--------------------------------------------------------------------------------
/include/SQLiteCpp/Savepoint.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Savepoint.h
3 | * @ingroup SQLiteCpp
4 | * @brief A Savepoint is a way to group multiple SQL statements into an atomic
5 | * secured operation. Similar to a transaction while allowing child savepoints.
6 | *
7 | * Copyright (c) 2020 Kelvin Hammond (hammond.kelvin@gmail.com)
8 | * Copyright (c) 2020-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
9 | *
10 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt or
11 | * copy at http://opensource.org/licenses/MIT)
12 | */
13 | #pragma once
14 |
15 | #include
16 | #include
17 |
18 | namespace SQLite
19 | {
20 |
21 | // Forward declaration
22 | class Database;
23 |
24 | /**
25 | * @brief RAII encapsulation of a SQLite Savepoint.
26 | *
27 | * SAVEPOINTs are a method of creating Transactions, similar to BEGIN and COMMIT,
28 | * except that the SAVEPOINT and RELEASE commands are named and may be nested..
29 | *
30 | * Resource Acquisition Is Initialization (RAII) means that the Savepoint
31 | * begins in the constructor and is rolled back in the destructor (unless committed before), so that there is
32 | * no need to worry about memory management or the validity of the underlying SQLite Connection.
33 | *
34 | * This method also offers big performances improvements compared to
35 | * individually executed statements.
36 | *
37 | * Caveats:
38 | *
39 | * 1) Calling COMMIT or committing a parent transaction or RELEASE on a parent
40 | * savepoint will cause this savepoint to be released.
41 | *
42 | * 2) Calling ROLLBACK TO or rolling back a parent savepoint will cause this
43 | * savepoint to be rolled back.
44 | *
45 | * 3) This savepoint is not saved to the database until this and all savepoints
46 | * or transaction in the savepoint stack have been released or committed.
47 | *
48 | * See also: https://sqlite.org/lang_savepoint.html
49 | *
50 | * Thread-safety: a Savepoint object shall not be shared by multiple threads, because:
51 | * 1) in the SQLite "Thread Safe" mode, "SQLite can be safely used by multiple threads
52 | * provided that no single database connection is used simultaneously in two or more threads."
53 | * 2) the SQLite "Serialized" mode is not supported by SQLiteC++,
54 | * because of the way it shares the underling SQLite precompiled statement
55 | * in a custom shared pointer (See the inner class "Statement::Ptr").
56 | */
57 | class SQLITECPP_API Savepoint
58 | {
59 | public:
60 | /**
61 | * @brief Begins the SQLite savepoint
62 | *
63 | * @param[in] aDatabase the SQLite Database Connection
64 | * @param[in] aName the name of the Savepoint
65 | *
66 | * Exception is thrown in case of error, then the Savepoint is NOT
67 | * initiated.
68 | */
69 | Savepoint(Database& aDatabase, const std::string& aName);
70 |
71 | // Savepoint is non-copyable
72 | Savepoint(const Savepoint&) = delete;
73 | Savepoint& operator=(const Savepoint&) = delete;
74 |
75 | /**
76 | * @brief Safely rollback the savepoint if it has not been committed.
77 | */
78 | ~Savepoint();
79 |
80 | /**
81 | * @brief Commit and release the savepoint.
82 | */
83 | void release();
84 |
85 | /**
86 | * @brief Rollback to the savepoint, but don't release it.
87 | */
88 | void rollbackTo();
89 | // @deprecated same as rollbackTo();
90 | void rollback() { rollbackTo(); }
91 |
92 | private:
93 | Database& mDatabase; ///< Reference to the SQLite Database Connection
94 | std::string msName; ///< Name of the Savepoint
95 | bool mbReleased = false; ///< True when release has been called
96 | };
97 |
98 | } // namespace SQLite
99 |
--------------------------------------------------------------------------------
/include/SQLiteCpp/Transaction.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Transaction.h
3 | * @ingroup SQLiteCpp
4 | * @brief A Transaction is way to group multiple SQL statements into an atomic secured operation.
5 | *
6 | * Copyright (c) 2012-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
7 | *
8 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
9 | * or copy at http://opensource.org/licenses/MIT)
10 | */
11 | #pragma once
12 |
13 | #include
14 | #include
15 |
16 | namespace SQLite
17 | {
18 |
19 | // Forward declaration
20 | class Database;
21 |
22 | /**
23 | * @brief Transaction behaviors when opening an SQLite transaction.
24 | * Names correspond directly to the behavior.
25 | */
26 | enum class TransactionBehavior {
27 | DEFERRED,
28 | IMMEDIATE,
29 | EXCLUSIVE,
30 | };
31 |
32 | /**
33 | * @brief RAII encapsulation of a SQLite Transaction.
34 | *
35 | * A Transaction is a way to group multiple SQL statements into an atomic secured operation;
36 | * either it succeeds, with all the changes committed to the database file,
37 | * or if it fails, all the changes are rolled back to the initial state.
38 | *
39 | * Resource Acquisition Is Initialization (RAII) means that the Transaction
40 | * begins in the constructor and is rolled back in the destructor (unless committed before), so that there is
41 | * no need to worry about memory management or the validity of the underlying SQLite Connection.
42 | *
43 | * This method also offers big performances improvements compared to individually executed statements.
44 | *
45 | * Thread-safety: a Transaction object shall not be shared by multiple threads, because :
46 | * 1) in the SQLite "Thread Safe" mode, "SQLite can be safely used by multiple threads
47 | * provided that no single database connection is used simultaneously in two or more threads."
48 | * 2) the SQLite "Serialized" mode is not supported by SQLiteC++,
49 | * because of the way it shares the underling SQLite precompiled statement
50 | * in a custom shared pointer (See the inner class "Statement::Ptr").
51 | */
52 | class SQLITECPP_API Transaction
53 | {
54 | public:
55 | /**
56 | * @brief Begins the SQLite transaction using the default transaction behavior.
57 | *
58 | * @param[in] aDatabase the SQLite Database Connection
59 | *
60 | * Exception is thrown in case of error, then the Transaction is NOT initiated.
61 | */
62 | explicit Transaction(Database& aDatabase);
63 |
64 | /**
65 | * @brief Begins the SQLite transaction with the specified behavior.
66 | *
67 | * @param[in] aDatabase the SQLite Database Connection
68 | * @param[in] behavior the requested transaction behavior
69 | *
70 | * Exception is thrown in case of error, then the Transaction is NOT initiated.
71 | */
72 | explicit Transaction(Database& aDatabase, TransactionBehavior behavior);
73 |
74 | // Transaction is non-copyable
75 | Transaction(const Transaction&) = delete;
76 | Transaction& operator=(const Transaction&) = delete;
77 |
78 | /**
79 | * @brief Safely rollback the transaction if it has not been committed.
80 | */
81 | ~Transaction();
82 |
83 | /**
84 | * @brief Commit the transaction.
85 | */
86 | void commit();
87 |
88 | /**
89 | * @brief Rollback the transaction
90 | */
91 | void rollback();
92 |
93 | private:
94 | Database& mDatabase; ///< Reference to the SQLite Database Connection
95 | bool mbCommited = false; ///< True when commit has been called
96 | };
97 |
98 | } // namespace SQLite
99 |
--------------------------------------------------------------------------------
/include/SQLiteCpp/Utils.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Utils.h
3 | * @ingroup SQLiteCpp
4 | * @brief Definition of the SQLITECPP_PURE_FUNC macro.
5 | *
6 | * Copyright (c) 2012-2023 Sebastien Rombauts (sebastien.rombauts@gmail.com)
7 | *
8 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
9 | * or copy at http://opensource.org/licenses/MIT)
10 | */
11 | #pragma once
12 |
13 | // macro taken from https://github.com/nemequ/hedley/blob/master/hedley.h that was in public domain at this time
14 | #if defined(__GNUC__) || defined(__GNUG__) || defined(__clang__) ||\
15 | (defined(__INTEL_COMPILER) && __INTEL_COMPILER > 1600) ||\
16 | (defined(__ARMCC_VERSION) && __ARMCC_VERSION > 4010000) ||\
17 | (\
18 | defined(__TI_COMPILER_VERSION__) && (\
19 | __TI_COMPILER_VERSION__ > 8003000 ||\
20 | (__TI_COMPILER_VERSION__ > 7003000 && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))\
21 | )\
22 | )
23 | #if defined(__has_attribute)
24 | #if !defined(SQLITECPP_PURE_FUNC) && __has_attribute(pure)
25 | #define SQLITECPP_PURE_FUNC __attribute__((pure))
26 | #endif
27 | #endif
28 | #endif
29 | #if !defined(SQLITECPP_PURE_FUNC)
30 | #define SQLITECPP_PURE_FUNC
31 | #endif
32 |
--------------------------------------------------------------------------------
/include/SQLiteCpp/VariadicBind.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @file VariadicBind.h
3 | * @ingroup SQLiteCpp
4 | * @brief Convenience function for Statement::bind(...)
5 | *
6 | * Copyright (c) 2016 Paul Dreik (github@pauldreik.se)
7 | * Copyright (c) 2016-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
8 | * Copyright (c) 2019 Maximilian Bachmann (contact@maxbachmann.de)
9 | *
10 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
11 | * or copy at http://opensource.org/licenses/MIT)
12 | */
13 | #pragma once
14 |
15 | #include
16 |
17 | #if (__cplusplus >= 201402L) || ( defined(_MSC_VER) && (_MSC_VER >= 1900) ) // c++14: Visual Studio 2015
18 | #include
19 | #endif // c++14
20 |
21 | /// @cond
22 | #include
23 | #include
24 |
25 | namespace SQLite
26 | {
27 | /// @endcond
28 |
29 | /**
30 | * \brief Convenience function for calling Statement::bind(...) once for each argument given.
31 | *
32 | * This takes care of incrementing the index between each calls to bind.
33 | *
34 | * This feature requires a c++11 capable compiler.
35 | *
36 | * \code{.cpp}
37 | * SQLite::Statement stm("SELECT * FROM MyTable WHERE colA>? && colB=? && colC");
38 | * SQLite::bind(stm,a,b,c);
39 | * //...is equivalent to
40 | * stm.bind(1,a);
41 | * stm.bind(2,b);
42 | * stm.bind(3,c);
43 | * \endcode
44 | * @param query statement
45 | * @param args zero or more args to bind.
46 | */
47 | template
48 | void bind(SQLite::Statement& query, const Args& ... args)
49 | {
50 | int pos = 0;
51 | (void)std::initializer_list{
52 | ((void)query.bind(++pos, std::forward(args)), 0)...
53 | };
54 | }
55 |
56 | #if (__cplusplus >= 201402L) || ( defined(_MSC_VER) && (_MSC_VER >= 1900) ) // c++14: Visual Studio 2015
57 |
58 | /**
59 | * \brief Convenience function for calling Statement::bind(...) once for each parameter of a tuple,
60 | * by forwarding them to the variadic template
61 | *
62 | * This feature requires a c++14 capable compiler.
63 | *
64 | * \code{.cpp}
65 | * SQLite::Statement stm("SELECT * FROM MyTable WHERE colA>? && colB=? && colC");
66 | * SQLite::bind(stm, std::make_tuple(a, b, c));
67 | * //...is equivalent to
68 | * stm.bind(1,a);
69 | * stm.bind(2,b);
70 | * stm.bind(3,c);
71 | * \endcode
72 | * @param query statement
73 | * @param tuple tuple with values to bind
74 | */
75 | template
76 | void bind(SQLite::Statement& query, const std::tuple &tuple)
77 | {
78 | bind(query, tuple, std::index_sequence_for());
79 | }
80 |
81 | /**
82 | * \brief Convenience function for calling Statement::bind(...) once for each parameter of a tuple,
83 | * by forwarding them to the variadic template. This function is just needed to convert the tuples
84 | * to parameter packs
85 | *
86 | * This feature requires a c++14 capable compiler.
87 | *
88 | * @param query statement
89 | * @param tuple tuple with values to bind
90 | */
91 | template
92 | void bind(SQLite::Statement& query, const std::tuple &tuple, std::index_sequence)
93 | {
94 | bind(query, std::get(tuple)...);
95 | }
96 | #endif // c++14
97 |
98 | } // namespace SQLite
99 |
--------------------------------------------------------------------------------
/meson.build:
--------------------------------------------------------------------------------
1 | project(
2 | 'SQLiteCpp', 'cpp',
3 | # SQLiteCpp supports C++11
4 | # however newer versions of gtest requires C++14
5 | default_options: ['cpp_std=c++14', 'warning_level=3'],
6 | license: 'MIT',
7 | version: '3.3.3',
8 | )
9 |
10 | cxx = meson.get_compiler('cpp')
11 | cpp_std = get_option('cpp_std')
12 |
13 | ## at best we might try to test if this code compiles
14 | ## testing for compilers or platforms is not reliable enough
15 | ## example: native clang on windows or mingw in windows
16 | unix_like_code = '''
17 | #if defined(unix) || defined(__unix__) || defined(__unix)
18 | // do nothing
19 | #else
20 | # error "Non Unix-like OS"
21 | #endif
22 | '''
23 | unix_like = cxx.compiles(unix_like_code, name : 'unix like environment')
24 |
25 | mingw_64_env_code = '''
26 | #if defined(__MINGW64__)
27 | // do nothing
28 | #else
29 | # error "Non MinGW-W64 environment"
30 | #endif
31 | '''
32 | mingw_64_env = cxx.compiles(mingw_64_env_code, name : 'MinGW-W64 environment')
33 |
34 | thread_dep = dependency('threads')
35 | # sqlite3 support
36 | sqlite3_dep = dependency(
37 | 'sqlite3',
38 | fallback: ['sqlite3', 'sqlite3_dep']
39 | )
40 |
41 | sqlitecpp_incl = [
42 | include_directories('include')
43 | ]
44 | sqlitecpp_srcs = files(
45 | 'src/Backup.cpp',
46 | 'src/Column.cpp',
47 | 'src/Database.cpp',
48 | 'src/Exception.cpp',
49 | 'src/Savepoint.cpp',
50 | 'src/Statement.cpp',
51 | 'src/Transaction.cpp',
52 | )
53 | sqlitecpp_args = cxx.get_supported_arguments(
54 | # included in meson by default
55 | # -Wall
56 | # included when warning_level=3
57 | #'-Wextra',
58 | #'-Wpedantic',
59 | '-Wswitch-enum',
60 | '-Wshadow',
61 | '-Wno-long-long',
62 | '-Wno-attributes',
63 | )
64 | sqlitecpp_link = []
65 | sqlitecpp_deps = [
66 | sqlite3_dep,
67 | thread_dep,
68 | ]
69 | ## used to override the default sqlitecpp options like cpp standard
70 | sqlitecpp_opts = []
71 |
72 | ## used to set required macros when using sqlitecpp
73 | sqlitecpp_dep_args = []
74 |
75 | ## tests
76 |
77 | sqlitecpp_test_srcs = files(
78 | 'tests/Column_test.cpp',
79 | 'tests/Database_test.cpp',
80 | 'tests/Savepoint_test.cpp',
81 | 'tests/Statement_test.cpp',
82 | 'tests/Backup_test.cpp',
83 | 'tests/Transaction_test.cpp',
84 | 'tests/VariadicBind_test.cpp',
85 | 'tests/Exception_test.cpp',
86 | 'tests/ExecuteMany_test.cpp',
87 | )
88 | sqlitecpp_test_args = []
89 |
90 |
91 | ## using MSVC headers requires c++14, if not will show an error on xstddef as:
92 | ## 'auto' return without trailing return type; deduced return types are a C++14 extension
93 | if host_machine.system() == 'windows'
94 | ## check if the std version is less than c++14
95 | if cpp_std.version_compare('
172 | int main() {
173 | sqlite3_enable_load_extension(0, 0);
174 | return 0;
175 | }
176 | ''',
177 | name: 'sqlite3_load_extension',
178 | dependencies: [sqlite3_dep])
179 | if not sqlite3_load_extension_support
180 | message('warning: Detected bundled SQLite3 in OSX, but it does not support load extension')
181 | message('warning: SQLiteCpp will be built without load extension support')
182 | message('warning: You can disable this warning by setting SQLITE_OMIT_LOAD_EXTENSION to false')
183 | sqlitecpp_args += ['-DSQLITE_OMIT_LOAD_EXTENSION']
184 | endif
185 | endif
186 | endif
187 |
188 |
189 |
190 | if unix_like
191 | sqlitecpp_args += [
192 | # -fPIC is included by default in meson
193 | # 'fPIC',
194 | ]
195 | # add dl dependency
196 | libdl_dep = cxx.find_library('dl')
197 | sqlitecpp_deps += [
198 | libdl_dep,
199 | ]
200 | endif
201 |
202 | if get_option('b_coverage')
203 | # Prevent the compiler from removing the unused inline functions so that they get tracked as "non-covered"
204 | sqlitecpp_args += [
205 | '-fkeep-inline-functions',
206 | '-fkeep-static-functions',
207 | ]
208 | endif
209 |
210 | sqlitecpp_static_args = sqlitecpp_args
211 | sqlitecpp_static_dep_args = sqlitecpp_dep_args
212 |
213 | # if windows and shared library
214 | if host_machine.system() == 'windows' and get_option('default_library') == 'shared'
215 | # compile with SQLITECPP_COMPILE_DLL and SQLITECPP_DLL_EXPORT=1
216 | sqlitecpp_args += [
217 | '-DSQLITECPP_COMPILE_DLL',
218 | '-DSQLITECPP_DLL_EXPORT',
219 | ]
220 | sqlitecpp_dep_args += [
221 | # we just need to define SQLITECPP_COMPILE_DLL
222 | '-DSQLITECPP_COMPILE_DLL',
223 | ]
224 | endif
225 |
226 |
227 | libsqlitecpp = library(
228 | 'sqlitecpp',
229 | sqlitecpp_srcs,
230 | include_directories: sqlitecpp_incl,
231 | cpp_args: sqlitecpp_args,
232 | dependencies: sqlitecpp_deps,
233 | # override the default options
234 | override_options: sqlitecpp_opts,
235 | install: true,
236 | # API version for SQLiteCpp shared library.
237 | version: '0',)
238 |
239 |
240 |
241 | if get_option('SQLITECPP_BUILD_TESTS')
242 | # for the unit tests we need to link against a static version of SQLiteCpp
243 | if get_option('default_library') == 'static'
244 | # we do not need to recomplile the library
245 | libsqlitecpp_static = libsqlitecpp
246 | else
247 | libsqlitecpp_static = static_library(
248 | 'sqlitecpp_static',
249 | sqlitecpp_srcs,
250 | include_directories: sqlitecpp_incl,
251 | cpp_args: sqlitecpp_static_args,
252 | dependencies: sqlitecpp_deps,
253 | # override the default options
254 | override_options: sqlitecpp_opts,)
255 | endif
256 | endif
257 |
258 | install_subdir(
259 | 'include/SQLiteCpp',
260 | install_dir: get_option('includedir'))
261 |
262 | sqlitecpp_dep = declare_dependency(
263 | include_directories: sqlitecpp_incl,
264 | link_with: libsqlitecpp,
265 | compile_args: sqlitecpp_dep_args,
266 | )
267 | if get_option('SQLITECPP_BUILD_TESTS')
268 | ## make the dependency static so the unit tests can link against it
269 | ## (mainly for windows as the symbols are not exported by default)
270 | sqlitecpp_static_dep = declare_dependency(
271 | include_directories: sqlitecpp_incl,
272 | link_with: libsqlitecpp_static,
273 | compile_args: sqlitecpp_static_dep_args,
274 | )
275 | endif
276 |
277 | if get_option('SQLITECPP_BUILD_TESTS')
278 | gtest_dep = dependency(
279 | 'gtest',
280 | main : true,
281 | fallback: ['gtest', 'gtest_main_dep'])
282 | # check for the current version of gtest as newer versions require newer C++ standards
283 | if gtest_dep.found()
284 | gtest_version = gtest_dep.version()
285 | minimum_standard = 'none'
286 | required_std_format = 'current Gtest version requires at least @0@, setting the minimum standard to @0@. You can disable this warning by setting cpp_std to @0@ or newer.'
287 | ## gtest 1.17.0 requires c++17 while gtest 1.14.0 requires c++14
288 | if gtest_version.version_compare('>=1.17.0') and cpp_std.version_compare('=1.14.0') and cpp_std.version_compare('
2 |
3 | SQLiteCpp
4 | 3.3.3
5 | A smart and easy to use C++ SQLite3 wrapper.
6 |
7 | Sébastien Rombauts
8 |
9 | MIT
10 |
11 | Sébastien Rombauts
12 |
13 | cmake
14 |
15 | libsqlite3-dev
16 |
17 |
18 | cmake
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/sqlite3/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # CMake file for compiling the sqlite3 static library under Windows (for ease of use)
2 | #
3 | # Copyright (c) 2012-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
4 | #
5 | # Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
6 | # or copy at http://opensource.org/licenses/MIT)
7 |
8 | # add sources of the "sqlite3" static library
9 | add_library(sqlite3
10 | sqlite3.c
11 | sqlite3.h
12 | )
13 |
14 | if (WIN32)
15 | if (BUILD_SHARED_LIBS)
16 | add_definitions("-DSQLITE_API=__declspec(dllexport)")
17 | endif()
18 | endif()
19 |
20 | add_library(SQLite::SQLite3 ALIAS sqlite3)
21 |
22 | target_include_directories(sqlite3
23 | PUBLIC
24 | $
25 | $)
26 |
27 | if (SQLITE_ENABLE_COLUMN_METADATA)
28 | # Enable the use of SQLite column metadata method
29 | # Require that the sqlite3 library is also compiled with this flag:
30 | target_compile_definitions(sqlite3 PUBLIC SQLITE_ENABLE_COLUMN_METADATA)
31 | endif (SQLITE_ENABLE_COLUMN_METADATA)
32 |
33 | if (SQLITE_ENABLE_RTREE)
34 | # Enable RTree extension when building sqlite3
35 | # See more here: https://sqlite.org/rtree.html
36 | target_compile_definitions(sqlite3 PUBLIC SQLITE_ENABLE_RTREE)
37 | message(STATUS "Compile sqlite3 with SQLITE_ENABLE_RTREE")
38 | endif (SQLITE_ENABLE_RTREE)
39 |
40 | if (SQLITE_ENABLE_DBSTAT_VTAB)
41 | # Enable DBSTAT extension when building sqlite3
42 | # See more here: https://www.sqlite.org/dbstat.html
43 | target_compile_definitions(sqlite3 PUBLIC SQLITE_ENABLE_DBSTAT_VTAB)
44 | message(STATUS "Compile sqlite3 with SQLITE_ENABLE_DBSTAT_VTAB")
45 | endif (SQLITE_ENABLE_DBSTAT_VTAB)
46 |
47 | if (SQLITE_OMIT_LOAD_EXTENSION)
48 | target_compile_definitions(sqlite3 PUBLIC SQLITE_OMIT_LOAD_EXTENSION)
49 | message(STATUS "Compile sqlite3 with SQLITE_OMIT_LOAD_EXTENSION")
50 | endif (SQLITE_OMIT_LOAD_EXTENSION)
51 |
52 | if (UNIX AND (CMAKE_COMPILER_IS_GNUCXX OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang"))
53 | set_target_properties(sqlite3 PROPERTIES COMPILE_FLAGS "-fPIC")
54 |
55 | # Put each function in its own section to allow the linker garbage
56 | # collection to remove unused section and produced a smaller
57 | # statically-lined executables.
58 | target_compile_options(sqlite3 PRIVATE "-ffunction-sections")
59 | endif (UNIX AND (CMAKE_COMPILER_IS_GNUCXX OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang"))
60 |
61 | if (UNIX AND CMAKE_COMPILER_IS_GNUCXX)
62 | if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)
63 | target_compile_options(sqlite3 PRIVATE "-Wimplicit-fallthrough=0")
64 | endif()
65 | if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.0)
66 | target_compile_options(sqlite3 PRIVATE "-Wno-cast-function-type")
67 | endif()
68 | endif()
69 |
70 | # Allow the library to be installed via "make install" and found with "find_package"
71 |
72 | include(GNUInstallDirs)
73 | install(TARGETS sqlite3
74 | EXPORT ${PROJECT_NAME}Targets
75 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
76 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
77 | COMPONENT libraries)
78 | install(FILES sqlite3.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT headers)
79 |
--------------------------------------------------------------------------------
/sqlite3/README.md:
--------------------------------------------------------------------------------
1 | sqlite3
2 | -------
3 |
4 | Copyright (c) 2012-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
5 |
6 | "sqlite3.c" and "sqlite3.h" files from sqlite-amalgamation-3490200.zip (SQLite 3.49.2 2025-05-07)
7 |
8 | Those files are provided for easy setup and compatibility under Windows/Linux/MacOS.
9 | They are used by default by the CMake build.
10 |
11 | Use -DSQLITECPP_INTERNAL_SQLITE=OFF to link against the Linux "libsqlite3-dev" package instead.
12 |
13 | ### License:
14 |
15 | All of the code and documentation in SQLite has been dedicated to the public domain by the authors.
16 |
--------------------------------------------------------------------------------
/src/Backup.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Backup.cpp
3 | * @ingroup SQLiteCpp
4 | * @brief Backup is used to backup a database file in a safe and online way.
5 | *
6 | * Copyright (c) 2015 Shibao HONG (shibaohong@outlook.com)
7 | * Copyright (c) 2015-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
8 | *
9 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
10 | * or copy at http://opensource.org/licenses/MIT)
11 | */
12 | #include
13 |
14 | #include
15 |
16 | #include
17 |
18 | namespace SQLite
19 | {
20 |
21 | // Initialize resource for SQLite database backup
22 | Backup::Backup(Database& aDestDatabase,
23 | const char* apDestDatabaseName,
24 | Database& aSrcDatabase,
25 | const char* apSrcDatabaseName)
26 | {
27 | mpSQLiteBackup.reset(sqlite3_backup_init(aDestDatabase.getHandle(),
28 | apDestDatabaseName,
29 | aSrcDatabase.getHandle(),
30 | apSrcDatabaseName));
31 | if (nullptr == mpSQLiteBackup)
32 | {
33 | // If an error occurs, the error code and message are attached to the destination database connection.
34 | throw SQLite::Exception(aDestDatabase.getHandle());
35 | }
36 | }
37 |
38 | Backup::Backup(Database& aDestDatabase,
39 | const std::string& aDestDatabaseName,
40 | Database& aSrcDatabase,
41 | const std::string& aSrcDatabaseName) :
42 | Backup(aDestDatabase, aDestDatabaseName.c_str(), aSrcDatabase, aSrcDatabaseName.c_str())
43 | {
44 | }
45 |
46 | Backup::Backup(Database &aDestDatabase, Database &aSrcDatabase) :
47 | Backup(aDestDatabase, "main", aSrcDatabase, "main")
48 | {
49 | }
50 |
51 | // Execute backup step with a given number of source pages to be copied
52 | int Backup::executeStep(const int aNumPage /* = -1 */)
53 | {
54 | const int res = sqlite3_backup_step(mpSQLiteBackup.get(), aNumPage);
55 | if (SQLITE_OK != res && SQLITE_DONE != res && SQLITE_BUSY != res && SQLITE_LOCKED != res)
56 | {
57 | throw SQLite::Exception(sqlite3_errstr(res), res);
58 | }
59 | return res;
60 | }
61 |
62 | // Get the number of remaining source pages to be copied in this backup process
63 | int Backup::getRemainingPageCount() const
64 | {
65 | return sqlite3_backup_remaining(mpSQLiteBackup.get());
66 | }
67 |
68 | // Get the number of total source pages to be copied in this backup process
69 | int Backup::getTotalPageCount() const
70 | {
71 | return sqlite3_backup_pagecount(mpSQLiteBackup.get());
72 | }
73 |
74 | // Release resource for SQLite database backup
75 | void SQLite::Backup::Deleter::operator()(sqlite3_backup* apBackup)
76 | {
77 | if (apBackup)
78 | {
79 | sqlite3_backup_finish(apBackup);
80 | }
81 | }
82 |
83 | } // namespace SQLite
84 |
--------------------------------------------------------------------------------
/src/Column.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Column.cpp
3 | * @ingroup SQLiteCpp
4 | * @brief Encapsulation of a Column in a row of the result pointed by the prepared SQLite::Statement.
5 | *
6 | * Copyright (c) 2012-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
7 | *
8 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
9 | * or copy at http://opensource.org/licenses/MIT)
10 | */
11 | #include
12 |
13 | #include
14 |
15 | #include
16 |
17 | namespace SQLite
18 | {
19 |
20 | const int INTEGER = SQLITE_INTEGER;
21 | const int FLOAT = SQLITE_FLOAT;
22 | const int TEXT = SQLITE_TEXT;
23 | const int BLOB = SQLITE_BLOB;
24 | const int Null = SQLITE_NULL;
25 |
26 |
27 | // Encapsulation of a Column in a row of the result pointed by the prepared Statement.
28 | Column::Column(const Statement::TStatementPtr& aStmtPtr, int aIndex) :
29 | mStmtPtr(aStmtPtr),
30 | mIndex(aIndex)
31 | {
32 | if (!aStmtPtr)
33 | {
34 | throw SQLite::Exception("Statement was destroyed");
35 | }
36 | }
37 |
38 | // Return the named assigned to this result column (potentially aliased)
39 | const char* Column::getName() const noexcept
40 | {
41 | return sqlite3_column_name(mStmtPtr.get(), mIndex);
42 | }
43 |
44 | #ifdef SQLITE_ENABLE_COLUMN_METADATA
45 | // Return the name of the table column that is the origin of this result column
46 | const char* Column::getOriginName() const noexcept
47 | {
48 | return sqlite3_column_origin_name(mStmtPtr.get(), mIndex);
49 | }
50 | #endif
51 |
52 | // Return the integer value of the column specified by its index starting at 0
53 | int32_t Column::getInt() const noexcept
54 | {
55 | return sqlite3_column_int(mStmtPtr.get(), mIndex);
56 | }
57 |
58 | // Return the unsigned integer value of the column specified by its index starting at 0
59 | uint32_t Column::getUInt() const noexcept
60 | {
61 | return static_cast(getInt64());
62 | }
63 |
64 | // Return the 64bits integer value of the column specified by its index starting at 0
65 | int64_t Column::getInt64() const noexcept
66 | {
67 | return sqlite3_column_int64(mStmtPtr.get(), mIndex);
68 | }
69 |
70 | // Return the double value of the column specified by its index starting at 0
71 | double Column::getDouble() const noexcept
72 | {
73 | return sqlite3_column_double(mStmtPtr.get(), mIndex);
74 | }
75 |
76 | // Return a pointer to the text value (NULL terminated string) of the column specified by its index starting at 0
77 | const char* Column::getText(const char* apDefaultValue /* = "" */) const noexcept
78 | {
79 | auto pText = reinterpret_cast(sqlite3_column_text(mStmtPtr.get(), mIndex));
80 | return (pText ? pText : apDefaultValue);
81 | }
82 |
83 | // Return a pointer to the blob value (*not* NULL terminated) of the column specified by its index starting at 0
84 | const void* Column::getBlob() const noexcept
85 | {
86 | return sqlite3_column_blob(mStmtPtr.get(), mIndex);
87 | }
88 |
89 | // Return a std::string to a TEXT or BLOB column
90 | std::string Column::getString() const
91 | {
92 | // Note: using sqlite3_column_blob and not sqlite3_column_text
93 | // - no need for sqlite3_column_text to add a \0 on the end, as we're getting the bytes length directly
94 | // however, we need to call sqlite3_column_bytes() to ensure correct format. It's a noop on a BLOB
95 | // or a TEXT value with the correct encoding (UTF-8). Otherwise it'll do a conversion to TEXT (UTF-8).
96 | (void)sqlite3_column_bytes(mStmtPtr.get(), mIndex);
97 | auto data = static_cast(sqlite3_column_blob(mStmtPtr.get(), mIndex));
98 |
99 | // SQLite docs: "The safest policy is to invoke… sqlite3_column_blob() followed by sqlite3_column_bytes()"
100 | // Note: std::string is ok to pass nullptr as first arg, if length is 0
101 | return std::string(data, sqlite3_column_bytes(mStmtPtr.get(), mIndex));
102 | }
103 |
104 | // Return the type of the value of the column
105 | int Column::getType() const noexcept
106 | {
107 | return sqlite3_column_type(mStmtPtr.get(), mIndex);
108 | }
109 |
110 | // Return the number of bytes used by the text value of the column
111 | int Column::getBytes() const noexcept
112 | {
113 | return sqlite3_column_bytes(mStmtPtr.get(), mIndex);
114 | }
115 |
116 | // Standard std::ostream inserter
117 | std::ostream& operator<<(std::ostream& aStream, const Column& aColumn)
118 | {
119 | aStream.write(aColumn.getText(), aColumn.getBytes());
120 | return aStream;
121 | }
122 |
123 | } // namespace SQLite
124 |
--------------------------------------------------------------------------------
/src/Database.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Database.cpp
3 | * @ingroup SQLiteCpp
4 | * @brief Management of a SQLite Database Connection.
5 | *
6 | * Copyright (c) 2012-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
7 | *
8 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
9 | * or copy at http://opensource.org/licenses/MIT)
10 | */
11 | #include
12 |
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | #include
19 | #include
20 | #include
21 |
22 | #ifndef SQLITE_DETERMINISTIC
23 | #define SQLITE_DETERMINISTIC 0x800
24 | #endif // SQLITE_DETERMINISTIC
25 |
26 | namespace SQLite
27 | {
28 |
29 | const int OK = SQLITE_OK;
30 | const int OPEN_READONLY = SQLITE_OPEN_READONLY;
31 | const int OPEN_READWRITE = SQLITE_OPEN_READWRITE;
32 | const int OPEN_CREATE = SQLITE_OPEN_CREATE;
33 | const int OPEN_URI = SQLITE_OPEN_URI;
34 | const int OPEN_MEMORY = SQLITE_OPEN_MEMORY;
35 | const int OPEN_NOMUTEX = SQLITE_OPEN_NOMUTEX;
36 | const int OPEN_FULLMUTEX = SQLITE_OPEN_FULLMUTEX;
37 | const int OPEN_SHAREDCACHE = SQLITE_OPEN_SHAREDCACHE;
38 | const int OPEN_PRIVATECACHE = SQLITE_OPEN_PRIVATECACHE;
39 | // check if sqlite version is >= 3.31.0 and SQLITE_OPEN_NOFOLLOW is defined
40 | #if SQLITE_VERSION_NUMBER >= 3031000 && defined(SQLITE_OPEN_NOFOLLOW)
41 | const int OPEN_NOFOLLOW = SQLITE_OPEN_NOFOLLOW;
42 | #else
43 | const int OPEN_NOFOLLOW = 0;
44 | #endif
45 |
46 | const char* const VERSION = SQLITE_VERSION;
47 | const int VERSION_NUMBER = SQLITE_VERSION_NUMBER;
48 |
49 | // Return SQLite version string using runtime call to the compiled library
50 | const char* getLibVersion() noexcept
51 | {
52 | return sqlite3_libversion();
53 | }
54 |
55 | // Return SQLite version number using runtime call to the compiled library
56 | int getLibVersionNumber() noexcept
57 | {
58 | return sqlite3_libversion_number();
59 | }
60 |
61 |
62 | // Open the provided database UTF-8 filename with SQLite::OPEN_xxx provided flags.
63 | Database::Database(const char* apFilename,
64 | const int aFlags /* = SQLite::OPEN_READONLY*/,
65 | const int aBusyTimeoutMs /* = 0 */,
66 | const char* apVfs /* = nullptr*/) :
67 | mFilename(apFilename)
68 | {
69 | sqlite3* handle;
70 | const int ret = sqlite3_open_v2(apFilename, &handle, aFlags, apVfs);
71 | mSQLitePtr.reset(handle);
72 | if (SQLITE_OK != ret)
73 | {
74 | throw SQLite::Exception(handle, ret);
75 | }
76 | if (aBusyTimeoutMs > 0)
77 | {
78 | setBusyTimeout(aBusyTimeoutMs);
79 | }
80 | }
81 |
82 | // Deleter functor to use with smart pointers to close the SQLite database connection in an RAII fashion.
83 | void Database::Deleter::operator()(sqlite3* apSQLite)
84 | {
85 | const int ret = sqlite3_close(apSQLite); // Calling sqlite3_close() with a nullptr argument is a harmless no-op.
86 |
87 | // Avoid unreferenced variable warning when build in release mode
88 | (void) ret;
89 |
90 | // Only case of error is SQLITE_BUSY: "database is locked" (some statements are not finalized)
91 | // Never throw an exception in a destructor :
92 | SQLITECPP_ASSERT(SQLITE_OK == ret, "database is locked"); // See SQLITECPP_ENABLE_ASSERT_HANDLER
93 | }
94 |
95 | // Set a busy handler that sleeps for a specified amount of time when a table is locked.
96 | void Database::setBusyTimeout(const int aBusyTimeoutMs)
97 | {
98 | const int ret = sqlite3_busy_timeout(getHandle(), aBusyTimeoutMs);
99 | check(ret);
100 | }
101 |
102 | // Shortcut to execute one or multiple SQL statements without results (UPDATE, INSERT, ALTER, COMMIT, CREATE...).
103 | // Return the number of changes.
104 | int Database::exec(const char* apQueries)
105 | {
106 | const int ret = tryExec(apQueries);
107 | check(ret);
108 |
109 | // Return the number of rows modified by those SQL statements (INSERT, UPDATE or DELETE only)
110 | return sqlite3_changes(getHandle());
111 | }
112 |
113 | int Database::tryExec(const char* apQueries) noexcept
114 | {
115 | return sqlite3_exec(getHandle(), apQueries, nullptr, nullptr, nullptr);
116 | }
117 |
118 | // Shortcut to execute a one step query and fetch the first column of the result.
119 | // WARNING: Be very careful with this dangerous method: you have to
120 | // make a COPY OF THE result, else it will be destroy before the next line
121 | // (when the underlying temporary Statement and Column objects are destroyed)
122 | // this is an issue only for pointer type result (ie. char* and blob)
123 | // (use the Column copy-constructor)
124 | Column Database::execAndGet(const char* apQuery)
125 | {
126 | Statement query(*this, apQuery);
127 | (void)query.executeStep(); // Can return false if no result, which will throw next line in getColumn()
128 | return query.getColumn(0);
129 | }
130 |
131 | // Shortcut to test if a table exists.
132 | bool Database::tableExists(const char* apTableName) const
133 | {
134 | Statement query(*this, "SELECT count(*) FROM sqlite_master WHERE type='table' AND name=?");
135 | query.bind(1, apTableName);
136 | (void)query.executeStep(); // Cannot return false, as the above query always return a result
137 | return (1 == query.getColumn(0).getInt());
138 | }
139 |
140 | // Get the rowid of the most recent successful INSERT into the database from the current connection.
141 | int64_t Database::getLastInsertRowid() const noexcept
142 | {
143 | return sqlite3_last_insert_rowid(getHandle());
144 | }
145 |
146 | // Get number of rows modified by last INSERT, UPDATE or DELETE statement (not DROP table).
147 | int Database::getChanges() const noexcept
148 | {
149 | return sqlite3_changes(getHandle());
150 | }
151 |
152 | // Get total number of rows modified by all INSERT, UPDATE or DELETE statement since connection.
153 | int Database::getTotalChanges() const noexcept
154 | {
155 | return sqlite3_total_changes(getHandle());
156 | }
157 |
158 | // Return the numeric result code for the most recent failed API call (if any).
159 | int Database::getErrorCode() const noexcept
160 | {
161 | return sqlite3_errcode(getHandle());
162 | }
163 |
164 | // Return the extended numeric result code for the most recent failed API call (if any).
165 | int Database::getExtendedErrorCode() const noexcept
166 | {
167 | return sqlite3_extended_errcode(getHandle());
168 | }
169 |
170 | // Return UTF-8 encoded English language explanation of the most recent failed API call (if any).
171 | const char* Database::getErrorMsg() const noexcept
172 | {
173 | return sqlite3_errmsg(getHandle());
174 | }
175 |
176 | // Attach a custom function to your sqlite database. Assumes UTF8 text representation.
177 | // Parameter details can be found here: http://www.sqlite.org/c3ref/create_function.html
178 | void Database::createFunction(const char* apFuncName,
179 | int aNbArg,
180 | bool abDeterministic,
181 | void* apApp,
182 | void (*apFunc)(sqlite3_context *, int, sqlite3_value **),
183 | void (*apStep)(sqlite3_context *, int, sqlite3_value **) /* = nullptr */,
184 | void (*apFinal)(sqlite3_context *) /* = nullptr */, // NOLINT(readability/casting)
185 | void (*apDestroy)(void *) /* = nullptr */)
186 | {
187 | int textRep = SQLITE_UTF8;
188 | // optimization if deterministic function (e.g. of nondeterministic function random())
189 | if (abDeterministic)
190 | {
191 | textRep = textRep | SQLITE_DETERMINISTIC;
192 | }
193 | const int ret = sqlite3_create_function_v2(getHandle(), apFuncName, aNbArg, textRep,
194 | apApp, apFunc, apStep, apFinal, apDestroy);
195 | check(ret);
196 | }
197 |
198 | // Load an extension into the sqlite database. Only affects the current connection.
199 | // Parameter details can be found here: http://www.sqlite.org/c3ref/load_extension.html
200 | void Database::loadExtension(const char* apExtensionName, const char *apEntryPointName)
201 | {
202 | #ifdef SQLITE_OMIT_LOAD_EXTENSION
203 | // Unused
204 | (void)apExtensionName;
205 | (void)apEntryPointName;
206 |
207 | throw SQLite::Exception("sqlite extensions are disabled");
208 | #else
209 | #ifdef SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION // Since SQLite 3.13 (2016-05-18):
210 | // Security warning:
211 | // It is recommended that the SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION method be used to enable only this interface.
212 | // The use of the sqlite3_enable_load_extension() interface should be avoided to keep the SQL load_extension()
213 | // disabled and prevent SQL injections from giving attackers access to extension loading capabilities.
214 | // (NOTE: not using nullptr: cannot pass object of non-POD type 'std::__1::nullptr_t' through variadic function)
215 | int ret = sqlite3_db_config(getHandle(), SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, NULL); // NOTE: not using nullptr
216 | #else
217 | int ret = sqlite3_enable_load_extension(getHandle(), 1);
218 | #endif
219 | check(ret);
220 |
221 | ret = sqlite3_load_extension(getHandle(), apExtensionName, apEntryPointName, 0);
222 | check(ret);
223 | #endif
224 | }
225 |
226 | // Set the key for the current sqlite database instance.
227 | void Database::key(const std::string& aKey) const
228 | {
229 | int passLen = static_cast(aKey.length());
230 | #ifdef SQLITE_HAS_CODEC
231 | if (passLen > 0)
232 | {
233 | const int ret = sqlite3_key(getHandle(), aKey.c_str(), passLen);
234 | check(ret);
235 | }
236 | #else // SQLITE_HAS_CODEC
237 | if (passLen > 0)
238 | {
239 | throw SQLite::Exception("No encryption support, recompile with SQLITE_HAS_CODEC to enable.");
240 | }
241 | #endif // SQLITE_HAS_CODEC
242 | }
243 |
244 | // Reset the key for the current sqlite database instance.
245 | void Database::rekey(const std::string& aNewKey) const
246 | {
247 | #ifdef SQLITE_HAS_CODEC
248 | int passLen = aNewKey.length();
249 | if (passLen > 0)
250 | {
251 | const int ret = sqlite3_rekey(getHandle(), aNewKey.c_str(), passLen);
252 | check(ret);
253 | }
254 | else
255 | {
256 | const int ret = sqlite3_rekey(getHandle(), nullptr, 0);
257 | check(ret);
258 | }
259 | #else // SQLITE_HAS_CODEC
260 | static_cast(aNewKey); // silence unused parameter warning
261 | throw SQLite::Exception("No encryption support, recompile with SQLITE_HAS_CODEC to enable.");
262 | #endif // SQLITE_HAS_CODEC
263 | }
264 |
265 | // Test if a file contains an unencrypted database.
266 | bool Database::isUnencrypted(const std::string& aFilename)
267 | {
268 | if (aFilename.empty())
269 | {
270 | throw SQLite::Exception("Could not open database, the aFilename parameter was empty.");
271 | }
272 |
273 | std::ifstream fileBuffer(aFilename.c_str(), std::ios::in | std::ios::binary);
274 | char header[16];
275 | if (fileBuffer.is_open())
276 | {
277 | fileBuffer.seekg(0, std::ios::beg);
278 | fileBuffer.getline(header, 16);
279 | fileBuffer.close();
280 | }
281 | else
282 | {
283 | throw SQLite::Exception("Error opening file: " + aFilename);
284 | }
285 |
286 | return strncmp(header, "SQLite format 3\000", 16) == 0;
287 | }
288 |
289 | // Parse header data from a database.
290 | Header Database::getHeaderInfo(const std::string& aFilename)
291 | {
292 | Header h;
293 | unsigned char buf[100];
294 | char* pBuf = reinterpret_cast(&buf[0]);
295 | char* pHeaderStr = reinterpret_cast(&h.headerStr[0]);
296 |
297 | if (aFilename.empty())
298 | {
299 | throw SQLite::Exception("Filename parameter is empty");
300 | }
301 |
302 | {
303 | std::ifstream fileBuffer(aFilename.c_str(), std::ios::in | std::ios::binary);
304 | if (fileBuffer.is_open())
305 | {
306 | fileBuffer.seekg(0, std::ios::beg);
307 | fileBuffer.read(pBuf, 100);
308 | fileBuffer.close();
309 | if (fileBuffer.gcount() < 100)
310 | {
311 | throw SQLite::Exception("File " + aFilename + " is too short");
312 | }
313 | }
314 | else
315 | {
316 | throw SQLite::Exception("Error opening file " + aFilename);
317 | }
318 | }
319 |
320 | // If the "magic string" can't be found then header is invalid, corrupt or unreadable
321 | memcpy(pHeaderStr, pBuf, 16);
322 | pHeaderStr[15] = '\0';
323 | if (strncmp(pHeaderStr, "SQLite format 3", 15) != 0)
324 | {
325 | throw SQLite::Exception("Invalid or encrypted SQLite header in file " + aFilename);
326 | }
327 |
328 | h.pageSizeBytes = (buf[16] << 8) | buf[17];
329 | h.fileFormatWriteVersion = buf[18];
330 | h.fileFormatReadVersion = buf[19];
331 | h.reservedSpaceBytes = buf[20];
332 | h.maxEmbeddedPayloadFrac = buf[21];
333 | h.minEmbeddedPayloadFrac = buf[22];
334 | h.leafPayloadFrac = buf[23];
335 |
336 | h.fileChangeCounter =
337 | (buf[24] << 24) |
338 | (buf[25] << 16) |
339 | (buf[26] << 8) |
340 | (buf[27] << 0);
341 |
342 | h.databaseSizePages =
343 | (buf[28] << 24) |
344 | (buf[29] << 16) |
345 | (buf[30] << 8) |
346 | (buf[31] << 0);
347 |
348 | h.firstFreelistTrunkPage =
349 | (buf[32] << 24) |
350 | (buf[33] << 16) |
351 | (buf[34] << 8) |
352 | (buf[35] << 0);
353 |
354 | h.totalFreelistPages =
355 | (buf[36] << 24) |
356 | (buf[37] << 16) |
357 | (buf[38] << 8) |
358 | (buf[39] << 0);
359 |
360 | h.schemaCookie =
361 | (buf[40] << 24) |
362 | (buf[41] << 16) |
363 | (buf[42] << 8) |
364 | (buf[43] << 0);
365 |
366 | h.schemaFormatNumber =
367 | (buf[44] << 24) |
368 | (buf[45] << 16) |
369 | (buf[46] << 8) |
370 | (buf[47] << 0);
371 |
372 | h.defaultPageCacheSizeBytes =
373 | (buf[48] << 24) |
374 | (buf[49] << 16) |
375 | (buf[50] << 8) |
376 | (buf[51] << 0);
377 |
378 | h.largestBTreePageNumber =
379 | (buf[52] << 24) |
380 | (buf[53] << 16) |
381 | (buf[54] << 8) |
382 | (buf[55] << 0);
383 |
384 | h.databaseTextEncoding =
385 | (buf[56] << 24) |
386 | (buf[57] << 16) |
387 | (buf[58] << 8) |
388 | (buf[59] << 0);
389 |
390 | h.userVersion =
391 | (buf[60] << 24) |
392 | (buf[61] << 16) |
393 | (buf[62] << 8) |
394 | (buf[63] << 0);
395 |
396 | h.incrementalVaccumMode =
397 | (buf[64] << 24) |
398 | (buf[65] << 16) |
399 | (buf[66] << 8) |
400 | (buf[67] << 0);
401 |
402 | h.applicationId =
403 | (buf[68] << 24) |
404 | (buf[69] << 16) |
405 | (buf[70] << 8) |
406 | (buf[71] << 0);
407 |
408 | h.versionValidFor =
409 | (buf[92] << 24) |
410 | (buf[93] << 16) |
411 | (buf[94] << 8) |
412 | (buf[95] << 0);
413 |
414 | h.sqliteVersion =
415 | (buf[96] << 24) |
416 | (buf[97] << 16) |
417 | (buf[98] << 8) |
418 | (buf[99] << 0);
419 |
420 | return h;
421 | }
422 |
423 | void Database::backup(const char* apFilename, BackupType aType)
424 | {
425 | // Open the database file identified by apFilename
426 | Database otherDatabase(apFilename, SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE);
427 |
428 | // For a 'Save' operation, data is copied from the current Database to the other. A 'Load' is the reverse.
429 | Database& src = (aType == BackupType::Save ? *this : otherDatabase);
430 | Database& dest = (aType == BackupType::Save ? otherDatabase : *this);
431 |
432 | // Set up the backup procedure to copy between the "main" databases of each connection
433 | Backup bkp(dest, src);
434 | bkp.executeStep(); // Execute all steps at once
435 |
436 | // RAII Finish Backup an Close the other Database
437 | }
438 |
439 | } // namespace SQLite
440 |
--------------------------------------------------------------------------------
/src/Exception.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Exception.cpp
3 | * @ingroup SQLiteCpp
4 | * @brief Encapsulation of the error message from SQLite3 on a std::runtime_error.
5 | *
6 | * Copyright (c) 2012-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
7 | *
8 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
9 | * or copy at http://opensource.org/licenses/MIT)
10 | */
11 | #include
12 |
13 | #include
14 |
15 | namespace SQLite
16 | {
17 |
18 | Exception::Exception(const char* aErrorMessage, int ret) :
19 | std::runtime_error(aErrorMessage),
20 | mErrcode(ret),
21 | mExtendedErrcode(-1)
22 | {
23 | }
24 |
25 | Exception::Exception(sqlite3* apSQLite) :
26 | std::runtime_error(sqlite3_errmsg(apSQLite)),
27 | mErrcode(sqlite3_errcode(apSQLite)),
28 | mExtendedErrcode(sqlite3_extended_errcode(apSQLite))
29 | {
30 | }
31 |
32 | Exception::Exception(sqlite3* apSQLite, int ret) :
33 | std::runtime_error(sqlite3_errmsg(apSQLite)),
34 | mErrcode(ret),
35 | mExtendedErrcode(sqlite3_extended_errcode(apSQLite))
36 | {
37 | }
38 |
39 | // Return a string, solely based on the error code
40 | const char* Exception::getErrorStr() const noexcept
41 | {
42 | return sqlite3_errstr(mErrcode);
43 | }
44 |
45 | } // namespace SQLite
46 |
--------------------------------------------------------------------------------
/src/Savepoint.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Savepoint.cpp
3 | * @ingroup SQLiteCpp
4 | * @brief A Savepoint is a way to group multiple SQL statements into an atomic
5 | * secured operation. Similar to a transaction while allowing child savepoints.
6 | *
7 | * Copyright (c) 2020 Kelvin Hammond (hammond.kelvin@gmail.com)
8 | * Copyright (c) 2020-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
9 | *
10 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt or
11 | * copy at http://opensource.org/licenses/MIT)
12 | */
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | namespace SQLite
20 | {
21 |
22 | // Begins the SQLite savepoint
23 | Savepoint::Savepoint(Database& aDatabase, const std::string& aName)
24 | : mDatabase(aDatabase), msName(aName)
25 | {
26 | // workaround because you cannot bind to SAVEPOINT
27 | // escape name for use in query
28 | Statement stmt(mDatabase, "SELECT quote(?)");
29 | stmt.bind(1, msName);
30 | stmt.executeStep();
31 | msName = stmt.getColumn(0).getText();
32 |
33 | mDatabase.exec(std::string("SAVEPOINT ") + msName);
34 | }
35 |
36 | // Safely rollback the savepoint if it has not been committed.
37 | Savepoint::~Savepoint()
38 | {
39 | if (!mbReleased)
40 | {
41 | try
42 | {
43 | rollback();
44 | release();
45 | }
46 | catch (SQLite::Exception&)
47 | {
48 | // Never throw an exception in a destructor: error if already released,
49 | // but no harm is caused by this.
50 | }
51 | }
52 | }
53 |
54 | // Release the savepoint and commit
55 | void Savepoint::release()
56 | {
57 | if (!mbReleased)
58 | {
59 | mDatabase.exec(std::string("RELEASE SAVEPOINT ") + msName);
60 | mbReleased = true;
61 | }
62 | else
63 | {
64 | throw SQLite::Exception("Savepoint already released.");
65 | }
66 | }
67 |
68 | // Rollback to the savepoint, but don't release it
69 | void Savepoint::rollbackTo()
70 | {
71 | if (!mbReleased)
72 | {
73 | mDatabase.exec(std::string("ROLLBACK TO SAVEPOINT ") + msName);
74 | }
75 | else
76 | {
77 | throw SQLite::Exception("Savepoint already released.");
78 | }
79 | }
80 |
81 | } // namespace SQLite
82 |
--------------------------------------------------------------------------------
/src/Statement.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Statement.cpp
3 | * @ingroup SQLiteCpp
4 | * @brief A prepared SQLite Statement is a compiled SQL query ready to be executed, pointing to a row of result.
5 | *
6 | * Copyright (c) 2012-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
7 | *
8 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
9 | * or copy at http://opensource.org/licenses/MIT)
10 | */
11 | #include
12 |
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | #include
19 |
20 | // check for if SQLite3 version >= 3.14.0
21 | #if SQLITE_VERSION_NUMBER < 3014000
22 | #warning "SQLite3 version is less than 3.14.0, so expanded SQL is not available"
23 | #warning "To use expanded SQL, please upgrade to SQLite3 version 3.14.0 or later"
24 | #warning "If you want to disable this warning, define SQLITECPP_DISABLE_SQLITE3_EXPANDED_SQL"
25 | #warning "or use the specific project option in your build system"
26 | #warning "disabling expanded SQL support"
27 | #define SQLITECPP_DISABLE_SQLITE3_EXPANDED_SQL
28 | #endif
29 |
30 |
31 | namespace SQLite
32 | {
33 |
34 | Statement::Statement(const Database& aDatabase, const char* apQuery) :
35 | mQuery(apQuery),
36 | mpSQLite(aDatabase.getHandle()),
37 | mpPreparedStatement(prepareStatement()) // prepare the SQL query (needs Database friendship)
38 | {
39 | mColumnCount = sqlite3_column_count(mpPreparedStatement.get());
40 | }
41 |
42 | Statement::Statement(Statement&& aStatement) noexcept :
43 | mQuery(std::move(aStatement.mQuery)),
44 | mpSQLite(aStatement.mpSQLite),
45 | mpPreparedStatement(std::move(aStatement.mpPreparedStatement)),
46 | mColumnCount(aStatement.mColumnCount),
47 | mbHasRow(aStatement.mbHasRow),
48 | mbDone(aStatement.mbDone),
49 | mColumnNames(std::move(aStatement.mColumnNames))
50 | {
51 | aStatement.mpSQLite = nullptr;
52 | aStatement.mColumnCount = 0;
53 | aStatement.mbHasRow = false;
54 | aStatement.mbDone = false;
55 | }
56 |
57 | // Reset the statement to make it ready for a new execution (see also #clearBindings() below)
58 | void Statement::reset()
59 | {
60 | const int ret = tryReset();
61 | check(ret);
62 | }
63 |
64 | int Statement::tryReset() noexcept
65 | {
66 | mbHasRow = false;
67 | mbDone = false;
68 | return sqlite3_reset(mpPreparedStatement.get());
69 | }
70 |
71 | // Clears away all the bindings of a prepared statement (can be associated with #reset() above).
72 | void Statement::clearBindings()
73 | {
74 | const int ret = sqlite3_clear_bindings(getPreparedStatement());
75 | check(ret);
76 | }
77 |
78 | int Statement::getIndex(const char * const apName) const
79 | {
80 | return sqlite3_bind_parameter_index(getPreparedStatement(), apName);
81 | }
82 |
83 | // Bind an 32bits int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
84 | void Statement::bind(const int aIndex, const int32_t aValue)
85 | {
86 | const int ret = sqlite3_bind_int(getPreparedStatement(), aIndex, aValue);
87 | check(ret);
88 | }
89 |
90 | // Bind a 32bits unsigned int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
91 | void Statement::bind(const int aIndex, const uint32_t aValue)
92 | {
93 | const int ret = sqlite3_bind_int64(getPreparedStatement(), aIndex, aValue);
94 | check(ret);
95 | }
96 |
97 | // Bind a 64bits int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
98 | void Statement::bind(const int aIndex, const int64_t aValue)
99 | {
100 | const int ret = sqlite3_bind_int64(getPreparedStatement(), aIndex, aValue);
101 | check(ret);
102 | }
103 |
104 | // Bind a double (64bits float) value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
105 | void Statement::bind(const int aIndex, const double aValue)
106 | {
107 | const int ret = sqlite3_bind_double(getPreparedStatement(), aIndex, aValue);
108 | check(ret);
109 | }
110 |
111 | // Bind a string value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
112 | void Statement::bind(const int aIndex, const std::string& aValue)
113 | {
114 | const int ret = sqlite3_bind_text(getPreparedStatement(), aIndex, aValue.c_str(),
115 | static_cast(aValue.size()), SQLITE_TRANSIENT);
116 | check(ret);
117 | }
118 |
119 | // Bind a text value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
120 | void Statement::bind(const int aIndex, const char* apValue)
121 | {
122 | const int ret = sqlite3_bind_text(getPreparedStatement(), aIndex, apValue, -1, SQLITE_TRANSIENT);
123 | check(ret);
124 | }
125 |
126 | // Bind a binary blob value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
127 | void Statement::bind(const int aIndex, const void* apValue, const int aSize)
128 | {
129 | const int ret = sqlite3_bind_blob(getPreparedStatement(), aIndex, apValue, aSize, SQLITE_TRANSIENT);
130 | check(ret);
131 | }
132 |
133 | // Bind a string value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
134 | void Statement::bindNoCopy(const int aIndex, const std::string& aValue)
135 | {
136 | const int ret = sqlite3_bind_text(getPreparedStatement(), aIndex, aValue.c_str(),
137 | static_cast(aValue.size()), SQLITE_STATIC);
138 | check(ret);
139 | }
140 |
141 | // Bind a text value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
142 | void Statement::bindNoCopy(const int aIndex, const char* apValue)
143 | {
144 | const int ret = sqlite3_bind_text(getPreparedStatement(), aIndex, apValue, -1, SQLITE_STATIC);
145 | check(ret);
146 | }
147 |
148 | // Bind a binary blob value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
149 | void Statement::bindNoCopy(const int aIndex, const void* apValue, const int aSize)
150 | {
151 | const int ret = sqlite3_bind_blob(getPreparedStatement(), aIndex, apValue, aSize, SQLITE_STATIC);
152 | check(ret);
153 | }
154 |
155 | // Bind a NULL value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
156 | void Statement::bind(const int aIndex)
157 | {
158 | const int ret = sqlite3_bind_null(getPreparedStatement(), aIndex);
159 | check(ret);
160 | }
161 |
162 |
163 | // Execute a step of the query to fetch one row of results
164 | bool Statement::executeStep()
165 | {
166 | const int ret = tryExecuteStep();
167 | if ((SQLITE_ROW != ret) && (SQLITE_DONE != ret)) // on row or no (more) row ready, else it's a problem
168 | {
169 | if (ret == sqlite3_errcode(mpSQLite))
170 | {
171 | throw SQLite::Exception(mpSQLite, ret);
172 | }
173 | else
174 | {
175 | throw SQLite::Exception("Statement needs to be reseted", ret);
176 | }
177 | }
178 |
179 | return mbHasRow; // true only if one row is accessible by getColumn(N)
180 | }
181 |
182 | // Execute a one-step query with no expected result, and return the number of changes.
183 | int Statement::exec()
184 | {
185 | const int ret = tryExecuteStep();
186 | if (SQLITE_DONE != ret) // the statement has finished executing successfully
187 | {
188 | if (SQLITE_ROW == ret)
189 | {
190 | throw SQLite::Exception("exec() does not expect results. Use executeStep.");
191 | }
192 | else if (ret == sqlite3_errcode(mpSQLite))
193 | {
194 | throw SQLite::Exception(mpSQLite, ret);
195 | }
196 | else
197 | {
198 | throw SQLite::Exception("Statement needs to be reseted", ret);
199 | }
200 | }
201 |
202 | // Return the number of rows modified by those SQL statements (INSERT, UPDATE or DELETE)
203 | return sqlite3_changes(mpSQLite);
204 | }
205 |
206 | int Statement::tryExecuteStep() noexcept
207 | {
208 | if (mbDone)
209 | {
210 | return SQLITE_MISUSE; // Statement needs to be reseted !
211 | }
212 |
213 | const int ret = sqlite3_step(mpPreparedStatement.get());
214 | if (SQLITE_ROW == ret) // one row is ready : call getColumn(N) to access it
215 | {
216 | mbHasRow = true;
217 | }
218 | else
219 | {
220 | mbHasRow = false;
221 | mbDone = SQLITE_DONE == ret; // check if the query has finished executing
222 | }
223 | return ret;
224 | }
225 |
226 |
227 | // Return a copy of the column data specified by its index starting at 0
228 | // (use the Column copy-constructor)
229 | Column Statement::getColumn(const int aIndex) const
230 | {
231 | checkRow();
232 | checkIndex(aIndex);
233 |
234 | // Share the Statement Object handle with the new Column created
235 | return Column(mpPreparedStatement, aIndex);
236 | }
237 |
238 | // Return a copy of the column data specified by its column name starting at 0
239 | // (use the Column copy-constructor)
240 | Column Statement::getColumn(const char* apName) const
241 | {
242 | checkRow();
243 | const int index = getColumnIndex(apName);
244 |
245 | // Share the Statement Object handle with the new Column created
246 | return Column(mpPreparedStatement, index);
247 | }
248 |
249 | // Test if the column is NULL
250 | bool Statement::isColumnNull(const int aIndex) const
251 | {
252 | checkRow();
253 | checkIndex(aIndex);
254 | return (SQLITE_NULL == sqlite3_column_type(getPreparedStatement(), aIndex));
255 | }
256 |
257 | bool Statement::isColumnNull(const char* apName) const
258 | {
259 | checkRow();
260 | const int index = getColumnIndex(apName);
261 | return (SQLITE_NULL == sqlite3_column_type(getPreparedStatement(), index));
262 | }
263 |
264 | // Return the named assigned to the specified result column (potentially aliased)
265 | const char* Statement::getColumnName(const int aIndex) const
266 | {
267 | checkIndex(aIndex);
268 | return sqlite3_column_name(getPreparedStatement(), aIndex);
269 | }
270 |
271 | #ifdef SQLITE_ENABLE_COLUMN_METADATA
272 | // Return the named assigned to the specified result column (potentially aliased)
273 | const char* Statement::getColumnOriginName(const int aIndex) const
274 | {
275 | checkIndex(aIndex);
276 | return sqlite3_column_origin_name(getPreparedStatement(), aIndex);
277 | }
278 | #endif
279 |
280 | // Return the index of the specified (potentially aliased) column name
281 | int Statement::getColumnIndex(const char* apName) const
282 | {
283 | // Build the map of column index by name on first call
284 | if (mColumnNames.empty())
285 | {
286 | for (int i = 0; i < mColumnCount; ++i)
287 | {
288 | const char* pName = sqlite3_column_name(getPreparedStatement(), i);
289 | mColumnNames[pName] = i;
290 | }
291 | }
292 |
293 | const auto iIndex = mColumnNames.find(apName);
294 | if (iIndex == mColumnNames.end())
295 | {
296 | throw SQLite::Exception("Unknown column name.");
297 | }
298 |
299 | return iIndex->second;
300 | }
301 |
302 | const char* Statement::getColumnDeclaredType(const int aIndex) const
303 | {
304 | checkIndex(aIndex);
305 | const char * result = sqlite3_column_decltype(getPreparedStatement(), aIndex);
306 | if (!result)
307 | {
308 | throw SQLite::Exception("Could not determine declared column type.");
309 | }
310 | else
311 | {
312 | return result;
313 | }
314 | }
315 |
316 | // Get number of rows modified by last INSERT, UPDATE or DELETE statement (not DROP table).
317 | int Statement::getChanges() const noexcept
318 | {
319 | return sqlite3_changes(mpSQLite);
320 | }
321 |
322 | int Statement::getBindParameterCount() const noexcept
323 | {
324 | return sqlite3_bind_parameter_count(mpPreparedStatement.get());
325 | }
326 |
327 | // Return the numeric result code for the most recent failed API call (if any).
328 | int Statement::getErrorCode() const noexcept
329 | {
330 | return sqlite3_errcode(mpSQLite);
331 | }
332 |
333 | // Return the extended numeric result code for the most recent failed API call (if any).
334 | int Statement::getExtendedErrorCode() const noexcept
335 | {
336 | return sqlite3_extended_errcode(mpSQLite);
337 | }
338 |
339 | // Return UTF-8 encoded English language explanation of the most recent failed API call (if any).
340 | const char* Statement::getErrorMsg() const noexcept
341 | {
342 | return sqlite3_errmsg(mpSQLite);
343 | }
344 |
345 |
346 | // Return a UTF-8 string containing the SQL text of prepared statement with bound parameters expanded.
347 | std::string Statement::getExpandedSQL() const {
348 | #ifdef SQLITECPP_DISABLE_SQLITE3_EXPANDED_SQL
349 | throw SQLite::Exception("this version of SQLiteCpp does not support expanded SQL");
350 | #else
351 | char* expanded = sqlite3_expanded_sql(getPreparedStatement());
352 | std::string expandedString(expanded);
353 | sqlite3_free(expanded);
354 | return expandedString;
355 | #endif
356 | }
357 |
358 |
359 | // Prepare SQLite statement object and return shared pointer to this object
360 | Statement::TStatementPtr Statement::prepareStatement()
361 | {
362 | sqlite3_stmt* statement;
363 | const int ret = sqlite3_prepare_v2(mpSQLite, mQuery.c_str(), static_cast(mQuery.size()), &statement, nullptr);
364 | if (SQLITE_OK != ret)
365 | {
366 | throw SQLite::Exception(mpSQLite, ret);
367 | }
368 | return Statement::TStatementPtr(statement, [](sqlite3_stmt* stmt)
369 | {
370 | sqlite3_finalize(stmt);
371 | });
372 | }
373 |
374 | // Return prepered statement object or throw
375 | sqlite3_stmt* Statement::getPreparedStatement() const
376 | {
377 | sqlite3_stmt* ret = mpPreparedStatement.get();
378 | if (ret)
379 | {
380 | return ret;
381 | }
382 | throw SQLite::Exception("Statement was not prepared.");
383 | }
384 |
385 | } // namespace SQLite
386 |
--------------------------------------------------------------------------------
/src/Transaction.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Transaction.cpp
3 | * @ingroup SQLiteCpp
4 | * @brief A Transaction is way to group multiple SQL statements into an atomic secured operation.
5 | *
6 | * Copyright (c) 2012-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
7 | *
8 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
9 | * or copy at http://opensource.org/licenses/MIT)
10 | */
11 | #include
12 |
13 | #include
14 | #include
15 |
16 | #include
17 |
18 | namespace SQLite
19 | {
20 |
21 | // Begins the SQLite transaction
22 | Transaction::Transaction(Database& aDatabase, TransactionBehavior behavior) :
23 | mDatabase(aDatabase)
24 | {
25 | const char *stmt;
26 | switch (behavior) {
27 | case TransactionBehavior::DEFERRED:
28 | stmt = "BEGIN DEFERRED";
29 | break;
30 | case TransactionBehavior::IMMEDIATE:
31 | stmt = "BEGIN IMMEDIATE";
32 | break;
33 | case TransactionBehavior::EXCLUSIVE:
34 | stmt = "BEGIN EXCLUSIVE";
35 | break;
36 | default:
37 | throw SQLite::Exception("invalid/unknown transaction behavior", SQLITE_ERROR);
38 | }
39 | mDatabase.exec(stmt);
40 | }
41 |
42 | // Begins the SQLite transaction
43 | Transaction::Transaction(Database &aDatabase) :
44 | mDatabase(aDatabase)
45 | {
46 | mDatabase.exec("BEGIN TRANSACTION");
47 | }
48 |
49 | // Safely rollback the transaction if it has not been committed.
50 | Transaction::~Transaction()
51 | {
52 | if (false == mbCommited)
53 | {
54 | try
55 | {
56 | mDatabase.exec("ROLLBACK TRANSACTION");
57 | }
58 | catch (SQLite::Exception&)
59 | {
60 | // Never throw an exception in a destructor: error if already rollbacked, but no harm is caused by this.
61 | }
62 | }
63 | }
64 |
65 | // Commit the transaction.
66 | void Transaction::commit()
67 | {
68 | if (false == mbCommited)
69 | {
70 | mDatabase.exec("COMMIT TRANSACTION");
71 | mbCommited = true;
72 | }
73 | else
74 | {
75 | throw SQLite::Exception("Transaction already committed.");
76 | }
77 | }
78 |
79 | // Rollback the transaction
80 | void Transaction::rollback()
81 | {
82 | if (false == mbCommited)
83 | {
84 | mDatabase.exec("ROLLBACK TRANSACTION");
85 | }
86 | else
87 | {
88 | throw SQLite::Exception("Transaction already committed.");
89 | }
90 | }
91 |
92 | } // namespace SQLite
93 |
--------------------------------------------------------------------------------
/subprojects/.gitignore:
--------------------------------------------------------------------------------
1 | #ignore everything here
2 | *
3 | # but not the wrap files and the .gitignore
4 | !*.wrap
5 | !*.gitignore
--------------------------------------------------------------------------------
/subprojects/gtest.wrap:
--------------------------------------------------------------------------------
1 | [wrap-file]
2 | directory = googletest-1.15.0
3 | source_url = https://github.com/google/googletest/archive/refs/tags/v1.15.0.tar.gz
4 | source_filename = gtest-1.15.0.tar.gz
5 | source_hash = 7315acb6bf10e99f332c8a43f00d5fbb1ee6ca48c52f6b936991b216c586aaad
6 | patch_filename = gtest_1.15.0-1_patch.zip
7 | patch_url = https://wrapdb.mesonbuild.com/v2/gtest_1.15.0-1/get_patch
8 | patch_hash = 5f8e484c48fdc1029c7fd08807bd2615f8c9d16f90df6d81984f4f292752c925
9 | source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/gtest_1.15.0-1/gtest-1.15.0.tar.gz
10 | wrapdb_version = 1.15.0-1
11 |
12 | [provide]
13 | gtest = gtest_dep
14 | gtest_main = gtest_main_dep
15 | gmock = gmock_dep
16 | gmock_main = gmock_main_dep
17 |
--------------------------------------------------------------------------------
/subprojects/sqlite3.wrap:
--------------------------------------------------------------------------------
1 | [wrap-file]
2 | directory = sqlite-amalgamation-3490200
3 | source_url = https://www.sqlite.org/2025/sqlite-amalgamation-3490200.zip
4 | source_filename = sqlite-amalgamation-3490200.zip
5 | source_hash = 921fc725517a694df7df38a2a3dfede6684024b5788d9de464187c612afb5918
6 | patch_filename = sqlite3_3.49.2-1_patch.zip
7 | patch_url = https://wrapdb.mesonbuild.com/v2/sqlite3_3.49.2-1/get_patch
8 | patch_hash = e3eef046409329c5c1ca8308255caa2266710fc1b9d8695fdedd04cebe42a690
9 | source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/sqlite3_3.49.2-1/sqlite-amalgamation-3490200.zip
10 | wrapdb_version = 3.49.2-1
11 |
12 | [provide]
13 | sqlite3 = sqlite3_dep
14 |
--------------------------------------------------------------------------------
/tests/Backup_test.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Backup_test.cpp
3 | * @ingroup tests
4 | * @brief Test of a SQLite Backup.
5 | *
6 | * Copyright (c) 2015 Shibao HONG (shibaohong@outlook.com)
7 | * Copyright (c) 2015-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
8 | *
9 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
10 | * or copy at http://opensource.org/licenses/MIT)
11 | */
12 |
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | #include // for SQLITE_ERROR, SQLITE_RANGE and SQLITE_DONE
19 |
20 | #include
21 |
22 | #include
23 |
24 | TEST(Backup, initException)
25 | {
26 | remove("backup_test.db3");
27 | {
28 | SQLite::Database srcDB("backup_test.db3", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE);
29 | srcDB.exec("CREATE TABLE backup_test (id INTEGER PRIMARY KEY, value TEXT)");
30 | ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (1, 'first')"));
31 | ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (2, 'second')"));
32 | EXPECT_THROW(SQLite::Backup backup(srcDB, srcDB), SQLite::Exception);
33 | EXPECT_THROW(SQLite::Backup backup(srcDB, "main", srcDB, "main"), SQLite::Exception);
34 | const std::string name("main");
35 | EXPECT_THROW(SQLite::Backup backup(srcDB, name, srcDB, name), SQLite::Exception);
36 | }
37 | remove("backup_test.db3");
38 | }
39 |
40 | TEST(Backup, executeStepOne)
41 | {
42 | remove("backup_test.db3");
43 | remove("backup_test.db3.backup");
44 | {
45 | SQLite::Database srcDB("backup_test.db3", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE);
46 | srcDB.exec("CREATE TABLE backup_test (id INTEGER PRIMARY KEY, value TEXT)");
47 | ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (1, 'first')"));
48 | ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (2, 'second')"));
49 |
50 | SQLite::Database destDB("backup_test.db3.backup", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE);
51 | SQLite::Backup backup(destDB, "main", srcDB, "main");
52 | int res = backup.executeStep(1); // backup only one page at a time
53 | ASSERT_EQ(SQLite::OK, res);
54 | const int total = backup.getTotalPageCount();
55 | ASSERT_EQ(2, total);
56 | int remaining = backup.getRemainingPageCount();
57 | ASSERT_EQ(1, remaining);
58 | res = backup.executeStep(1); // backup the second and last page
59 | ASSERT_EQ(SQLITE_DONE, res);
60 | remaining = backup.getRemainingPageCount();
61 | ASSERT_EQ(0, remaining);
62 |
63 | SQLite::Statement query(destDB, "SELECT * FROM backup_test ORDER BY id ASC");
64 | ASSERT_TRUE(query.executeStep());
65 | EXPECT_EQ(1, query.getColumn(0).getInt());
66 | EXPECT_STREQ("first", query.getColumn(1));
67 | ASSERT_TRUE(query.executeStep());
68 | EXPECT_EQ(2, query.getColumn(0).getInt());
69 | EXPECT_STREQ("second", query.getColumn(1));
70 | }
71 | remove("backup_test.db3");
72 | remove("backup_test.db3.backup");
73 | }
74 |
75 | TEST(Backup, executeStepAll)
76 | {
77 | remove("backup_test.db3");
78 | remove("backup_test.db3.backup");
79 | {
80 | SQLite::Database srcDB("backup_test.db3", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE);
81 | srcDB.exec("CREATE TABLE backup_test (id INTEGER PRIMARY KEY, value TEXT)");
82 | ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (1, 'first')"));
83 | ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (2, 'second')"));
84 |
85 | SQLite::Database destDB("backup_test.db3.backup", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE);
86 | SQLite::Backup backup(destDB, srcDB);
87 | const int res = backup.executeStep(); // uses default argument "-1" => execute all steps at once
88 | ASSERT_EQ(res, SQLITE_DONE);
89 | const int total = backup.getTotalPageCount();
90 | ASSERT_EQ(2, total);
91 | const int remaining = backup.getRemainingPageCount();
92 | ASSERT_EQ(0, remaining);
93 |
94 | SQLite::Statement query(destDB, "SELECT * FROM backup_test ORDER BY id ASC");
95 | ASSERT_TRUE(query.executeStep());
96 | EXPECT_EQ(1, query.getColumn(0).getInt());
97 | EXPECT_STREQ("first", query.getColumn(1));
98 | ASSERT_TRUE(query.executeStep());
99 | EXPECT_EQ(2, query.getColumn(0).getInt());
100 | EXPECT_STREQ("second", query.getColumn(1));
101 | }
102 | remove("backup_test.db3");
103 | remove("backup_test.db3.backup");
104 | }
105 |
106 | TEST(Backup, executeStepException)
107 | {
108 | remove("backup_test.db3");
109 | remove("backup_test.db3.backup");
110 | {
111 | SQLite::Database srcDB("backup_test.db3", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE);
112 | srcDB.exec("CREATE TABLE backup_test (id INTEGER PRIMARY KEY, value TEXT)");
113 | ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (1, 'first')"));
114 | ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (2, 'second')"));
115 | {
116 | SQLite::Database destDB("backup_test.db3.backup", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE);
117 | (void)destDB;
118 | }
119 | {
120 | SQLite::Database destDB("backup_test.db3.backup", SQLite::OPEN_READONLY);
121 | SQLite::Backup backup(destDB, srcDB);
122 | EXPECT_THROW(backup.executeStep(), SQLite::Exception);
123 | }
124 | }
125 | remove("backup_test.db3");
126 | remove("backup_test.db3.backup");
127 | }
128 |
--------------------------------------------------------------------------------
/tests/Column_test.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Column_test.cpp
3 | * @ingroup tests
4 | * @brief Test of a SQLiteCpp Column.
5 | *
6 | * Copyright (c) 2012-2025 Sebastien Rombauts (sebastien.rombauts@gmail.com)
7 | *
8 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
9 | * or copy at http://opensource.org/licenses/MIT)
10 | */
11 |
12 | #include
13 | #include
14 | #include
15 |
16 | #include
17 |
18 | #include
19 | #include
20 |
21 |
22 | static void test_column_basis(bool utf16)
23 | {
24 | // Create a new database
25 | SQLite::Database db(":memory:", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE);
26 | EXPECT_EQ(SQLite::OK, db.getErrorCode());
27 | EXPECT_EQ(SQLite::OK, db.getExtendedErrorCode());
28 |
29 | if (utf16)
30 | {
31 | EXPECT_EQ(0, db.exec("PRAGMA encoding = 'UTF-16';"));
32 | }
33 |
34 | // Create a new table
35 | EXPECT_EQ(0, db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, msg TEXT, int INTEGER, double REAL, binary BLOB, empty TEXT)"));
36 | EXPECT_TRUE(db.tableExists("test"));
37 | EXPECT_TRUE(db.tableExists(std::string("test")));
38 | EXPECT_EQ(0, db.getLastInsertRowid());
39 |
40 | // Create a first row (autoid: 1) with all kind of data and a null value
41 | SQLite::Statement insert(db, "INSERT INTO test VALUES (NULL, 'first', -123, 0.123, ?, NULL)");
42 | // Bind the blob value to the first parameter of the SQL query
43 | const char buffer[] = {'b', 'l', '\0', 'b'}; // "bl\0b" : 4 char, with a null byte inside
44 | const int size = sizeof(buffer); // size = 4
45 | const void* blob = &buffer;
46 | insert.bind(1, blob, size);
47 | // Execute the one-step query to insert the row
48 | EXPECT_EQ(1, insert.exec());
49 | EXPECT_EQ(1, db.getLastInsertRowid());
50 | EXPECT_EQ(1, db.getChanges());
51 | EXPECT_EQ(1, db.getTotalChanges());
52 |
53 | EXPECT_THROW(insert.exec(), SQLite::Exception); // exec() shall throw as it needs to be reseted
54 |
55 | // Compile a SQL query
56 | SQLite::Statement query(db, "SELECT * FROM test");
57 | EXPECT_STREQ("SELECT * FROM test", query.getQuery().c_str());
58 | EXPECT_EQ(6, query.getColumnCount ());
59 | query.executeStep();
60 | EXPECT_TRUE (query.hasRow());
61 | EXPECT_FALSE(query.isDone());
62 |
63 | // validates every variant of cast operators, and conversions of types
64 | {
65 | const int64_t id1 = query.getColumn(0); // operator int64_t()
66 | const int32_t id2 = query.getColumn(0); // operator int32_t()
67 | const int id3 = query.getColumn(0); // operator int32_t()
68 | const int16_t id4 = query.getColumn(0); // operator int32_t()
69 | const short id5 = query.getColumn(0); // operator int32_t()
70 | const int8_t id6 = query.getColumn(0); // operator int32_t()
71 | const char id7 = query.getColumn(0); // operator int32_t()
72 | const unsigned int uint1 = query.getColumn(0); // operator unsigned int()
73 | const uint32_t uint2 = query.getColumn(0); // operator unsigned int()
74 | const unsigned char uint3 = query.getColumn(0); // operator unsigned char()
75 | const unsigned short uint4 = query.getColumn(0); // operator unsigned short()
76 | const char* ptxt = query.getColumn(1); // operator const char*()
77 | const std::string msg = query.getColumn(1); // operator std::string() (or const char* with MSVC)
78 | const int integer = query.getColumn(2); // operator int()
79 | const double real = query.getColumn(3); // operator double()
80 | const void* pblob = query.getColumn(4); // operator void*()
81 | #if !defined(_MSC_VER) || _MSC_VER >= 1900
82 | // This implicit cast should use operator std::string()
83 | // but would fallback to const char* with MSVC 2010-2013 (witch does not work with the NULL char in the middle)
84 | const std::string sblob = query.getColumn(4); // operator std::string()
85 | #endif
86 | const void* pempty = query.getColumn(5); // operator void*()
87 | EXPECT_EQ(1, id1);
88 | EXPECT_EQ(1, id2);
89 | EXPECT_EQ(1, id3);
90 | EXPECT_EQ(1, id4);
91 | EXPECT_EQ(1, id5);
92 | EXPECT_EQ(1, id6);
93 | EXPECT_EQ(1, id7);
94 | EXPECT_EQ(1U, uint1);
95 | EXPECT_EQ(1U, uint2);
96 | EXPECT_EQ(1U, uint3);
97 | EXPECT_EQ(1U, uint4);
98 | EXPECT_STREQ("first", ptxt);
99 | EXPECT_EQ("first", msg);
100 | EXPECT_EQ(-123, integer);
101 | EXPECT_DOUBLE_EQ(0.123, real);
102 | EXPECT_EQ(0, memcmp("bl\0b", pblob, size));
103 | #if !defined(_MSC_VER) || _MSC_VER >= 1900
104 | EXPECT_EQ((size_t)size, sblob.size());
105 | EXPECT_EQ(0, memcmp("bl\0b", &sblob[0], size));
106 | #endif
107 | EXPECT_EQ(NULL, pempty);
108 | }
109 |
110 | query.reset();
111 | query.executeStep();
112 |
113 | // validates every variant of explicit getters
114 | {
115 | int64_t id = query.getColumn(0).getInt64();
116 | const unsigned int uint1 = query.getColumn(0).getUInt();
117 | const uint32_t uint2 = query.getColumn(0).getUInt();
118 | const std::string msg1 = query.getColumn(1).getString();
119 | const char* ptxt = query.getColumn(1).getText();
120 | const std::string msg2 = query.getColumn(1).getText();
121 | const int integer = query.getColumn(2).getInt();
122 | const double real = query.getColumn(3).getDouble();
123 | const void* pblob = query.getColumn(4).getBlob();
124 | const std::string sblob = query.getColumn(4).getString();
125 | EXPECT_EQ(1, id);
126 | EXPECT_EQ(1U, uint1);
127 | EXPECT_EQ(1U, uint2);
128 | EXPECT_STREQ("first", ptxt);
129 | EXPECT_EQ("first", msg1);
130 | EXPECT_EQ("first", msg2);
131 | EXPECT_EQ(-123, integer);
132 | EXPECT_DOUBLE_EQ(0.123, real);
133 | EXPECT_EQ(0, memcmp("bl\0b", pblob, 4));
134 | EXPECT_EQ(0, memcmp("bl\0b", &sblob[0], 4));
135 | }
136 |
137 | // Validate getBytes(), getType(), isInteger(), isNull()...
138 | EXPECT_EQ(SQLite::INTEGER, query.getColumn(0).getType());
139 | EXPECT_EQ(true, query.getColumn(0).isInteger());
140 | EXPECT_EQ(false, query.getColumn(0).isFloat());
141 | EXPECT_EQ(false, query.getColumn(0).isText());
142 | EXPECT_EQ(false, query.getColumn(0).isBlob());
143 | EXPECT_EQ(false, query.getColumn(0).isNull());
144 | EXPECT_STREQ("1", query.getColumn(0).getText()); // convert to TEXT via text func
145 | EXPECT_EQ(1, query.getColumn(0).getBytes()); // size of the string "1" without the null terminator
146 | EXPECT_EQ(SQLite::TEXT, query.getColumn(1).getType());
147 | EXPECT_EQ(false, query.getColumn(1).isInteger());
148 | EXPECT_EQ(false, query.getColumn(1).isFloat());
149 | EXPECT_EQ(true, query.getColumn(1).isText());
150 | EXPECT_EQ(false, query.getColumn(1).isBlob());
151 | EXPECT_EQ(false, query.getColumn(1).isNull());
152 | EXPECT_STREQ("first", query.getColumn(1).getString().c_str()); // convert to TEXT via string func
153 | EXPECT_EQ(5, query.getColumn(1).getBytes()); // size of the string "first"
154 | EXPECT_EQ(SQLite::INTEGER, query.getColumn(2).getType());
155 | EXPECT_EQ(true, query.getColumn(2).isInteger());
156 | EXPECT_EQ(false, query.getColumn(2).isFloat());
157 | EXPECT_EQ(false, query.getColumn(2).isText());
158 | EXPECT_EQ(false, query.getColumn(2).isBlob());
159 | EXPECT_EQ(false, query.getColumn(2).isNull());
160 | EXPECT_STREQ("-123", query.getColumn(2).getText()); // convert to string
161 | EXPECT_EQ(4, query.getColumn(2).getBytes()); // size of the string "-123"
162 | EXPECT_EQ(SQLite::FLOAT, query.getColumn(3).getType());
163 | EXPECT_EQ(false, query.getColumn(3).isInteger());
164 | EXPECT_EQ(true, query.getColumn(3).isFloat());
165 | EXPECT_EQ(false, query.getColumn(3).isText());
166 | EXPECT_EQ(false, query.getColumn(3).isBlob());
167 | EXPECT_EQ(false, query.getColumn(3).isNull());
168 | EXPECT_STREQ("0.123", query.getColumn(3).getText()); // convert to string
169 | EXPECT_EQ(5, query.getColumn(3).getBytes()); // size of the string "0.123"
170 | EXPECT_EQ(SQLite::BLOB, query.getColumn(4).getType());
171 | EXPECT_EQ(false, query.getColumn(4).isInteger());
172 | EXPECT_EQ(false, query.getColumn(4).isFloat());
173 | EXPECT_EQ(false, query.getColumn(4).isText());
174 | EXPECT_EQ(true, query.getColumn(4).isBlob());
175 | EXPECT_EQ(false, query.getColumn(4).isNull());
176 | EXPECT_EQ(4, query.getColumn(4).getBytes()); // size of the blob "bl\0b" with the null char
177 | EXPECT_EQ(SQLite::Null, query.getColumn(5).getType());
178 | EXPECT_EQ(false, query.getColumn(5).isInteger());
179 | EXPECT_EQ(false, query.getColumn(5).isFloat());
180 | EXPECT_EQ(false, query.getColumn(5).isText());
181 | EXPECT_EQ(false, query.getColumn(5).isBlob());
182 | EXPECT_EQ(true, query.getColumn(5).isNull());
183 | EXPECT_STREQ("", query.getColumn(5).getText()); // convert to string
184 | EXPECT_EQ(0, query.getColumn(5).getBytes()); // size of the string "" without the null terminator
185 |
186 | query.reset();
187 | query.executeStep();
188 |
189 | // Use intermediate Column objects (this is not the recommended way to use the API)
190 | {
191 | const SQLite::Column id = query.getColumn(0);
192 | EXPECT_EQ(1, id.getInt64());
193 | const SQLite::Column msg = query.getColumn(1);
194 | EXPECT_EQ("first", msg.getString());
195 | const SQLite::Column integer = query.getColumn(2);
196 | EXPECT_EQ(-123, integer.getInt());
197 | const SQLite::Column dbl = query.getColumn(3);
198 | EXPECT_DOUBLE_EQ(0.123, dbl.getDouble());
199 | }
200 | }
201 |
202 | TEST(Column, basis)
203 | {
204 | test_column_basis(false);
205 | }
206 |
207 | TEST(Column, basis16)
208 | {
209 | test_column_basis(true);
210 | }
211 |
212 | TEST(Column, getName)
213 | {
214 | // Create a new database
215 | SQLite::Database db(":memory:", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE);
216 | EXPECT_EQ(0, db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, msg TEXT)"));
217 | EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, 'first')"));
218 |
219 | // Compile a SQL query, using the "id" column name as-is, but aliasing the "msg" column with new name "value"
220 | SQLite::Statement query(db, "SELECT id, msg as value FROM test");
221 | query.executeStep();
222 |
223 | // Show how to get the aliased names of the result columns.
224 | const std::string name0 = query.getColumn(0).getName();
225 | const std::string name1 = query.getColumn(1).getName();
226 | EXPECT_EQ("id", name0);
227 | EXPECT_EQ("value", name1);
228 |
229 | #ifdef SQLITE_ENABLE_COLUMN_METADATA
230 | // Show how to get origin names of the table columns from which theses result columns come from.
231 | // Requires the SQLITE_ENABLE_COLUMN_METADATA preprocessor macro to be
232 | // also defined at compile times of the SQLite library itself.
233 | const std::string oname0 = query.getColumn(0).getOriginName();
234 | const std::string oname1 = query.getColumn(1).getOriginName();
235 | EXPECT_EQ("id", oname0);
236 | EXPECT_EQ("msg", oname1);
237 | #endif
238 | }
239 |
240 | TEST(Column, stream)
241 | {
242 | // Create a new database
243 | SQLite::Database db(":memory:", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE);
244 | EXPECT_EQ(0, db.exec("CREATE TABLE test (msg TEXT)"));
245 | SQLite::Statement insert(db, "INSERT INTO test VALUES (?)");
246 |
247 | // content to test
248 | const char str_[] = "stringwith\0embedded";
249 | std::string str(str_, sizeof(str_)-1);
250 |
251 | insert.bind(1, str);
252 | // Execute the one-step query to insert the row
253 | EXPECT_EQ(1, insert.exec());
254 | EXPECT_EQ(1, db.getChanges());
255 | EXPECT_EQ(1, db.getTotalChanges());
256 |
257 | SQLite::Statement query(db, "SELECT * FROM test");
258 | query.executeStep();
259 | std::stringstream ss;
260 | ss << query.getColumn(0);
261 | std::string content = ss.str();
262 | EXPECT_EQ(content, str);
263 | }
264 |
265 | TEST(Column, shared_ptr)
266 | {
267 | // Create a new database
268 | SQLite::Database db(":memory:", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE);
269 | EXPECT_EQ(0, db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, msg TEXT)"));
270 | EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (42, 'fortytwo')"));
271 | const char* query_str = "SELECT id, msg FROM test";
272 |
273 | std::unique_ptr query{ new SQLite::Statement(db, query_str) };
274 | query->executeStep();
275 |
276 | auto column0 = query->getColumn(0);
277 | auto column1 = query->getColumn(1);
278 | query.reset();
279 |
280 | EXPECT_EQ(42, column0.getInt());
281 | EXPECT_STREQ("fortytwo", column1.getText());
282 |
283 | query.reset(new SQLite::Statement(db, query_str));
284 | query->executeStep();
285 | column0 = query->getColumn(0);
286 | EXPECT_EQ(true, column0.isInteger());
287 | query->executeStep(); // query is done
288 |
289 | // Undefined behavior
290 | // auto x = column0.getInt();
291 |
292 | query.reset();
293 |
294 | // Undefined behavior
295 | // auto x = column0.getInt();
296 | // bool isInt = column0.isInteger();
297 |
298 | EXPECT_STREQ("id", column0.getName());
299 | }
300 |
--------------------------------------------------------------------------------
/tests/Exception_test.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Transaction_test.cpp
3 | * @ingroup tests
4 | * @brief Test of a SQLite Transaction.
5 | *
6 | * Copyright (c) 2012-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
7 | *
8 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
9 | * or copy at http://opensource.org/licenses/MIT)
10 | */
11 |
12 | #include
13 |
14 | #include
15 |
16 | #include
17 |
18 | TEST(Exception, copy)
19 | {
20 | const SQLite::Exception ex1("some error", 2);
21 | const SQLite::Exception ex2 = ex1;
22 | EXPECT_STREQ(ex1.what(), ex2.what());
23 | EXPECT_EQ(ex1.getErrorCode(), ex2.getErrorCode());
24 | EXPECT_EQ(ex1.getExtendedErrorCode(), ex2.getExtendedErrorCode());
25 | }
26 |
27 | // see http://eel.is/c++draft/exception#2 or http://www.cplusplus.com/reference/exception/exception/operator=/
28 | // an assignment operator is expected to be avaiable
29 | TEST(Exception, assignment)
30 | {
31 | const char message[] = "some error";
32 | const SQLite::Exception ex1(message, 1);
33 | SQLite::Exception ex2("another error", 2);
34 |
35 | ex2 = ex1;
36 |
37 | EXPECT_STREQ(ex2.what(), message);
38 | EXPECT_EQ(ex2.getErrorCode(), 1);
39 | EXPECT_EQ(ex2.getExtendedErrorCode(), -1);
40 | EXPECT_STREQ(ex2.getErrorStr(), "SQL logic error");
41 | }
42 |
43 | TEST(Exception, throw_catch)
44 | {
45 | const char message[] = "some error";
46 | try
47 | {
48 | throw SQLite::Exception(message);
49 | }
50 | catch (const std::runtime_error& ex)
51 | {
52 | EXPECT_STREQ(ex.what(), message);
53 | }
54 | }
55 |
56 |
57 | TEST(Exception, constructor)
58 | {
59 | const char msg1[] = "some error";
60 | std::string msg2 = "another error";
61 | {
62 | const SQLite::Exception ex(msg1);
63 | EXPECT_STREQ(ex.what(), msg1);
64 | EXPECT_EQ(ex.getErrorCode(), -1);
65 | EXPECT_EQ(ex.getExtendedErrorCode(), -1);
66 | EXPECT_STREQ("unknown error", ex.getErrorStr());
67 | }
68 | {
69 | const SQLite::Exception ex(msg2);
70 | EXPECT_STREQ(ex.what(), msg2.c_str());
71 | EXPECT_EQ(ex.getErrorCode(), -1);
72 | EXPECT_EQ(ex.getExtendedErrorCode(), -1);
73 | EXPECT_STREQ("unknown error", ex.getErrorStr());
74 | }
75 | {
76 | const SQLite::Exception ex(msg1, 1);
77 | EXPECT_STREQ(ex.what(), msg1);
78 | EXPECT_EQ(ex.getErrorCode(), 1);
79 | EXPECT_EQ(ex.getExtendedErrorCode(), -1);
80 | EXPECT_STREQ(ex.getErrorStr(), "SQL logic error");
81 | }
82 | {
83 | const SQLite::Exception ex(msg2, 2);
84 | EXPECT_STREQ(ex.what(), msg2.c_str());
85 | EXPECT_EQ(ex.getErrorCode(), 2);
86 | EXPECT_EQ(ex.getExtendedErrorCode(), -1);
87 | EXPECT_STREQ(ex.getErrorStr(), "unknown error");
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/tests/ExecuteMany_test.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file VariadicBind_test.cpp
3 | * @ingroup tests
4 | * @brief Test of variadic bind
5 | *
6 | * Copyright (c) 2019 Maximilian Bachmann (contact@maxbachmann.de)
7 | * Copyright (c) 2019-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
8 | *
9 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
10 | * or copy at http://opensource.org/licenses/MIT)
11 | */
12 |
13 | #include
14 | #include
15 | #include
16 |
17 | #include
18 |
19 | #include
20 |
21 | #if (__cplusplus >= 201402L) || ( defined(_MSC_VER) && (_MSC_VER >= 1900) ) // c++14: Visual Studio 2015
22 | TEST(ExecuteMany, invalid)
23 | {
24 | // Create a new database
25 | SQLite::Database db(":memory:", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE);
26 |
27 | EXPECT_EQ(0, db.exec("DROP TABLE IF EXISTS test"));
28 | EXPECT_EQ(0, db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT DEFAULT 'default')"));
29 | EXPECT_TRUE(db.tableExists("test"));
30 | {
31 | execute_many(db, "INSERT INTO test VALUES (?, ?)",
32 | 1,
33 | std::make_tuple(2),
34 | std::make_tuple(3, "three")
35 | );
36 | }
37 | // make sure the content is as expected
38 | {
39 | SQLite::Statement query(db, std::string{"SELECT id, value FROM test ORDER BY id"});
40 | std::vector > results;
41 | while (query.executeStep())
42 | {
43 | const int id = query.getColumn(0);
44 | std::string value = query.getColumn(1);
45 | results.emplace_back( id, std::move(value) );
46 | }
47 | EXPECT_EQ(std::size_t(3), results.size());
48 |
49 | EXPECT_EQ(std::make_pair(1,std::string{""}), results.at(0));
50 | EXPECT_EQ(std::make_pair(2,std::string{""}), results.at(1));
51 | EXPECT_EQ(std::make_pair(3,std::string{"three"}), results.at(2));
52 | }
53 | }
54 | #endif // c++14
55 |
--------------------------------------------------------------------------------
/tests/Savepoint_test.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Savepoint_test.cpp
3 | * @ingroup tests
4 | * @brief Test of a SQLite Savepoint.
5 | *
6 | * Copyright (c) 2020 Kelvin Hammond (hammond.kelvin@gmail.com)
7 | *
8 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt or
9 | * copy at http://opensource.org/licenses/MIT)
10 | */
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | #include
20 |
21 | TEST(Savepoint, commitRollback)
22 | {
23 | // Create a new database
24 | SQLite::Database db(":memory:", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE);
25 | EXPECT_EQ(SQLite::OK, db.getErrorCode());
26 |
27 | {
28 | // Begin savepoint
29 | SQLite::Savepoint savepoint(db, "sp1");
30 |
31 | EXPECT_EQ(0, db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)"));
32 | EXPECT_EQ(SQLite::OK, db.getErrorCode());
33 |
34 | // Insert a first value
35 | EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, 'first')"));
36 | EXPECT_EQ(1, db.getLastInsertRowid());
37 |
38 | // release savepoint
39 | savepoint.release();
40 |
41 | // Commit again throw an exception
42 | EXPECT_THROW(savepoint.release(), SQLite::Exception);
43 | EXPECT_THROW(savepoint.rollback(), SQLite::Exception);
44 | }
45 |
46 | // Auto rollback if no release() before the end of scope
47 | {
48 | // Begin savepoint
49 | SQLite::Savepoint savepoint(db, "sp2");
50 |
51 | // Insert a second value (that will be rollbacked)
52 | EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, 'third')"));
53 | EXPECT_EQ(2, db.getLastInsertRowid());
54 |
55 | // end of scope: automatic rollback
56 | }
57 |
58 | // Auto rollback of a transaction on error / exception
59 | try
60 | {
61 | // Begin savepoint
62 | SQLite::Savepoint savepoint(db, "sp3");
63 |
64 | // Insert a second value (that will be rollbacked)
65 | EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, 'second')"));
66 | EXPECT_EQ(2, db.getLastInsertRowid());
67 |
68 | // Execute with an error => exception with auto-rollback
69 | db.exec("DesiredSyntaxError to raise an exception to rollback the transaction");
70 |
71 | GTEST_FATAL_FAILURE_("we should never get there");
72 | savepoint.release(); // We should never get there
73 | }
74 | catch (std::exception& e)
75 | {
76 | std::cout << "SQLite exception: " << e.what() << std::endl;
77 | // expected error, see above
78 | }
79 |
80 | // Double rollback with a manual command before the end of scope
81 | {
82 | // Begin savepoint
83 | SQLite::Savepoint savepoint(db, "sp4");
84 |
85 | // Insert a second value (that will be rollbacked)
86 | EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, 'third')"));
87 | EXPECT_EQ(2, db.getLastInsertRowid());
88 |
89 | // Execute a manual rollback
90 | savepoint.rollback();
91 |
92 | // end of scope: the automatic rollback should not raise an error because it is harmless
93 | }
94 |
95 | // Check the results (expect only one row of result, as all other one have
96 | // been rollbacked)
97 | SQLite::Statement query(db, "SELECT * FROM test");
98 | int nbRows = 0;
99 | while (query.executeStep())
100 | {
101 | nbRows++;
102 | EXPECT_EQ(1, query.getColumn(0).getInt());
103 | EXPECT_STREQ("first", query.getColumn(1).getText());
104 | }
105 | EXPECT_EQ(1, nbRows);
106 | }
107 |
--------------------------------------------------------------------------------
/tests/Transaction_test.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Transaction_test.cpp
3 | * @ingroup tests
4 | * @brief Test of a SQLite Transaction.
5 | *
6 | * Copyright (c) 2012-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
7 | *
8 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
9 | * or copy at http://opensource.org/licenses/MIT)
10 | */
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | #include
18 |
19 | #include
20 |
21 | TEST(Transaction, commitRollback)
22 | {
23 | // Create a new database
24 | SQLite::Database db(":memory:", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE);
25 | EXPECT_EQ(SQLite::OK, db.getErrorCode());
26 |
27 | {
28 | // Begin transaction
29 | SQLite::Transaction transaction(db);
30 |
31 | EXPECT_EQ(0, db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)"));
32 | EXPECT_EQ(SQLite::OK, db.getErrorCode());
33 |
34 | // Insert a first value
35 | EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, 'first')"));
36 | EXPECT_EQ(1, db.getLastInsertRowid());
37 |
38 | // Commit transaction
39 | transaction.commit();
40 |
41 | // Commit again throw an exception
42 | EXPECT_THROW(transaction.commit(), SQLite::Exception);
43 | }
44 |
45 | // ensure transactions with different types are well-formed
46 | {
47 | for (auto behavior : {
48 | SQLite::TransactionBehavior::DEFERRED,
49 | SQLite::TransactionBehavior::IMMEDIATE,
50 | SQLite::TransactionBehavior::EXCLUSIVE })
51 | {
52 | SQLite::Transaction transaction(db, behavior);
53 | transaction.commit();
54 | }
55 |
56 | EXPECT_THROW(SQLite::Transaction(db, static_cast(-1)), SQLite::Exception);
57 | }
58 |
59 | // Auto rollback if no commit() before the end of scope
60 | {
61 | // Begin transaction
62 | SQLite::Transaction transaction(db);
63 |
64 | // Insert a second value (that will be rollbacked)
65 | EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, 'third')"));
66 | EXPECT_EQ(2, db.getLastInsertRowid());
67 |
68 | // end of scope: automatic rollback
69 | }
70 |
71 | // Auto rollback of a transaction on error/exception
72 | try
73 | {
74 | // Begin transaction
75 | SQLite::Transaction transaction(db);
76 |
77 | // Insert a second value (that will be rollbacked)
78 | EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, 'second')"));
79 | EXPECT_EQ(2, db.getLastInsertRowid());
80 |
81 | // Execute with an error => exception with auto-rollback
82 | db.exec("DesiredSyntaxError to raise an exception to rollback the transaction");
83 |
84 | GTEST_FATAL_FAILURE_("we should never get there");
85 | transaction.commit(); // We should never get there
86 | }
87 | catch (std::exception& e)
88 | {
89 | std::cout << "SQLite exception: " << e.what() << std::endl;
90 | // expected error, see above
91 | }
92 |
93 | // Double rollback with a manual command before the end of scope
94 | {
95 | // Begin transaction
96 | SQLite::Transaction transaction(db);
97 |
98 | // Insert a second value (that will be rollbacked)
99 | EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, 'third')"));
100 | EXPECT_EQ(2, db.getLastInsertRowid());
101 |
102 | // Execute a manual rollback
103 | transaction.rollback();
104 |
105 | // end of scope: the automatic rollback should not raise an error because it is harmless
106 | }
107 |
108 | // Check the results (expect only one row of result, as all other one have been rollbacked)
109 | SQLite::Statement query(db, "SELECT * FROM test");
110 | int nbRows = 0;
111 | while (query.executeStep())
112 | {
113 | nbRows++;
114 | EXPECT_EQ(1, query.getColumn(0).getInt());
115 | EXPECT_STREQ("first", query.getColumn(1).getText());
116 | }
117 | EXPECT_EQ(1, nbRows);
118 | }
119 |
--------------------------------------------------------------------------------
/tests/VariadicBind_test.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file VariadicBind_test.cpp
3 | * @ingroup tests
4 | * @brief Test of variadic bind
5 | *
6 | * Copyright (c) 2016 Paul Dreik (github@pauldreik.se)
7 | * Copyright (c) 2016-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
8 | * Copyright (c) 2019 Maximilian Bachmann (github@maxbachmann)
9 | *
10 | * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
11 | * or copy at http://opensource.org/licenses/MIT)
12 | */
13 |
14 | #include
15 | #include
16 | #include
17 |
18 | #include
19 |
20 | #include
21 |
22 | #if (__cplusplus >= 201103L) || ( defined(_MSC_VER) && (_MSC_VER >= 1800) ) // c++11: Visual Studio 2013
23 | TEST(VariadicBind, invalid)
24 | {
25 | // Create a new database
26 | SQLite::Database db(":memory:", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE);
27 |
28 | EXPECT_EQ(0, db.exec("DROP TABLE IF EXISTS test"));
29 | EXPECT_EQ(0,
30 | db.exec(
31 | "CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT DEFAULT 'default') "));
32 | EXPECT_EQ(0,
33 | db.exec(
34 | "CREATE TABLE test2 (id INTEGER PRIMARY KEY, value TEXT DEFAULT 'default') "));
35 | EXPECT_TRUE(db.tableExists("test"));
36 | EXPECT_TRUE(db.tableExists("test2"));
37 |
38 | {
39 | SQLite::Statement query(db, "INSERT INTO test VALUES (?, ?)");
40 |
41 | // bind one argument less than expected - should be fine.
42 | // the unspecified argument should be set to null, not the default.
43 | SQLite::bind(query, 1);
44 | EXPECT_EQ(1, query.exec());
45 | query.reset();
46 |
47 | // bind all arguments - should work just fine
48 | SQLite::bind(query, 2, "two");
49 | EXPECT_EQ(1, query.exec());
50 | query.reset();
51 |
52 | // bind too many arguments - should throw.
53 | EXPECT_THROW(SQLite::bind(query, 3, "three", 0), SQLite::Exception);
54 | EXPECT_EQ(1, query.exec());
55 | }
56 | // make sure the content is as expected
57 | {
58 | SQLite::Statement query(db, std::string{"SELECT id, value FROM test ORDER BY id"});
59 | std::vector > results;
60 | while (query.executeStep())
61 | {
62 | const int id = query.getColumn(0);
63 | std::string value = query.getColumn(1);
64 | results.emplace_back( id, std::move(value) );
65 | }
66 | EXPECT_EQ(std::size_t(3), results.size());
67 |
68 | EXPECT_EQ(std::make_pair(1,std::string{""}), results.at(0));
69 | EXPECT_EQ(std::make_pair(2,std::string{"two"}), results.at(1));
70 | EXPECT_EQ(std::make_pair(3,std::string{"three"}), results.at(2));
71 | }
72 | #if (__cplusplus >= 201402L) || ( defined(_MSC_VER) && (_MSC_VER >= 1900) ) // c++14: Visual Studio 2015
73 | {
74 | SQLite::Statement query(db, "INSERT INTO test2 VALUES (?, ?)");
75 |
76 | // bind one argument less than expected - should be fine.
77 | // the unspecified argument should be set to null, not the default.
78 | SQLite::bind(query, std::make_tuple(1));
79 | EXPECT_EQ(1, query.exec());
80 | query.reset();
81 |
82 | // bind all arguments - should work just fine
83 | SQLite::bind(query, std::make_tuple(2, "two"));
84 | EXPECT_EQ(1, query.exec());
85 | query.reset();
86 |
87 | // bind too many arguments - should throw.
88 | EXPECT_THROW(SQLite::bind(query, std::make_tuple(3, "three", 0)), SQLite::Exception);
89 | EXPECT_EQ(1, query.exec());
90 | }
91 | // make sure the content is as expected
92 | {
93 | SQLite::Statement query(db, std::string{"SELECT id, value FROM test2 ORDER BY id"});
94 | std::vector > results;
95 | while (query.executeStep())
96 | {
97 | const int id = query.getColumn(0);
98 | std::string value = query.getColumn(1);
99 | results.emplace_back( id, std::move(value) );
100 | }
101 | EXPECT_EQ(std::size_t(3), results.size());
102 |
103 | EXPECT_EQ(std::make_pair(1,std::string{""}), results.at(0));
104 | EXPECT_EQ(std::make_pair(2,std::string{"two"}), results.at(1));
105 | EXPECT_EQ(std::make_pair(3,std::string{"three"}), results.at(2));
106 | }
107 | #endif // c++14
108 | }
109 | #endif // c++11
110 |
--------------------------------------------------------------------------------