├── .github └── workflows │ └── tests.yaml ├── LICENSE ├── MANIFEST.in ├── README.md ├── TODO ├── build-scripts ├── README ├── _build_wheels.sh ├── build.sh └── cleanup.sh ├── pysqlite3 ├── __init__.py └── dbapi2.py ├── setup.cfg ├── setup.py ├── src ├── blob.c ├── blob.h ├── cache.c ├── cache.h ├── connection.c ├── connection.h ├── cursor.c ├── cursor.h ├── microprotocols.c ├── microprotocols.h ├── module.c ├── module.h ├── prepare_protocol.c ├── prepare_protocol.h ├── row.c ├── row.h ├── statement.c ├── statement.h ├── util.c └── util.h └── tests ├── __init__.py ├── __main__.py ├── backup.py ├── dbapi.py ├── factory.py ├── hooks.py ├── regression.py ├── transactions.py ├── ttypes.py └── userfunctions.py /.github/workflows/tests.yaml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: [push] 3 | jobs: 4 | tests: 5 | name: ${{ matrix.python-version }} 6 | runs-on: ubuntu-latest 7 | strategy: 8 | fail-fast: false 9 | matrix: 10 | python-version: [3.8, 3.9, "3.10", "3.11", "3.12", "3.13"] 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: actions/setup-python@v2 14 | with: 15 | python-version: ${{ matrix.python-version }} 16 | - name: package deps 17 | run: | 18 | sudo apt-get install libsqlite3-dev 19 | pip install setuptools 20 | python setup.py build_ext -i 21 | - name: runtests 22 | env: 23 | PYTHONPATH: '.:$PYTHONPATH' 24 | run: python tests/ 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2004-2007 Gerhard Häring 2 | 3 | This software is provided 'as-is', without any express or implied warranty. In 4 | no event will the authors be held liable for any damages arising from the use 5 | of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it freely, 9 | subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software in 13 | a product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 19 | 3. This notice may not be removed or altered from any source distribution. 20 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include MANIFEST.in 2 | include README.md 3 | include LICENSE 4 | include setup.py 5 | include src/*.h 6 | include src/*.c 7 | 8 | global-exclude *~ *.pyc 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | pysqlite3 2 | ========= 3 | 4 | This library takes the SQLite module from Python 3 and packages it as a 5 | separately-installable module. 6 | 7 | This may be useful for creating SQLite modules capable of working with other 8 | versions of SQLite (via the amalgamation option). 9 | 10 | Additional features: 11 | 12 | * User-defined window functions (requires SQLite >= 3.25) 13 | * Flags and VFS an be specified when opening connection 14 | * Incremental BLOB I/O, [bpo-24905](https://github.com/python/cpython/pull/271) 15 | * Improved error messages, [bpo-16379](https://github.com/python/cpython/pull/1108) 16 | * Simplified detection of DML statements via `sqlite3_stmt_readonly`. 17 | * Sqlite native backup API (also present in standard library 3.7 and newer). 18 | 19 | A completely self-contained binary package (wheel) is available for versions 20 | 0.4.1 and newer as `pysqlite3-binary`. This package contains the latest release 21 | of SQLite compiled with numerous extensions, and requires no external 22 | dependencies. 23 | 24 | Building with System SQLite 25 | --------------------------- 26 | 27 | If you intend to use the system SQLite, you can install with: 28 | 29 | ``` 30 | $ pip install pysqlite3 31 | ``` 32 | 33 | Alternatively you can clone or download the repo and use `setup.py` to 34 | build `pysqlite3` linked against the system SQLite: 35 | 36 | ``` 37 | $ python setup.py build 38 | ``` 39 | 40 | Building a statically-linked library 41 | ------------------------------------ 42 | 43 | To build a completely self-contained `pysqlite3`, you can use: 44 | 45 | ``` 46 | $ python setup.py build_full 47 | ``` 48 | 49 | This will download the latest Sqlite release amalgamation, extract the 50 | appropriate `sqlite3.c` and `sqlite3.h` files into the project directory, and 51 | compile a self-contained extension. 52 | 53 | To build `pysqlite3` statically-linked against a particular version of SQLite, 54 | you need to obtain the SQLite3 source code and copy `sqlite3.c` and `sqlite3.h` 55 | into the source tree. 56 | 57 | ``` 58 | # Download the latest release of SQLite source code and build the source 59 | # amalgamation files (sqlite3.c and sqlite3.h). 60 | $ wget https://www.sqlite.org/src/tarball/sqlite.tar.gz?r=release \ 61 | -O sqlite.tar.gz 62 | $ tar xzf sqlite.tar.gz 63 | $ cd sqlite/ 64 | $ ./configure 65 | $ make sqlite3.c 66 | 67 | # Copy the sqlite3 amalgamation files into the root of the pysqlite3 checkout 68 | # and run build_static + build: 69 | $ cp sqlite/sqlite3.[ch] pysqlite3/ 70 | $ cd pysqlite3 71 | $ python setup.py build_static build 72 | ``` 73 | 74 | You now have a statically-linked, completely self-contained `pysqlite3`. 75 | 76 | Using the binary package 77 | ------------------------ 78 | 79 | A binary package (wheel) is available for linux with a completely 80 | self-contained `pysqlite3`, statically-linked against the most recent release 81 | of SQLite with many features/extensions enabled. 82 | 83 | ``` 84 | $ pip install pysqlite3-binary 85 | ``` 86 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | * Support for PRAGMA KEY / REKEY and encryption. 2 | -------------------------------------------------------------------------------- /build-scripts/README: -------------------------------------------------------------------------------- 1 | ### Building wheels 2 | 3 | This directory contains a utility script (`build.sh`) which can be used to 4 | create completely self-contained manylinux wheels for Python 3.6 - 3.8. The 5 | build script fetches the latest release of Sqlite and generates the source 6 | amalgamation and header file, which are then compiled into `pysqlite3`. The 7 | resulting Python package can be deployed to any linux environment and will 8 | utilize the latest Sqlite source code with extensions compiled in. 9 | 10 | The package name for the wheels is `pysqlite3-binary` to differentiate it from 11 | the standard `pysqlite3` source distribution. The source distribution will link 12 | against the system sqlite by default, though you can provide your own 13 | `sqlite3.c` and `sqlite3.h` and use `setup.py build_static` to create a 14 | self-contained package as well. 15 | 16 | Build artifacts are placed in the `wheelhouse/` directory. 17 | -------------------------------------------------------------------------------- /build-scripts/_build_wheels.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Volume (cwd of build script) is mounted at /io. 4 | # A checkout of pysqlite3 is cloned beforehand by the build.sh script. 5 | cd /io/pysqlite3 6 | 7 | sed -i "s|name='pysqlite3-binary'|name=PACKAGE_NAME|g" setup.py 8 | 9 | PY36="/opt/python/cp36-cp36m/bin" 10 | "${PY36}/python" setup.py build_static 11 | 12 | PY37="/opt/python/cp37-cp37m/bin" 13 | "${PY37}/python" setup.py build_static 14 | 15 | PY38="/opt/python/cp38-cp38/bin" 16 | "${PY38}/python" setup.py build_static 17 | 18 | PY39="/opt/python/cp39-cp39/bin" 19 | "${PY39}/python" setup.py build_static 20 | 21 | PY310="/opt/python/cp310-cp310/bin" 22 | "${PY310}/python" setup.py build_static 23 | 24 | PY311="/opt/python/cp311-cp311/bin" 25 | "${PY311}/python" setup.py build_static 26 | 27 | PY312="/opt/python/cp312-cp312/bin" 28 | "${PY312}/python" setup.py build_static 29 | 30 | PY313="/opt/python/cp313-cp313/bin" 31 | "${PY313}/pip" install setuptools 32 | "${PY313}/python" setup.py build_static 33 | 34 | sed -i "s|name=PACKAGE_NAME|name='pysqlite3-binary'|g" setup.py 35 | 36 | "${PY36}/pip" wheel /io/pysqlite3 -w /io/wheelhouse 37 | "${PY37}/pip" wheel /io/pysqlite3 -w /io/wheelhouse 38 | "${PY38}/pip" wheel /io/pysqlite3 -w /io/wheelhouse 39 | "${PY39}/pip" wheel /io/pysqlite3 -w /io/wheelhouse 40 | "${PY310}/pip" wheel /io/pysqlite3 -w /io/wheelhouse 41 | "${PY311}/pip" wheel /io/pysqlite3 -w /io/wheelhouse 42 | "${PY312}/pip" wheel /io/pysqlite3 -w /io/wheelhouse 43 | "${PY313}/pip" wheel /io/pysqlite3 -w /io/wheelhouse 44 | 45 | for whl in /io/wheelhouse/*.whl; do 46 | auditwheel repair "$whl" -w /io/wheelhouse/ 47 | done 48 | -------------------------------------------------------------------------------- /build-scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e -x 4 | 5 | # Fetch the source code for the latest release of Sqlite. 6 | if [[ ! -d "sqlite" ]]; then 7 | wget https://www.sqlite.org/src/tarball/sqlite.tar.gz?r=release -O sqlite.tar.gz 8 | tar xzf sqlite.tar.gz 9 | cd sqlite/ 10 | LIBS="-lm" ./configure --disable-tcl --enable-tempstore=always 11 | make sqlite3.c 12 | cd ../ 13 | rm sqlite.tar.gz 14 | fi 15 | 16 | # Grab the pysqlite3 source code. 17 | if [[ ! -d "./pysqlite3" ]]; then 18 | git clone git@github.com:coleifer/pysqlite3 19 | fi 20 | 21 | # Copy the sqlite3 source amalgamation into the pysqlite3 directory so we can 22 | # create a self-contained extension module. 23 | cp "sqlite/sqlite3.c" pysqlite3/ 24 | cp "sqlite/sqlite3.h" pysqlite3/ 25 | 26 | # Create the wheels and strip symbols to produce manylinux wheels. 27 | docker run -it -v $(pwd):/io quay.io/pypa/manylinux2014_x86_64 /io/_build_wheels.sh 28 | 29 | # Remove un-stripped wheels. 30 | sudo rm ./wheelhouse/*-linux_* 31 | -------------------------------------------------------------------------------- /build-scripts/cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cleanup="sqlite pysqlite3 wheelhouse" 4 | for p in $cleanup; do 5 | if [[ -d "$p" ]]; then 6 | sudo rm -rf "$p" 7 | fi 8 | done 9 | -------------------------------------------------------------------------------- /pysqlite3/__init__.py: -------------------------------------------------------------------------------- 1 | # pysqlite2/__init__.py: the pysqlite2 package. 2 | # 3 | # Copyright (C) 2005 Gerhard Haring 4 | # 5 | # This file is part of pysqlite. 6 | # 7 | # This software is provided 'as-is', without any express or implied 8 | # warranty. In no event will the authors be held liable for any damages 9 | # arising from the use of this software. 10 | # 11 | # Permission is granted to anyone to use this software for any purpose, 12 | # including commercial applications, and to alter it and redistribute it 13 | # freely, subject to the following restrictions: 14 | # 15 | # 1. The origin of this software must not be misrepresented; you must not 16 | # claim that you wrote the original software. If you use this software 17 | # in a product, an acknowledgment in the product documentation would be 18 | # appreciated but is not required. 19 | # 2. Altered source versions must be plainly marked as such, and must not be 20 | # misrepresented as being the original software. 21 | # 3. This notice may not be removed or altered from any source distribution. 22 | 23 | from pysqlite3.dbapi2 import * 24 | -------------------------------------------------------------------------------- /pysqlite3/dbapi2.py: -------------------------------------------------------------------------------- 1 | #-*- coding: ISO-8859-1 -*- 2 | # pysqlite2/dbapi2.py: the DB-API 2.0 interface 3 | # 4 | # Copyright (C) 2004-2005 Gerhard Häring 5 | # 6 | # This file is part of pysqlite. 7 | # 8 | # This software is provided 'as-is', without any express or implied 9 | # warranty. In no event will the authors be held liable for any damages 10 | # arising from the use of this software. 11 | # 12 | # Permission is granted to anyone to use this software for any purpose, 13 | # including commercial applications, and to alter it and redistribute it 14 | # freely, subject to the following restrictions: 15 | # 16 | # 1. The origin of this software must not be misrepresented; you must not 17 | # claim that you wrote the original software. If you use this software 18 | # in a product, an acknowledgment in the product documentation would be 19 | # appreciated but is not required. 20 | # 2. Altered source versions must be plainly marked as such, and must not be 21 | # misrepresented as being the original software. 22 | # 3. This notice may not be removed or altered from any source distribution. 23 | 24 | import datetime 25 | import time 26 | import collections.abc 27 | 28 | from pysqlite3._sqlite3 import * 29 | 30 | paramstyle = "qmark" 31 | 32 | threadsafety = 1 33 | 34 | apilevel = "2.0" 35 | 36 | Date = datetime.date 37 | 38 | Time = datetime.time 39 | 40 | Timestamp = datetime.datetime 41 | 42 | def DateFromTicks(ticks): 43 | return Date(*time.localtime(ticks)[:3]) 44 | 45 | def TimeFromTicks(ticks): 46 | return Time(*time.localtime(ticks)[3:6]) 47 | 48 | def TimestampFromTicks(ticks): 49 | return Timestamp(*time.localtime(ticks)[:6]) 50 | 51 | version_info = tuple([int(x) for x in version.split(".")]) 52 | sqlite_version_info = tuple([int(x) for x in sqlite_version.split(".")]) 53 | 54 | Binary = memoryview 55 | collections.abc.Sequence.register(Row) 56 | 57 | def register_adapters_and_converters(): 58 | def adapt_date(val): 59 | return val.isoformat() 60 | 61 | def adapt_datetime(val): 62 | return val.isoformat(" ") 63 | 64 | def convert_date(val): 65 | return datetime.date(*map(int, val.split(b"-"))) 66 | 67 | def convert_timestamp(val): 68 | datepart, timepart = val.split(b" ") 69 | year, month, day = map(int, datepart.split(b"-")) 70 | timepart_full = timepart.split(b".") 71 | hours, minutes, seconds = map(int, timepart_full[0].split(b":")) 72 | if len(timepart_full) == 2: 73 | microseconds = int('{:0<6.6}'.format(timepart_full[1].decode())) 74 | else: 75 | microseconds = 0 76 | 77 | val = datetime.datetime(year, month, day, hours, minutes, seconds, microseconds) 78 | return val 79 | 80 | 81 | register_adapter(datetime.date, adapt_date) 82 | register_adapter(datetime.datetime, adapt_datetime) 83 | register_converter("date", convert_date) 84 | register_converter("timestamp", convert_timestamp) 85 | 86 | register_adapters_and_converters() 87 | 88 | # Clean up namespace 89 | 90 | del(register_adapters_and_converters) 91 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [build_ext] 2 | include_dirs=/usr/include 3 | library_dirs=/usr/lib 4 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: ISO-8859-1 -*- 2 | # setup.py: the distutils script 3 | # 4 | import os 5 | import re 6 | import setuptools 7 | import shutil 8 | import sys 9 | import tempfile 10 | 11 | from distutils import log 12 | from distutils.command.build_ext import build_ext 13 | from setuptools import Extension 14 | 15 | # If you need to change anything, it should be enough to change setup.cfg. 16 | 17 | PACKAGE_NAME = 'pysqlite3' 18 | VERSION = '0.5.4' 19 | 20 | # define sqlite sources 21 | sources = [os.path.join('src', source) 22 | for source in ["module.c", "connection.c", "cursor.c", "cache.c", 23 | "microprotocols.c", "prepare_protocol.c", 24 | "statement.c", "util.c", "row.c", "blob.c"]] 25 | 26 | # define packages 27 | packages = [PACKAGE_NAME] 28 | EXTENSION_MODULE_NAME = "._sqlite3" 29 | 30 | # Work around clang raising hard error for unused arguments 31 | if sys.platform == "darwin": 32 | os.environ['CFLAGS'] = "-Qunused-arguments" 33 | log.info("CFLAGS: " + os.environ['CFLAGS']) 34 | 35 | 36 | def quote_argument(arg): 37 | q = '\\"' if sys.platform == 'win32' and sys.version_info < (3, 9) else '"' 38 | return q + arg + q 39 | 40 | define_macros = [('MODULE_NAME', quote_argument(PACKAGE_NAME + '.dbapi2'))] 41 | 42 | 43 | class SystemLibSqliteBuilder(build_ext): 44 | description = "Builds a C extension linking against libsqlite3 library" 45 | 46 | def build_extension(self, ext): 47 | log.info(self.description) 48 | 49 | # For some reason, when setup.py develop is run, it ignores the 50 | # configuration in setup.cfg, so we just explicitly add libsqlite3. 51 | # Oddly, running setup.py build_ext -i (for in-place) works fine and 52 | # correctly reads the setup.cfg. 53 | ext.libraries.append('sqlite3') 54 | build_ext.build_extension(self, ext) 55 | 56 | 57 | class AmalgationLibSqliteBuilder(build_ext): 58 | description = "Builds a C extension using a sqlite3 amalgamation" 59 | 60 | amalgamation_root = "." 61 | amalgamation_header = os.path.join(amalgamation_root, 'sqlite3.h') 62 | amalgamation_source = os.path.join(amalgamation_root, 'sqlite3.c') 63 | 64 | amalgamation_message = ('Sqlite amalgamation not found. Please download ' 65 | 'or build the amalgamation and make sure the ' 66 | 'following files are present in the pysqlite3 ' 67 | 'folder: sqlite3.h, sqlite3.c') 68 | 69 | def check_amalgamation(self): 70 | if not os.path.exists(self.amalgamation_root): 71 | os.mkdir(self.amalgamation_root) 72 | 73 | header_exists = os.path.exists(self.amalgamation_header) 74 | source_exists = os.path.exists(self.amalgamation_source) 75 | if not header_exists or not source_exists: 76 | raise RuntimeError(self.amalgamation_message) 77 | 78 | def build_extension(self, ext): 79 | log.info(self.description) 80 | 81 | # it is responsibility of user to provide amalgamation 82 | self.check_amalgamation() 83 | 84 | # Feature-ful library. 85 | features = ( 86 | 'ALLOW_COVERING_INDEX_SCAN', 87 | 'ENABLE_FTS3', 88 | 'ENABLE_FTS3_PARENTHESIS', 89 | 'ENABLE_FTS4', 90 | 'ENABLE_FTS5', 91 | 'ENABLE_JSON1', 92 | 'ENABLE_LOAD_EXTENSION', 93 | 'ENABLE_MATH_FUNCTIONS', 94 | 'ENABLE_RTREE', 95 | 'ENABLE_STAT4', 96 | 'ENABLE_UPDATE_DELETE_LIMIT', 97 | 'SOUNDEX', 98 | 'USE_URI', 99 | ) 100 | for feature in features: 101 | ext.define_macros.append(('SQLITE_%s' % feature, '1')) 102 | 103 | # Always use memory for temp store. 104 | ext.define_macros.append(("SQLITE_TEMP_STORE", "3")) 105 | 106 | # Increase the maximum number of "host parameters" which SQLite will accept 107 | ext.define_macros.append(("SQLITE_MAX_VARIABLE_NUMBER", "250000")) 108 | 109 | # Increase maximum allowed memory-map size to 1TB 110 | ext.define_macros.append(("SQLITE_MAX_MMAP_SIZE", str(2**40))) 111 | 112 | ext.include_dirs.append(self.amalgamation_root) 113 | ext.sources.append(os.path.join(self.amalgamation_root, "sqlite3.c")) 114 | 115 | if sys.platform != "win32": 116 | # Include math library, required for fts5. 117 | ext.extra_link_args.append("-lm") 118 | 119 | build_ext.build_extension(self, ext) 120 | 121 | def __setattr__(self, k, v): 122 | # Make sure we don't link against the SQLite 123 | # library, no matter what setup.cfg says 124 | if k == "libraries": 125 | v = None 126 | self.__dict__[k] = v 127 | 128 | 129 | class FullBuilder(AmalgationLibSqliteBuilder): 130 | def build_extension(self, ext): 131 | from urllib.request import urlopen 132 | import zipfile 133 | try: 134 | with urlopen('https://sqlite.org/download.html') as fh: 135 | html = fh.read().decode('utf8') 136 | except Exception as exc: 137 | raise RuntimeError('Could not download Sqlite amalgamation: %s' % exc) 138 | 139 | match = re.search(r'(\d{4}/sqlite-amalgamation-(\d+)\.zip)', html) 140 | if match is None: 141 | raise RuntimeError('Could not find Sqlite amalgamation on download page.') 142 | link, version = match.groups() 143 | url = 'https://sqlite.org/%s' % link 144 | with tempfile.NamedTemporaryFile(suffix='.zip') as tmp: 145 | print('Downloading sqlite source code: %s' % url) 146 | with urlopen(url) as fh: 147 | shutil.copyfileobj(fh, tmp) 148 | tmp.seek(0) 149 | with zipfile.ZipFile(tmp) as zf: 150 | for path in zf.namelist(): 151 | filename = os.path.basename(path) 152 | if filename not in ('sqlite3.c', 'sqlite3.h'): 153 | continue 154 | 155 | with zf.open(path) as src, \ 156 | open(os.path.join(self.amalgamation_root, filename), 'wb') as dest: 157 | shutil.copyfileobj(src, dest) 158 | 159 | super(FullBuilder, self).build_extension(ext) 160 | 161 | 162 | def get_setup_args(): 163 | return dict( 164 | name=PACKAGE_NAME, 165 | version=VERSION, 166 | description="DB-API 2.0 interface for Sqlite 3.x", 167 | long_description='', 168 | author="Charles Leifer", 169 | author_email="coleifer@gmail.com", 170 | license="zlib/libpng", 171 | platforms="ALL", 172 | url="https://github.com/coleifer/pysqlite3", 173 | package_dir={PACKAGE_NAME: "pysqlite3"}, 174 | packages=packages, 175 | ext_modules=[Extension( 176 | name=PACKAGE_NAME + EXTENSION_MODULE_NAME, 177 | sources=sources, 178 | define_macros=define_macros) 179 | ], 180 | classifiers=[ 181 | "Development Status :: 4 - Beta", 182 | "Intended Audience :: Developers", 183 | "License :: OSI Approved :: zlib/libpng License", 184 | "Operating System :: MacOS :: MacOS X", 185 | "Operating System :: Microsoft :: Windows", 186 | "Operating System :: POSIX", 187 | "Programming Language :: C", 188 | "Programming Language :: Python", 189 | "Topic :: Database :: Database Engines/Servers", 190 | "Topic :: Software Development :: Libraries :: Python Modules"], 191 | cmdclass={ 192 | "build_static": AmalgationLibSqliteBuilder, 193 | "build_ext": SystemLibSqliteBuilder, 194 | "build_full": FullBuilder, 195 | } 196 | ) 197 | 198 | 199 | if __name__ == "__main__": 200 | setuptools.setup(**get_setup_args()) 201 | -------------------------------------------------------------------------------- /src/blob.c: -------------------------------------------------------------------------------- 1 | #include "blob.h" 2 | #include "util.h" 3 | 4 | 5 | int pysqlite_blob_init(pysqlite_Blob *self, pysqlite_Connection* connection, 6 | sqlite3_blob *blob) 7 | { 8 | Py_INCREF(connection); 9 | self->connection = connection; 10 | self->offset = 0; 11 | self->blob = blob; 12 | self->in_weakreflist = NULL; 13 | 14 | Py_BEGIN_ALLOW_THREADS 15 | self->length = sqlite3_blob_bytes(self->blob); 16 | Py_END_ALLOW_THREADS 17 | 18 | if (!pysqlite_check_thread(self->connection)) { 19 | return -1; 20 | } 21 | return 0; 22 | } 23 | 24 | static void remove_blob_from_connection_blob_list(pysqlite_Blob *self) 25 | { 26 | Py_ssize_t i; 27 | PyObject *item, *ref; 28 | 29 | for (i = 0; i < PyList_GET_SIZE(self->connection->blobs); i++) { 30 | item = PyList_GET_ITEM(self->connection->blobs, i); 31 | if (PyWeakref_GetRef(item, &ref) == 1) { 32 | if (ref == (PyObject *)self) { 33 | PyList_SetSlice(self->connection->blobs, i, i+1, NULL); 34 | break; 35 | } 36 | } 37 | } 38 | } 39 | 40 | static void _close_blob_inner(pysqlite_Blob* self) 41 | { 42 | sqlite3_blob *blob; 43 | 44 | /* close the blob */ 45 | blob = self->blob; 46 | self->blob = NULL; 47 | if (blob) { 48 | Py_BEGIN_ALLOW_THREADS 49 | sqlite3_blob_close(blob); 50 | Py_END_ALLOW_THREADS 51 | } 52 | 53 | /* remove from connection weaklist */ 54 | remove_blob_from_connection_blob_list(self); 55 | if (self->in_weakreflist != NULL) { 56 | PyObject_ClearWeakRefs((PyObject*)self); 57 | } 58 | } 59 | 60 | static void pysqlite_blob_dealloc(pysqlite_Blob* self) 61 | { 62 | _close_blob_inner(self); 63 | Py_XDECREF(self->connection); 64 | Py_TYPE(self)->tp_free((PyObject*)self); 65 | } 66 | 67 | 68 | /* 69 | * Checks if a blob object is usable (i. e. not closed). 70 | * 71 | * 0 => error; 1 => ok 72 | */ 73 | int pysqlite_check_blob(pysqlite_Blob *blob) 74 | { 75 | 76 | if (!blob->blob) { 77 | PyErr_SetString(pysqlite_ProgrammingError, 78 | "Cannot operate on a closed blob."); 79 | return 0; 80 | } else if (!pysqlite_check_connection(blob->connection) || 81 | !pysqlite_check_thread(blob->connection)) { 82 | return 0; 83 | } else { 84 | return 1; 85 | } 86 | } 87 | 88 | 89 | PyObject* pysqlite_blob_close(pysqlite_Blob *self) 90 | { 91 | 92 | if (!pysqlite_check_blob(self)) { 93 | return NULL; 94 | } 95 | 96 | _close_blob_inner(self); 97 | Py_RETURN_NONE; 98 | }; 99 | 100 | 101 | static Py_ssize_t pysqlite_blob_length(pysqlite_Blob *self) 102 | { 103 | if (!pysqlite_check_blob(self)) { 104 | return -1; 105 | } 106 | 107 | return self->length; 108 | }; 109 | 110 | static PyObject* inner_read(pysqlite_Blob *self, int read_length, int offset) 111 | { 112 | PyObject *buffer; 113 | char *raw_buffer; 114 | int rc; 115 | 116 | buffer = PyBytes_FromStringAndSize(NULL, read_length); 117 | if (!buffer) { 118 | return NULL; 119 | } 120 | raw_buffer = PyBytes_AS_STRING(buffer); 121 | 122 | Py_BEGIN_ALLOW_THREADS 123 | rc = sqlite3_blob_read(self->blob, raw_buffer, read_length, self->offset); 124 | Py_END_ALLOW_THREADS 125 | 126 | if (rc != SQLITE_OK){ 127 | Py_DECREF(buffer); 128 | /* For some reason after modifying blob the 129 | error is not set on the connection db. */ 130 | if (rc == SQLITE_ABORT) { 131 | PyErr_SetString(pysqlite_OperationalError, 132 | "Cannot operate on modified blob"); 133 | } else { 134 | _pysqlite_seterror(self->connection->db); 135 | } 136 | return NULL; 137 | } 138 | return buffer; 139 | } 140 | 141 | 142 | PyObject* pysqlite_blob_read(pysqlite_Blob *self, PyObject *args) 143 | { 144 | int read_length = -1; 145 | PyObject *buffer; 146 | 147 | if (!PyArg_ParseTuple(args, "|i", &read_length)) { 148 | return NULL; 149 | } 150 | 151 | if (!pysqlite_check_blob(self)) { 152 | return NULL; 153 | } 154 | 155 | if (read_length < 0) { 156 | /* same as file read. */ 157 | read_length = self->length; 158 | } 159 | 160 | /* making sure we don't read more then blob size */ 161 | if (read_length > self->length - self->offset) { 162 | read_length = self->length - self->offset; 163 | } 164 | 165 | buffer = inner_read(self, read_length, self->offset); 166 | 167 | if (buffer != NULL) { 168 | /* update offset on sucess. */ 169 | self->offset += read_length; 170 | } 171 | 172 | return buffer; 173 | }; 174 | 175 | static int write_inner(pysqlite_Blob *self, const void *buf, Py_ssize_t len, int offset) 176 | { 177 | int rc; 178 | 179 | Py_BEGIN_ALLOW_THREADS 180 | rc = sqlite3_blob_write(self->blob, buf, len, offset); 181 | Py_END_ALLOW_THREADS 182 | if (rc != SQLITE_OK) { 183 | /* For some reason after modifying blob the 184 | error is not set on the connection db. */ 185 | if (rc == SQLITE_ABORT) { 186 | PyErr_SetString(pysqlite_OperationalError, 187 | "Cannot operate on modified blob"); 188 | } else { 189 | _pysqlite_seterror(self->connection->db); 190 | } 191 | return -1; 192 | } 193 | return 0; 194 | } 195 | 196 | 197 | PyObject* pysqlite_blob_write(pysqlite_Blob *self, PyObject *data) 198 | { 199 | Py_buffer data_buffer; 200 | int rc; 201 | 202 | if (PyObject_GetBuffer(data, &data_buffer, PyBUF_SIMPLE) < 0) { 203 | return NULL; 204 | } 205 | 206 | if (data_buffer.len > INT_MAX) { 207 | PyErr_SetString(PyExc_OverflowError, 208 | "data longer than INT_MAX bytes"); 209 | PyBuffer_Release(&data_buffer); 210 | return NULL; 211 | } 212 | 213 | if (data_buffer.len > self->length - self->offset) { 214 | PyErr_SetString(PyExc_ValueError, 215 | "data longer than blob length"); 216 | PyBuffer_Release(&data_buffer); 217 | return NULL; 218 | } 219 | 220 | if (!pysqlite_check_blob(self)) { 221 | PyBuffer_Release(&data_buffer); 222 | return NULL; 223 | } 224 | 225 | rc = write_inner(self, data_buffer.buf, data_buffer.len, self->offset); 226 | 227 | if (rc == 0) { 228 | self->offset += (int)data_buffer.len; 229 | PyBuffer_Release(&data_buffer); 230 | Py_RETURN_NONE; 231 | } else { 232 | PyBuffer_Release(&data_buffer); 233 | return NULL; 234 | } 235 | } 236 | 237 | 238 | PyObject* pysqlite_blob_seek(pysqlite_Blob *self, PyObject *args) 239 | { 240 | int offset, from_what = 0; 241 | 242 | if (!PyArg_ParseTuple(args, "i|i", &offset, &from_what)) { 243 | return NULL; 244 | } 245 | 246 | 247 | if (!pysqlite_check_blob(self)) { 248 | return NULL; 249 | } 250 | 251 | switch (from_what) { 252 | case 0: // relative to blob begin 253 | break; 254 | case 1: // relative to current position 255 | if (offset > INT_MAX - self->offset) { 256 | goto overflow; 257 | } 258 | offset = self->offset + offset; 259 | break; 260 | case 2: // relative to blob end 261 | if (offset > INT_MAX - self->length) { 262 | goto overflow; 263 | } 264 | offset = self->length + offset; 265 | break; 266 | default: 267 | PyErr_SetString(PyExc_ValueError, 268 | "from_what should be 0, 1 or 2"); 269 | return NULL; 270 | } 271 | 272 | if (offset < 0 || offset > self->length) { 273 | PyErr_SetString(PyExc_ValueError, "offset out of blob range"); 274 | return NULL; 275 | } 276 | 277 | self->offset = offset; 278 | Py_RETURN_NONE; 279 | 280 | overflow: 281 | PyErr_SetString(PyExc_OverflowError, "seek offset result in overflow"); 282 | return NULL; 283 | } 284 | 285 | 286 | PyObject* pysqlite_blob_tell(pysqlite_Blob *self) 287 | { 288 | if (!pysqlite_check_blob(self)) { 289 | return NULL; 290 | } 291 | 292 | return PyLong_FromLong(self->offset); 293 | } 294 | 295 | 296 | PyObject* pysqlite_blob_enter(pysqlite_Blob *self) 297 | { 298 | if (!pysqlite_check_blob(self)) { 299 | return NULL; 300 | } 301 | 302 | Py_INCREF(self); 303 | return (PyObject *)self; 304 | } 305 | 306 | 307 | PyObject* pysqlite_blob_exit(pysqlite_Blob *self, PyObject *args) 308 | { 309 | PyObject *res; 310 | if (!pysqlite_check_blob(self)) { 311 | return NULL; 312 | } 313 | 314 | res = pysqlite_blob_close(self); 315 | if (!res) { 316 | return NULL; 317 | } 318 | Py_XDECREF(res); 319 | 320 | Py_RETURN_FALSE; 321 | } 322 | 323 | static PyObject* pysqlite_blob_concat(pysqlite_Blob *self, PyObject *args) 324 | { 325 | if (pysqlite_check_blob(self)) { 326 | PyErr_SetString(PyExc_SystemError, 327 | "Blob don't support concatenation"); 328 | } 329 | return NULL; 330 | } 331 | 332 | static PyObject* pysqlite_blob_repeat(pysqlite_Blob *self, PyObject *args) 333 | { 334 | if (pysqlite_check_blob(self)) { 335 | PyErr_SetString(PyExc_SystemError, 336 | "Blob don't support repeat operation"); 337 | } 338 | return NULL; 339 | } 340 | 341 | static int pysqlite_blob_contains(pysqlite_Blob *self, PyObject *args) 342 | { 343 | if (pysqlite_check_blob(self)) { 344 | PyErr_SetString(PyExc_SystemError, 345 | "Blob don't support contains operation"); 346 | } 347 | return -1; 348 | } 349 | 350 | static PyObject* pysqlite_blob_item(pysqlite_Blob *self, Py_ssize_t i) 351 | { 352 | if (!pysqlite_check_blob(self)) { 353 | return NULL; 354 | } 355 | 356 | if (i < 0 || i >= self->length) { 357 | PyErr_SetString(PyExc_IndexError, "Blob index out of range"); 358 | return NULL; 359 | } 360 | 361 | return inner_read(self, 1, i); 362 | } 363 | 364 | static int pysqlite_blob_ass_item(pysqlite_Blob *self, Py_ssize_t i, PyObject *v) 365 | { 366 | const char *buf; 367 | 368 | if (!pysqlite_check_blob(self)) { 369 | return -1; 370 | } 371 | 372 | if (i < 0 || i >= self->length) { 373 | PyErr_SetString(PyExc_IndexError, "Blob index out of range"); 374 | return -1; 375 | } 376 | if (v == NULL) { 377 | PyErr_SetString(PyExc_TypeError, 378 | "Blob object doesn't support item deletion"); 379 | return -1; 380 | } 381 | if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) { 382 | PyErr_SetString(PyExc_IndexError, 383 | "Blob assignment must be length-1 bytes()"); 384 | return -1; 385 | } 386 | 387 | buf = PyBytes_AsString(v); 388 | return write_inner(self, buf, 1, i); 389 | } 390 | 391 | 392 | static PyObject * pysqlite_blob_subscript(pysqlite_Blob *self, PyObject *item) 393 | { 394 | if (!pysqlite_check_blob(self)) { 395 | return NULL; 396 | } 397 | 398 | if (PyIndex_Check(item)) { 399 | Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); 400 | if (i == -1 && PyErr_Occurred()) 401 | return NULL; 402 | if (i < 0) 403 | i += self->length; 404 | if (i < 0 || i >= self->length) { 405 | PyErr_SetString(PyExc_IndexError, 406 | "Blob index out of range"); 407 | return NULL; 408 | } 409 | // TODO: I am not sure... 410 | return inner_read(self, 1, i); 411 | } 412 | else if (PySlice_Check(item)) { 413 | Py_ssize_t start, stop, step, slicelen; 414 | 415 | if (PySlice_GetIndicesEx(item, self->length, 416 | &start, &stop, &step, &slicelen) < 0) { 417 | return NULL; 418 | } 419 | 420 | if (slicelen <= 0) { 421 | return PyBytes_FromStringAndSize("", 0); 422 | } else if (step == 1) { 423 | return inner_read(self, slicelen, start); 424 | } else { 425 | char *result_buf = (char *)PyMem_Malloc(slicelen); 426 | char *data_buff = NULL; 427 | Py_ssize_t cur, i; 428 | PyObject *result; 429 | int rc; 430 | 431 | if (result_buf == NULL) 432 | return PyErr_NoMemory(); 433 | 434 | data_buff = (char *)PyMem_Malloc(stop - start); 435 | if (data_buff == NULL) { 436 | PyMem_Free(result_buf); 437 | return PyErr_NoMemory(); 438 | } 439 | 440 | Py_BEGIN_ALLOW_THREADS 441 | rc = sqlite3_blob_read(self->blob, data_buff, stop - start, start); 442 | Py_END_ALLOW_THREADS 443 | 444 | if (rc != SQLITE_OK){ 445 | /* For some reason after modifying blob the 446 | error is not set on the connection db. */ 447 | if (rc == SQLITE_ABORT) { 448 | PyErr_SetString(pysqlite_OperationalError, 449 | "Cannot operate on modified blob"); 450 | } else { 451 | _pysqlite_seterror(self->connection->db); 452 | } 453 | PyMem_Free(result_buf); 454 | PyMem_Free(data_buff); 455 | return NULL; 456 | } 457 | 458 | for (cur = 0, i = 0; i < slicelen; 459 | cur += step, i++) { 460 | result_buf[i] = data_buff[cur]; 461 | } 462 | result = PyBytes_FromStringAndSize(result_buf, 463 | slicelen); 464 | PyMem_Free(result_buf); 465 | PyMem_Free(data_buff); 466 | return result; 467 | } 468 | } 469 | else { 470 | PyErr_SetString(PyExc_TypeError, 471 | "Blob indices must be integers"); 472 | return NULL; 473 | } 474 | } 475 | 476 | 477 | static int pysqlite_blob_ass_subscript(pysqlite_Blob *self, PyObject *item, PyObject *value) 478 | { 479 | int rc = 0; 480 | 481 | if (!pysqlite_check_blob(self)) { 482 | return -1; 483 | } 484 | 485 | if (PyIndex_Check(item)) { 486 | Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); 487 | const char *buf; 488 | 489 | if (i == -1 && PyErr_Occurred()) 490 | return -1; 491 | if (i < 0) 492 | i += self->length; 493 | if (i < 0 || i >= self->length) { 494 | PyErr_SetString(PyExc_IndexError, 495 | "Blob index out of range"); 496 | return -1; 497 | } 498 | if (value == NULL) { 499 | PyErr_SetString(PyExc_TypeError, 500 | "Blob doesn't support item deletion"); 501 | return -1; 502 | } 503 | if (! (PyBytes_Check(value) && PyBytes_Size(value)==1) ) { 504 | PyErr_SetString(PyExc_IndexError, 505 | "Blob assignment must be length-1 bytes()"); 506 | return -1; 507 | } 508 | 509 | buf = PyBytes_AsString(value); 510 | return write_inner(self, buf, 1, i); 511 | } 512 | else if (PySlice_Check(item)) { 513 | Py_ssize_t start, stop, step, slicelen; 514 | Py_buffer vbuf; 515 | 516 | if (PySlice_GetIndicesEx(item, 517 | self->length, &start, &stop, 518 | &step, &slicelen) < 0) { 519 | return -1; 520 | } 521 | if (value == NULL) { 522 | PyErr_SetString(PyExc_TypeError, 523 | "Blob object doesn't support slice deletion"); 524 | return -1; 525 | } 526 | if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0) 527 | return -1; 528 | if (vbuf.len != slicelen) { 529 | PyErr_SetString(PyExc_IndexError, 530 | "Blob slice assignment is wrong size"); 531 | PyBuffer_Release(&vbuf); 532 | return -1; 533 | } 534 | 535 | if (slicelen == 0) { 536 | } 537 | else if (step == 1) { 538 | rc = write_inner(self, vbuf.buf, slicelen, start); 539 | } 540 | else { 541 | Py_ssize_t cur, i; 542 | char *data_buff; 543 | 544 | 545 | data_buff = (char *)PyMem_Malloc(stop - start); 546 | if (data_buff == NULL) { 547 | PyErr_NoMemory(); 548 | return -1; 549 | } 550 | 551 | Py_BEGIN_ALLOW_THREADS 552 | rc = sqlite3_blob_read(self->blob, data_buff, stop - start, start); 553 | Py_END_ALLOW_THREADS 554 | 555 | if (rc != SQLITE_OK){ 556 | /* For some reason after modifying blob the 557 | error is not set on the connection db. */ 558 | if (rc == SQLITE_ABORT) { 559 | PyErr_SetString(pysqlite_OperationalError, 560 | "Cannot operate on modified blob"); 561 | } else { 562 | _pysqlite_seterror(self->connection->db); 563 | } 564 | PyMem_Free(data_buff); 565 | rc = -1; 566 | } 567 | 568 | for (cur = 0, i = 0; 569 | i < slicelen; 570 | cur += step, i++) 571 | { 572 | data_buff[cur] = ((char *)vbuf.buf)[i]; 573 | } 574 | 575 | Py_BEGIN_ALLOW_THREADS 576 | rc = sqlite3_blob_write(self->blob, data_buff, stop - start, start); 577 | Py_END_ALLOW_THREADS 578 | 579 | if (rc != SQLITE_OK){ 580 | /* For some reason after modifying blob the 581 | error is not set on the connection db. */ 582 | if (rc == SQLITE_ABORT) { 583 | PyErr_SetString(pysqlite_OperationalError, 584 | "Cannot operate on modified blob"); 585 | } else { 586 | _pysqlite_seterror(self->connection->db); 587 | } 588 | PyMem_Free(data_buff); 589 | rc = -1; 590 | } 591 | rc = 0; 592 | 593 | } 594 | PyBuffer_Release(&vbuf); 595 | return rc; 596 | } 597 | else { 598 | PyErr_SetString(PyExc_TypeError, 599 | "Blob indices must be integer"); 600 | return -1; 601 | } 602 | } 603 | 604 | 605 | static PyMethodDef blob_methods[] = { 606 | {"read", (PyCFunction)pysqlite_blob_read, METH_VARARGS, 607 | PyDoc_STR("read data from blob")}, 608 | {"write", (PyCFunction)pysqlite_blob_write, METH_O, 609 | PyDoc_STR("write data to blob")}, 610 | {"close", (PyCFunction)pysqlite_blob_close, METH_NOARGS, 611 | PyDoc_STR("close blob")}, 612 | {"seek", (PyCFunction)pysqlite_blob_seek, METH_VARARGS, 613 | PyDoc_STR("change blob current offset")}, 614 | {"tell", (PyCFunction)pysqlite_blob_tell, METH_NOARGS, 615 | PyDoc_STR("return blob current offset")}, 616 | {"__enter__", (PyCFunction)pysqlite_blob_enter, METH_NOARGS, 617 | PyDoc_STR("blob context manager enter")}, 618 | {"__exit__", (PyCFunction)pysqlite_blob_exit, METH_VARARGS, 619 | PyDoc_STR("blob context manager exit")}, 620 | {NULL, NULL} 621 | }; 622 | 623 | static PySequenceMethods blob_sequence_methods = { 624 | .sq_length = (lenfunc)pysqlite_blob_length, 625 | .sq_concat = (binaryfunc)pysqlite_blob_concat, 626 | .sq_repeat = (ssizeargfunc)pysqlite_blob_repeat, 627 | .sq_item = (ssizeargfunc)pysqlite_blob_item, 628 | .sq_ass_item = (ssizeobjargproc)pysqlite_blob_ass_item, 629 | .sq_contains = (objobjproc)pysqlite_blob_contains, 630 | }; 631 | 632 | static PyMappingMethods blob_mapping_methods = { 633 | (lenfunc)pysqlite_blob_length, 634 | (binaryfunc)pysqlite_blob_subscript, 635 | (objobjargproc)pysqlite_blob_ass_subscript, 636 | }; 637 | 638 | PyTypeObject pysqlite_BlobType = { 639 | PyVarObject_HEAD_INIT(NULL, 0) 640 | MODULE_NAME ".Blob", 641 | .tp_basicsize = sizeof(pysqlite_Blob), 642 | .tp_dealloc = (destructor)pysqlite_blob_dealloc, 643 | .tp_as_sequence = &blob_sequence_methods, 644 | .tp_as_mapping = &blob_mapping_methods, 645 | .tp_flags = Py_TPFLAGS_DEFAULT, 646 | .tp_weaklistoffset = offsetof(pysqlite_Blob, in_weakreflist), 647 | .tp_methods = blob_methods, 648 | }; 649 | 650 | extern int pysqlite_blob_setup_types(void) 651 | { 652 | pysqlite_BlobType.tp_new = PyType_GenericNew; 653 | return PyType_Ready(&pysqlite_BlobType); 654 | } 655 | -------------------------------------------------------------------------------- /src/blob.h: -------------------------------------------------------------------------------- 1 | #ifndef PYSQLITE_BLOB_H 2 | #define PYSQLITE_BLOB_H 3 | #include "Python.h" 4 | #include "sqlite3.h" 5 | #include "connection.h" 6 | 7 | typedef struct 8 | { 9 | PyObject_HEAD 10 | pysqlite_Connection* connection; 11 | sqlite3_blob *blob; 12 | int offset; 13 | int length; 14 | 15 | PyObject* in_weakreflist; /* List of weak references */ 16 | } pysqlite_Blob; 17 | 18 | extern PyTypeObject pysqlite_BlobType; 19 | 20 | int pysqlite_blob_init(pysqlite_Blob* self, pysqlite_Connection* connection, 21 | sqlite3_blob *blob); 22 | PyObject* pysqlite_blob_close(pysqlite_Blob *self); 23 | 24 | int pysqlite_blob_setup_types(void); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/cache.c: -------------------------------------------------------------------------------- 1 | /* cache .c - a LRU cache 2 | * 3 | * Copyright (C) 2004-2010 Gerhard Häring 4 | * 5 | * This file is part of pysqlite. 6 | * 7 | * This software is provided 'as-is', without any express or implied 8 | * warranty. In no event will the authors be held liable for any damages 9 | * arising from the use of this software. 10 | * 11 | * Permission is granted to anyone to use this software for any purpose, 12 | * including commercial applications, and to alter it and redistribute it 13 | * freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not 16 | * claim that you wrote the original software. If you use this software 17 | * in a product, an acknowledgment in the product documentation would be 18 | * appreciated but is not required. 19 | * 2. Altered source versions must be plainly marked as such, and must not be 20 | * misrepresented as being the original software. 21 | * 3. This notice may not be removed or altered from any source distribution. 22 | */ 23 | 24 | #include "cache.h" 25 | #include 26 | 27 | /* only used internally */ 28 | pysqlite_Node* pysqlite_new_node(PyObject* key, PyObject* data) 29 | { 30 | pysqlite_Node* node; 31 | 32 | node = (pysqlite_Node*) (pysqlite_NodeType.tp_alloc(&pysqlite_NodeType, 0)); 33 | if (!node) { 34 | return NULL; 35 | } 36 | 37 | Py_INCREF(key); 38 | node->key = key; 39 | 40 | Py_INCREF(data); 41 | node->data = data; 42 | 43 | node->prev = NULL; 44 | node->next = NULL; 45 | 46 | return node; 47 | } 48 | 49 | void pysqlite_node_dealloc(pysqlite_Node* self) 50 | { 51 | Py_DECREF(self->key); 52 | Py_DECREF(self->data); 53 | 54 | Py_TYPE(self)->tp_free((PyObject*)self); 55 | } 56 | 57 | int pysqlite_cache_init(pysqlite_Cache* self, PyObject* args, PyObject* kwargs) 58 | { 59 | PyObject* factory; 60 | int size = 10; 61 | 62 | self->factory = NULL; 63 | 64 | if (!PyArg_ParseTuple(args, "O|i", &factory, &size)) { 65 | return -1; 66 | } 67 | 68 | /* minimum cache size is 5 entries */ 69 | if (size < 5) { 70 | size = 5; 71 | } 72 | self->size = size; 73 | self->first = NULL; 74 | self->last = NULL; 75 | 76 | self->mapping = PyDict_New(); 77 | if (!self->mapping) { 78 | return -1; 79 | } 80 | 81 | Py_INCREF(factory); 82 | self->factory = factory; 83 | 84 | self->decref_factory = 1; 85 | 86 | return 0; 87 | } 88 | 89 | void pysqlite_cache_dealloc(pysqlite_Cache* self) 90 | { 91 | pysqlite_Node* node; 92 | pysqlite_Node* delete_node; 93 | 94 | if (!self->factory) { 95 | /* constructor failed, just get out of here */ 96 | return; 97 | } 98 | 99 | /* iterate over all nodes and deallocate them */ 100 | node = self->first; 101 | while (node) { 102 | delete_node = node; 103 | node = node->next; 104 | Py_DECREF(delete_node); 105 | } 106 | 107 | if (self->decref_factory) { 108 | Py_DECREF(self->factory); 109 | } 110 | Py_DECREF(self->mapping); 111 | 112 | Py_TYPE(self)->tp_free((PyObject*)self); 113 | } 114 | 115 | PyObject* pysqlite_cache_get(pysqlite_Cache* self, PyObject* key) 116 | { 117 | pysqlite_Node* node; 118 | pysqlite_Node* ptr; 119 | PyObject* data; 120 | 121 | node = (pysqlite_Node*)PyDict_GetItemWithError(self->mapping, key); 122 | if (node) { 123 | /* an entry for this key already exists in the cache */ 124 | 125 | /* increase usage counter of the node found */ 126 | if (node->count < LONG_MAX) { 127 | node->count++; 128 | } 129 | 130 | /* if necessary, reorder entries in the cache by swapping positions */ 131 | if (node->prev && node->count > node->prev->count) { 132 | ptr = node->prev; 133 | 134 | while (ptr->prev && node->count > ptr->prev->count) { 135 | ptr = ptr->prev; 136 | } 137 | 138 | if (node->next) { 139 | node->next->prev = node->prev; 140 | } else { 141 | self->last = node->prev; 142 | } 143 | if (node->prev) { 144 | node->prev->next = node->next; 145 | } 146 | if (ptr->prev) { 147 | ptr->prev->next = node; 148 | } else { 149 | self->first = node; 150 | } 151 | 152 | node->next = ptr; 153 | node->prev = ptr->prev; 154 | if (!node->prev) { 155 | self->first = node; 156 | } 157 | ptr->prev = node; 158 | } 159 | } 160 | else if (PyErr_Occurred()) { 161 | return NULL; 162 | } 163 | else { 164 | /* There is no entry for this key in the cache, yet. We'll insert a new 165 | * entry in the cache, and make space if necessary by throwing the 166 | * least used item out of the cache. */ 167 | 168 | if (PyDict_Size(self->mapping) == self->size) { 169 | if (self->last) { 170 | node = self->last; 171 | 172 | if (PyDict_DelItem(self->mapping, self->last->key) != 0) { 173 | return NULL; 174 | } 175 | 176 | if (node->prev) { 177 | node->prev->next = NULL; 178 | } 179 | self->last = node->prev; 180 | node->prev = NULL; 181 | 182 | Py_DECREF(node); 183 | } 184 | } 185 | 186 | /* We cannot replace this by PyObject_CallOneArg() since 187 | * PyObject_CallFunction() has a special case when using a 188 | * single tuple as argument. */ 189 | data = PyObject_CallFunction(self->factory, "O", key); 190 | 191 | if (!data) { 192 | return NULL; 193 | } 194 | 195 | node = pysqlite_new_node(key, data); 196 | if (!node) { 197 | return NULL; 198 | } 199 | node->prev = self->last; 200 | 201 | Py_DECREF(data); 202 | 203 | if (PyDict_SetItem(self->mapping, key, (PyObject*)node) != 0) { 204 | Py_DECREF(node); 205 | return NULL; 206 | } 207 | 208 | if (self->last) { 209 | self->last->next = node; 210 | } else { 211 | self->first = node; 212 | } 213 | self->last = node; 214 | } 215 | 216 | Py_INCREF(node->data); 217 | return node->data; 218 | } 219 | 220 | PyObject* pysqlite_cache_display(pysqlite_Cache* self, PyObject* args) 221 | { 222 | pysqlite_Node* ptr; 223 | PyObject* prevkey; 224 | PyObject* nextkey; 225 | PyObject* display_str; 226 | 227 | ptr = self->first; 228 | 229 | while (ptr) { 230 | if (ptr->prev) { 231 | prevkey = ptr->prev->key; 232 | } else { 233 | prevkey = Py_None; 234 | } 235 | 236 | if (ptr->next) { 237 | nextkey = ptr->next->key; 238 | } else { 239 | nextkey = Py_None; 240 | } 241 | 242 | display_str = PyUnicode_FromFormat("%S <- %S -> %S\n", 243 | prevkey, ptr->key, nextkey); 244 | if (!display_str) { 245 | return NULL; 246 | } 247 | PyObject_Print(display_str, stdout, Py_PRINT_RAW); 248 | Py_DECREF(display_str); 249 | 250 | ptr = ptr->next; 251 | } 252 | 253 | Py_RETURN_NONE; 254 | } 255 | 256 | static PyMethodDef cache_methods[] = { 257 | {"get", (PyCFunction)pysqlite_cache_get, METH_O, 258 | PyDoc_STR("Gets an entry from the cache or calls the factory function to produce one.")}, 259 | {"display", (PyCFunction)pysqlite_cache_display, METH_NOARGS, 260 | PyDoc_STR("For debugging only.")}, 261 | {NULL, NULL} 262 | }; 263 | 264 | PyTypeObject pysqlite_NodeType = { 265 | PyVarObject_HEAD_INIT(NULL, 0) 266 | MODULE_NAME "Node", /* tp_name */ 267 | sizeof(pysqlite_Node), /* tp_basicsize */ 268 | 0, /* tp_itemsize */ 269 | (destructor)pysqlite_node_dealloc, /* tp_dealloc */ 270 | 0, /* tp_print */ 271 | 0, /* tp_getattr */ 272 | 0, /* tp_setattr */ 273 | 0, /* tp_reserved */ 274 | 0, /* tp_repr */ 275 | 0, /* tp_as_number */ 276 | 0, /* tp_as_sequence */ 277 | 0, /* tp_as_mapping */ 278 | 0, /* tp_hash */ 279 | 0, /* tp_call */ 280 | 0, /* tp_str */ 281 | 0, /* tp_getattro */ 282 | 0, /* tp_setattro */ 283 | 0, /* tp_as_buffer */ 284 | Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ 285 | 0, /* tp_doc */ 286 | 0, /* tp_traverse */ 287 | 0, /* tp_clear */ 288 | 0, /* tp_richcompare */ 289 | 0, /* tp_weaklistoffset */ 290 | 0, /* tp_iter */ 291 | 0, /* tp_iternext */ 292 | 0, /* tp_methods */ 293 | 0, /* tp_members */ 294 | 0, /* tp_getset */ 295 | 0, /* tp_base */ 296 | 0, /* tp_dict */ 297 | 0, /* tp_descr_get */ 298 | 0, /* tp_descr_set */ 299 | 0, /* tp_dictoffset */ 300 | (initproc)0, /* tp_init */ 301 | 0, /* tp_alloc */ 302 | 0, /* tp_new */ 303 | 0 /* tp_free */ 304 | }; 305 | 306 | PyTypeObject pysqlite_CacheType = { 307 | PyVarObject_HEAD_INIT(NULL, 0) 308 | MODULE_NAME ".Cache", /* tp_name */ 309 | sizeof(pysqlite_Cache), /* tp_basicsize */ 310 | 0, /* tp_itemsize */ 311 | (destructor)pysqlite_cache_dealloc, /* tp_dealloc */ 312 | 0, /* tp_print */ 313 | 0, /* tp_getattr */ 314 | 0, /* tp_setattr */ 315 | 0, /* tp_reserved */ 316 | 0, /* tp_repr */ 317 | 0, /* tp_as_number */ 318 | 0, /* tp_as_sequence */ 319 | 0, /* tp_as_mapping */ 320 | 0, /* tp_hash */ 321 | 0, /* tp_call */ 322 | 0, /* tp_str */ 323 | 0, /* tp_getattro */ 324 | 0, /* tp_setattro */ 325 | 0, /* tp_as_buffer */ 326 | Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ 327 | 0, /* tp_doc */ 328 | 0, /* tp_traverse */ 329 | 0, /* tp_clear */ 330 | 0, /* tp_richcompare */ 331 | 0, /* tp_weaklistoffset */ 332 | 0, /* tp_iter */ 333 | 0, /* tp_iternext */ 334 | cache_methods, /* tp_methods */ 335 | 0, /* tp_members */ 336 | 0, /* tp_getset */ 337 | 0, /* tp_base */ 338 | 0, /* tp_dict */ 339 | 0, /* tp_descr_get */ 340 | 0, /* tp_descr_set */ 341 | 0, /* tp_dictoffset */ 342 | (initproc)pysqlite_cache_init, /* tp_init */ 343 | 0, /* tp_alloc */ 344 | 0, /* tp_new */ 345 | 0 /* tp_free */ 346 | }; 347 | 348 | extern int pysqlite_cache_setup_types(void) 349 | { 350 | int rc; 351 | 352 | pysqlite_NodeType.tp_new = PyType_GenericNew; 353 | pysqlite_CacheType.tp_new = PyType_GenericNew; 354 | 355 | rc = PyType_Ready(&pysqlite_NodeType); 356 | if (rc < 0) { 357 | return rc; 358 | } 359 | 360 | rc = PyType_Ready(&pysqlite_CacheType); 361 | return rc; 362 | } 363 | -------------------------------------------------------------------------------- /src/cache.h: -------------------------------------------------------------------------------- 1 | /* cache.h - definitions for the LRU cache 2 | * 3 | * Copyright (C) 2004-2010 Gerhard Häring 4 | * 5 | * This file is part of pysqlite. 6 | * 7 | * This software is provided 'as-is', without any express or implied 8 | * warranty. In no event will the authors be held liable for any damages 9 | * arising from the use of this software. 10 | * 11 | * Permission is granted to anyone to use this software for any purpose, 12 | * including commercial applications, and to alter it and redistribute it 13 | * freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not 16 | * claim that you wrote the original software. If you use this software 17 | * in a product, an acknowledgment in the product documentation would be 18 | * appreciated but is not required. 19 | * 2. Altered source versions must be plainly marked as such, and must not be 20 | * misrepresented as being the original software. 21 | * 3. This notice may not be removed or altered from any source distribution. 22 | */ 23 | 24 | #ifndef PYSQLITE_CACHE_H 25 | #define PYSQLITE_CACHE_H 26 | #define PY_SSIZE_T_CLEAN 27 | #include "Python.h" 28 | 29 | /* The LRU cache is implemented as a combination of a doubly-linked with a 30 | * dictionary. The list items are of type 'Node' and the dictionary has the 31 | * nodes as values. */ 32 | 33 | typedef struct _pysqlite_Node 34 | { 35 | PyObject_HEAD 36 | PyObject* key; 37 | PyObject* data; 38 | long count; 39 | struct _pysqlite_Node* prev; 40 | struct _pysqlite_Node* next; 41 | } pysqlite_Node; 42 | 43 | typedef struct 44 | { 45 | PyObject_HEAD 46 | int size; 47 | 48 | /* a dictionary mapping keys to Node entries */ 49 | PyObject* mapping; 50 | 51 | /* the factory callable */ 52 | PyObject* factory; 53 | 54 | pysqlite_Node* first; 55 | pysqlite_Node* last; 56 | 57 | /* if set, decrement the factory function when the Cache is deallocated. 58 | * this is almost always desirable, but not in the pysqlite context */ 59 | int decref_factory; 60 | } pysqlite_Cache; 61 | 62 | extern PyTypeObject pysqlite_NodeType; 63 | extern PyTypeObject pysqlite_CacheType; 64 | 65 | int pysqlite_node_init(pysqlite_Node* self, PyObject* args, PyObject* kwargs); 66 | void pysqlite_node_dealloc(pysqlite_Node* self); 67 | 68 | int pysqlite_cache_init(pysqlite_Cache* self, PyObject* args, PyObject* kwargs); 69 | void pysqlite_cache_dealloc(pysqlite_Cache* self); 70 | PyObject* pysqlite_cache_get(pysqlite_Cache* self, PyObject* args); 71 | 72 | int pysqlite_cache_setup_types(void); 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /src/connection.h: -------------------------------------------------------------------------------- 1 | /* connection.h - definitions for the connection type 2 | * 3 | * Copyright (C) 2004-2010 Gerhard Häring 4 | * 5 | * This file is part of pysqlite. 6 | * 7 | * This software is provided 'as-is', without any express or implied 8 | * warranty. In no event will the authors be held liable for any damages 9 | * arising from the use of this software. 10 | * 11 | * Permission is granted to anyone to use this software for any purpose, 12 | * including commercial applications, and to alter it and redistribute it 13 | * freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not 16 | * claim that you wrote the original software. If you use this software 17 | * in a product, an acknowledgment in the product documentation would be 18 | * appreciated but is not required. 19 | * 2. Altered source versions must be plainly marked as such, and must not be 20 | * misrepresented as being the original software. 21 | * 3. This notice may not be removed or altered from any source distribution. 22 | */ 23 | 24 | #ifndef PYSQLITE_CONNECTION_H 25 | #define PYSQLITE_CONNECTION_H 26 | #define PY_SSIZE_T_CLEAN 27 | #include "Python.h" 28 | #include "pythread.h" 29 | #include "structmember.h" 30 | 31 | #include "cache.h" 32 | #include "module.h" 33 | 34 | #include "sqlite3.h" 35 | 36 | typedef struct 37 | { 38 | PyObject_HEAD 39 | sqlite3* db; 40 | 41 | /* the type detection mode. Only 0, PARSE_DECLTYPES, PARSE_COLNAMES or a 42 | * bitwise combination thereof makes sense */ 43 | int detect_types; 44 | 45 | /* the timeout value in seconds for database locks */ 46 | double timeout; 47 | 48 | /* for internal use in the timeout handler: when did the timeout handler 49 | * first get called with count=0? */ 50 | double timeout_started; 51 | 52 | /* None for autocommit, otherwise a PyUnicode with the isolation level */ 53 | PyObject* isolation_level; 54 | 55 | /* NULL for autocommit, otherwise a string with the BEGIN statement */ 56 | const char* begin_statement; 57 | 58 | /* 1 if a check should be performed for each API call if the connection is 59 | * used from the same thread it was created in */ 60 | int check_same_thread; 61 | 62 | int initialized; 63 | 64 | /* thread identification of the thread the connection was created in */ 65 | unsigned long thread_ident; 66 | 67 | pysqlite_Cache* statement_cache; 68 | 69 | /* Lists of weak references to statements, blobs and cursors used within this connection */ 70 | PyObject* statements; 71 | PyObject* cursors; 72 | PyObject* blobs; 73 | 74 | /* Counters for how many statements/cursors were created in the connection. May be 75 | * reset to 0 at certain intervals */ 76 | int created_statements; 77 | int created_cursors; 78 | 79 | PyObject* row_factory; 80 | 81 | /* Determines how bytestrings from SQLite are converted to Python objects: 82 | * - PyUnicode_Type: Python Unicode objects are constructed from UTF-8 bytestrings 83 | * - PyBytes_Type: The bytestrings are returned as-is. 84 | * - Any custom callable: Any object returned from the callable called with the bytestring 85 | * as single parameter. 86 | */ 87 | PyObject* text_factory; 88 | 89 | /* remember references to functions/classes used in trace/progress/auth cb */ 90 | PyObject* function_pinboard_trace_callback; 91 | PyObject* function_pinboard_progress_handler; 92 | PyObject* function_pinboard_authorizer_cb; 93 | PyObject* function_pinboard_busy_handler_cb; 94 | 95 | /* a dictionary of registered collation name => collation callable mappings */ 96 | PyObject* collations; 97 | 98 | /* Exception objects */ 99 | PyObject* Warning; 100 | PyObject* Error; 101 | PyObject* InterfaceError; 102 | PyObject* DatabaseError; 103 | PyObject* DataError; 104 | PyObject* OperationalError; 105 | PyObject* IntegrityError; 106 | PyObject* InternalError; 107 | PyObject* ProgrammingError; 108 | PyObject* NotSupportedError; 109 | } pysqlite_Connection; 110 | 111 | extern PyTypeObject pysqlite_ConnectionType; 112 | 113 | PyObject* pysqlite_connection_alloc(PyTypeObject* type, int aware); 114 | void pysqlite_connection_dealloc(pysqlite_Connection* self); 115 | PyObject* pysqlite_connection_cursor(pysqlite_Connection* self, PyObject* args, PyObject* kwargs); 116 | PyObject* pysqlite_connection_close(pysqlite_Connection* self, PyObject* args); 117 | PyObject* _pysqlite_connection_begin(pysqlite_Connection* self); 118 | PyObject* pysqlite_connection_commit(pysqlite_Connection* self, PyObject* args); 119 | PyObject* pysqlite_connection_rollback(pysqlite_Connection* self, PyObject* args); 120 | PyObject* pysqlite_connection_new(PyTypeObject* type, PyObject* args, PyObject* kw); 121 | int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject* kwargs); 122 | 123 | int pysqlite_connection_register_cursor(pysqlite_Connection* connection, PyObject* cursor); 124 | int pysqlite_check_thread(pysqlite_Connection* self); 125 | int pysqlite_check_connection(pysqlite_Connection* con); 126 | 127 | int pysqlite_connection_setup_types(void); 128 | 129 | #endif 130 | -------------------------------------------------------------------------------- /src/cursor.c: -------------------------------------------------------------------------------- 1 | /* cursor.c - the cursor type 2 | * 3 | * Copyright (C) 2004-2010 Gerhard Häring 4 | * 5 | * This file is part of pysqlite. 6 | * 7 | * This software is provided 'as-is', without any express or implied 8 | * warranty. In no event will the authors be held liable for any damages 9 | * arising from the use of this software. 10 | * 11 | * Permission is granted to anyone to use this software for any purpose, 12 | * including commercial applications, and to alter it and redistribute it 13 | * freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not 16 | * claim that you wrote the original software. If you use this software 17 | * in a product, an acknowledgment in the product documentation would be 18 | * appreciated but is not required. 19 | * 2. Altered source versions must be plainly marked as such, and must not be 20 | * misrepresented as being the original software. 21 | * 3. This notice may not be removed or altered from any source distribution. 22 | */ 23 | 24 | #include "cursor.h" 25 | #include "module.h" 26 | #include "util.h" 27 | 28 | PyObject* pysqlite_cursor_iternext(pysqlite_Cursor* self); 29 | 30 | static const char errmsg_fetch_across_rollback[] = "Cursor needed to be reset because of commit/rollback and can no longer be fetched from."; 31 | 32 | static int pysqlite_cursor_init(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs) 33 | { 34 | pysqlite_Connection* connection; 35 | 36 | if (!PyArg_ParseTuple(args, "O!", &pysqlite_ConnectionType, &connection)) 37 | { 38 | return -1; 39 | } 40 | 41 | Py_INCREF(connection); 42 | Py_XSETREF(self->connection, connection); 43 | Py_CLEAR(self->statement); 44 | Py_CLEAR(self->next_row); 45 | Py_CLEAR(self->row_cast_map); 46 | 47 | Py_INCREF(Py_None); 48 | Py_XSETREF(self->description, Py_None); 49 | 50 | Py_INCREF(Py_None); 51 | Py_XSETREF(self->lastrowid, Py_None); 52 | 53 | self->arraysize = 1; 54 | self->closed = 0; 55 | self->reset = 0; 56 | 57 | self->rowcount = -1L; 58 | 59 | Py_INCREF(Py_None); 60 | Py_XSETREF(self->row_factory, Py_None); 61 | 62 | if (!pysqlite_check_thread(self->connection)) { 63 | return -1; 64 | } 65 | 66 | if (!pysqlite_connection_register_cursor(connection, (PyObject*)self)) { 67 | return -1; 68 | } 69 | 70 | self->initialized = 1; 71 | 72 | return 0; 73 | } 74 | 75 | static void pysqlite_cursor_dealloc(pysqlite_Cursor* self) 76 | { 77 | /* Reset the statement if the user has not closed the cursor */ 78 | if (self->statement) { 79 | pysqlite_statement_reset(self->statement); 80 | Py_DECREF(self->statement); 81 | } 82 | 83 | Py_XDECREF(self->connection); 84 | Py_XDECREF(self->row_cast_map); 85 | Py_XDECREF(self->description); 86 | Py_XDECREF(self->lastrowid); 87 | Py_XDECREF(self->row_factory); 88 | Py_XDECREF(self->next_row); 89 | 90 | if (self->in_weakreflist != NULL) { 91 | PyObject_ClearWeakRefs((PyObject*)self); 92 | } 93 | 94 | Py_TYPE(self)->tp_free((PyObject*)self); 95 | } 96 | 97 | static PyObject * 98 | _pysqlite_get_converter(const char *keystr, Py_ssize_t keylen) 99 | { 100 | PyObject *key; 101 | PyObject *upcase_key; 102 | PyObject *retval; 103 | _Py_IDENTIFIER(upper); 104 | 105 | key = PyUnicode_FromStringAndSize(keystr, keylen); 106 | if (!key) { 107 | return NULL; 108 | } 109 | upcase_key = _PyObject_CallMethodId(key, &PyId_upper, NULL); 110 | Py_DECREF(key); 111 | if (!upcase_key) { 112 | return NULL; 113 | } 114 | 115 | retval = PyDict_GetItemWithError(_pysqlite_converters, upcase_key); 116 | Py_DECREF(upcase_key); 117 | 118 | return retval; 119 | } 120 | 121 | static int 122 | pysqlite_build_row_cast_map(pysqlite_Cursor* self) 123 | { 124 | int i; 125 | const char* pos; 126 | const char* colname; 127 | const char* decltype; 128 | PyObject* converter; 129 | 130 | if (!self->connection->detect_types) { 131 | return 0; 132 | } 133 | 134 | Py_XSETREF(self->row_cast_map, PyList_New(0)); 135 | if (!self->row_cast_map) { 136 | return -1; 137 | } 138 | 139 | for (i = 0; i < sqlite3_column_count(self->statement->st); i++) { 140 | converter = NULL; 141 | 142 | if (self->connection->detect_types & PARSE_COLNAMES) { 143 | colname = sqlite3_column_name(self->statement->st, i); 144 | if (colname) { 145 | const char *type_start = NULL; 146 | for (pos = colname; *pos != 0; pos++) { 147 | if (*pos == '[') { 148 | type_start = pos + 1; 149 | } 150 | else if (*pos == ']' && type_start != NULL) { 151 | converter = _pysqlite_get_converter(type_start, pos - type_start); 152 | if (!converter && PyErr_Occurred()) { 153 | Py_CLEAR(self->row_cast_map); 154 | return -1; 155 | } 156 | break; 157 | } 158 | } 159 | } 160 | } 161 | 162 | if (!converter && self->connection->detect_types & PARSE_DECLTYPES) { 163 | decltype = sqlite3_column_decltype(self->statement->st, i); 164 | if (decltype) { 165 | for (pos = decltype;;pos++) { 166 | /* Converter names are split at '(' and blanks. 167 | * This allows 'INTEGER NOT NULL' to be treated as 'INTEGER' and 168 | * 'NUMBER(10)' to be treated as 'NUMBER', for example. 169 | * In other words, it will work as people expect it to work.*/ 170 | if (*pos == ' ' || *pos == '(' || *pos == 0) { 171 | converter = _pysqlite_get_converter(decltype, pos - decltype); 172 | if (!converter && PyErr_Occurred()) { 173 | Py_CLEAR(self->row_cast_map); 174 | return -1; 175 | } 176 | break; 177 | } 178 | } 179 | } 180 | } 181 | 182 | if (!converter) { 183 | converter = Py_None; 184 | } 185 | 186 | if (PyList_Append(self->row_cast_map, converter) != 0) { 187 | Py_CLEAR(self->row_cast_map); 188 | return -1; 189 | } 190 | } 191 | 192 | return 0; 193 | } 194 | 195 | static PyObject * 196 | _pysqlite_build_column_name(pysqlite_Cursor *self, const char *colname) 197 | { 198 | const char* pos; 199 | Py_ssize_t len; 200 | 201 | if (!colname) { 202 | Py_RETURN_NONE; 203 | } 204 | 205 | if (self->connection->detect_types & PARSE_COLNAMES) { 206 | for (pos = colname; *pos; pos++) { 207 | if (*pos == '[') { 208 | if ((pos != colname) && (*(pos-1) == ' ')) { 209 | pos--; 210 | } 211 | break; 212 | } 213 | } 214 | len = pos - colname; 215 | } 216 | else { 217 | len = strlen(colname); 218 | } 219 | return PyUnicode_FromStringAndSize(colname, len); 220 | } 221 | 222 | static PyObject * 223 | _pysqlite_build_column_decltype(pysqlite_Cursor *self, const char *decltype) 224 | { 225 | if (!decltype) { 226 | Py_RETURN_NONE; 227 | } 228 | return PyUnicode_FromStringAndSize(decltype, strlen(decltype)); 229 | } 230 | 231 | /* 232 | * Returns a row from the currently active SQLite statement 233 | * 234 | * Precondidition: 235 | * - sqlite3_step() has been called before and it returned SQLITE_ROW. 236 | */ 237 | static PyObject * 238 | _pysqlite_fetch_one_row(pysqlite_Cursor* self) 239 | { 240 | int i, numcols; 241 | PyObject* row; 242 | PyObject* item = NULL; 243 | int coltype; 244 | PyObject* converter; 245 | PyObject* converted; 246 | Py_ssize_t nbytes; 247 | const char* val_str; 248 | char buf[200]; 249 | const char* colname; 250 | PyObject* error_msg; 251 | 252 | if (self->reset) { 253 | PyErr_SetString(pysqlite_InterfaceError, errmsg_fetch_across_rollback); 254 | return NULL; 255 | } 256 | 257 | Py_BEGIN_ALLOW_THREADS 258 | numcols = sqlite3_data_count(self->statement->st); 259 | Py_END_ALLOW_THREADS 260 | 261 | row = PyTuple_New(numcols); 262 | if (!row) 263 | return NULL; 264 | 265 | for (i = 0; i < numcols; i++) { 266 | if (self->connection->detect_types 267 | && self->row_cast_map != NULL 268 | && i < PyList_GET_SIZE(self->row_cast_map)) 269 | { 270 | converter = PyList_GET_ITEM(self->row_cast_map, i); 271 | } 272 | else { 273 | converter = Py_None; 274 | } 275 | 276 | if (converter != Py_None) { 277 | nbytes = sqlite3_column_bytes(self->statement->st, i); 278 | val_str = (const char*)sqlite3_column_blob(self->statement->st, i); 279 | if (!val_str) { 280 | Py_INCREF(Py_None); 281 | converted = Py_None; 282 | } else { 283 | item = PyBytes_FromStringAndSize(val_str, nbytes); 284 | if (!item) 285 | goto error; 286 | converted = PyObject_CallFunction(converter, "O", item); 287 | Py_DECREF(item); 288 | } 289 | } else { 290 | Py_BEGIN_ALLOW_THREADS 291 | coltype = sqlite3_column_type(self->statement->st, i); 292 | Py_END_ALLOW_THREADS 293 | if (coltype == SQLITE_NULL) { 294 | Py_INCREF(Py_None); 295 | converted = Py_None; 296 | } else if (coltype == SQLITE_INTEGER) { 297 | converted = PyLong_FromLongLong(sqlite3_column_int64(self->statement->st, i)); 298 | } else if (coltype == SQLITE_FLOAT) { 299 | converted = PyFloat_FromDouble(sqlite3_column_double(self->statement->st, i)); 300 | } else if (coltype == SQLITE_TEXT) { 301 | val_str = (const char*)sqlite3_column_text(self->statement->st, i); 302 | nbytes = sqlite3_column_bytes(self->statement->st, i); 303 | if (self->connection->text_factory == (PyObject*)&PyUnicode_Type) { 304 | converted = PyUnicode_FromStringAndSize(val_str, nbytes); 305 | if (!converted && PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) { 306 | PyErr_Clear(); 307 | colname = sqlite3_column_name(self->statement->st, i); 308 | if (!colname) { 309 | colname = ""; 310 | } 311 | PyOS_snprintf(buf, sizeof(buf) - 1, "Could not decode to UTF-8 column '%s' with text '%s'", 312 | colname , val_str); 313 | error_msg = PyUnicode_Decode(buf, strlen(buf), "ascii", "replace"); 314 | if (!error_msg) { 315 | PyErr_SetString(pysqlite_OperationalError, "Could not decode to UTF-8"); 316 | } else { 317 | PyErr_SetObject(pysqlite_OperationalError, error_msg); 318 | Py_DECREF(error_msg); 319 | } 320 | } 321 | } else if (self->connection->text_factory == (PyObject*)&PyBytes_Type) { 322 | converted = PyBytes_FromStringAndSize(val_str, nbytes); 323 | } else if (self->connection->text_factory == (PyObject*)&PyByteArray_Type) { 324 | converted = PyByteArray_FromStringAndSize(val_str, nbytes); 325 | } else { 326 | converted = PyObject_CallFunction(self->connection->text_factory, "y#", val_str, nbytes); 327 | } 328 | } else { 329 | /* coltype == SQLITE_BLOB */ 330 | nbytes = sqlite3_column_bytes(self->statement->st, i); 331 | converted = PyBytes_FromStringAndSize( 332 | sqlite3_column_blob(self->statement->st, i), nbytes); 333 | } 334 | } 335 | 336 | if (!converted) { 337 | goto error; 338 | } 339 | PyTuple_SET_ITEM(row, i, converted); 340 | } 341 | 342 | if (PyErr_Occurred()) 343 | goto error; 344 | 345 | return row; 346 | 347 | error: 348 | Py_DECREF(row); 349 | return NULL; 350 | } 351 | 352 | /* 353 | * Checks if a cursor object is usable. 354 | * 355 | * 0 => error; 1 => ok 356 | */ 357 | static int check_cursor(pysqlite_Cursor* cur) 358 | { 359 | if (!cur->initialized) { 360 | PyErr_SetString(pysqlite_ProgrammingError, "Base Cursor.__init__ not called."); 361 | return 0; 362 | } 363 | 364 | if (cur->closed) { 365 | PyErr_SetString(pysqlite_ProgrammingError, "Cannot operate on a closed cursor."); 366 | return 0; 367 | } 368 | 369 | if (cur->locked) { 370 | PyErr_SetString(pysqlite_ProgrammingError, "Recursive use of cursors not allowed."); 371 | return 0; 372 | } 373 | 374 | return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection); 375 | } 376 | 377 | static PyObject * 378 | _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args) 379 | { 380 | PyObject* operation; 381 | PyObject* parameters_list = NULL; 382 | PyObject* parameters_iter = NULL; 383 | PyObject* parameters = NULL; 384 | int i; 385 | int rc; 386 | PyObject* func_args; 387 | PyObject* result; 388 | int numcols; 389 | PyObject* column_name; 390 | PyObject* column_decltype; 391 | PyObject* second_argument = NULL; 392 | sqlite_int64 lastrowid; 393 | 394 | if (!check_cursor(self)) { 395 | goto error; 396 | } 397 | 398 | self->locked = 1; 399 | self->reset = 0; 400 | 401 | Py_CLEAR(self->next_row); 402 | 403 | if (multiple) { 404 | /* executemany() */ 405 | if (!PyArg_ParseTuple(args, "UO", &operation, &second_argument)) { 406 | goto error; 407 | } 408 | 409 | if (PyIter_Check(second_argument)) { 410 | /* iterator */ 411 | Py_INCREF(second_argument); 412 | parameters_iter = second_argument; 413 | } else { 414 | /* sequence */ 415 | parameters_iter = PyObject_GetIter(second_argument); 416 | if (!parameters_iter) { 417 | goto error; 418 | } 419 | } 420 | } else { 421 | /* execute() */ 422 | if (!PyArg_ParseTuple(args, "U|O", &operation, &second_argument)) { 423 | goto error; 424 | } 425 | 426 | parameters_list = PyList_New(0); 427 | if (!parameters_list) { 428 | goto error; 429 | } 430 | 431 | if (second_argument == NULL) { 432 | second_argument = PyTuple_New(0); 433 | if (!second_argument) { 434 | goto error; 435 | } 436 | } else { 437 | Py_INCREF(second_argument); 438 | } 439 | if (PyList_Append(parameters_list, second_argument) != 0) { 440 | Py_DECREF(second_argument); 441 | goto error; 442 | } 443 | Py_DECREF(second_argument); 444 | 445 | parameters_iter = PyObject_GetIter(parameters_list); 446 | if (!parameters_iter) { 447 | goto error; 448 | } 449 | } 450 | 451 | if (self->statement != NULL) { 452 | /* There is an active statement */ 453 | pysqlite_statement_reset(self->statement); 454 | } 455 | 456 | /* reset description and rowcount */ 457 | Py_INCREF(Py_None); 458 | Py_SETREF(self->description, Py_None); 459 | self->rowcount = 0L; 460 | 461 | func_args = PyTuple_New(1); 462 | if (!func_args) { 463 | goto error; 464 | } 465 | Py_INCREF(operation); 466 | if (PyTuple_SetItem(func_args, 0, operation) != 0) { 467 | goto error; 468 | } 469 | 470 | if (self->statement) { 471 | (void)pysqlite_statement_reset(self->statement); 472 | } 473 | 474 | Py_XSETREF(self->statement, 475 | (pysqlite_Statement *)pysqlite_cache_get(self->connection->statement_cache, func_args)); 476 | Py_DECREF(func_args); 477 | 478 | if (!self->statement) { 479 | goto error; 480 | } 481 | 482 | if (self->statement->in_use) { 483 | Py_SETREF(self->statement, 484 | PyObject_New(pysqlite_Statement, &pysqlite_StatementType)); 485 | if (!self->statement) { 486 | goto error; 487 | } 488 | rc = pysqlite_statement_create(self->statement, self->connection, operation); 489 | if (rc != SQLITE_OK) { 490 | Py_CLEAR(self->statement); 491 | goto error; 492 | } 493 | } 494 | 495 | pysqlite_statement_reset(self->statement); 496 | pysqlite_statement_mark_dirty(self->statement); 497 | 498 | /* We start a transaction implicitly before a DML statement. 499 | SELECT is the only exception. See #9924. */ 500 | if (self->connection->begin_statement && self->statement->is_dml) { 501 | if (sqlite3_get_autocommit(self->connection->db)) { 502 | result = _pysqlite_connection_begin(self->connection); 503 | if (!result) { 504 | goto error; 505 | } 506 | Py_DECREF(result); 507 | } 508 | } 509 | 510 | while (1) { 511 | parameters = PyIter_Next(parameters_iter); 512 | if (!parameters) { 513 | break; 514 | } 515 | 516 | pysqlite_statement_mark_dirty(self->statement); 517 | 518 | pysqlite_statement_bind_parameters(self->statement, parameters); 519 | if (PyErr_Occurred()) { 520 | goto error; 521 | } 522 | 523 | rc = pysqlite_step(self->statement->st, self->connection); 524 | if (rc != SQLITE_DONE && rc != SQLITE_ROW) { 525 | if (PyErr_Occurred()) { 526 | /* there was an error that occurred in a user-defined callback */ 527 | if (_pysqlite_enable_callback_tracebacks) { 528 | PyErr_Print(); 529 | } else { 530 | PyErr_Clear(); 531 | } 532 | } 533 | (void)pysqlite_statement_reset(self->statement); 534 | _pysqlite_seterror(self->connection->db); 535 | goto error; 536 | } 537 | 538 | if (pysqlite_build_row_cast_map(self) != 0) { 539 | PyErr_Format(pysqlite_OperationalError, "Error while building row_cast_map"); 540 | goto error; 541 | } 542 | 543 | assert(rc == SQLITE_ROW || rc == SQLITE_DONE); 544 | Py_BEGIN_ALLOW_THREADS 545 | numcols = sqlite3_column_count(self->statement->st); 546 | Py_END_ALLOW_THREADS 547 | if (self->description == Py_None && numcols > 0) { 548 | Py_SETREF(self->description, PyTuple_New(numcols)); 549 | if (!self->description) { 550 | goto error; 551 | } 552 | for (i = 0; i < numcols; i++) { 553 | const char *colname; 554 | const char *decltype; 555 | colname = sqlite3_column_name(self->statement->st, i); 556 | if (colname == NULL) { 557 | PyErr_NoMemory(); 558 | goto error; 559 | } 560 | column_name = _pysqlite_build_column_name(self, colname); 561 | if (!column_name) { 562 | goto error; 563 | } 564 | decltype = sqlite3_column_decltype(self->statement->st, i); 565 | column_decltype = _pysqlite_build_column_decltype(self, decltype); 566 | if (!column_decltype) { 567 | Py_DECREF(column_name); 568 | goto error; 569 | } 570 | 571 | PyObject *descriptor = PyTuple_Pack(7, column_name, column_decltype, 572 | Py_None, Py_None, Py_None, 573 | Py_None, Py_None); 574 | Py_DECREF(column_name); 575 | Py_DECREF(column_decltype); 576 | if (descriptor == NULL) { 577 | goto error; 578 | } 579 | PyTuple_SET_ITEM(self->description, i, descriptor); 580 | } 581 | } 582 | 583 | if (self->statement->is_dml) { 584 | self->rowcount += (long)sqlite3_changes(self->connection->db); 585 | } else { 586 | self->rowcount= -1L; 587 | } 588 | 589 | if (!multiple) { 590 | Py_DECREF(self->lastrowid); 591 | Py_BEGIN_ALLOW_THREADS 592 | lastrowid = sqlite3_last_insert_rowid(self->connection->db); 593 | Py_END_ALLOW_THREADS 594 | self->lastrowid = PyLong_FromLongLong(lastrowid); 595 | } 596 | 597 | if (rc == SQLITE_ROW) { 598 | if (multiple) { 599 | PyErr_SetString(pysqlite_ProgrammingError, "executemany() can only execute DML statements."); 600 | goto error; 601 | } 602 | 603 | self->next_row = _pysqlite_fetch_one_row(self); 604 | if (self->next_row == NULL) 605 | goto error; 606 | } else if (rc == SQLITE_DONE && !multiple) { 607 | pysqlite_statement_reset(self->statement); 608 | Py_CLEAR(self->statement); 609 | } 610 | 611 | if (multiple) { 612 | pysqlite_statement_reset(self->statement); 613 | } 614 | Py_XDECREF(parameters); 615 | } 616 | 617 | error: 618 | Py_XDECREF(parameters); 619 | Py_XDECREF(parameters_iter); 620 | Py_XDECREF(parameters_list); 621 | 622 | self->locked = 0; 623 | 624 | if (PyErr_Occurred()) { 625 | self->rowcount = -1L; 626 | return NULL; 627 | } else { 628 | Py_INCREF(self); 629 | return (PyObject*)self; 630 | } 631 | } 632 | 633 | PyObject* pysqlite_cursor_execute(pysqlite_Cursor* self, PyObject* args) 634 | { 635 | return _pysqlite_query_execute(self, 0, args); 636 | } 637 | 638 | PyObject* pysqlite_cursor_executemany(pysqlite_Cursor* self, PyObject* args) 639 | { 640 | return _pysqlite_query_execute(self, 1, args); 641 | } 642 | 643 | static PyObject * 644 | pysqlite_cursor_executescript(pysqlite_Cursor* self, PyObject* args) 645 | { 646 | PyObject* script_obj; 647 | const char* script_cstr; 648 | sqlite3_stmt* statement; 649 | int rc; 650 | PyObject* result; 651 | 652 | if (!PyArg_ParseTuple(args, "O", &script_obj)) { 653 | return NULL; 654 | } 655 | 656 | if (!check_cursor(self)) { 657 | return NULL; 658 | } 659 | 660 | self->reset = 0; 661 | 662 | if (PyUnicode_Check(script_obj)) { 663 | script_cstr = PyUnicode_AsUTF8(script_obj); 664 | if (!script_cstr) { 665 | return NULL; 666 | } 667 | } else { 668 | PyErr_SetString(PyExc_ValueError, "script argument must be unicode."); 669 | return NULL; 670 | } 671 | 672 | /* commit first */ 673 | result = pysqlite_connection_commit(self->connection, NULL); 674 | if (!result) { 675 | goto error; 676 | } 677 | Py_DECREF(result); 678 | 679 | while (1) { 680 | Py_BEGIN_ALLOW_THREADS 681 | rc = sqlite3_prepare_v2(self->connection->db, 682 | script_cstr, 683 | -1, 684 | &statement, 685 | &script_cstr); 686 | Py_END_ALLOW_THREADS 687 | if (rc != SQLITE_OK) { 688 | _pysqlite_seterror(self->connection->db); 689 | goto error; 690 | } 691 | 692 | /* execute statement, and ignore results of SELECT statements */ 693 | do { 694 | rc = pysqlite_step(statement, self->connection); 695 | if (PyErr_Occurred()) { 696 | (void)sqlite3_finalize(statement); 697 | goto error; 698 | } 699 | } while (rc == SQLITE_ROW); 700 | 701 | if (rc != SQLITE_DONE) { 702 | (void)sqlite3_finalize(statement); 703 | _pysqlite_seterror(self->connection->db); 704 | goto error; 705 | } 706 | 707 | rc = sqlite3_finalize(statement); 708 | if (rc != SQLITE_OK) { 709 | _pysqlite_seterror(self->connection->db); 710 | goto error; 711 | } 712 | 713 | if (*script_cstr == (char)0) { 714 | break; 715 | } 716 | } 717 | 718 | error: 719 | if (PyErr_Occurred()) { 720 | return NULL; 721 | } else { 722 | Py_INCREF(self); 723 | return (PyObject*)self; 724 | } 725 | } 726 | 727 | PyObject* pysqlite_cursor_iternext(pysqlite_Cursor *self) 728 | { 729 | PyObject* next_row_tuple; 730 | PyObject* next_row; 731 | int rc; 732 | 733 | if (!check_cursor(self)) { 734 | return NULL; 735 | } 736 | 737 | if (self->reset) { 738 | PyErr_SetString(pysqlite_InterfaceError, errmsg_fetch_across_rollback); 739 | return NULL; 740 | } 741 | 742 | if (!self->next_row) { 743 | if (self->statement) { 744 | (void)pysqlite_statement_reset(self->statement); 745 | Py_CLEAR(self->statement); 746 | } 747 | return NULL; 748 | } 749 | 750 | next_row_tuple = self->next_row; 751 | assert(next_row_tuple != NULL); 752 | self->next_row = NULL; 753 | 754 | if (self->row_factory != Py_None) { 755 | next_row = PyObject_CallFunction(self->row_factory, "OO", self, next_row_tuple); 756 | if (next_row == NULL) { 757 | self->next_row = next_row_tuple; 758 | return NULL; 759 | } 760 | Py_DECREF(next_row_tuple); 761 | } else { 762 | next_row = next_row_tuple; 763 | } 764 | 765 | if (self->statement) { 766 | rc = pysqlite_step(self->statement->st, self->connection); 767 | if (PyErr_Occurred()) { 768 | (void)pysqlite_statement_reset(self->statement); 769 | Py_DECREF(next_row); 770 | return NULL; 771 | } 772 | if (rc != SQLITE_DONE && rc != SQLITE_ROW) { 773 | (void)pysqlite_statement_reset(self->statement); 774 | Py_DECREF(next_row); 775 | _pysqlite_seterror(self->connection->db); 776 | return NULL; 777 | } 778 | 779 | if (rc == SQLITE_ROW) { 780 | self->next_row = _pysqlite_fetch_one_row(self); 781 | if (self->next_row == NULL) { 782 | (void)pysqlite_statement_reset(self->statement); 783 | return NULL; 784 | } 785 | } 786 | } 787 | 788 | return next_row; 789 | } 790 | 791 | PyObject* pysqlite_cursor_fetchone(pysqlite_Cursor* self, PyObject* args) 792 | { 793 | PyObject* row; 794 | 795 | row = pysqlite_cursor_iternext(self); 796 | if (!row && !PyErr_Occurred()) { 797 | Py_RETURN_NONE; 798 | } 799 | 800 | return row; 801 | } 802 | 803 | PyObject* pysqlite_cursor_fetchmany(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs) 804 | { 805 | static char *kwlist[] = {"size", NULL}; 806 | 807 | PyObject* row; 808 | PyObject* list; 809 | int maxrows = self->arraysize; 810 | int counter = 0; 811 | 812 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:fetchmany", kwlist, &maxrows)) { 813 | return NULL; 814 | } 815 | 816 | list = PyList_New(0); 817 | if (!list) { 818 | return NULL; 819 | } 820 | 821 | while ((row = pysqlite_cursor_iternext(self))) { 822 | PyList_Append(list, row); 823 | Py_XDECREF(row); 824 | 825 | if (++counter == maxrows) { 826 | break; 827 | } 828 | } 829 | 830 | if (PyErr_Occurred()) { 831 | Py_DECREF(list); 832 | return NULL; 833 | } else { 834 | return list; 835 | } 836 | } 837 | 838 | PyObject* pysqlite_cursor_fetchall(pysqlite_Cursor* self, PyObject* args) 839 | { 840 | PyObject* row; 841 | PyObject* list; 842 | 843 | list = PyList_New(0); 844 | if (!list) { 845 | return NULL; 846 | } 847 | 848 | while ((row = pysqlite_cursor_iternext(self))) { 849 | PyList_Append(list, row); 850 | Py_XDECREF(row); 851 | } 852 | 853 | if (PyErr_Occurred()) { 854 | Py_DECREF(list); 855 | return NULL; 856 | } else { 857 | return list; 858 | } 859 | } 860 | 861 | PyObject* pysqlite_noop(pysqlite_Connection* self, PyObject* args) 862 | { 863 | /* don't care, return None */ 864 | Py_RETURN_NONE; 865 | } 866 | 867 | PyObject* pysqlite_cursor_close(pysqlite_Cursor* self, PyObject* args) 868 | { 869 | if (!self->connection) { 870 | PyErr_SetString(pysqlite_ProgrammingError, 871 | "Base Cursor.__init__ not called."); 872 | return NULL; 873 | } 874 | if (!pysqlite_check_thread(self->connection) || !pysqlite_check_connection(self->connection)) { 875 | return NULL; 876 | } 877 | 878 | if (self->statement) { 879 | (void)pysqlite_statement_reset(self->statement); 880 | Py_CLEAR(self->statement); 881 | } 882 | 883 | self->closed = 1; 884 | 885 | Py_RETURN_NONE; 886 | } 887 | 888 | static PyMethodDef cursor_methods[] = { 889 | {"execute", (PyCFunction)pysqlite_cursor_execute, METH_VARARGS, 890 | PyDoc_STR("Executes a SQL statement.")}, 891 | {"executemany", (PyCFunction)pysqlite_cursor_executemany, METH_VARARGS, 892 | PyDoc_STR("Repeatedly executes a SQL statement.")}, 893 | {"executescript", (PyCFunction)pysqlite_cursor_executescript, METH_VARARGS, 894 | PyDoc_STR("Executes a multiple SQL statements at once. Non-standard.")}, 895 | {"fetchone", (PyCFunction)pysqlite_cursor_fetchone, METH_NOARGS, 896 | PyDoc_STR("Fetches one row from the resultset.")}, 897 | {"fetchmany", (PyCFunction)(void(*)(void))pysqlite_cursor_fetchmany, METH_VARARGS|METH_KEYWORDS, 898 | PyDoc_STR("Fetches several rows from the resultset.")}, 899 | {"fetchall", (PyCFunction)pysqlite_cursor_fetchall, METH_NOARGS, 900 | PyDoc_STR("Fetches all rows from the resultset.")}, 901 | {"close", (PyCFunction)pysqlite_cursor_close, METH_NOARGS, 902 | PyDoc_STR("Closes the cursor.")}, 903 | {"setinputsizes", (PyCFunction)pysqlite_noop, METH_VARARGS, 904 | PyDoc_STR("Required by DB-API. Does nothing in pysqlite.")}, 905 | {"setoutputsize", (PyCFunction)pysqlite_noop, METH_VARARGS, 906 | PyDoc_STR("Required by DB-API. Does nothing in pysqlite.")}, 907 | {NULL, NULL} 908 | }; 909 | 910 | static struct PyMemberDef cursor_members[] = 911 | { 912 | {"connection", T_OBJECT, offsetof(pysqlite_Cursor, connection), READONLY}, 913 | {"description", T_OBJECT, offsetof(pysqlite_Cursor, description), READONLY}, 914 | {"arraysize", T_INT, offsetof(pysqlite_Cursor, arraysize), 0}, 915 | {"lastrowid", T_OBJECT, offsetof(pysqlite_Cursor, lastrowid), READONLY}, 916 | {"rowcount", T_LONG, offsetof(pysqlite_Cursor, rowcount), READONLY}, 917 | {"row_factory", T_OBJECT, offsetof(pysqlite_Cursor, row_factory), 0}, 918 | {NULL} 919 | }; 920 | 921 | static const char cursor_doc[] = 922 | PyDoc_STR("SQLite database cursor class."); 923 | 924 | PyTypeObject pysqlite_CursorType = { 925 | PyVarObject_HEAD_INIT(NULL, 0) 926 | MODULE_NAME ".Cursor", /* tp_name */ 927 | sizeof(pysqlite_Cursor), /* tp_basicsize */ 928 | 0, /* tp_itemsize */ 929 | (destructor)pysqlite_cursor_dealloc, /* tp_dealloc */ 930 | 0, /* tp_print */ 931 | 0, /* tp_getattr */ 932 | 0, /* tp_setattr */ 933 | 0, /* tp_reserved */ 934 | 0, /* tp_repr */ 935 | 0, /* tp_as_number */ 936 | 0, /* tp_as_sequence */ 937 | 0, /* tp_as_mapping */ 938 | 0, /* tp_hash */ 939 | 0, /* tp_call */ 940 | 0, /* tp_str */ 941 | 0, /* tp_getattro */ 942 | 0, /* tp_setattro */ 943 | 0, /* tp_as_buffer */ 944 | Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ 945 | cursor_doc, /* tp_doc */ 946 | 0, /* tp_traverse */ 947 | 0, /* tp_clear */ 948 | 0, /* tp_richcompare */ 949 | offsetof(pysqlite_Cursor, in_weakreflist), /* tp_weaklistoffset */ 950 | PyObject_SelfIter, /* tp_iter */ 951 | (iternextfunc)pysqlite_cursor_iternext, /* tp_iternext */ 952 | cursor_methods, /* tp_methods */ 953 | cursor_members, /* tp_members */ 954 | 0, /* tp_getset */ 955 | 0, /* tp_base */ 956 | 0, /* tp_dict */ 957 | 0, /* tp_descr_get */ 958 | 0, /* tp_descr_set */ 959 | 0, /* tp_dictoffset */ 960 | (initproc)pysqlite_cursor_init, /* tp_init */ 961 | 0, /* tp_alloc */ 962 | 0, /* tp_new */ 963 | 0 /* tp_free */ 964 | }; 965 | 966 | extern int pysqlite_cursor_setup_types(void) 967 | { 968 | pysqlite_CursorType.tp_new = PyType_GenericNew; 969 | return PyType_Ready(&pysqlite_CursorType); 970 | } 971 | -------------------------------------------------------------------------------- /src/cursor.h: -------------------------------------------------------------------------------- 1 | /* cursor.h - definitions for the cursor type 2 | * 3 | * Copyright (C) 2004-2010 Gerhard Häring 4 | * 5 | * This file is part of pysqlite. 6 | * 7 | * This software is provided 'as-is', without any express or implied 8 | * warranty. In no event will the authors be held liable for any damages 9 | * arising from the use of this software. 10 | * 11 | * Permission is granted to anyone to use this software for any purpose, 12 | * including commercial applications, and to alter it and redistribute it 13 | * freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not 16 | * claim that you wrote the original software. If you use this software 17 | * in a product, an acknowledgment in the product documentation would be 18 | * appreciated but is not required. 19 | * 2. Altered source versions must be plainly marked as such, and must not be 20 | * misrepresented as being the original software. 21 | * 3. This notice may not be removed or altered from any source distribution. 22 | */ 23 | 24 | #ifndef PYSQLITE_CURSOR_H 25 | #define PYSQLITE_CURSOR_H 26 | #define PY_SSIZE_T_CLEAN 27 | #include "Python.h" 28 | 29 | #include "statement.h" 30 | #include "connection.h" 31 | #include "module.h" 32 | 33 | typedef struct 34 | { 35 | PyObject_HEAD 36 | pysqlite_Connection* connection; 37 | PyObject* description; 38 | PyObject* row_cast_map; 39 | int arraysize; 40 | PyObject* lastrowid; 41 | long rowcount; 42 | PyObject* row_factory; 43 | pysqlite_Statement* statement; 44 | int closed; 45 | int reset; 46 | int locked; 47 | int initialized; 48 | 49 | /* the next row to be returned, NULL if no next row available */ 50 | PyObject* next_row; 51 | 52 | PyObject* in_weakreflist; /* List of weak references */ 53 | } pysqlite_Cursor; 54 | 55 | extern PyTypeObject pysqlite_CursorType; 56 | 57 | PyObject* pysqlite_cursor_execute(pysqlite_Cursor* self, PyObject* args); 58 | PyObject* pysqlite_cursor_executemany(pysqlite_Cursor* self, PyObject* args); 59 | PyObject* pysqlite_cursor_getiter(pysqlite_Cursor *self); 60 | PyObject* pysqlite_cursor_iternext(pysqlite_Cursor *self); 61 | PyObject* pysqlite_cursor_fetchone(pysqlite_Cursor* self, PyObject* args); 62 | PyObject* pysqlite_cursor_fetchmany(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs); 63 | PyObject* pysqlite_cursor_fetchall(pysqlite_Cursor* self, PyObject* args); 64 | PyObject* pysqlite_noop(pysqlite_Connection* self, PyObject* args); 65 | PyObject* pysqlite_cursor_close(pysqlite_Cursor* self, PyObject* args); 66 | 67 | int pysqlite_cursor_setup_types(void); 68 | 69 | #define UNKNOWN (-1) 70 | #endif 71 | -------------------------------------------------------------------------------- /src/microprotocols.c: -------------------------------------------------------------------------------- 1 | /* microprotocols.c - minimalist and non-validating protocols implementation 2 | * 3 | * Copyright (C) 2003-2004 Federico Di Gregorio 4 | * 5 | * This file is part of psycopg and was adapted for pysqlite. Federico Di 6 | * Gregorio gave the permission to use it within pysqlite under the following 7 | * license: 8 | * 9 | * This software is provided 'as-is', without any express or implied 10 | * warranty. In no event will the authors be held liable for any damages 11 | * arising from the use of this software. 12 | * 13 | * Permission is granted to anyone to use this software for any purpose, 14 | * including commercial applications, and to alter it and redistribute it 15 | * freely, subject to the following restrictions: 16 | * 17 | * 1. The origin of this software must not be misrepresented; you must not 18 | * claim that you wrote the original software. If you use this software 19 | * in a product, an acknowledgment in the product documentation would be 20 | * appreciated but is not required. 21 | * 2. Altered source versions must be plainly marked as such, and must not be 22 | * misrepresented as being the original software. 23 | * 3. This notice may not be removed or altered from any source distribution. 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | #include "cursor.h" 30 | #include "microprotocols.h" 31 | #include "prepare_protocol.h" 32 | 33 | 34 | /** the adapters registry **/ 35 | 36 | static PyObject *psyco_adapters = NULL; 37 | 38 | /* pysqlite_microprotocols_init - initialize the adapters dictionary */ 39 | 40 | int 41 | pysqlite_microprotocols_init(PyObject *dict) 42 | { 43 | /* create adapters dictionary and put it in module namespace */ 44 | if ((psyco_adapters = PyDict_New()) == NULL) { 45 | return -1; 46 | } 47 | 48 | return PyDict_SetItemString(dict, "adapters", psyco_adapters); 49 | } 50 | 51 | 52 | /* pysqlite_microprotocols_add - add a reverse type-caster to the dictionary */ 53 | 54 | int 55 | pysqlite_microprotocols_add(PyTypeObject *type, PyObject *proto, PyObject *cast) 56 | { 57 | PyObject* key; 58 | int rc; 59 | 60 | if (proto == NULL) proto = (PyObject*)&pysqlite_PrepareProtocolType; 61 | 62 | key = Py_BuildValue("(OO)", (PyObject*)type, proto); 63 | if (!key) { 64 | return -1; 65 | } 66 | 67 | rc = PyDict_SetItem(psyco_adapters, key, cast); 68 | Py_DECREF(key); 69 | 70 | return rc; 71 | } 72 | 73 | /* pysqlite_microprotocols_adapt - adapt an object to the built-in protocol */ 74 | 75 | PyObject * 76 | pysqlite_microprotocols_adapt(PyObject *obj, PyObject *proto, PyObject *alt) 77 | { 78 | PyObject *adapter, *key, *adapted; 79 | 80 | /* we don't check for exact type conformance as specified in PEP 246 81 | because the pysqlite_PrepareProtocolType type is abstract and there is no 82 | way to get a quotable object to be its instance */ 83 | 84 | /* look for an adapter in the registry */ 85 | key = Py_BuildValue("(OO)", (PyObject*)obj->ob_type, proto); 86 | if (!key) { 87 | return NULL; 88 | } 89 | adapter = PyDict_GetItemWithError(psyco_adapters, key); 90 | Py_DECREF(key); 91 | if (adapter) { 92 | Py_INCREF(adapter); 93 | adapted = PyObject_CallFunctionObjArgs(adapter, obj, NULL); 94 | Py_DECREF(adapter); 95 | return adapted; 96 | } 97 | if (PyErr_Occurred()) { 98 | return NULL; 99 | } 100 | 101 | /* try to have the protocol adapt this object*/ 102 | if (PyObject_HasAttrString(proto, "__adapt__")) { 103 | _Py_IDENTIFIER(__adapt__); 104 | adapted = _PyObject_CallMethodId(proto, &PyId___adapt__, "O", obj); 105 | 106 | if (adapted == Py_None) { 107 | Py_DECREF(adapted); 108 | } 109 | else if (adapted || !PyErr_ExceptionMatches(PyExc_TypeError)) { 110 | return adapted; 111 | } 112 | else { 113 | PyErr_Clear(); 114 | } 115 | } 116 | 117 | /* and finally try to have the object adapt itself */ 118 | if (PyObject_HasAttrString(obj, "__conform__")) { 119 | _Py_IDENTIFIER(__conform__); 120 | PyObject *adapted = _PyObject_CallMethodId(obj, &PyId___conform__,"O", proto); 121 | 122 | if (adapted == Py_None) { 123 | Py_DECREF(adapted); 124 | } 125 | else if (adapted || !PyErr_ExceptionMatches(PyExc_TypeError)) { 126 | return adapted; 127 | } 128 | else { 129 | PyErr_Clear(); 130 | } 131 | } 132 | 133 | if (alt) { 134 | Py_INCREF(alt); 135 | return alt; 136 | } 137 | 138 | /* else set the right exception and return NULL */ 139 | PyErr_SetString(pysqlite_ProgrammingError, "can't adapt"); 140 | return NULL; 141 | } 142 | 143 | /** module-level functions **/ 144 | 145 | PyObject * 146 | pysqlite_adapt(pysqlite_Cursor *self, PyObject *args) 147 | { 148 | PyObject *obj, *alt = NULL; 149 | PyObject *proto = (PyObject*)&pysqlite_PrepareProtocolType; 150 | 151 | if (!PyArg_ParseTuple(args, "O|OO", &obj, &proto, &alt)) return NULL; 152 | return pysqlite_microprotocols_adapt(obj, proto, alt); 153 | } 154 | -------------------------------------------------------------------------------- /src/microprotocols.h: -------------------------------------------------------------------------------- 1 | /* microprotocols.c - definitions for minimalist and non-validating protocols 2 | * 3 | * Copyright (C) 2003-2004 Federico Di Gregorio 4 | * 5 | * This file is part of psycopg and was adapted for pysqlite. Federico Di 6 | * Gregorio gave the permission to use it within pysqlite under the following 7 | * license: 8 | * 9 | * This software is provided 'as-is', without any express or implied 10 | * warranty. In no event will the authors be held liable for any damages 11 | * arising from the use of this software. 12 | * 13 | * Permission is granted to anyone to use this software for any purpose, 14 | * including commercial applications, and to alter it and redistribute it 15 | * freely, subject to the following restrictions: 16 | * 17 | * 1. The origin of this software must not be misrepresented; you must not 18 | * claim that you wrote the original software. If you use this software 19 | * in a product, an acknowledgment in the product documentation would be 20 | * appreciated but is not required. 21 | * 2. Altered source versions must be plainly marked as such, and must not be 22 | * misrepresented as being the original software. 23 | * 3. This notice may not be removed or altered from any source distribution. 24 | */ 25 | 26 | #ifndef PSYCOPG_MICROPROTOCOLS_H 27 | #define PSYCOPG_MICROPROTOCOLS_H 1 28 | 29 | #define PY_SSIZE_T_CLEAN 30 | #include 31 | 32 | /** the names of the three mandatory methods **/ 33 | 34 | #define MICROPROTOCOLS_GETQUOTED_NAME "getquoted" 35 | #define MICROPROTOCOLS_GETSTRING_NAME "getstring" 36 | #define MICROPROTOCOLS_GETBINARY_NAME "getbinary" 37 | 38 | /** exported functions **/ 39 | 40 | /* used by module.c to init the microprotocols system */ 41 | extern int pysqlite_microprotocols_init(PyObject *dict); 42 | extern int pysqlite_microprotocols_add( 43 | PyTypeObject *type, PyObject *proto, PyObject *cast); 44 | extern PyObject *pysqlite_microprotocols_adapt( 45 | PyObject *obj, PyObject *proto, PyObject *alt); 46 | 47 | extern PyObject * 48 | pysqlite_adapt(pysqlite_Cursor* self, PyObject *args); 49 | #define pysqlite_adapt_doc \ 50 | "adapt(obj, protocol, alternate) -> adapt obj to given protocol. Non-standard." 51 | 52 | #endif /* !defined(PSYCOPG_MICROPROTOCOLS_H) */ 53 | -------------------------------------------------------------------------------- /src/module.c: -------------------------------------------------------------------------------- 1 | /* module.c - the module itself 2 | * 3 | * Copyright (C) 2004-2010 Gerhard Häring 4 | * 5 | * This file is part of pysqlite. 6 | * 7 | * This software is provided 'as-is', without any express or implied 8 | * warranty. In no event will the authors be held liable for any damages 9 | * arising from the use of this software. 10 | * 11 | * Permission is granted to anyone to use this software for any purpose, 12 | * including commercial applications, and to alter it and redistribute it 13 | * freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not 16 | * claim that you wrote the original software. If you use this software 17 | * in a product, an acknowledgment in the product documentation would be 18 | * appreciated but is not required. 19 | * 2. Altered source versions must be plainly marked as such, and must not be 20 | * misrepresented as being the original software. 21 | * 3. This notice may not be removed or altered from any source distribution. 22 | */ 23 | 24 | #include "connection.h" 25 | #include "statement.h" 26 | #include "cursor.h" 27 | #include "cache.h" 28 | #include "prepare_protocol.h" 29 | #include "microprotocols.h" 30 | #include "row.h" 31 | #include "blob.h" 32 | 33 | #if SQLITE_VERSION_NUMBER >= 3003003 34 | #define HAVE_SHARED_CACHE 35 | #endif 36 | 37 | /* static objects at module-level */ 38 | 39 | PyObject *pysqlite_Error = NULL; 40 | PyObject *pysqlite_Warning = NULL; 41 | PyObject *pysqlite_InterfaceError = NULL; 42 | PyObject *pysqlite_DatabaseError = NULL; 43 | PyObject *pysqlite_InternalError = NULL; 44 | PyObject *pysqlite_OperationalError = NULL; 45 | PyObject *pysqlite_ProgrammingError = NULL; 46 | PyObject *pysqlite_IntegrityError = NULL; 47 | PyObject *pysqlite_DataError = NULL; 48 | PyObject *pysqlite_NotSupportedError = NULL; 49 | 50 | PyObject* _pysqlite_converters = NULL; 51 | int _pysqlite_enable_callback_tracebacks = 0; 52 | int pysqlite_BaseTypeAdapted = 0; 53 | 54 | static PyObject* module_connect(PyObject* self, PyObject* args, PyObject* 55 | kwargs) 56 | { 57 | /* Python seems to have no way of extracting a single keyword-arg at 58 | * C-level, so this code is redundant with the one in connection_init in 59 | * connection.c and must always be copied from there ... */ 60 | 61 | static char *kwlist[] = { 62 | "database", "timeout", "detect_types", "isolation_level", 63 | "check_same_thread", "factory", "cached_statements", "uri", 64 | "flags", "vfs", NULL 65 | }; 66 | PyObject* database; 67 | int detect_types = 0; 68 | PyObject* isolation_level; 69 | PyObject* factory = NULL; 70 | int check_same_thread = 1; 71 | int cached_statements; 72 | int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; 73 | char *vfs = NULL; 74 | int uri = 0; 75 | double timeout = 5.0; 76 | 77 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|diOiOipiz", kwlist, 78 | &database, &timeout, &detect_types, 79 | &isolation_level, &check_same_thread, 80 | &factory, &cached_statements, &uri, 81 | &flags, &vfs)) 82 | { 83 | return NULL; 84 | } 85 | 86 | if (factory == NULL) { 87 | factory = (PyObject*)&pysqlite_ConnectionType; 88 | } 89 | 90 | return PyObject_Call(factory, args, kwargs); 91 | } 92 | 93 | PyDoc_STRVAR(module_connect_doc, 94 | "connect(database[, timeout, detect_types, isolation_level,\n\ 95 | check_same_thread, factory, cached_statements, uri, flags, vfs])\n\ 96 | \n\ 97 | Opens a connection to the SQLite database file *database*. You can use\n\ 98 | \":memory:\" to open a database connection to a database that resides in\n\ 99 | RAM instead of on disk."); 100 | 101 | static PyObject* module_complete(PyObject* self, PyObject* args, PyObject* 102 | kwargs) 103 | { 104 | static char *kwlist[] = {"statement", NULL}; 105 | char* statement; 106 | 107 | PyObject* result; 108 | 109 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &statement)) 110 | { 111 | return NULL; 112 | } 113 | 114 | if (sqlite3_complete(statement)) { 115 | result = Py_True; 116 | } else { 117 | result = Py_False; 118 | } 119 | 120 | Py_INCREF(result); 121 | 122 | return result; 123 | } 124 | 125 | PyDoc_STRVAR(module_complete_doc, 126 | "complete_statement(sql)\n\ 127 | \n\ 128 | Checks if a string contains a complete SQL statement. Non-standard."); 129 | 130 | #ifdef HAVE_SHARED_CACHE 131 | static PyObject* module_enable_shared_cache(PyObject* self, PyObject* args, PyObject* 132 | kwargs) 133 | { 134 | static char *kwlist[] = {"do_enable", NULL}; 135 | int do_enable; 136 | int rc; 137 | 138 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &do_enable)) 139 | { 140 | return NULL; 141 | } 142 | 143 | rc = sqlite3_enable_shared_cache(do_enable); 144 | 145 | if (rc != SQLITE_OK) { 146 | PyErr_SetString(pysqlite_OperationalError, "Changing the shared_cache flag failed"); 147 | return NULL; 148 | } else { 149 | Py_RETURN_NONE; 150 | } 151 | } 152 | 153 | PyDoc_STRVAR(module_enable_shared_cache_doc, 154 | "enable_shared_cache(do_enable)\n\ 155 | \n\ 156 | Enable or disable shared cache mode for the calling thread.\n\ 157 | Experimental/Non-standard."); 158 | #endif /* HAVE_SHARED_CACHE */ 159 | 160 | static PyObject* module_register_adapter(PyObject* self, PyObject* args) 161 | { 162 | PyTypeObject* type; 163 | PyObject* caster; 164 | int rc; 165 | 166 | if (!PyArg_ParseTuple(args, "OO", &type, &caster)) { 167 | return NULL; 168 | } 169 | 170 | /* a basic type is adapted; there's a performance optimization if that's not the case 171 | * (99 % of all usages) */ 172 | if (type == &PyLong_Type || type == &PyFloat_Type 173 | || type == &PyUnicode_Type || type == &PyByteArray_Type) { 174 | pysqlite_BaseTypeAdapted = 1; 175 | } 176 | 177 | rc = pysqlite_microprotocols_add(type, (PyObject*)&pysqlite_PrepareProtocolType, caster); 178 | if (rc == -1) 179 | return NULL; 180 | 181 | Py_RETURN_NONE; 182 | } 183 | 184 | PyDoc_STRVAR(module_register_adapter_doc, 185 | "register_adapter(type, callable)\n\ 186 | \n\ 187 | Registers an adapter with pysqlite's adapter registry. Non-standard."); 188 | 189 | static PyObject* module_register_converter(PyObject* self, PyObject* args) 190 | { 191 | PyObject* orig_name; 192 | PyObject* name = NULL; 193 | PyObject* callable; 194 | PyObject* retval = NULL; 195 | _Py_IDENTIFIER(upper); 196 | 197 | if (!PyArg_ParseTuple(args, "UO", &orig_name, &callable)) { 198 | return NULL; 199 | } 200 | 201 | /* convert the name to upper case */ 202 | name = _PyObject_CallMethodId(orig_name, &PyId_upper, NULL); 203 | if (!name) { 204 | goto error; 205 | } 206 | 207 | if (PyDict_SetItem(_pysqlite_converters, name, callable) != 0) { 208 | goto error; 209 | } 210 | 211 | Py_INCREF(Py_None); 212 | retval = Py_None; 213 | error: 214 | Py_XDECREF(name); 215 | return retval; 216 | } 217 | 218 | PyDoc_STRVAR(module_register_converter_doc, 219 | "register_converter(typename, callable)\n\ 220 | \n\ 221 | Registers a converter with pysqlite. Non-standard."); 222 | 223 | static PyObject* enable_callback_tracebacks(PyObject* self, PyObject* args) 224 | { 225 | if (!PyArg_ParseTuple(args, "i", &_pysqlite_enable_callback_tracebacks)) { 226 | return NULL; 227 | } 228 | 229 | Py_RETURN_NONE; 230 | } 231 | 232 | PyDoc_STRVAR(enable_callback_tracebacks_doc, 233 | "enable_callback_tracebacks(flag)\n\ 234 | \n\ 235 | Enable or disable callback functions throwing errors to stderr."); 236 | 237 | static void converters_init(PyObject* dict) 238 | { 239 | _pysqlite_converters = PyDict_New(); 240 | if (!_pysqlite_converters) { 241 | return; 242 | } 243 | 244 | PyDict_SetItemString(dict, "converters", _pysqlite_converters); 245 | } 246 | 247 | static PyMethodDef module_methods[] = { 248 | {"connect", (PyCFunction)(void(*)(void))module_connect, 249 | METH_VARARGS | METH_KEYWORDS, module_connect_doc}, 250 | {"complete_statement", (PyCFunction)(void(*)(void))module_complete, 251 | METH_VARARGS | METH_KEYWORDS, module_complete_doc}, 252 | #ifdef HAVE_SHARED_CACHE 253 | {"enable_shared_cache", (PyCFunction)(void(*)(void))module_enable_shared_cache, 254 | METH_VARARGS | METH_KEYWORDS, module_enable_shared_cache_doc}, 255 | #endif 256 | {"register_adapter", (PyCFunction)module_register_adapter, 257 | METH_VARARGS, module_register_adapter_doc}, 258 | {"register_converter", (PyCFunction)module_register_converter, 259 | METH_VARARGS, module_register_converter_doc}, 260 | {"adapt", (PyCFunction)pysqlite_adapt, METH_VARARGS, 261 | pysqlite_adapt_doc}, 262 | {"enable_callback_tracebacks", (PyCFunction)enable_callback_tracebacks, 263 | METH_VARARGS, enable_callback_tracebacks_doc}, 264 | {NULL, NULL} 265 | }; 266 | 267 | struct _IntConstantPair { 268 | const char *constant_name; 269 | int constant_value; 270 | }; 271 | 272 | typedef struct _IntConstantPair IntConstantPair; 273 | 274 | /* sqlite API error codes */ 275 | static const IntConstantPair _error_codes[] = { 276 | {"SQLITE_OK", SQLITE_OK}, 277 | {"SQLITE_ERROR", SQLITE_ERROR}, 278 | {"SQLITE_INTERNAL", SQLITE_INTERNAL}, 279 | {"SQLITE_PERM", SQLITE_PERM}, 280 | {"SQLITE_ABORT", SQLITE_ABORT}, 281 | {"SQLITE_BUSY", SQLITE_BUSY}, 282 | {"SQLITE_LOCKED", SQLITE_LOCKED}, 283 | {"SQLITE_NOMEM", SQLITE_NOMEM}, 284 | {"SQLITE_READONLY", SQLITE_READONLY}, 285 | {"SQLITE_INTERRUPT", SQLITE_INTERRUPT}, 286 | {"SQLITE_IOERR", SQLITE_IOERR}, 287 | {"SQLITE_CORRUPT", SQLITE_CORRUPT}, 288 | {"SQLITE_NOTFOUND", SQLITE_NOTFOUND}, 289 | {"SQLITE_FULL", SQLITE_FULL}, 290 | {"SQLITE_CANTOPEN", SQLITE_CANTOPEN}, 291 | {"SQLITE_PROTOCOL", SQLITE_PROTOCOL}, 292 | {"SQLITE_EMPTY", SQLITE_EMPTY}, 293 | {"SQLITE_SCHEMA", SQLITE_SCHEMA}, 294 | {"SQLITE_TOOBIG", SQLITE_TOOBIG}, 295 | {"SQLITE_CONSTRAINT", SQLITE_CONSTRAINT}, 296 | {"SQLITE_MISMATCH", SQLITE_MISMATCH}, 297 | {"SQLITE_MISUSE", SQLITE_MISUSE}, 298 | #ifdef SQLITE_NOLFS 299 | {"SQLITE_NOLFS", SQLITE_NOLFS}, 300 | #endif 301 | #ifdef SQLITE_AUTH 302 | {"SQLITE_AUTH", SQLITE_AUTH}, 303 | #endif 304 | #ifdef SQLITE_FORMAT 305 | {"SQLITE_FORMAT", SQLITE_FORMAT}, 306 | #endif 307 | #ifdef SQLITE_RANGE 308 | {"SQLITE_RANGE", SQLITE_RANGE}, 309 | #endif 310 | #ifdef SQLITE_NOTADB 311 | {"SQLITE_NOTADB", SQLITE_NOTADB}, 312 | #endif 313 | {"SQLITE_DONE", SQLITE_DONE}, 314 | {"SQLITE_ROW", SQLITE_ROW}, 315 | {(char*)NULL, 0}, 316 | {"SQLITE_UNKNOWN", -1} 317 | }; 318 | 319 | const char *sqlite3ErrName(int rc) { 320 | int i; 321 | for (i = 0; _error_codes[i].constant_name != 0; i++) { 322 | if (_error_codes[i].constant_value == rc) 323 | return _error_codes[i].constant_name; 324 | } 325 | // No error code matched. 326 | return _error_codes[i+1].constant_name; 327 | } 328 | 329 | static const IntConstantPair _int_constants[] = { 330 | {"PARSE_DECLTYPES", PARSE_DECLTYPES}, 331 | {"PARSE_COLNAMES", PARSE_COLNAMES}, 332 | 333 | {"SQLITE_OK", SQLITE_OK}, 334 | /* enumerated return values for sqlite3_set_authorizer() callback */ 335 | {"SQLITE_DENY", SQLITE_DENY}, 336 | {"SQLITE_IGNORE", SQLITE_IGNORE}, 337 | 338 | /* enumerated values for sqlite3_set_authorizer() callback */ 339 | {"SQLITE_CREATE_INDEX", SQLITE_CREATE_INDEX}, 340 | {"SQLITE_CREATE_TABLE", SQLITE_CREATE_TABLE}, 341 | {"SQLITE_CREATE_TEMP_INDEX", SQLITE_CREATE_TEMP_INDEX}, 342 | {"SQLITE_CREATE_TEMP_TABLE", SQLITE_CREATE_TEMP_TABLE}, 343 | {"SQLITE_CREATE_TEMP_TRIGGER", SQLITE_CREATE_TEMP_TRIGGER}, 344 | {"SQLITE_CREATE_TEMP_VIEW", SQLITE_CREATE_TEMP_VIEW}, 345 | {"SQLITE_CREATE_TRIGGER", SQLITE_CREATE_TRIGGER}, 346 | {"SQLITE_CREATE_VIEW", SQLITE_CREATE_VIEW}, 347 | {"SQLITE_DELETE", SQLITE_DELETE}, 348 | {"SQLITE_DROP_INDEX", SQLITE_DROP_INDEX}, 349 | {"SQLITE_DROP_TABLE", SQLITE_DROP_TABLE}, 350 | {"SQLITE_DROP_TEMP_INDEX", SQLITE_DROP_TEMP_INDEX}, 351 | {"SQLITE_DROP_TEMP_TABLE", SQLITE_DROP_TEMP_TABLE}, 352 | {"SQLITE_DROP_TEMP_TRIGGER", SQLITE_DROP_TEMP_TRIGGER}, 353 | {"SQLITE_DROP_TEMP_VIEW", SQLITE_DROP_TEMP_VIEW}, 354 | {"SQLITE_DROP_TRIGGER", SQLITE_DROP_TRIGGER}, 355 | {"SQLITE_DROP_VIEW", SQLITE_DROP_VIEW}, 356 | {"SQLITE_INSERT", SQLITE_INSERT}, 357 | {"SQLITE_OPEN_CREATE", SQLITE_OPEN_CREATE}, 358 | {"SQLITE_OPEN_FULLMUTEX", SQLITE_OPEN_FULLMUTEX}, 359 | {"SQLITE_OPEN_MEMORY", SQLITE_OPEN_MEMORY}, 360 | {"SQLITE_OPEN_NOMUTEX", SQLITE_OPEN_NOMUTEX}, 361 | {"SQLITE_OPEN_PRIVATECACHE", SQLITE_OPEN_PRIVATECACHE}, 362 | {"SQLITE_OPEN_READONLY", SQLITE_OPEN_READONLY}, 363 | {"SQLITE_OPEN_SHAREDCACHE", SQLITE_OPEN_SHAREDCACHE}, 364 | {"SQLITE_OPEN_READWRITE", SQLITE_OPEN_READWRITE}, 365 | {"SQLITE_OPEN_URI", SQLITE_OPEN_URI}, 366 | {"SQLITE_PRAGMA", SQLITE_PRAGMA}, 367 | {"SQLITE_READ", SQLITE_READ}, 368 | {"SQLITE_SELECT", SQLITE_SELECT}, 369 | {"SQLITE_TRANSACTION", SQLITE_TRANSACTION}, 370 | {"SQLITE_UPDATE", SQLITE_UPDATE}, 371 | {"SQLITE_ATTACH", SQLITE_ATTACH}, 372 | {"SQLITE_DETACH", SQLITE_DETACH}, 373 | #if SQLITE_VERSION_NUMBER >= 3002001 374 | {"SQLITE_ALTER_TABLE", SQLITE_ALTER_TABLE}, 375 | {"SQLITE_REINDEX", SQLITE_REINDEX}, 376 | #endif 377 | #if SQLITE_VERSION_NUMBER >= 3003000 378 | {"SQLITE_ANALYZE", SQLITE_ANALYZE}, 379 | #endif 380 | #if SQLITE_VERSION_NUMBER >= 3003007 381 | {"SQLITE_CREATE_VTABLE", SQLITE_CREATE_VTABLE}, 382 | {"SQLITE_DROP_VTABLE", SQLITE_DROP_VTABLE}, 383 | #endif 384 | #if SQLITE_VERSION_NUMBER >= 3003008 385 | {"SQLITE_FUNCTION", SQLITE_FUNCTION}, 386 | #endif 387 | #if SQLITE_VERSION_NUMBER >= 3006008 388 | {"SQLITE_SAVEPOINT", SQLITE_SAVEPOINT}, 389 | #endif 390 | #if SQLITE_VERSION_NUMBER >= 3008003 391 | {"SQLITE_RECURSIVE", SQLITE_RECURSIVE}, 392 | #endif 393 | #if SQLITE_VERSION_NUMBER >= 3006011 394 | {"SQLITE_DONE", SQLITE_DONE}, 395 | #endif 396 | {(char*)NULL, 0} 397 | }; 398 | 399 | 400 | static struct PyModuleDef _sqlite3module = { 401 | PyModuleDef_HEAD_INIT, 402 | "_sqlite3", 403 | NULL, 404 | -1, 405 | module_methods, 406 | NULL, 407 | NULL, 408 | NULL, 409 | NULL 410 | }; 411 | 412 | 413 | static int add_to_dict(PyObject *dict, const char *key, int value) 414 | { 415 | int sawerror; 416 | PyObject *value_obj = PyLong_FromLong(value); 417 | PyObject *name = PyUnicode_FromString(key); 418 | 419 | if (!value_obj || !name) { 420 | Py_XDECREF(name); 421 | Py_XDECREF(value_obj); 422 | return 1; 423 | } 424 | 425 | sawerror = PyDict_SetItem(dict, name, value_obj) < 0; 426 | 427 | Py_DECREF(value_obj); 428 | Py_DECREF(name); 429 | 430 | if (sawerror) 431 | return 1; 432 | return 0; 433 | } 434 | 435 | PyMODINIT_FUNC PyInit__sqlite3(void) 436 | { 437 | PyObject *module, *dict; 438 | PyObject *tmp_obj; 439 | int i; 440 | 441 | int rc = sqlite3_initialize(); 442 | if (rc != SQLITE_OK) { 443 | PyErr_SetString(PyExc_ImportError, sqlite3_errstr(rc)); 444 | return NULL; 445 | } 446 | 447 | module = PyModule_Create(&_sqlite3module); 448 | 449 | if (!module || 450 | (pysqlite_row_setup_types() < 0) || 451 | (pysqlite_cursor_setup_types() < 0) || 452 | (pysqlite_connection_setup_types() < 0) || 453 | (pysqlite_cache_setup_types() < 0) || 454 | (pysqlite_statement_setup_types() < 0) || 455 | (pysqlite_prepare_protocol_setup_types() < 0) || 456 | (pysqlite_blob_setup_types() < 0) 457 | ) { 458 | Py_XDECREF(module); 459 | return NULL; 460 | } 461 | 462 | Py_INCREF(&pysqlite_ConnectionType); 463 | PyModule_AddObject(module, "Connection", (PyObject*) &pysqlite_ConnectionType); 464 | Py_INCREF(&pysqlite_CursorType); 465 | PyModule_AddObject(module, "Cursor", (PyObject*) &pysqlite_CursorType); 466 | Py_INCREF(&pysqlite_CacheType); 467 | PyModule_AddObject(module, "Statement", (PyObject*)&pysqlite_StatementType); 468 | Py_INCREF(&pysqlite_StatementType); 469 | PyModule_AddObject(module, "Cache", (PyObject*) &pysqlite_CacheType); 470 | Py_INCREF(&pysqlite_PrepareProtocolType); 471 | PyModule_AddObject(module, "PrepareProtocol", (PyObject*) &pysqlite_PrepareProtocolType); 472 | Py_INCREF(&pysqlite_RowType); 473 | PyModule_AddObject(module, "Row", (PyObject*) &pysqlite_RowType); 474 | 475 | if (!(dict = PyModule_GetDict(module))) { 476 | goto error; 477 | } 478 | 479 | /*** Create DB-API Exception hierarchy */ 480 | 481 | if (!(pysqlite_Error = PyErr_NewException(MODULE_NAME ".Error", PyExc_Exception, NULL))) { 482 | goto error; 483 | } 484 | PyDict_SetItemString(dict, "Error", pysqlite_Error); 485 | 486 | if (!(pysqlite_Warning = PyErr_NewException(MODULE_NAME ".Warning", PyExc_Exception, NULL))) { 487 | goto error; 488 | } 489 | PyDict_SetItemString(dict, "Warning", pysqlite_Warning); 490 | 491 | /* Error subclasses */ 492 | 493 | if (!(pysqlite_InterfaceError = PyErr_NewException(MODULE_NAME ".InterfaceError", pysqlite_Error, NULL))) { 494 | goto error; 495 | } 496 | PyDict_SetItemString(dict, "InterfaceError", pysqlite_InterfaceError); 497 | 498 | if (!(pysqlite_DatabaseError = PyErr_NewException(MODULE_NAME ".DatabaseError", pysqlite_Error, NULL))) { 499 | goto error; 500 | } 501 | PyDict_SetItemString(dict, "DatabaseError", pysqlite_DatabaseError); 502 | 503 | /* pysqlite_DatabaseError subclasses */ 504 | 505 | if (!(pysqlite_InternalError = PyErr_NewException(MODULE_NAME ".InternalError", pysqlite_DatabaseError, NULL))) { 506 | goto error; 507 | } 508 | PyDict_SetItemString(dict, "InternalError", pysqlite_InternalError); 509 | 510 | if (!(pysqlite_OperationalError = PyErr_NewException(MODULE_NAME ".OperationalError", pysqlite_DatabaseError, NULL))) { 511 | goto error; 512 | } 513 | PyDict_SetItemString(dict, "OperationalError", pysqlite_OperationalError); 514 | 515 | if (!(pysqlite_ProgrammingError = PyErr_NewException(MODULE_NAME ".ProgrammingError", pysqlite_DatabaseError, NULL))) { 516 | goto error; 517 | } 518 | PyDict_SetItemString(dict, "ProgrammingError", pysqlite_ProgrammingError); 519 | 520 | if (!(pysqlite_IntegrityError = PyErr_NewException(MODULE_NAME ".IntegrityError", pysqlite_DatabaseError,NULL))) { 521 | goto error; 522 | } 523 | PyDict_SetItemString(dict, "IntegrityError", pysqlite_IntegrityError); 524 | 525 | if (!(pysqlite_DataError = PyErr_NewException(MODULE_NAME ".DataError", pysqlite_DatabaseError, NULL))) { 526 | goto error; 527 | } 528 | PyDict_SetItemString(dict, "DataError", pysqlite_DataError); 529 | 530 | if (!(pysqlite_NotSupportedError = PyErr_NewException(MODULE_NAME ".NotSupportedError", pysqlite_DatabaseError, NULL))) { 531 | goto error; 532 | } 533 | PyDict_SetItemString(dict, "NotSupportedError", pysqlite_NotSupportedError); 534 | 535 | /* In Python 2.x, setting Connection.text_factory to 536 | OptimizedUnicode caused Unicode objects to be returned for 537 | non-ASCII data and bytestrings to be returned for ASCII data. 538 | Now OptimizedUnicode is an alias for str, so it has no 539 | effect. */ 540 | Py_INCREF((PyObject*)&PyUnicode_Type); 541 | PyDict_SetItemString(dict, "OptimizedUnicode", (PyObject*)&PyUnicode_Type); 542 | 543 | /* Set integer constants */ 544 | for (i = 0; _int_constants[i].constant_name != NULL; i++) { 545 | if (add_to_dict(dict, _int_constants[i].constant_name, 546 | _int_constants[i].constant_value) != 0) 547 | goto error; 548 | } 549 | 550 | /* Set error constants */ 551 | for (i = 0; _error_codes[i].constant_name != 0; i++) { 552 | if (add_to_dict(dict, _error_codes[i].constant_name, 553 | _error_codes[i].constant_value) != 0) 554 | goto error; 555 | } 556 | 557 | if (!(tmp_obj = PyUnicode_FromString(PYSQLITE_VERSION))) { 558 | goto error; 559 | } 560 | PyDict_SetItemString(dict, "version", tmp_obj); 561 | Py_DECREF(tmp_obj); 562 | 563 | if (!(tmp_obj = PyUnicode_FromString(sqlite3_libversion()))) { 564 | goto error; 565 | } 566 | PyDict_SetItemString(dict, "sqlite_version", tmp_obj); 567 | Py_DECREF(tmp_obj); 568 | 569 | /* initialize microprotocols layer */ 570 | pysqlite_microprotocols_init(dict); 571 | 572 | /* initialize the default converters */ 573 | converters_init(dict); 574 | 575 | error: 576 | if (PyErr_Occurred()) 577 | { 578 | PyErr_SetString(PyExc_ImportError, MODULE_NAME ": init failed"); 579 | Py_XDECREF(module); 580 | module = NULL; 581 | } 582 | return module; 583 | } 584 | -------------------------------------------------------------------------------- /src/module.h: -------------------------------------------------------------------------------- 1 | /* module.h - definitions for the module 2 | * 3 | * Copyright (C) 2004-2010 Gerhard Häring 4 | * 5 | * This file is part of pysqlite. 6 | * 7 | * This software is provided 'as-is', without any express or implied 8 | * warranty. In no event will the authors be held liable for any damages 9 | * arising from the use of this software. 10 | * 11 | * Permission is granted to anyone to use this software for any purpose, 12 | * including commercial applications, and to alter it and redistribute it 13 | * freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not 16 | * claim that you wrote the original software. If you use this software 17 | * in a product, an acknowledgment in the product documentation would be 18 | * appreciated but is not required. 19 | * 2. Altered source versions must be plainly marked as such, and must not be 20 | * misrepresented as being the original software. 21 | * 3. This notice may not be removed or altered from any source distribution. 22 | */ 23 | 24 | #ifndef PYSQLITE_MODULE_H 25 | #define PYSQLITE_MODULE_H 26 | #define PY_SSIZE_T_CLEAN 27 | #include "Python.h" 28 | 29 | #define PYSQLITE_VERSION "2.6.0" 30 | 31 | extern PyObject* pysqlite_Error; 32 | extern PyObject* pysqlite_Warning; 33 | extern PyObject* pysqlite_InterfaceError; 34 | extern PyObject* pysqlite_DatabaseError; 35 | extern PyObject* pysqlite_InternalError; 36 | extern PyObject* pysqlite_OperationalError; 37 | extern PyObject* pysqlite_ProgrammingError; 38 | extern PyObject* pysqlite_IntegrityError; 39 | extern PyObject* pysqlite_DataError; 40 | extern PyObject* pysqlite_NotSupportedError; 41 | 42 | /* A dictionary, mapping column types (INTEGER, VARCHAR, etc.) to converter 43 | * functions, that convert the SQL value to the appropriate Python value. 44 | * The key is uppercase. 45 | */ 46 | extern PyObject* _pysqlite_converters; 47 | 48 | extern int _pysqlite_enable_callback_tracebacks; 49 | extern int pysqlite_BaseTypeAdapted; 50 | 51 | extern const char *sqlite3ErrName(int rc); 52 | 53 | #define PARSE_DECLTYPES 1 54 | #define PARSE_COLNAMES 2 55 | #endif 56 | -------------------------------------------------------------------------------- /src/prepare_protocol.c: -------------------------------------------------------------------------------- 1 | /* prepare_protocol.c - the protocol for preparing values for SQLite 2 | * 3 | * Copyright (C) 2005-2010 Gerhard Häring 4 | * 5 | * This file is part of pysqlite. 6 | * 7 | * This software is provided 'as-is', without any express or implied 8 | * warranty. In no event will the authors be held liable for any damages 9 | * arising from the use of this software. 10 | * 11 | * Permission is granted to anyone to use this software for any purpose, 12 | * including commercial applications, and to alter it and redistribute it 13 | * freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not 16 | * claim that you wrote the original software. If you use this software 17 | * in a product, an acknowledgment in the product documentation would be 18 | * appreciated but is not required. 19 | * 2. Altered source versions must be plainly marked as such, and must not be 20 | * misrepresented as being the original software. 21 | * 3. This notice may not be removed or altered from any source distribution. 22 | */ 23 | 24 | #include "prepare_protocol.h" 25 | 26 | int pysqlite_prepare_protocol_init(pysqlite_PrepareProtocol* self, PyObject* args, PyObject* kwargs) 27 | { 28 | return 0; 29 | } 30 | 31 | void pysqlite_prepare_protocol_dealloc(pysqlite_PrepareProtocol* self) 32 | { 33 | Py_TYPE(self)->tp_free((PyObject*)self); 34 | } 35 | 36 | PyTypeObject pysqlite_PrepareProtocolType= { 37 | PyVarObject_HEAD_INIT(NULL, 0) 38 | MODULE_NAME ".PrepareProtocol", /* tp_name */ 39 | sizeof(pysqlite_PrepareProtocol), /* tp_basicsize */ 40 | 0, /* tp_itemsize */ 41 | (destructor)pysqlite_prepare_protocol_dealloc, /* tp_dealloc */ 42 | 0, /* tp_print */ 43 | 0, /* tp_getattr */ 44 | 0, /* tp_setattr */ 45 | 0, /* tp_reserved */ 46 | 0, /* tp_repr */ 47 | 0, /* tp_as_number */ 48 | 0, /* tp_as_sequence */ 49 | 0, /* tp_as_mapping */ 50 | 0, /* tp_hash */ 51 | 0, /* tp_call */ 52 | 0, /* tp_str */ 53 | 0, /* tp_getattro */ 54 | 0, /* tp_setattro */ 55 | 0, /* tp_as_buffer */ 56 | Py_TPFLAGS_DEFAULT, /* tp_flags */ 57 | 0, /* tp_doc */ 58 | 0, /* tp_traverse */ 59 | 0, /* tp_clear */ 60 | 0, /* tp_richcompare */ 61 | 0, /* tp_weaklistoffset */ 62 | 0, /* tp_iter */ 63 | 0, /* tp_iternext */ 64 | 0, /* tp_methods */ 65 | 0, /* tp_members */ 66 | 0, /* tp_getset */ 67 | 0, /* tp_base */ 68 | 0, /* tp_dict */ 69 | 0, /* tp_descr_get */ 70 | 0, /* tp_descr_set */ 71 | 0, /* tp_dictoffset */ 72 | (initproc)pysqlite_prepare_protocol_init, /* tp_init */ 73 | 0, /* tp_alloc */ 74 | 0, /* tp_new */ 75 | 0 /* tp_free */ 76 | }; 77 | 78 | extern int pysqlite_prepare_protocol_setup_types(void) 79 | { 80 | int rc; 81 | pysqlite_PrepareProtocolType.tp_new = PyType_GenericNew; 82 | //Py_TYPE(&pysqlite_PrepareProtocolType)= &PyType_Type; 83 | rc = PyType_Ready(&pysqlite_PrepareProtocolType); 84 | return rc; 85 | //return PyType_Ready(&pysqlite_PrepareProtocolType); 86 | } 87 | -------------------------------------------------------------------------------- /src/prepare_protocol.h: -------------------------------------------------------------------------------- 1 | /* prepare_protocol.h - the protocol for preparing values for SQLite 2 | * 3 | * Copyright (C) 2005-2010 Gerhard Häring 4 | * 5 | * This file is part of pysqlite. 6 | * 7 | * This software is provided 'as-is', without any express or implied 8 | * warranty. In no event will the authors be held liable for any damages 9 | * arising from the use of this software. 10 | * 11 | * Permission is granted to anyone to use this software for any purpose, 12 | * including commercial applications, and to alter it and redistribute it 13 | * freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not 16 | * claim that you wrote the original software. If you use this software 17 | * in a product, an acknowledgment in the product documentation would be 18 | * appreciated but is not required. 19 | * 2. Altered source versions must be plainly marked as such, and must not be 20 | * misrepresented as being the original software. 21 | * 3. This notice may not be removed or altered from any source distribution. 22 | */ 23 | 24 | #ifndef PYSQLITE_PREPARE_PROTOCOL_H 25 | #define PYSQLITE_PREPARE_PROTOCOL_H 26 | #define PY_SSIZE_T_CLEAN 27 | #include "Python.h" 28 | 29 | typedef struct 30 | { 31 | PyObject_HEAD 32 | } pysqlite_PrepareProtocol; 33 | 34 | extern PyTypeObject pysqlite_PrepareProtocolType; 35 | 36 | int pysqlite_prepare_protocol_init(pysqlite_PrepareProtocol* self, PyObject* args, PyObject* kwargs); 37 | void pysqlite_prepare_protocol_dealloc(pysqlite_PrepareProtocol* self); 38 | 39 | int pysqlite_prepare_protocol_setup_types(void); 40 | 41 | #define UNKNOWN (-1) 42 | #endif 43 | -------------------------------------------------------------------------------- /src/row.c: -------------------------------------------------------------------------------- 1 | /* row.c - an enhanced tuple for database rows 2 | * 3 | * Copyright (C) 2005-2010 Gerhard Häring 4 | * 5 | * This file is part of pysqlite. 6 | * 7 | * This software is provided 'as-is', without any express or implied 8 | * warranty. In no event will the authors be held liable for any damages 9 | * arising from the use of this software. 10 | * 11 | * Permission is granted to anyone to use this software for any purpose, 12 | * including commercial applications, and to alter it and redistribute it 13 | * freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not 16 | * claim that you wrote the original software. If you use this software 17 | * in a product, an acknowledgment in the product documentation would be 18 | * appreciated but is not required. 19 | * 2. Altered source versions must be plainly marked as such, and must not be 20 | * misrepresented as being the original software. 21 | * 3. This notice may not be removed or altered from any source distribution. 22 | */ 23 | 24 | #include "row.h" 25 | #include "cursor.h" 26 | 27 | void pysqlite_row_dealloc(pysqlite_Row* self) 28 | { 29 | Py_XDECREF(self->data); 30 | Py_XDECREF(self->description); 31 | 32 | Py_TYPE(self)->tp_free((PyObject*)self); 33 | } 34 | 35 | static PyObject * 36 | pysqlite_row_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) 37 | { 38 | pysqlite_Row *self; 39 | PyObject* data; 40 | pysqlite_Cursor* cursor; 41 | 42 | assert(type != NULL && type->tp_alloc != NULL); 43 | 44 | if (!PyArg_ParseTuple(args, "OO", &cursor, &data)) 45 | return NULL; 46 | 47 | if (!PyObject_TypeCheck((PyObject*)cursor, &pysqlite_CursorType)) { 48 | PyErr_SetString(PyExc_TypeError, "instance of cursor required for first argument"); 49 | return NULL; 50 | } 51 | 52 | if (!PyTuple_Check(data)) { 53 | PyErr_SetString(PyExc_TypeError, "tuple required for second argument"); 54 | return NULL; 55 | } 56 | 57 | self = (pysqlite_Row *) type->tp_alloc(type, 0); 58 | if (self == NULL) 59 | return NULL; 60 | 61 | Py_INCREF(data); 62 | self->data = data; 63 | 64 | Py_INCREF(cursor->description); 65 | self->description = cursor->description; 66 | 67 | return (PyObject *) self; 68 | } 69 | 70 | PyObject* pysqlite_row_item(pysqlite_Row* self, Py_ssize_t idx) 71 | { 72 | PyObject* item = PyTuple_GetItem(self->data, idx); 73 | Py_XINCREF(item); 74 | return item; 75 | } 76 | 77 | static int 78 | equal_ignore_case(PyObject *left, PyObject *right) 79 | { 80 | int eq = PyObject_RichCompareBool(left, right, Py_EQ); 81 | if (eq) { 82 | return eq; 83 | } 84 | if (!PyUnicode_Check(left) || !PyUnicode_Check(right)) { 85 | return 0; 86 | } 87 | if (!PyUnicode_IS_ASCII(left) || !PyUnicode_IS_ASCII(right)) { 88 | return 0; 89 | } 90 | 91 | Py_ssize_t len = PyUnicode_GET_LENGTH(left); 92 | if (PyUnicode_GET_LENGTH(right) != len) { 93 | return 0; 94 | } 95 | const Py_UCS1 *p1 = PyUnicode_1BYTE_DATA(left); 96 | const Py_UCS1 *p2 = PyUnicode_1BYTE_DATA(right); 97 | for (; len; len--, p1++, p2++) { 98 | if (Py_TOLOWER(*p1) != Py_TOLOWER(*p2)) { 99 | return 0; 100 | } 101 | } 102 | return 1; 103 | } 104 | 105 | PyObject* pysqlite_row_subscript(pysqlite_Row* self, PyObject* idx) 106 | { 107 | Py_ssize_t _idx; 108 | Py_ssize_t nitems, i; 109 | PyObject* item; 110 | 111 | if (PyLong_Check(idx)) { 112 | _idx = PyNumber_AsSsize_t(idx, PyExc_IndexError); 113 | if (_idx == -1 && PyErr_Occurred()) 114 | return NULL; 115 | if (_idx < 0) 116 | _idx += PyTuple_GET_SIZE(self->data); 117 | item = PyTuple_GetItem(self->data, _idx); 118 | Py_XINCREF(item); 119 | return item; 120 | } else if (PyUnicode_Check(idx)) { 121 | nitems = PyTuple_Size(self->description); 122 | 123 | for (i = 0; i < nitems; i++) { 124 | PyObject *obj; 125 | obj = PyTuple_GET_ITEM(self->description, i); 126 | obj = PyTuple_GET_ITEM(obj, 0); 127 | int eq = equal_ignore_case(idx, obj); 128 | if (eq < 0) { 129 | return NULL; 130 | } 131 | 132 | if (eq) { 133 | /* found item */ 134 | item = PyTuple_GetItem(self->data, i); 135 | Py_INCREF(item); 136 | return item; 137 | } 138 | } 139 | 140 | PyErr_SetString(PyExc_IndexError, "No item with that key"); 141 | return NULL; 142 | } 143 | else if (PySlice_Check(idx)) { 144 | return PyObject_GetItem(self->data, idx); 145 | } 146 | else { 147 | PyErr_SetString(PyExc_IndexError, "Index must be int or string"); 148 | return NULL; 149 | } 150 | } 151 | 152 | static Py_ssize_t 153 | pysqlite_row_length(pysqlite_Row* self) 154 | { 155 | return PyTuple_GET_SIZE(self->data); 156 | } 157 | 158 | PyObject* pysqlite_row_keys(pysqlite_Row* self, PyObject *Py_UNUSED(ignored)) 159 | { 160 | PyObject* list; 161 | Py_ssize_t nitems, i; 162 | 163 | list = PyList_New(0); 164 | if (!list) { 165 | return NULL; 166 | } 167 | nitems = PyTuple_Size(self->description); 168 | 169 | for (i = 0; i < nitems; i++) { 170 | if (PyList_Append(list, PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0)) != 0) { 171 | Py_DECREF(list); 172 | return NULL; 173 | } 174 | } 175 | 176 | return list; 177 | } 178 | 179 | static PyObject* pysqlite_iter(pysqlite_Row* self) 180 | { 181 | return PyObject_GetIter(self->data); 182 | } 183 | 184 | static Py_hash_t pysqlite_row_hash(pysqlite_Row *self) 185 | { 186 | return PyObject_Hash(self->description) ^ PyObject_Hash(self->data); 187 | } 188 | 189 | static PyObject* pysqlite_row_richcompare(pysqlite_Row *self, PyObject *_other, int opid) 190 | { 191 | if (opid != Py_EQ && opid != Py_NE) 192 | Py_RETURN_NOTIMPLEMENTED; 193 | 194 | if (PyObject_TypeCheck(_other, &pysqlite_RowType)) { 195 | pysqlite_Row *other = (pysqlite_Row *)_other; 196 | int eq = PyObject_RichCompareBool(self->description, other->description, Py_EQ); 197 | if (eq < 0) { 198 | return NULL; 199 | } 200 | if (eq) { 201 | return PyObject_RichCompare(self->data, other->data, opid); 202 | } 203 | return PyBool_FromLong(opid != Py_EQ); 204 | } 205 | Py_RETURN_NOTIMPLEMENTED; 206 | } 207 | 208 | PyMappingMethods pysqlite_row_as_mapping = { 209 | /* mp_length */ (lenfunc)pysqlite_row_length, 210 | /* mp_subscript */ (binaryfunc)pysqlite_row_subscript, 211 | /* mp_ass_subscript */ (objobjargproc)0, 212 | }; 213 | 214 | static PySequenceMethods pysqlite_row_as_sequence = { 215 | /* sq_length */ (lenfunc)pysqlite_row_length, 216 | /* sq_concat */ 0, 217 | /* sq_repeat */ 0, 218 | /* sq_item */ (ssizeargfunc)pysqlite_row_item, 219 | }; 220 | 221 | 222 | static PyMethodDef pysqlite_row_methods[] = { 223 | {"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS, 224 | PyDoc_STR("Returns the keys of the row.")}, 225 | {NULL, NULL} 226 | }; 227 | 228 | 229 | PyTypeObject pysqlite_RowType = { 230 | PyVarObject_HEAD_INIT(NULL, 0) 231 | MODULE_NAME ".Row", /* tp_name */ 232 | sizeof(pysqlite_Row), /* tp_basicsize */ 233 | 0, /* tp_itemsize */ 234 | (destructor)pysqlite_row_dealloc, /* tp_dealloc */ 235 | 0, /* tp_print */ 236 | 0, /* tp_getattr */ 237 | 0, /* tp_setattr */ 238 | 0, /* tp_reserved */ 239 | 0, /* tp_repr */ 240 | 0, /* tp_as_number */ 241 | 0, /* tp_as_sequence */ 242 | 0, /* tp_as_mapping */ 243 | (hashfunc)pysqlite_row_hash, /* tp_hash */ 244 | 0, /* tp_call */ 245 | 0, /* tp_str */ 246 | 0, /* tp_getattro */ 247 | 0, /* tp_setattro */ 248 | 0, /* tp_as_buffer */ 249 | Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ 250 | 0, /* tp_doc */ 251 | (traverseproc)0, /* tp_traverse */ 252 | 0, /* tp_clear */ 253 | (richcmpfunc)pysqlite_row_richcompare, /* tp_richcompare */ 254 | 0, /* tp_weaklistoffset */ 255 | (getiterfunc)pysqlite_iter, /* tp_iter */ 256 | 0, /* tp_iternext */ 257 | pysqlite_row_methods, /* tp_methods */ 258 | 0, /* tp_members */ 259 | 0, /* tp_getset */ 260 | 0, /* tp_base */ 261 | 0, /* tp_dict */ 262 | 0, /* tp_descr_get */ 263 | 0, /* tp_descr_set */ 264 | 0, /* tp_dictoffset */ 265 | 0, /* tp_init */ 266 | 0, /* tp_alloc */ 267 | 0, /* tp_new */ 268 | 0 /* tp_free */ 269 | }; 270 | 271 | extern int pysqlite_row_setup_types(void) 272 | { 273 | pysqlite_RowType.tp_new = pysqlite_row_new; 274 | pysqlite_RowType.tp_as_mapping = &pysqlite_row_as_mapping; 275 | pysqlite_RowType.tp_as_sequence = &pysqlite_row_as_sequence; 276 | return PyType_Ready(&pysqlite_RowType); 277 | } 278 | -------------------------------------------------------------------------------- /src/row.h: -------------------------------------------------------------------------------- 1 | /* row.h - an enhanced tuple for database rows 2 | * 3 | * Copyright (C) 2005-2010 Gerhard Häring 4 | * 5 | * This file is part of pysqlite. 6 | * 7 | * This software is provided 'as-is', without any express or implied 8 | * warranty. In no event will the authors be held liable for any damages 9 | * arising from the use of this software. 10 | * 11 | * Permission is granted to anyone to use this software for any purpose, 12 | * including commercial applications, and to alter it and redistribute it 13 | * freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not 16 | * claim that you wrote the original software. If you use this software 17 | * in a product, an acknowledgment in the product documentation would be 18 | * appreciated but is not required. 19 | * 2. Altered source versions must be plainly marked as such, and must not be 20 | * misrepresented as being the original software. 21 | * 3. This notice may not be removed or altered from any source distribution. 22 | */ 23 | 24 | #ifndef PYSQLITE_ROW_H 25 | #define PYSQLITE_ROW_H 26 | #define PY_SSIZE_T_CLEAN 27 | #include "Python.h" 28 | 29 | typedef struct _Row 30 | { 31 | PyObject_HEAD 32 | PyObject* data; 33 | PyObject* description; 34 | } pysqlite_Row; 35 | 36 | extern PyTypeObject pysqlite_RowType; 37 | 38 | int pysqlite_row_setup_types(void); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/statement.c: -------------------------------------------------------------------------------- 1 | /* statement.c - the statement type 2 | * 3 | * Copyright (C) 2005-2010 Gerhard Häring 4 | * 5 | * This file is part of pysqlite. 6 | * 7 | * This software is provided 'as-is', without any express or implied 8 | * warranty. In no event will the authors be held liable for any damages 9 | * arising from the use of this software. 10 | * 11 | * Permission is granted to anyone to use this software for any purpose, 12 | * including commercial applications, and to alter it and redistribute it 13 | * freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not 16 | * claim that you wrote the original software. If you use this software 17 | * in a product, an acknowledgment in the product documentation would be 18 | * appreciated but is not required. 19 | * 2. Altered source versions must be plainly marked as such, and must not be 20 | * misrepresented as being the original software. 21 | * 3. This notice may not be removed or altered from any source distribution. 22 | */ 23 | 24 | #include "statement.h" 25 | #include "cursor.h" 26 | #include "connection.h" 27 | #include "microprotocols.h" 28 | #include "prepare_protocol.h" 29 | #include "util.h" 30 | 31 | /* prototypes */ 32 | static int pysqlite_check_remaining_sql(const char* tail); 33 | 34 | typedef enum { 35 | LINECOMMENT_1, 36 | IN_LINECOMMENT, 37 | COMMENTSTART_1, 38 | IN_COMMENT, 39 | COMMENTEND_1, 40 | NORMAL 41 | } parse_remaining_sql_state; 42 | 43 | typedef enum { 44 | TYPE_LONG, 45 | TYPE_FLOAT, 46 | TYPE_UNICODE, 47 | TYPE_BUFFER, 48 | TYPE_UNKNOWN 49 | } parameter_type; 50 | 51 | int pysqlite_statement_create(pysqlite_Statement* self, pysqlite_Connection* connection, PyObject* sql) 52 | { 53 | const char* tail; 54 | int rc; 55 | const char* sql_cstr; 56 | Py_ssize_t sql_cstr_len; 57 | const char* p; 58 | 59 | self->st = NULL; 60 | self->in_use = 0; 61 | 62 | assert(PyUnicode_Check(sql)); 63 | 64 | sql_cstr = PyUnicode_AsUTF8AndSize(sql, &sql_cstr_len); 65 | if (sql_cstr == NULL) { 66 | rc = PYSQLITE_SQL_WRONG_TYPE; 67 | return rc; 68 | } 69 | if (strlen(sql_cstr) != (size_t)sql_cstr_len) { 70 | PyErr_SetString(PyExc_ValueError, "the query contains a null character"); 71 | return PYSQLITE_SQL_WRONG_TYPE; 72 | } 73 | 74 | self->in_weakreflist = NULL; 75 | Py_INCREF(sql); 76 | self->sql = sql; 77 | 78 | Py_BEGIN_ALLOW_THREADS 79 | rc = sqlite3_prepare_v2(connection->db, 80 | sql_cstr, 81 | -1, 82 | &self->st, 83 | &tail); 84 | self->is_dml = !sqlite3_stmt_readonly(self->st); 85 | Py_END_ALLOW_THREADS 86 | 87 | /* To retain backward-compatibility, we need to treat DDL and certain types 88 | * of transactions as being "not-dml". 89 | */ 90 | if (self->is_dml) { 91 | for (p = sql_cstr; *p != 0; p++) { 92 | switch (*p) { 93 | case ' ': 94 | case '\r': 95 | case '\n': 96 | case '\t': 97 | continue; 98 | } 99 | 100 | /* DML iff statement is not a CREATE/DROP/BEGIN. */ 101 | self->is_dml = (PyOS_strnicmp(p, "begin", 5) && 102 | PyOS_strnicmp(p, "create", 6) && 103 | PyOS_strnicmp(p, "drop", 4) && 104 | PyOS_strnicmp(p, "alter", 5) && 105 | PyOS_strnicmp(p, "analyze", 7) && 106 | PyOS_strnicmp(p, "reindex", 7) && 107 | PyOS_strnicmp(p, "vacuum", 6) && 108 | PyOS_strnicmp(p, "pragma", 6)); 109 | break; 110 | } 111 | } 112 | 113 | self->db = connection->db; 114 | 115 | if (rc == SQLITE_OK && pysqlite_check_remaining_sql(tail)) { 116 | (void)sqlite3_finalize(self->st); 117 | self->st = NULL; 118 | rc = PYSQLITE_TOO_MUCH_SQL; 119 | } 120 | 121 | return rc; 122 | } 123 | 124 | int pysqlite_statement_bind_parameter(pysqlite_Statement* self, int pos, PyObject* parameter) 125 | { 126 | int rc = SQLITE_OK; 127 | const char *string; 128 | Py_ssize_t buflen; 129 | parameter_type paramtype; 130 | 131 | if (parameter == Py_None) { 132 | rc = sqlite3_bind_null(self->st, pos); 133 | goto final; 134 | } 135 | 136 | if (PyLong_CheckExact(parameter)) { 137 | paramtype = TYPE_LONG; 138 | } else if (PyFloat_CheckExact(parameter)) { 139 | paramtype = TYPE_FLOAT; 140 | } else if (PyUnicode_CheckExact(parameter)) { 141 | paramtype = TYPE_UNICODE; 142 | } else if (PyLong_Check(parameter)) { 143 | paramtype = TYPE_LONG; 144 | } else if (PyFloat_Check(parameter)) { 145 | paramtype = TYPE_FLOAT; 146 | } else if (PyUnicode_Check(parameter)) { 147 | paramtype = TYPE_UNICODE; 148 | } else if (PyObject_CheckBuffer(parameter)) { 149 | paramtype = TYPE_BUFFER; 150 | } else { 151 | paramtype = TYPE_UNKNOWN; 152 | } 153 | 154 | switch (paramtype) { 155 | case TYPE_LONG: { 156 | sqlite_int64 value = _pysqlite_long_as_int64(parameter); 157 | if (value == -1 && PyErr_Occurred()) 158 | rc = -1; 159 | else 160 | rc = sqlite3_bind_int64(self->st, pos, value); 161 | break; 162 | } 163 | case TYPE_FLOAT: 164 | rc = sqlite3_bind_double(self->st, pos, PyFloat_AsDouble(parameter)); 165 | break; 166 | case TYPE_UNICODE: 167 | string = PyUnicode_AsUTF8AndSize(parameter, &buflen); 168 | if (string == NULL) 169 | return -1; 170 | if (buflen > INT_MAX) { 171 | PyErr_SetString(PyExc_OverflowError, 172 | "string longer than INT_MAX bytes"); 173 | return -1; 174 | } 175 | rc = sqlite3_bind_text(self->st, pos, string, (int)buflen, SQLITE_TRANSIENT); 176 | break; 177 | case TYPE_BUFFER: { 178 | Py_buffer view; 179 | if (PyObject_GetBuffer(parameter, &view, PyBUF_SIMPLE) != 0) { 180 | PyErr_SetString(PyExc_ValueError, "could not convert BLOB to buffer"); 181 | return -1; 182 | } 183 | if (view.len > INT_MAX) { 184 | PyErr_SetString(PyExc_OverflowError, 185 | "BLOB longer than INT_MAX bytes"); 186 | PyBuffer_Release(&view); 187 | return -1; 188 | } 189 | rc = sqlite3_bind_blob(self->st, pos, view.buf, (int)view.len, SQLITE_TRANSIENT); 190 | PyBuffer_Release(&view); 191 | break; 192 | } 193 | case TYPE_UNKNOWN: 194 | rc = -1; 195 | } 196 | 197 | final: 198 | return rc; 199 | } 200 | 201 | /* returns 0 if the object is one of Python's internal ones that don't need to be adapted */ 202 | static int _need_adapt(PyObject* obj) 203 | { 204 | if (pysqlite_BaseTypeAdapted) { 205 | return 1; 206 | } 207 | 208 | if (PyLong_CheckExact(obj) || PyFloat_CheckExact(obj) 209 | || PyUnicode_CheckExact(obj) || PyByteArray_CheckExact(obj)) { 210 | return 0; 211 | } else { 212 | return 1; 213 | } 214 | } 215 | 216 | void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* parameters) 217 | { 218 | PyObject* current_param; 219 | PyObject* adapted; 220 | const char* binding_name; 221 | int i; 222 | int rc; 223 | int num_params_needed; 224 | Py_ssize_t num_params; 225 | 226 | Py_BEGIN_ALLOW_THREADS 227 | num_params_needed = sqlite3_bind_parameter_count(self->st); 228 | Py_END_ALLOW_THREADS 229 | 230 | if (PyTuple_CheckExact(parameters) || PyList_CheckExact(parameters) || (!PyDict_Check(parameters) && PySequence_Check(parameters))) { 231 | /* parameters passed as sequence */ 232 | if (PyTuple_CheckExact(parameters)) { 233 | num_params = PyTuple_GET_SIZE(parameters); 234 | } else if (PyList_CheckExact(parameters)) { 235 | num_params = PyList_GET_SIZE(parameters); 236 | } else { 237 | num_params = PySequence_Size(parameters); 238 | } 239 | if (num_params != num_params_needed) { 240 | PyErr_Format(pysqlite_ProgrammingError, 241 | "Incorrect number of bindings supplied. The current " 242 | "statement uses %d, and there are %zd supplied.", 243 | num_params_needed, num_params); 244 | return; 245 | } 246 | for (i = 0; i < num_params; i++) { 247 | if (PyTuple_CheckExact(parameters)) { 248 | current_param = PyTuple_GET_ITEM(parameters, i); 249 | Py_XINCREF(current_param); 250 | } else if (PyList_CheckExact(parameters)) { 251 | current_param = PyList_GET_ITEM(parameters, i); 252 | Py_XINCREF(current_param); 253 | } else { 254 | current_param = PySequence_GetItem(parameters, i); 255 | } 256 | if (!current_param) { 257 | return; 258 | } 259 | 260 | if (!_need_adapt(current_param)) { 261 | adapted = current_param; 262 | } else { 263 | adapted = pysqlite_microprotocols_adapt(current_param, (PyObject*)&pysqlite_PrepareProtocolType, current_param); 264 | Py_DECREF(current_param); 265 | if (!adapted) { 266 | return; 267 | } 268 | } 269 | 270 | rc = pysqlite_statement_bind_parameter(self, i + 1, adapted); 271 | Py_DECREF(adapted); 272 | 273 | if (rc != SQLITE_OK) { 274 | if (!PyErr_Occurred()) { 275 | PyErr_Format(pysqlite_InterfaceError, "Error binding parameter %d - probably unsupported type.", i); 276 | } 277 | return; 278 | } 279 | } 280 | } else if (PyDict_Check(parameters)) { 281 | /* parameters passed as dictionary */ 282 | for (i = 1; i <= num_params_needed; i++) { 283 | PyObject *binding_name_obj; 284 | Py_BEGIN_ALLOW_THREADS 285 | binding_name = sqlite3_bind_parameter_name(self->st, i); 286 | Py_END_ALLOW_THREADS 287 | if (!binding_name) { 288 | PyErr_Format(pysqlite_ProgrammingError, "Binding %d has no name, but you supplied a dictionary (which has only names).", i); 289 | return; 290 | } 291 | 292 | binding_name++; /* skip first char (the colon) */ 293 | binding_name_obj = PyUnicode_FromString(binding_name); 294 | if (!binding_name_obj) { 295 | return; 296 | } 297 | if (PyDict_CheckExact(parameters)) { 298 | current_param = PyDict_GetItemWithError(parameters, binding_name_obj); 299 | Py_XINCREF(current_param); 300 | } else { 301 | current_param = PyObject_GetItem(parameters, binding_name_obj); 302 | } 303 | Py_DECREF(binding_name_obj); 304 | if (!current_param) { 305 | if (!PyErr_Occurred() || PyErr_ExceptionMatches(PyExc_LookupError)) { 306 | PyErr_Format(pysqlite_ProgrammingError, "You did not supply a value for binding %d.", i); 307 | } 308 | return; 309 | } 310 | 311 | if (!_need_adapt(current_param)) { 312 | adapted = current_param; 313 | } else { 314 | adapted = pysqlite_microprotocols_adapt(current_param, (PyObject*)&pysqlite_PrepareProtocolType, current_param); 315 | Py_DECREF(current_param); 316 | if (!adapted) { 317 | return; 318 | } 319 | } 320 | 321 | rc = pysqlite_statement_bind_parameter(self, i, adapted); 322 | Py_DECREF(adapted); 323 | 324 | if (rc != SQLITE_OK) { 325 | if (!PyErr_Occurred()) { 326 | PyErr_Format(pysqlite_InterfaceError, "Error binding parameter :%s - probably unsupported type.", binding_name); 327 | } 328 | return; 329 | } 330 | } 331 | } else { 332 | PyErr_SetString(PyExc_ValueError, "parameters are of unsupported type"); 333 | } 334 | } 335 | 336 | int pysqlite_statement_finalize(pysqlite_Statement* self) 337 | { 338 | int rc; 339 | 340 | rc = SQLITE_OK; 341 | if (self->st) { 342 | Py_BEGIN_ALLOW_THREADS 343 | rc = sqlite3_finalize(self->st); 344 | Py_END_ALLOW_THREADS 345 | self->st = NULL; 346 | } 347 | 348 | self->in_use = 0; 349 | 350 | return rc; 351 | } 352 | 353 | int pysqlite_statement_reset(pysqlite_Statement* self) 354 | { 355 | int rc; 356 | 357 | rc = SQLITE_OK; 358 | 359 | if (self->in_use && self->st) { 360 | Py_BEGIN_ALLOW_THREADS 361 | rc = sqlite3_reset(self->st); 362 | Py_END_ALLOW_THREADS 363 | 364 | if (rc == SQLITE_OK) { 365 | self->in_use = 0; 366 | } 367 | } 368 | 369 | return rc; 370 | } 371 | 372 | void pysqlite_statement_mark_dirty(pysqlite_Statement* self) 373 | { 374 | self->in_use = 1; 375 | } 376 | 377 | void pysqlite_statement_dealloc(pysqlite_Statement* self) 378 | { 379 | if (self->st) { 380 | Py_BEGIN_ALLOW_THREADS 381 | sqlite3_finalize(self->st); 382 | Py_END_ALLOW_THREADS 383 | } 384 | 385 | self->st = NULL; 386 | 387 | Py_XDECREF(self->sql); 388 | 389 | if (self->in_weakreflist != NULL) { 390 | PyObject_ClearWeakRefs((PyObject*)self); 391 | } 392 | 393 | Py_TYPE(self)->tp_free((PyObject*)self); 394 | } 395 | 396 | /* 397 | * Checks if there is anything left in an SQL string after SQLite compiled it. 398 | * This is used to check if somebody tried to execute more than one SQL command 399 | * with one execute()/executemany() command, which the DB-API and we don't 400 | * allow. 401 | * 402 | * Returns 1 if there is more left than should be. 0 if ok. 403 | */ 404 | static int pysqlite_check_remaining_sql(const char* tail) 405 | { 406 | const char* pos = tail; 407 | 408 | parse_remaining_sql_state state = NORMAL; 409 | 410 | for (;;) { 411 | switch (*pos) { 412 | case 0: 413 | return 0; 414 | case '-': 415 | if (state == NORMAL) { 416 | state = LINECOMMENT_1; 417 | } else if (state == LINECOMMENT_1) { 418 | state = IN_LINECOMMENT; 419 | } 420 | break; 421 | case ' ': 422 | case '\t': 423 | break; 424 | case '\n': 425 | case 13: 426 | if (state == IN_LINECOMMENT) { 427 | state = NORMAL; 428 | } 429 | break; 430 | case '/': 431 | if (state == NORMAL) { 432 | state = COMMENTSTART_1; 433 | } else if (state == COMMENTEND_1) { 434 | state = NORMAL; 435 | } else if (state == COMMENTSTART_1) { 436 | return 1; 437 | } 438 | break; 439 | case '*': 440 | if (state == NORMAL) { 441 | return 1; 442 | } else if (state == LINECOMMENT_1) { 443 | return 1; 444 | } else if (state == COMMENTSTART_1) { 445 | state = IN_COMMENT; 446 | } else if (state == IN_COMMENT) { 447 | state = COMMENTEND_1; 448 | } 449 | break; 450 | default: 451 | if (state == COMMENTEND_1) { 452 | state = IN_COMMENT; 453 | } else if (state == IN_LINECOMMENT) { 454 | } else if (state == IN_COMMENT) { 455 | } else { 456 | return 1; 457 | } 458 | } 459 | 460 | pos++; 461 | } 462 | 463 | return 0; 464 | } 465 | 466 | PyTypeObject pysqlite_StatementType = { 467 | PyVarObject_HEAD_INIT(NULL, 0) 468 | MODULE_NAME ".Statement", /* tp_name */ 469 | sizeof(pysqlite_Statement), /* tp_basicsize */ 470 | 0, /* tp_itemsize */ 471 | (destructor)pysqlite_statement_dealloc, /* tp_dealloc */ 472 | 0, /* tp_print */ 473 | 0, /* tp_getattr */ 474 | 0, /* tp_setattr */ 475 | 0, /* tp_reserved */ 476 | 0, /* tp_repr */ 477 | 0, /* tp_as_number */ 478 | 0, /* tp_as_sequence */ 479 | 0, /* tp_as_mapping */ 480 | 0, /* tp_hash */ 481 | 0, /* tp_call */ 482 | 0, /* tp_str */ 483 | 0, /* tp_getattro */ 484 | 0, /* tp_setattro */ 485 | 0, /* tp_as_buffer */ 486 | Py_TPFLAGS_DEFAULT, /* tp_flags */ 487 | 0, /* tp_doc */ 488 | 0, /* tp_traverse */ 489 | 0, /* tp_clear */ 490 | 0, /* tp_richcompare */ 491 | offsetof(pysqlite_Statement, in_weakreflist), /* tp_weaklistoffset */ 492 | 0, /* tp_iter */ 493 | 0, /* tp_iternext */ 494 | 0, /* tp_methods */ 495 | 0, /* tp_members */ 496 | 0, /* tp_getset */ 497 | 0, /* tp_base */ 498 | 0, /* tp_dict */ 499 | 0, /* tp_descr_get */ 500 | 0, /* tp_descr_set */ 501 | 0, /* tp_dictoffset */ 502 | (initproc)0, /* tp_init */ 503 | 0, /* tp_alloc */ 504 | 0, /* tp_new */ 505 | 0 /* tp_free */ 506 | }; 507 | 508 | extern int pysqlite_statement_setup_types(void) 509 | { 510 | pysqlite_StatementType.tp_new = PyType_GenericNew; 511 | return PyType_Ready(&pysqlite_StatementType); 512 | } 513 | -------------------------------------------------------------------------------- /src/statement.h: -------------------------------------------------------------------------------- 1 | /* statement.h - definitions for the statement type 2 | * 3 | * Copyright (C) 2005-2010 Gerhard Häring 4 | * 5 | * This file is part of pysqlite. 6 | * 7 | * This software is provided 'as-is', without any express or implied 8 | * warranty. In no event will the authors be held liable for any damages 9 | * arising from the use of this software. 10 | * 11 | * Permission is granted to anyone to use this software for any purpose, 12 | * including commercial applications, and to alter it and redistribute it 13 | * freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not 16 | * claim that you wrote the original software. If you use this software 17 | * in a product, an acknowledgment in the product documentation would be 18 | * appreciated but is not required. 19 | * 2. Altered source versions must be plainly marked as such, and must not be 20 | * misrepresented as being the original software. 21 | * 3. This notice may not be removed or altered from any source distribution. 22 | */ 23 | 24 | #ifndef PYSQLITE_STATEMENT_H 25 | #define PYSQLITE_STATEMENT_H 26 | #define PY_SSIZE_T_CLEAN 27 | #include "Python.h" 28 | 29 | #include "connection.h" 30 | #include "sqlite3.h" 31 | 32 | #define PYSQLITE_TOO_MUCH_SQL (-100) 33 | #define PYSQLITE_SQL_WRONG_TYPE (-101) 34 | 35 | typedef struct 36 | { 37 | PyObject_HEAD 38 | sqlite3* db; 39 | sqlite3_stmt* st; 40 | PyObject* sql; 41 | int in_use; 42 | int is_dml; 43 | PyObject* in_weakreflist; /* List of weak references */ 44 | } pysqlite_Statement; 45 | 46 | extern PyTypeObject pysqlite_StatementType; 47 | 48 | int pysqlite_statement_create(pysqlite_Statement* self, pysqlite_Connection* connection, PyObject* sql); 49 | void pysqlite_statement_dealloc(pysqlite_Statement* self); 50 | 51 | int pysqlite_statement_bind_parameter(pysqlite_Statement* self, int pos, PyObject* parameter); 52 | void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* parameters); 53 | 54 | int pysqlite_statement_finalize(pysqlite_Statement* self); 55 | int pysqlite_statement_reset(pysqlite_Statement* self); 56 | void pysqlite_statement_mark_dirty(pysqlite_Statement* self); 57 | 58 | int pysqlite_statement_setup_types(void); 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /src/util.c: -------------------------------------------------------------------------------- 1 | /* util.c - various utility functions 2 | * 3 | * Copyright (C) 2005-2010 Gerhard Häring 4 | * 5 | * This file is part of pysqlite. 6 | * 7 | * This software is provided 'as-is', without any express or implied 8 | * warranty. In no event will the authors be held liable for any damages 9 | * arising from the use of this software. 10 | * 11 | * Permission is granted to anyone to use this software for any purpose, 12 | * including commercial applications, and to alter it and redistribute it 13 | * freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not 16 | * claim that you wrote the original software. If you use this software 17 | * in a product, an acknowledgment in the product documentation would be 18 | * appreciated but is not required. 19 | * 2. Altered source versions must be plainly marked as such, and must not be 20 | * misrepresented as being the original software. 21 | * 3. This notice may not be removed or altered from any source distribution. 22 | */ 23 | 24 | #include "module.h" 25 | #include "connection.h" 26 | 27 | int pysqlite_step(sqlite3_stmt* statement, pysqlite_Connection* connection) 28 | { 29 | int rc; 30 | 31 | Py_BEGIN_ALLOW_THREADS 32 | rc = sqlite3_step(statement); 33 | Py_END_ALLOW_THREADS 34 | 35 | return rc; 36 | } 37 | 38 | /** 39 | * Checks the SQLite error code and sets the appropriate DB-API exception. 40 | * Returns the error code (0 means no error occurred). 41 | */ 42 | int _pysqlite_seterror(sqlite3* db) 43 | { 44 | PyObject *exc_class; 45 | int errorcode = sqlite3_errcode(db); 46 | 47 | switch (errorcode) 48 | { 49 | case SQLITE_OK: 50 | PyErr_Clear(); 51 | return errorcode; 52 | case SQLITE_INTERNAL: 53 | case SQLITE_NOTFOUND: 54 | exc_class = pysqlite_InternalError; 55 | break; 56 | case SQLITE_NOMEM: 57 | (void)PyErr_NoMemory(); 58 | return errorcode; 59 | case SQLITE_ERROR: 60 | case SQLITE_PERM: 61 | case SQLITE_ABORT: 62 | case SQLITE_BUSY: 63 | case SQLITE_LOCKED: 64 | case SQLITE_READONLY: 65 | case SQLITE_INTERRUPT: 66 | case SQLITE_IOERR: 67 | case SQLITE_FULL: 68 | case SQLITE_CANTOPEN: 69 | case SQLITE_PROTOCOL: 70 | case SQLITE_EMPTY: 71 | case SQLITE_SCHEMA: 72 | exc_class = pysqlite_OperationalError; 73 | break; 74 | case SQLITE_CORRUPT: 75 | exc_class = pysqlite_DatabaseError; 76 | break; 77 | case SQLITE_TOOBIG: 78 | exc_class = pysqlite_DataError; 79 | break; 80 | case SQLITE_CONSTRAINT: 81 | case SQLITE_MISMATCH: 82 | exc_class = pysqlite_IntegrityError; 83 | break; 84 | case SQLITE_MISUSE: 85 | exc_class = pysqlite_ProgrammingError;; 86 | break; 87 | default: 88 | exc_class = pysqlite_DatabaseError; 89 | break; 90 | } 91 | 92 | /* Create and set the exception. */ 93 | { 94 | const char *error_msg; 95 | const char *error_name; 96 | PyObject *exc = NULL; 97 | PyObject *args = NULL; 98 | PyObject *py_code = NULL; 99 | PyObject *py_name = NULL; 100 | 101 | error_name = sqlite3ErrName(errorcode); 102 | 103 | error_msg = sqlite3_errmsg(db); 104 | 105 | args = Py_BuildValue("(s)", error_msg); 106 | if (!args) 107 | goto error; 108 | 109 | exc = PyObject_Call(exc_class, args, NULL); 110 | if (!exc) 111 | goto error; 112 | 113 | py_code = Py_BuildValue("i", errorcode); 114 | if (!py_code) 115 | goto error; 116 | 117 | if (PyObject_SetAttrString(exc, "sqlite_errorcode", py_code) < 0) 118 | goto error; 119 | 120 | py_name = Py_BuildValue("s", error_name); 121 | if (!py_name) 122 | goto error; 123 | 124 | if (PyObject_SetAttrString(exc, "sqlite_errorname", py_name) < 0) 125 | goto error; 126 | 127 | PyErr_SetObject((PyObject *) Py_TYPE(exc), exc); 128 | 129 | error: 130 | Py_XDECREF(py_code); 131 | Py_XDECREF(py_name); 132 | Py_XDECREF(args); 133 | Py_XDECREF(exc); 134 | } 135 | 136 | return errorcode; 137 | } 138 | 139 | #ifdef WORDS_BIGENDIAN 140 | # define IS_LITTLE_ENDIAN 0 141 | #else 142 | # define IS_LITTLE_ENDIAN 1 143 | #endif 144 | 145 | sqlite_int64 146 | _pysqlite_long_as_int64(PyObject * py_val) 147 | { 148 | int overflow; 149 | long long value = PyLong_AsLongLongAndOverflow(py_val, &overflow); 150 | if (value == -1 && PyErr_Occurred()) 151 | return -1; 152 | if (!overflow) { 153 | # if SIZEOF_LONG_LONG > 8 154 | if (-0x8000000000000000LL <= value && value <= 0x7FFFFFFFFFFFFFFFLL) 155 | # endif 156 | return value; 157 | } 158 | else if (sizeof(value) < sizeof(sqlite_int64)) { 159 | sqlite_int64 int64val; 160 | #if PY_VERSION_HEX < 0x030D0000 161 | if (_PyLong_AsByteArray((PyLongObject *)py_val, 162 | (unsigned char *)&int64val, sizeof(int64val), 163 | IS_LITTLE_ENDIAN, 1 /* signed */) >= 0) { 164 | #else 165 | if (_PyLong_AsByteArray((PyLongObject *)py_val, 166 | (unsigned char *)&int64val, sizeof(int64val), 167 | IS_LITTLE_ENDIAN, 1 /* signed */, 1) >= 0) { 168 | #endif 169 | return int64val; 170 | } 171 | } 172 | PyErr_SetString(PyExc_OverflowError, 173 | "Python int too large to convert to SQLite INTEGER"); 174 | return -1; 175 | } 176 | -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | /* util.h - various utility functions 2 | * 3 | * Copyright (C) 2005-2010 Gerhard Häring 4 | * 5 | * This file is part of pysqlite. 6 | * 7 | * This software is provided 'as-is', without any express or implied 8 | * warranty. In no event will the authors be held liable for any damages 9 | * arising from the use of this software. 10 | * 11 | * Permission is granted to anyone to use this software for any purpose, 12 | * including commercial applications, and to alter it and redistribute it 13 | * freely, subject to the following restrictions: 14 | * 15 | * 1. The origin of this software must not be misrepresented; you must not 16 | * claim that you wrote the original software. If you use this software 17 | * in a product, an acknowledgment in the product documentation would be 18 | * appreciated but is not required. 19 | * 2. Altered source versions must be plainly marked as such, and must not be 20 | * misrepresented as being the original software. 21 | * 3. This notice may not be removed or altered from any source distribution. 22 | */ 23 | 24 | #ifndef PYSQLITE_UTIL_H 25 | #define PYSQLITE_UTIL_H 26 | #define PY_SSIZE_T_CLEAN 27 | #include "Python.h" 28 | #include "pythread.h" 29 | #include "sqlite3.h" 30 | #include "connection.h" 31 | 32 | int pysqlite_step(sqlite3_stmt* statement, pysqlite_Connection* connection); 33 | 34 | /** 35 | * Checks the SQLite error code and sets the appropriate DB-API exception. 36 | * Returns the error code (0 means no error occurred). 37 | */ 38 | int _pysqlite_seterror(sqlite3* db); 39 | 40 | sqlite_int64 _pysqlite_long_as_int64(PyObject * value); 41 | 42 | #ifndef _Py_CAST 43 | # define _Py_CAST(type, expr) ((type)(expr)) 44 | #endif 45 | 46 | // Cast argument to PyObject* type. 47 | #ifndef _PyObject_CAST 48 | # define _PyObject_CAST(op) _Py_CAST(PyObject*, op) 49 | #endif 50 | 51 | #if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_NewRef) 52 | static inline PyObject* _Py_NewRef(PyObject *obj) 53 | { 54 | Py_INCREF(obj); 55 | return obj; 56 | } 57 | #define Py_NewRef(obj) _Py_NewRef(_PyObject_CAST(obj)) 58 | #endif 59 | 60 | #if PY_VERSION_HEX < 0x030D0000 61 | static inline int PyWeakref_GetRef(PyObject *ref, PyObject **pobj) 62 | { 63 | PyObject *obj; 64 | if (ref != NULL && !PyWeakref_Check(ref)) { 65 | *pobj = NULL; 66 | PyErr_SetString(PyExc_TypeError, "expected a weakref"); 67 | return -1; 68 | } 69 | obj = PyWeakref_GetObject(ref); 70 | if (obj == NULL) { 71 | // SystemError if ref is NULL 72 | *pobj = NULL; 73 | return -1; 74 | } 75 | if (obj == Py_None) { 76 | *pobj = NULL; 77 | return 0; 78 | } 79 | *pobj = Py_NewRef(obj); 80 | return (*pobj != NULL); 81 | } 82 | #endif 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coleifer/pysqlite3/ca810790b75f4ec18fd24f7d83f8f81e22f069ff/tests/__init__.py -------------------------------------------------------------------------------- /tests/__main__.py: -------------------------------------------------------------------------------- 1 | import optparse 2 | import sys 3 | import unittest 4 | 5 | from tests.backup import suite as backup_suite 6 | from tests.dbapi import suite as dbapi_suite 7 | from tests.factory import suite as factory_suite 8 | from tests.hooks import suite as hooks_suite 9 | from tests.regression import suite as regression_suite 10 | from tests.transactions import suite as transactions_suite 11 | from tests.ttypes import suite as types_suite 12 | from tests.userfunctions import suite as userfunctions_suite 13 | 14 | 15 | def test(verbosity=1, failfast=False): 16 | runner = unittest.TextTestRunner(verbosity=verbosity, failfast=failfast) 17 | all_tests = unittest.TestSuite(( 18 | backup_suite(), 19 | dbapi_suite(), 20 | factory_suite(), 21 | hooks_suite(), 22 | regression_suite(), 23 | transactions_suite(), 24 | types_suite(), 25 | userfunctions_suite())) 26 | results = runner.run(all_tests) 27 | return results.failures, results.errors 28 | 29 | 30 | if __name__ == '__main__': 31 | parser = optparse.OptionParser() 32 | parser.add_option('-v', '--verbosity', default=1, dest='verbosity', 33 | type='int', help='output verbosity, default=1') 34 | parser.add_option('-f', '--failfast', action='store_true', dest='failfast') 35 | options, args = parser.parse_args() 36 | 37 | failures, errors = test(options.verbosity, options.failfast) 38 | if failures or errors: 39 | sys.exit(1) 40 | -------------------------------------------------------------------------------- /tests/backup.py: -------------------------------------------------------------------------------- 1 | from pysqlite3 import dbapi2 as sqlite 2 | import unittest 3 | 4 | 5 | @unittest.skipIf(sqlite.sqlite_version_info < (3, 6, 11), "Backup API not supported") 6 | class BackupTests(unittest.TestCase): 7 | def setUp(self): 8 | cx = self.cx = sqlite.connect(":memory:") 9 | cx.execute('CREATE TABLE foo (key INTEGER)') 10 | cx.executemany('INSERT INTO foo (key) VALUES (?)', [(3,), (4,)]) 11 | cx.commit() 12 | 13 | def tearDown(self): 14 | self.cx.close() 15 | 16 | def verify_backup(self, bckcx): 17 | result = bckcx.execute("SELECT key FROM foo ORDER BY key").fetchall() 18 | self.assertEqual(result[0][0], 3) 19 | self.assertEqual(result[1][0], 4) 20 | 21 | def test_bad_target_none(self): 22 | with self.assertRaises(TypeError): 23 | self.cx.backup(None) 24 | 25 | def test_bad_target_filename(self): 26 | with self.assertRaises(TypeError): 27 | self.cx.backup('some_file_name.db') 28 | 29 | def test_bad_target_same_connection(self): 30 | with self.assertRaises(ValueError): 31 | self.cx.backup(self.cx) 32 | 33 | def test_bad_target_closed_connection(self): 34 | bck = sqlite.connect(':memory:') 35 | bck.close() 36 | with self.assertRaises(sqlite.ProgrammingError): 37 | self.cx.backup(bck) 38 | 39 | def test_bad_target_in_transaction(self): 40 | bck = sqlite.connect(':memory:') 41 | bck.execute('CREATE TABLE bar (key INTEGER)') 42 | bck.executemany('INSERT INTO bar (key) VALUES (?)', [(3,), (4,)]) 43 | with self.assertRaises(sqlite.OperationalError) as cm: 44 | self.cx.backup(bck) 45 | if sqlite.sqlite_version_info < (3, 8, 8): 46 | self.assertEqual(str(cm.exception), 'target is in transaction') 47 | 48 | def test_keyword_only_args(self): 49 | with self.assertRaises(TypeError): 50 | with sqlite.connect(':memory:') as bck: 51 | self.cx.backup(bck, 1) 52 | 53 | def test_simple(self): 54 | with sqlite.connect(':memory:') as bck: 55 | self.cx.backup(bck) 56 | self.verify_backup(bck) 57 | 58 | def test_progress(self): 59 | journal = [] 60 | 61 | def progress(status, remaining, total): 62 | journal.append(status) 63 | 64 | with sqlite.connect(':memory:') as bck: 65 | self.cx.backup(bck, pages=1, progress=progress) 66 | self.verify_backup(bck) 67 | 68 | self.assertEqual(len(journal), 2) 69 | self.assertEqual(journal[0], sqlite.SQLITE_OK) 70 | self.assertEqual(journal[1], sqlite.SQLITE_DONE) 71 | 72 | def test_progress_all_pages_at_once_1(self): 73 | journal = [] 74 | 75 | def progress(status, remaining, total): 76 | journal.append(remaining) 77 | 78 | with sqlite.connect(':memory:') as bck: 79 | self.cx.backup(bck, progress=progress) 80 | self.verify_backup(bck) 81 | 82 | self.assertEqual(len(journal), 1) 83 | self.assertEqual(journal[0], 0) 84 | 85 | def test_progress_all_pages_at_once_2(self): 86 | journal = [] 87 | 88 | def progress(status, remaining, total): 89 | journal.append(remaining) 90 | 91 | with sqlite.connect(':memory:') as bck: 92 | self.cx.backup(bck, pages=-1, progress=progress) 93 | self.verify_backup(bck) 94 | 95 | self.assertEqual(len(journal), 1) 96 | self.assertEqual(journal[0], 0) 97 | 98 | def test_sleep(self): 99 | with self.assertRaises(ValueError) as bm: 100 | with sqlite.connect(':memory:') as bck: 101 | self.cx.backup(bck, sleep=-1) 102 | self.assertEqual(str(bm.exception), 'sleep must be greater-than or equal to zero') 103 | 104 | with self.assertRaises(TypeError): 105 | with sqlite.connect(':memory:') as bck: 106 | self.cx.backup(bck, sleep=None) 107 | 108 | with sqlite.connect(':memory:') as bck: 109 | self.cx.backup(bck, sleep=10) 110 | self.verify_backup(bck) 111 | 112 | def test_non_callable_progress(self): 113 | with self.assertRaises(TypeError) as cm: 114 | with sqlite.connect(':memory:') as bck: 115 | self.cx.backup(bck, pages=1, progress='bar') 116 | self.assertEqual(str(cm.exception), 'progress argument must be a callable') 117 | 118 | def test_modifying_progress(self): 119 | journal = [] 120 | 121 | def progress(status, remaining, total): 122 | if not journal: 123 | self.cx.execute('INSERT INTO foo (key) VALUES (?)', (remaining+1000,)) 124 | self.cx.commit() 125 | journal.append(remaining) 126 | 127 | with sqlite.connect(':memory:') as bck: 128 | self.cx.backup(bck, pages=1, progress=progress) 129 | self.verify_backup(bck) 130 | 131 | result = bck.execute("SELECT key FROM foo" 132 | " WHERE key >= 1000" 133 | " ORDER BY key").fetchall() 134 | self.assertEqual(result[0][0], 1001) 135 | 136 | self.assertEqual(len(journal), 3) 137 | self.assertEqual(journal[0], 1) 138 | self.assertEqual(journal[1], 1) 139 | self.assertEqual(journal[2], 0) 140 | 141 | def test_failing_progress(self): 142 | def progress(status, remaining, total): 143 | raise SystemError('nearly out of space') 144 | 145 | with self.assertRaises(SystemError) as err: 146 | with sqlite.connect(':memory:') as bck: 147 | self.cx.backup(bck, progress=progress) 148 | self.assertEqual(str(err.exception), 'nearly out of space') 149 | 150 | def test_database_source_name(self): 151 | with sqlite.connect(':memory:') as bck: 152 | self.cx.backup(bck, name='main') 153 | with sqlite.connect(':memory:') as bck: 154 | self.cx.backup(bck, name='temp') 155 | with self.assertRaises(sqlite.OperationalError) as cm: 156 | with sqlite.connect(':memory:') as bck: 157 | self.cx.backup(bck, name='non-existing') 158 | self.assertIn( 159 | str(cm.exception), 160 | ['SQL logic error', 'SQL logic error or missing database'] 161 | ) 162 | 163 | self.cx.execute("ATTACH DATABASE ':memory:' AS attached_db") 164 | self.cx.execute('CREATE TABLE attached_db.foo (key INTEGER)') 165 | self.cx.executemany('INSERT INTO attached_db.foo (key) VALUES (?)', [(3,), (4,)]) 166 | self.cx.commit() 167 | with sqlite.connect(':memory:') as bck: 168 | self.cx.backup(bck, name='attached_db') 169 | self.verify_backup(bck) 170 | 171 | 172 | def suite(): 173 | loader = unittest.TestLoader() 174 | tests = [loader.loadTestsFromTestCase(t) for t in ( 175 | BackupTests,)] 176 | return unittest.TestSuite(tests) 177 | 178 | def test(): 179 | runner = unittest.TextTestRunner() 180 | runner.run(suite()) 181 | 182 | if __name__ == "__main__": 183 | test() 184 | -------------------------------------------------------------------------------- /tests/dbapi.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coleifer/pysqlite3/ca810790b75f4ec18fd24f7d83f8f81e22f069ff/tests/dbapi.py -------------------------------------------------------------------------------- /tests/factory.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coleifer/pysqlite3/ca810790b75f4ec18fd24f7d83f8f81e22f069ff/tests/factory.py -------------------------------------------------------------------------------- /tests/hooks.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coleifer/pysqlite3/ca810790b75f4ec18fd24f7d83f8f81e22f069ff/tests/hooks.py -------------------------------------------------------------------------------- /tests/regression.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coleifer/pysqlite3/ca810790b75f4ec18fd24f7d83f8f81e22f069ff/tests/regression.py -------------------------------------------------------------------------------- /tests/transactions.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coleifer/pysqlite3/ca810790b75f4ec18fd24f7d83f8f81e22f069ff/tests/transactions.py -------------------------------------------------------------------------------- /tests/ttypes.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coleifer/pysqlite3/ca810790b75f4ec18fd24f7d83f8f81e22f069ff/tests/ttypes.py -------------------------------------------------------------------------------- /tests/userfunctions.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coleifer/pysqlite3/ca810790b75f4ec18fd24f7d83f8f81e22f069ff/tests/userfunctions.py --------------------------------------------------------------------------------