New upstream release 2.7.0 upstream upstream/2.7.0
authorJoel Rosdahl <joel@debian.org>
Sun, 16 Aug 2015 13:52:55 +0000 (15:52 +0200)
committerJoel Rosdahl <joel@debian.org>
Sun, 16 Aug 2015 13:52:55 +0000 (15:52 +0200)
58 files changed:
.gitignore [new file with mode: 0644]
.hgignore [new file with mode: 0644]
.travis.yml [new file with mode: 0644]
LICENSE
PKG-INFO [deleted file]
README.md [new file with mode: 0644]
benchmarks/fetch.py [new file with mode: 0644]
benchmarks/insert.py [new file with mode: 0644]
doc/default.css [new file with mode: 0644]
doc/docutils.css [new file with mode: 0644]
doc/install-source.txt [deleted file]
doc/sphinx/.templates/.keepme [new file with mode: 0644]
doc/sphinx/conf.py
doc/sphinx/sqlite3.rst
lib/__init__.py
lib/dbapi2.py
lib/test/__init__.py
lib/test/dbapi.py
lib/test/factory.py
lib/test/hooks.py
lib/test/py25/py25tests.py
lib/test/regression.py
lib/test/transactions.py
lib/test/types.py
lib/test/userfunctions.py
misc/Makefile [new file with mode: 0644]
misc/announce_template.txt [new file with mode: 0644]
misc/eager.py [new file with mode: 0644]
misc/lru.py [new file with mode: 0755]
misc/patterns.py [new file with mode: 0644]
mkwin32.py [new file with mode: 0755]
scripts/stress.py [new file with mode: 0644]
scripts/test-pysqlite [new file with mode: 0755]
setup.cfg
setup.py
src/backup.c [new file with mode: 0644]
src/backup.h
src/cache.c
src/cache.h
src/connection.c
src/connection.h
src/cursor.c
src/cursor.h
src/module.c
src/module.h
src/prepare_protocol.c
src/prepare_protocol.h
src/row.c
src/row.h
src/sqlite_constants.h [new file with mode: 0644]
src/sqlitecompat.h
src/statement.c
src/statement.h
src/util.c
src/util.h
test.sh [new file with mode: 0755]
tox.ini [new file with mode: 0644]
update_sqlite_constants.py [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..96c9977
--- /dev/null
@@ -0,0 +1,8 @@
+*~
+*.pyc
+*.swp
+build
+sqlite3.c
+sqlite3.h
+sqlite3ext.h
+shell.c
diff --git a/.hgignore b/.hgignore
new file mode 100644 (file)
index 0000000..eedc0ba
--- /dev/null
+++ b/.hgignore
@@ -0,0 +1,6 @@
+syntax: glob
+amalgamation
+build
+dist/*
+pysqlite.egg-info/
+*.pyc
diff --git a/.travis.yml b/.travis.yml
new file mode 100644 (file)
index 0000000..24b325e
--- /dev/null
@@ -0,0 +1,7 @@
+sudo: false
+language: python
+python:
+  - "2.6"
+  - "2.7"
+install: pip install tox-travis
+script: tox
diff --git a/LICENSE b/LICENSE
index 268c33b..1f679a2 100644 (file)
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2004-2007 Gerhard Häring
+Copyright (c) 2004-2015 Gerhard Häring
 
 This software is provided 'as-is', without any express or implied warranty. In
 no event will the authors be held liable for any damages arising from the use
diff --git a/PKG-INFO b/PKG-INFO
deleted file mode 100644 (file)
index e0fdf08..0000000
--- a/PKG-INFO
+++ /dev/null
@@ -1,25 +0,0 @@
-Metadata-Version: 1.0
-Name: pysqlite
-Version: 2.6.3
-Summary: DB-API 2.0 interface for SQLite 3.x
-Home-page: http://pysqlite.googlecode.com/
-Author: Gerhard Haering
-Author-email: gh@ghaering.de
-License: zlib/libpng license
-Download-URL: http://code.google.com/p/pysqlite/downloads/list
-Description: Python interface to SQLite 3
-        
-        pysqlite is an interface to the SQLite 3.x embedded relational database engine.
-        It is almost fully compliant with the Python database API version 2.0 also
-        exposes the unique features of SQLite.
-Platform: ALL
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: zlib/libpng License
-Classifier: Operating System :: MacOS :: MacOS X
-Classifier: Operating System :: Microsoft :: Windows
-Classifier: Operating System :: POSIX
-Classifier: Programming Language :: C
-Classifier: Programming Language :: Python
-Classifier: Topic :: Database :: Database Engines/Servers
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..eed6757
--- /dev/null
+++ b/README.md
@@ -0,0 +1,6 @@
+pysqlite
+========
+
+Python DB-API module for SQLite 3.
+
+Online documentation can be found [here] (https://pysqlite.readthedocs.org/en/latest/sqlite3.html).
diff --git a/benchmarks/fetch.py b/benchmarks/fetch.py
new file mode 100644 (file)
index 0000000..a80efd9
--- /dev/null
@@ -0,0 +1,97 @@
+import time\r
+\r
+def yesno(question):\r
+    val = raw_input(question + " ")\r
+    return val.startswith("y") or val.startswith("Y")\r
+\r
+use_pysqlite2 = yesno("Use pysqlite 2.0?")\r
+if use_pysqlite2:\r
+    use_custom_types = yesno("Use custom types?")\r
+    use_dictcursor = yesno("Use dict cursor?")\r
+    use_rowcursor = yesno("Use row cursor?")\r
+else:\r
+    use_tuple = yesno("Use rowclass=tuple?")\r
+\r
+if use_pysqlite2:\r
+    from pysqlite2 import dbapi2 as sqlite\r
+else:\r
+    import sqlite\r
+\r
+def dict_factory(cursor, row):\r
+    d = {}\r
+    for idx, col in enumerate(cursor.description):\r
+        d[col[0]] = row[idx]\r
+    return d\r
+\r
+if use_pysqlite2:\r
+    def dict_factory(cursor, row):\r
+        d = {}\r
+        for idx, col in enumerate(cursor.description):\r
+            d[col[0]] = row[idx]\r
+        return d\r
+\r
+    class DictCursor(sqlite.Cursor):\r
+        def __init__(self, *args, **kwargs):\r
+            sqlite.Cursor.__init__(self, *args, **kwargs)\r
+            self.row_factory = dict_factory\r
+\r
+    class RowCursor(sqlite.Cursor):\r
+        def __init__(self, *args, **kwargs):\r
+            sqlite.Cursor.__init__(self, *args, **kwargs)\r
+            self.row_factory = sqlite.Row\r
+\r
+def create_db():\r
+    if sqlite.version_info > (2, 0):\r
+        if use_custom_types:\r
+            con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES|sqlite.PARSE_COLNAMES)\r
+            sqlite.register_converter("text", lambda x: "<%s>" % x)\r
+        else:\r
+            con = sqlite.connect(":memory:")\r
+        if use_dictcursor:\r
+            cur = con.cursor(factory=DictCursor)\r
+        elif use_rowcursor:\r
+            cur = con.cursor(factory=RowCursor)\r
+        else:\r
+            cur = con.cursor()\r
+    else:\r
+        if use_tuple:\r
+            con = sqlite.connect(":memory:")\r
+            con.rowclass = tuple\r
+            cur = con.cursor()\r
+        else:\r
+            con = sqlite.connect(":memory:")\r
+            cur = con.cursor()\r
+    cur.execute("""\r
+        create table test(v text, f float, i integer)\r
+        """)\r
+    return (con, cur)\r
+\r
+def test():\r
+    row = ("sdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffasfd", 3.14, 42)\r
+    l = []\r
+    for i in range(1000):\r
+        l.append(row)\r
+\r
+    con, cur = create_db()\r
+\r
+    if sqlite.version_info > (2, 0):\r
+        sql = "insert into test(v, f, i) values (?, ?, ?)"\r
+    else:\r
+        sql = "insert into test(v, f, i) values (%s, %s, %s)"\r
+\r
+    for i in range(50):\r
+        cur.executemany(sql, l)\r
+\r
+    cur.execute("select count(*) as cnt from test")\r
+\r
+    starttime = time.time()\r
+    for i in range(50):\r
+        cur.execute("select v, f, i from test")\r
+        l = cur.fetchall()\r
+    endtime = time.time()\r
+\r
+    print "elapsed:", endtime - starttime\r
+\r
+if __name__ == "__main__":\r
+    test()\r
+\r
diff --git a/benchmarks/insert.py b/benchmarks/insert.py
new file mode 100644 (file)
index 0000000..d2a8d9d
--- /dev/null
@@ -0,0 +1,61 @@
+import time\r
+\r
+def yesno(question):\r
+    val = raw_input(question + " ")\r
+    return val.startswith("y") or val.startswith("Y")\r
+\r
+use_pysqlite2 = yesno("Use pysqlite 2.0?")\r
+use_autocommit = yesno("Use autocommit?")\r
+use_executemany= yesno("Use executemany?")\r
+\r
+if use_pysqlite2:\r
+    from pysqlite2 import dbapi2 as sqlite\r
+else:\r
+    import sqlite\r
+\r
+\r
+def create_db():\r
+    con = sqlite.connect(":memory:")\r
+    if use_autocommit:\r
+        if use_pysqlite2:\r
+            con.isolation_level = None\r
+        else:\r
+            con.autocommit = True\r
+    cur = con.cursor()\r
+    cur.execute("""\r
+        create table test(v text, f float, i integer)\r
+        """)\r
+    cur.close()\r
+    return con\r
+\r
+def test():\r
+    row = ("sdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffasfd", 3.14, 42)\r
+    l = []\r
+    for i in range(1000):\r
+        l.append(row)\r
+\r
+    con = create_db()\r
+    cur = con.cursor()\r
+\r
+    if sqlite.version_info > (2, 0):\r
+        sql = "insert into test(v, f, i) values (?, ?, ?)"\r
+    else:\r
+        sql = "insert into test(v, f, i) values (%s, %s, %s)"\r
+\r
+    starttime = time.time()\r
+    for i in range(50):\r
+        if use_executemany:\r
+            cur.executemany(sql, l)\r
+        else:\r
+            for r in l:\r
+                cur.execute(sql, r)\r
+    endtime = time.time()\r
+\r
+    print "elapsed", endtime - starttime\r
+\r
+    cur.execute("select count(*) from test")\r
+    print "rows:", cur.fetchone()[0]\r
+\r
+if __name__ == "__main__":\r
+    test()\r
+\r
diff --git a/doc/default.css b/doc/default.css
new file mode 100644 (file)
index 0000000..05ca4b1
--- /dev/null
@@ -0,0 +1,10 @@
+@import url(docutils.css);
+@import url(silvercity.css);
+
+div.code-block{
+margin-left: 2em ;
+margin-right: 2em ;
+background-color: #eeeeee;
+font-family: "Courier New", Courier, monospace;
+font-size: 10pt;
+}
diff --git a/doc/docutils.css b/doc/docutils.css
new file mode 100644 (file)
index 0000000..43074c6
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:Date: $Date: 2005-04-25 22:24:49 +0200 (Mon, 25 Apr 2005) $
+:Version: $Revision: 3256 $
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+*/
+
+/* "! important" is used here to override other ``margin-top`` and
+   ``margin-bottom`` styles that are later in the stylesheet or 
+   more specific.  See http://www.w3.org/TR/CSS1#the-cascade */
+.first {
+  margin-top: 0 ! important }
+
+.last {
+  margin-bottom: 0 ! important }
+
+.hidden {
+  display: none }
+
+a.toc-backref {
+  text-decoration: none ;
+  color: black }
+
+blockquote.epigraph {
+  margin: 2em 5em ; }
+
+dl.docutils dd {
+  margin-bottom: 0.5em }
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+  font-weight: bold }
+*/
+
+div.abstract {
+  margin: 2em 5em }
+
+div.abstract p.topic-title {
+  font-weight: bold ;
+  text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+  margin: 2em ;
+  border: medium outset ;
+  padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: red ;
+  font-weight: bold ;
+  font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+   compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+  margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+  margin-top: 0.5em }
+*/
+
+div.dedication {
+  margin: 2em 5em ;
+  text-align: center ;
+  font-style: italic }
+
+div.dedication p.topic-title {
+  font-weight: bold ;
+  font-style: normal }
+
+div.figure {
+  margin-left: 2em }
+
+div.footer, div.header {
+  font-size: smaller }
+
+div.line-block {
+  display: block ;
+  margin-top: 1em ;
+  margin-bottom: 1em }
+
+div.line-block div.line-block {
+  margin-top: 0 ;
+  margin-bottom: 0 ;
+  margin-left: 1.5em }
+
+div.sidebar {
+  margin-left: 1em ;
+  border: medium outset ;
+  padding: 1em ;
+  background-color: #ffffee ;
+  width: 40% ;
+  float: right ;
+  clear: right }
+
+div.sidebar p.rubric {
+  font-family: sans-serif ;
+  font-size: medium }
+
+div.system-messages {
+  margin: 5em }
+
+div.system-messages h1 {
+  color: red }
+
+div.system-message {
+  border: medium outset ;
+  padding: 1em }
+
+div.system-message p.system-message-title {
+  color: red ;
+  font-weight: bold }
+
+div.topic {
+  margin: 2em }
+
+h1.title {
+  text-align: center }
+
+h2.subtitle {
+  text-align: center }
+
+hr.docutils {
+  width: 75% }
+
+ol.simple, ul.simple {
+  margin-bottom: 1em }
+
+ol.arabic {
+  list-style: decimal }
+
+ol.loweralpha {
+  list-style: lower-alpha }
+
+ol.upperalpha {
+  list-style: upper-alpha }
+
+ol.lowerroman {
+  list-style: lower-roman }
+
+ol.upperroman {
+  list-style: upper-roman }
+
+p.attribution {
+  text-align: right ;
+  margin-left: 50% }
+
+p.caption {
+  font-style: italic }
+
+p.credits {
+  font-style: italic ;
+  font-size: smaller }
+
+p.label {
+  white-space: nowrap }
+
+p.rubric {
+  font-weight: bold ;
+  font-size: larger ;
+  color: maroon ;
+  text-align: center }
+
+p.sidebar-title {
+  font-family: sans-serif ;
+  font-weight: bold ;
+  font-size: larger }
+
+p.sidebar-subtitle {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+p.topic-title {
+  font-weight: bold }
+
+pre.address {
+  margin-bottom: 0 ;
+  margin-top: 0 ;
+  font-family: serif ;
+  font-size: 100% }
+
+pre.line-block {
+  font-family: serif ;
+  font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+  margin-left: 2em ;
+  margin-right: 2em ;
+  background-color: #eeeeee }
+
+span.classifier {
+  font-family: sans-serif ;
+  font-style: oblique }
+
+span.classifier-delimiter {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+span.interpreted {
+  font-family: sans-serif }
+
+span.option {
+  white-space: nowrap }
+
+span.pre {
+  white-space: pre }
+
+span.problematic {
+  color: red }
+
+table.citation {
+  border-left: solid thin gray }
+
+table.docinfo {
+  margin: 2em 4em }
+
+table.docutils {
+  margin-top: 0.5em ;
+  margin-bottom: 0.5em }
+
+table.footnote {
+  border-left: solid thin black }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+  padding-left: 0.5em ;
+  padding-right: 0.5em ;
+  vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+  font-weight: bold ;
+  text-align: left ;
+  white-space: nowrap ;
+  padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+  font-size: 100% }
+
+tt.docutils {
+  background-color: #eeeeee }
+
+ul.auto-toc {
+  list-style-type: none }
+
+body {
+ background-color: #eeeeff;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+}
diff --git a/doc/install-source.txt b/doc/install-source.txt
deleted file mode 100644 (file)
index 90a3ce7..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
--------------------------------------------------
-pysqlite installation guide - source distribution
--------------------------------------------------
-
-\(c\) 2005 Gerhard Häring
-
-Note: For Windows users, it is recommended that you use the win32 binary
-  distribution of pysqlite!
-
-Steps:
-
-  - `Step 1: Satisfy the dependencies`_
-  - `Step 2: Compile pysqlite`_
-  - `Step 3: Install pysqlite`_
-  - `Step 4: Test your pysqlite installation`_
-
-Step 1: Satisfy The Dependencies
-================================
-
-pysqlite requires a valid combination of the dependencies in the list below.
-
-Detailed instructions on how to install each dependency are beyond the scope of
-this document; consult the dependency distributor for installation
-instructions.
-
-Dependencies:
-
- 1. Operating System and C Compiler - one of:
-
-    * Linux/FreeBSD/NetBSD/OpenBSD and GCC
-
-    * Other POSIX-compliant operating system and a C compiler
-
- 2. SQLite:
-
-    * SQLite version 3.0.8 or later (as of pysqlite 2.2.0). This means we need
-      the SQLite library installed - either statically or dynamically linked -
-      and the SQLite header files. On Linux, the chances are very high that
-      your distribution offers packages for SQLite 3. Be sure to verify the
-      package is recent enough (version 3.0.8 or higher) and that you're
-      installing the development package as well, which will be need for
-      building pysqlite. On Debian and derivatives, the package to look for is
-      called libsqlite3-dev.
-
- 3. Python:
-
-    * Python 2.3 or later
-
-Step 2: Compile pysqlite
-========================
-
-Once you have successfully installed the dependencies, you may proceed with the
-installation of pysqlite itself.
-
-pysqlite has full support for the distutils_, the standard facility for Python
-package distribution and installation. Full instructions for using the
-distutils are available in `this section of the Python documentation`_, but you
-can skip them unless you have an otherwise insoluble problem.
-
-Open a command prompt, change to the directory where you decompressed the
-pysqlite source distribution, and type::
-
-  python setup.py build
-
-The installation script, setup.py, will attempt to automatically detect the
-information needed by the C compiler; then it will invoke the distutils to
-perform the actual compilation. If you installed automatic distributions of the
-dependencies that place themselves in standard locations (on UNIX-style
-operating systems), the compilation should proceed without incident.
-
-Otherwise you will have to customize the build process. That's what the file
-*setup.cfg* is meant for. It's contains a few lines that you can customize so
-your C compiler will find the library and header files and you can also do a
-few other tweaks, like build pysqlite in debug mode.
-
-After you've customized *setup.cfg* appropriately, try invoking ``python
-setup.py build`` again.
-
-If setup.py raises no errors and its output concludes with something like
-"Creating library...", then you are ready to proceed to the next step.
-
-If you receive an error message from the compiler, then try to look at the
-first error it reports. Other errors will most likely be aftereffects from the
-first error (like not finding the sqlite3.h header file).
-
-
-Step 3: Install pysqlite
-========================
-
-During this step, the setup script moves the *pysqlite2* package (including the
-newly compiled C extension) to the standard package directory of your Python
-installation so that Python will be able to import pysqlite2.dbapi2 and
-pysqlite2.test.
-
-In addition to the Python code and shared library files actually used by the
-Python interpreter, the setup script typically installs some supporting files,
-such as documentation. Depending on your system configuration, these supporting
-files may be placed in the same directory or a different directory from the
-files used by the Python interpreter.
-
-Run the following command::
-
-  python setup.py install
-
-The setup script will install pysqlite, listing each file it installs.
-
-Errors during this step are rare because compilation (the finicky part of this
-process) has already taken place; installation is really just a matter of
-copying files. However, there will be file system permission errors if the
-Python installation directory is not writable by the user running the setup
-script. If you encounter such an error, try one of the following:
-
-- Log in as a user who has the required file system permissions and repeat the
-  installation step.
-- Manually copy the directory build/lib.platform-pyver/pysqlite2 (which
-  contains the Python modules and compiled library files created during the
-  compilation step) to a directory in your PYTHONPATH. This approach will not
-  install the supporting files, but they are for the benefit of the programmer
-  rather than the Python interpreter anyway. 
-
-Step 4: Test Your pysqlite Installation
-=======================================
-
-Switch to a directory other than the temporary directory into which you
-decompressed the source distribution (to avoid conflict between the copy of
-pysqlite in that directory and the copy placed under the standard Python
-site-packages directory), then run the pysqlite test suite by starting a Python
-interpreter for the Python version you installed pysqlite for and entering the
-following::
-
-    >>> from pysqlite2 import test
-    >>> test.test()
-    .....................................................................................................
-    ----------------------------------------------------------------------
-    Ran 101 tests in 0.182s
-
-If the test suite runs without any errors, you are finished.
-
-You should not encounter any errors at this stage since you have already
-completed the compilation and installation steps successfully. If you do,
-please report them to the `pysqlite bug tracker`_ or the `pysqlite mailing
-list`_.
-
-.. _distutils: http://www.python.org/sigs/distutils-sig/
-.. _this section of the Python documentation: http://www.python.org/doc/current/inst/inst.html
-.. _pysqlite bug tracker: http://pysqlite.googlecode.com/
-.. _pysqlite mailing list: http://itsystementwicklung.de/cgi-bin/mailman/listinfo/list-pysqlite
diff --git a/doc/sphinx/.templates/.keepme b/doc/sphinx/.templates/.keepme
new file mode 100644 (file)
index 0000000..e69de29
index 6528513..27fbc03 100644 (file)
@@ -34,15 +34,15 @@ master_doc = 'index'
 
 # General substitutions.
 project = 'pysqlite'
-copyright = u'2008-2009, Gerhard Häring'
+copyright = u'2008-2015, Gerhard Häring'
 
 # The default replacements for |version| and |release|, also used in various
 # other places throughout the built documents.
 #
 # The short X.Y version.
-version = '2.6'
+version = '2.7'
 # The full version, including alpha/beta/rc tags.
-release = '2.6.0'
+release = '2.7.0'
 
 # There are two options for replacing |today|: either, you set today to some
 # non-false value, then it is used:
index a0d5de8..e7ee7b1 100644 (file)
@@ -90,7 +90,7 @@ This example uses the iterator form::
 
 .. seealso::
 
-   http://code.google.com/p/pysqlite/
+   http://github.com/ghaering/pysqlite
       The pysqlite web page -- sqlite3 is developed externally under the name
       "pysqlite".
 
@@ -151,7 +151,7 @@ Module functions and constants
    For the *isolation_level* parameter, please see the
    :attr:`Connection.isolation_level` property of :class:`Connection` objects.
 
-   SQLite natively supports only the types TEXT, INTEGER, FLOAT, BLOB and NULL. If
+   SQLite natively supports only the types TEXT, INTEGER, REAL, BLOB and NULL. If
    you want to use other types you must add support for them yourself. The
    *detect_types* parameter and the using custom **converters** registered with the
    module-level :func:`register_converter` function allow you to easily do that.
@@ -353,6 +353,24 @@ Connection Objects
    one. All necessary constants are available in the :mod:`sqlite3` module.
 
 
+.. method:: Connection.get_limit(limit_id)
+
+   This routine returns the current value of the limit specified by the
+   constant limit_id.
+
+   Please consult the SQLite documentation about the possible values for the
+   limit_id parameter.
+
+
+.. method:: Connection.set_limit(limit_id, new_value)
+
+   This routine sets a new value for the limit specified by the
+   constant limit_id.
+
+   Please consult the SQLite documentation about the possible values for the
+   limit_id parameter.
+
+
 .. method:: Connection.set_progress_handler(handler, n)
 
    This routine registers a callback. The callback is invoked for every *n*
@@ -453,6 +471,13 @@ A :class:`Cursor` instance has the following attributes and methods:
 
    A SQLite database cursor has the following attributes and methods:
 
+.. method:: Cursor.close()
+
+   Close the cursor now (rather than whenever __del__ is called).
+
+   The cursor will be unusable from this point forward; an Error (or subclass)
+   exception will be raised if any operation is attempted with the cursor.
+
 .. method:: Cursor.execute(sql, [parameters])
 
    Executes an SQL statement. The SQL statement may be parametrized (i. e.
index 4028868..ed2bf84 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/__init__.py: the pysqlite2 package.
 #
-# Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2005-2015 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
index 1a12704..52e4d0a 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/dbapi2.py: the DB-API 2.0 interface
 #
-# Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2004-2015 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
@@ -65,12 +65,12 @@ def register_adapters_and_converters():
     def convert_timestamp(val):
         datepart, timepart = val.split(" ")
         year, month, day = map(int, datepart.split("-"))
-        timepart_full = timepart.split(".")
-        hours, minutes, seconds = map(int, timepart_full[0].split(":"))
-        if len(timepart_full) == 2:
-            microseconds = int(timepart_full[1])
-        else:
-            microseconds = 0
+        hours_part, minutes_part, seconds_part = timepart.split(":")
+        hours, minutes = int(hours_part), int(minutes_part)
+
+        sec_part, _, sub_sec_part = seconds_part.partition(".")
+        seconds = int(sec_part)
+        microseconds = int(sub_sec_part + "0" * (6 - len(sub_sec_part)))
 
         val = datetime.datetime(year, month, day, hours, minutes, seconds, microseconds)
         return val
index bc2ddd5..618d10f 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/test/__init__.py: the package containing the test suite
 #
-# Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2004-2015 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
 #    misrepresented as being the original software.
 # 3. This notice may not be removed or altered from any source distribution.
 
-import os, sys
 import unittest
-
-if os.path.exists("extended_setup.py"):
-    print "-" * 75
-    print "You should not run the test suite from the pysqlite build directory."
-    print "This does not work well because the extension module cannot be found."
-    print "Just run the test suite from somewhere else, please!"
-    print "-" * 75
-    sys.exit(1)
+import sys
 
 from pysqlite2.test import dbapi, types, userfunctions, factory, transactions,\
     hooks, regression, dump
-from pysqlite2 import dbapi2 as sqlite
 
 def suite():
     tests = [dbapi.suite(), types.suite(), userfunctions.suite(),
index ea0b417..bd13038 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/test/dbapi.py: tests for DB-API compliance
 #
-# Copyright (C) 2004-2009 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2004-2015 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
index 4bed94e..25921c4 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/test/factory.py: tests for the various factories in pysqlite
 #
-# Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2005-2015 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
index 8452988..60adb5b 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/test/hooks.py: tests for various SQLite-specific hooks
 #
-# Copyright (C) 2006-2007 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2006-2015 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
@@ -21,7 +21,7 @@
 #    misrepresented as being the original software.
 # 3. This notice may not be removed or altered from any source distribution.
 
-import os, unittest
+import unittest
 import pysqlite2.dbapi2 as sqlite
 
 class CollationTests(unittest.TestCase):
@@ -122,29 +122,6 @@ class ProgressTests(unittest.TestCase):
         self.assertTrue(progress_calls)
 
 
-    def CheckOpcodeCount(self):
-        """
-        Test that the opcode argument is respected.
-        """
-        con = sqlite.connect(":memory:")
-        progress_calls = []
-        def progress():
-            progress_calls.append(None)
-            return 0
-        con.set_progress_handler(progress, 1)
-        curs = con.cursor()
-        curs.execute("""
-            create table foo (a, b)
-            """)
-        first_count = len(progress_calls)
-        progress_calls = []
-        con.set_progress_handler(progress, 2)
-        curs.execute("""
-            create table bar (a, b)
-            """)
-        second_count = len(progress_calls)
-        self.assertTrue(first_count > second_count)
-
     def CheckCancelOperation(self):
         """
         Test that returning a non-zero value stops the operation in progress.
@@ -175,10 +152,31 @@ class ProgressTests(unittest.TestCase):
         con.execute("select 1 union select 2 union select 3").fetchall()
         self.assertEqual(action, 0, "progress handler was not cleared")
 
+class LimitTests(unittest.TestCase):
+    def CheckGetLimit(self):
+        """
+        Test that the get limit method return something useful.
+        """
+        con = sqlite.connect(":memory:")
+        val = con.get_limit(sqlite.SQLITE_LIMIT_VARIABLE_NUMBER)
+        self.assertTrue(val > 0)
+
+    def CheckSetLimit(self):
+        """
+        Test that the set limit method actally changes limits.
+        """
+        con = sqlite.connect(":memory:")
+        oldval = con.get_limit(sqlite.SQLITE_LIMIT_VARIABLE_NUMBER)
+        con.set_limit(sqlite.SQLITE_LIMIT_VARIABLE_NUMBER, oldval - 1)
+        newval = con.get_limit(sqlite.SQLITE_LIMIT_VARIABLE_NUMBER)
+
+        self.assertEqual(newval, oldval - 1)
+
 def suite():
     collation_suite = unittest.makeSuite(CollationTests, "Check")
     progress_suite = unittest.makeSuite(ProgressTests, "Check")
-    return unittest.TestSuite((collation_suite, progress_suite))
+    limit_suite = unittest.makeSuite(LimitTests, "Check")
+    return unittest.TestSuite((collation_suite, progress_suite, limit_suite))
 
 def test():
     runner = unittest.TextTestRunner()
index c75e507..20ddfe8 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/test/regression.py: pysqlite regression tests
 #
-# Copyright (C) 2007 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2007-2015 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
index e09abf6..778df64 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/test/regression.py: pysqlite regression tests
 #
-# Copyright (C) 2006-2009 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2006-2015 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
@@ -259,6 +259,29 @@ class RegressionTests(unittest.TestCase):
         self.assertRaises(TypeError, con.set_authorizer, var)
         self.assertRaises(TypeError, con.set_progress_handler, var)
 
+    def CheckRecursiveCursorUse(self):
+        """
+        http://bugs.python.org/issue10811
+
+        Recursively using a cursor, such as when reusing it from a generator led to segfaults.
+        Now we catch recursive cursor usage and raise a ProgrammingError.
+        """
+        con = sqlite.connect(":memory:")
+
+        cur = con.cursor()
+        cur.execute("create table a (bar)")
+        cur.execute("create table b (baz)")
+
+        def foo():
+            cur.execute("insert into a (bar) values (?)", (1,))
+            yield 1
+
+        try:
+            cur.executemany("insert into b (baz) values (?)", ((i,) for i in foo()))
+            self.fail("should have raised ProgrammingError")
+        except sqlite.ProgrammingError:
+            pass
+
 def suite():
     regression_suite = unittest.makeSuite(RegressionTests, "Check")
     return unittest.TestSuite((regression_suite,))
index cc6a8de..a957ac2 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/test/transactions.py: tests transactions
 #
-# Copyright (C) 2005-2009 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2005-2015 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
@@ -21,8 +21,8 @@
 #    misrepresented as being the original software.
 # 3. This notice may not be removed or altered from any source distribution.
 
-import sys
-import os, unittest
+import os
+import unittest
 import pysqlite2.dbapi2 as sqlite
 
 def get_db_path():
index 6de704b..5b78e29 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/test/types.py: tests for type conversion and detection
 #
-# Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2005-2015 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
@@ -102,6 +102,16 @@ class SqliteTypeTests(unittest.TestCase):
         finally:
             self.con.text_factory = orig_text_factory
 
+    def CheckBinaryString(self):
+        bin_string = u"foo\x00bar"
+        self.cur.execute("select ?", (bin_string,))
+        self.assertEqual(self.cur.fetchone()[0], bin_string)
+
+    def CheckBinaryByteString(self):
+        bin_string = "bla\x00bla"
+        self.cur.execute("select ?", (bin_string,))
+        self.assertEqual(self.cur.fetchone()[0], bin_string)
+
 class DeclTypesTests(unittest.TestCase):
     class Foo:
         def __init__(self, _val):
@@ -137,6 +147,7 @@ class DeclTypesTests(unittest.TestCase):
         sqlite.converters["FOO"] = DeclTypesTests.Foo
         sqlite.converters["WRONG"] = lambda x: "WRONG"
         sqlite.converters["NUMBER"] = float
+        sqlite.converters["TEXT"] = str
 
     def tearDown(self):
         del sqlite.converters["FLOAT"]
@@ -153,6 +164,19 @@ class DeclTypesTests(unittest.TestCase):
         row = self.cur.fetchone()
         self.assertEqual(row[0], "foo")
 
+    def CheckTextEmptyString(self):
+        """
+        Make sure that empty strings are converted to empty strings and not to None.
+        """
+        self.cur.execute("insert into test(s) values (?)", ("",))
+        self.cur.execute("insert into test(s) values (?)", (None,))
+        self.cur.execute('select s as "s [TEXT]" from test')
+        row = self.cur.fetchone()
+        self.assertEqual(row[0], "")
+        row = self.cur.fetchone()
+        self.assertEqual(row[0], None)
+
+
     def CheckSmallInt(self):
         # default
         self.cur.execute("insert into test(i) values (?)", (42,))
@@ -383,20 +407,27 @@ class DateTimeTests(unittest.TestCase):
         self.assertEqual(type(ts), datetime.datetime)
         self.assertEqual(ts.year, now.year)
 
-    def CheckDateTimeSubSeconds(self):
+    def CheckDateTimeMicroseconds(self):
         ts = sqlite.Timestamp(2004, 2, 14, 7, 15, 0, 500000)
         self.cur.execute("insert into test(ts) values (?)", (ts,))
         self.cur.execute("select ts from test")
         ts2 = self.cur.fetchone()[0]
         self.assertEqual(ts, ts2)
 
-    def CheckDateTimeSubSecondsFloatingPoint(self):
+    def CheckDateTimeMicrosecondsFloatingPoint(self):
         ts = sqlite.Timestamp(2004, 2, 14, 7, 15, 0, 510241)
         self.cur.execute("insert into test(ts) values (?)", (ts,))
         self.cur.execute("select ts from test")
         ts2 = self.cur.fetchone()[0]
         self.assertEqual(ts, ts2)
 
+    def CheckDateTimeMiliSeconds(self):
+        ts = sqlite.Timestamp(2004, 2, 14, 7, 15, 0, 500000)
+        self.cur.execute("insert into test(ts) values ('2004-02-14 07:15:00.500')")
+        self.cur.execute("select ts from test")
+        ts2 = self.cur.fetchone()[0]
+        self.assertEqual(ts, ts2)
+
 def suite():
     sqlite_type_suite = unittest.makeSuite(SqliteTypeTests, "Check")
     decltypes_type_suite = unittest.makeSuite(DeclTypesTests, "Check")
index c8866b3..49d9341 100644 (file)
@@ -2,7 +2,7 @@
 # pysqlite2/test/userfunctions.py: tests for user-defined functions and
 #                                  aggregates.
 #
-# Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2005-2015 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
diff --git a/misc/Makefile b/misc/Makefile
new file mode 100644 (file)
index 0000000..47c4ef4
--- /dev/null
@@ -0,0 +1,64 @@
+#####################################################################\r
+# Makefile originally written by Hans Oesterholt-Dijkema\r
+# Adapted and sanitized by Gerhard Haering for use with the pysqlite\r
+# project.\r
+#\r
+# It works with the free MSVC2003 toolkit as well as with MS Visual\r
+# Studio 2003.\r
+#\r
+# Makefile for SQLITE for use with GNU Make (MinGW/MSYS) \r
+# and the MSVC2003 free toolkit. Expects the MSVC Free SDK\r
+# installed along with the MSVC2003 free toolkit.\r
+#  \r
+# Expects $INCLUDE, $LIB, $PATH set right for use with CL.EXE in\r
+# MSYS. NEEDS MSYS for clean: and install:, for making only: \r
+# Works also in the Visual C++ Toolkit 2003 Command Prompt,\r
+# provided %INCLUDE%, %LIB%, %PATH% are set accordingly.\r
+#####################################################################\r
+\r
+CL=cl\r
+CLFLAGS=-O2 -Og -G7\r
+LINK=link\r
+PREFIX=$$VCTOOLKITINSTALLDIR\r
+INCINST=$(PREFIX)/include\r
+LIBINST=$(PREFIX)/lib\r
+BININST=$(PREFIX)/bin\r
+\r
+SQLITE_OBJ = alter.o analyze.o attach.o auth.o btree.o build.o \\r
+         callback.o complete.o date.o \\r
+         delete.o expr.o func.o hash.o insert.o \\r
+         main.o opcodes.o os.o os_unix.o os_win.o \\r
+         pager.o parse.o pragma.o prepare.o printf.o random.o \\r
+         select.o table.o tokenize.o trigger.o update.o \\r
+         util.o vacuum.o \\r
+         vdbe.o vdbeapi.o vdbeaux.o vdbefifo.o vdbemem.o \\r
+         where.o utf.o legacy.o loadext.o vtab.o\r
+\r
+\r
+SQLITE_OBJ = alter.o analyze.o attach.o auth.o btmutex.o btree.o build.o callback.o \\r
+        complete.o date.o delete.o expr.o func.o hash.o insert.o journal.o \\r
+        legacy.o loadext.o main.o malloc.o mem1.o mem2.o mem3.o mutex.o \\r
+        mutex_w32.o opcodes.o os.o os_win.o pager.o parse.o pragma.o prepare.o \\r
+        printf.o random.o select.o table.o tokenize.o trigger.o update.o utf.o \\r
+        util.o vacuum.o vdbeapi.o vdbeaux.o vdbeblob.o vdbe.o vdbefifo.o vdbemem.o \\r
+        vtab.o where.o\r
+\r
+SQLITE_PRG_OBJ=shell.o \r
+\r
+all: sqlite3.lib\r
+       @echo "done"\r
\r
+clean:\r
+       rm -f *.dll *.lib *.exp *.exe *.o\r
+\r
+sqlite3.exe: sqlite3.dll $(SQLITE_PRG_OBJ)\r
+       $(LINK) -OUT:sqlite3.exe $(SQLITE_PRG_OBJ) sqlite3.lib\r
+\r
+sqlite3static.lib: $(SQLITE_OBJ)\r
+       $(LINK) -LIB -OUT:sqlite3static.lib $(SQLITE_OBJ)\r
+\r
+sqlite3.dll: $(SQLITE_OBJ)\r
+       $(LINK) -OUT:sqlite3.dll -dll -def:sqlite3.def $(SQLITE_OBJ)\r
+\r
+%.o:   %.c\r
+       $(CL) -c $(CLFLAGS) -Fo$@ $<\r
diff --git a/misc/announce_template.txt b/misc/announce_template.txt
new file mode 100644 (file)
index 0000000..98080be
--- /dev/null
@@ -0,0 +1,20 @@
+pysqlite x.y.z released
+=======================
+
+Release focus: minor bugfixes, minor new features.
+
+pysqlite is a DB-API 2.0-compliant database interface for SQLite.
+
+SQLite is a in-process library that implements a self-contained,
+serverless, zero-configuration, transactional SQL database
+engine.
+
+Go to http://pysqlite.googlecode.com/ for downloads, online documentation and
+for reporting bugs.
+
+Changes
+=======
+
+Compatibility
+=============
+
diff --git a/misc/eager.py b/misc/eager.py
new file mode 100644 (file)
index 0000000..d32d946
--- /dev/null
@@ -0,0 +1,51 @@
+from pysqlite2 import dbapi2 as sqlite3
+
+Cursor = sqlite3.Cursor
+
+class EagerCursor(Cursor):
+    def __init__(self, con):
+        Cursor.__init__(self, con)
+        self.rows = []
+        self.pos = 0
+
+    def execute(self, *args):
+        sqlite3.Cursor.execute(self, *args)
+        self.rows = Cursor.fetchall(self)
+        self.pos = 0
+
+    def fetchone(self):
+        try:
+            row = self.rows[self.pos]
+            self.pos += 1
+            return row
+        except IndexError:
+            return None
+
+    def fetchmany(self, num=None):
+        if num is None:
+            num = self.arraysize
+
+        result = self.rows[self.pos:self.pos+num]
+        self.pos += num
+        return result
+
+    def fetchall(self):
+        result = self.rows[self.pos:]
+        self.pos = len(self.rows)
+        return result
+
+def test():
+    con = sqlite3.connect(":memory:")
+    cur = con.cursor(EagerCursor)
+    cur.execute("create table test(foo)")
+    cur.executemany("insert into test(foo) values (?)", [(3,), (4,), (5,)])
+    cur.execute("select * from test")
+    print cur.fetchone()
+    print cur.fetchone()
+    print cur.fetchone()
+    print cur.fetchone()
+    print cur.fetchone()
+
+if __name__ == "__main__":
+    test()
+
diff --git a/misc/lru.py b/misc/lru.py
new file mode 100755 (executable)
index 0000000..a40aaac
--- /dev/null
@@ -0,0 +1,127 @@
+#-*- coding: ISO-8859-1 -*-\r
+# lru.py - a simple LRU cache, which will be rewritten in C later\r
+#\r
+# Copyright (C) 2004-2015 Gerhard Häring <gh@ghaering.de>\r
+#\r
+# This file is part of pysqlite.\r
+#\r
+# This software is provided 'as-is', without any express or implied\r
+# warranty.  In no event will the authors be held liable for any damages\r
+# arising from the use of this software.\r
+#\r
+# Permission is granted to anyone to use this software for any purpose,\r
+# including commercial applications, and to alter it and redistribute it\r
+# freely, subject to the following restrictions:\r
+#\r
+# 1. The origin of this software must not be misrepresented; you must not\r
+#    claim that you wrote the original software. If you use this software\r
+#    in a product, an acknowledgment in the product documentation would be\r
+#    appreciated but is not required.\r
+# 2. Altered source versions must be plainly marked as such, and must not be\r
+#    misrepresented as being the original software.\r
+# 3. This notice may not be removed or altered from any source distribution.\r
+\r
+class Node:\r
+    def __init__(self, key, data):\r
+        self.key = key\r
+        self.data = data\r
+        self.count = 1\r
+        self.prev, self.next = None, None\r
+\r
+class Cache:\r
+    def __init__(self, factory, maxlen):\r
+        self.first, self.last = None, None\r
+        self.maxlen = maxlen\r
+        self.mapping = {}\r
+        self.factory = factory\r
+\r
+    def get(self, key):\r
+        if key in self.mapping:\r
+            nd = self.mapping[key]\r
+            nd.count += 1\r
+\r
+            if nd.prev and nd.count > nd.prev.count:\r
+                ptr = nd.prev\r
+                while ptr.prev is not None and nd.count > ptr.prev.count:\r
+                    ptr = ptr.prev\r
+\r
+                # Move nd before ptr\r
+                if nd.next:\r
+                    nd.next.prev = nd.prev\r
+                else:\r
+                    self.last = nd.prev\r
+                if nd.prev:\r
+                    nd.prev.next = nd.next\r
+                if ptr.prev:\r
+                    ptr.prev.next = nd\r
+                else:\r
+                    self.first = nd\r
+\r
+                save = nd.next\r
+                nd.next = ptr\r
+                nd.prev = ptr.prev\r
+                if nd.prev is None:\r
+                    self.first = nd\r
+                ptr.prev = nd\r
+                #ptr.next = save\r
+        else:\r
+            if len(self.mapping) == self.maxlen:\r
+                if self.last:\r
+                    nd = self.last\r
+                    self.mapping[self.last.key] = None\r
+                    del self.mapping[self.last.key]\r
+                    if nd.prev:\r
+                        nd.prev.next = None\r
+                    self.last = nd.prev\r
+                    nd.prev = None\r
+\r
+            obj = self.factory(key)\r
+            nd = Node(key, obj)\r
+            nd.prev = self.last\r
+            nd.next = None\r
+            if self.last:\r
+                self.last.next = nd\r
+            else:\r
+                self.first = nd\r
+            self.last = nd\r
+            self.mapping[key] = nd\r
+        return nd.data\r
+\r
+    def display(self):\r
+        nd = self.first\r
+        while nd:\r
+            prevkey, nextkey = None, None\r
+            if nd.prev: prevkey = nd.prev.key\r
+            if nd.next: nextkey = nd.next.key\r
+            print "%4s <- %4s -> %s\t(%i)" % (prevkey, nd.key, nextkey, nd.count)\r
+            nd = nd.next\r
+\r
+if __name__ == "__main__":\r
+    def create(s):\r
+        return s\r
+\r
+    import random\r
+    cache = Cache(create, 5)\r
+    if 1:\r
+        chars = list("abcdefghijklmnopqrstuvwxyz")\r
+        lst = []\r
+        for i in range(100):\r
+            idx = random.randint(0, len(chars) - 1)\r
+            what = chars[idx]\r
+            lst.append(what)\r
+            cache.get(chars[idx])\r
+        cache.display()\r
+        #print "-" * 50\r
+        #print lst\r
+        #print "-" * 50\r
+    else:\r
+        lst = \\r
+            ['y', 'y', 'b', 'v', 'x', 'f', 'h', 'n', 'g', 'k', 'o', 'q', 'p', 'e', 'm', 'c', 't', 'y', 'c', 's', 'p', 's', 'j', 'm', \\r
+             'u', 'f', 'z', 'x', 'v', 'r', 'w', 'e', 'm', 'd', 'w', 's', 'b', 'r', 'd', 'e', 'h', 'g', 'e', 't', 'p', 'b', 'e', 'i', \\r
+             'g', 'n']\r
+        #lst = ['c', 'c', 'b', 'b', 'd', 'd', 'g', 'c', 'c', 'd'] \r
+        for item in lst:\r
+            cache.get(item)\r
+        cache.display()\r
+\r
+\r
diff --git a/misc/patterns.py b/misc/patterns.py
new file mode 100644 (file)
index 0000000..be8237b
--- /dev/null
@@ -0,0 +1,110 @@
+from __future__ import with_statement
+from pysqlite2 import dbapi2 as sqlite3
+from datetime import datetime, timedelta
+import time
+
+def read_modify_write():
+    # Open connection and create example schema and data.
+    # In reality, open a database file instead of an in-memory database.
+    con = sqlite3.connect(":memory:")
+    cur = con.cursor()
+    cur.executescript("""
+    create table test(id integer primary key, data);
+    insert into test(data) values ('foo');
+    insert into test(data) values ('bar');
+    insert into test(data) values ('baz');
+    """)
+
+    # The read part. There are two ways for fetching data using pysqlite.
+    # 1. "Lazy-reading"
+    #    cur.execute("select ...")
+    #    for row in cur:
+    #       ...
+    #
+    #    Advantage: Low memory consumption, good for large resultsets, data is
+    #    fetched on demand.
+    #    Disadvantage: Database locked as long as you iterate over cursor.
+    #
+    # 2. "Eager reading"
+    #   cur.fetchone() to fetch one row
+    #   cur.fetchall() to fetch all rows
+    #   Advantage: Locks cleared ASAP.
+    #   Disadvantage: fetchall() may build large lists.
+
+    cur.execute("select id, data from test where id=?", (2,))
+    row = cur.fetchone()
+
+    # Stupid way to modify the data column.
+    lst = list(row)
+    lst[1] = lst[1] + " & more"
+
+    # This is the suggested recipe to modify data using pysqlite. We use
+    # pysqlite's proprietary API to use the connection object as a context
+    # manager.  This is equivalent to the following code:
+    #
+    # try:
+    #     cur.execute("...")
+    # except:
+    #     con.rollback()
+    #     raise
+    # finally:
+    #     con.commit()
+    #
+    # This makes sure locks are cleared - either by commiting or rolling back
+    # the transaction.
+    #
+    # If the rollback happens because of concurrency issues, you just have to
+    # try again until it succeeds.  Much more likely is that the rollback and
+    # the raised exception happen because of other reasons, though (constraint
+    # violation, etc.) - don't forget to roll back on errors.
+    #
+    # Or use this recipe. It's useful and gets everything done in two lines of
+    # code.
+    with con:
+        cur.execute("update test set data=? where id=?", (lst[1], lst[0]))
+
+def delete_older_than():
+    # Use detect_types if you want to use date/time types in pysqlite.
+    con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_COLNAMES)
+    cur = con.cursor()
+
+    # With "DEFAULT current_timestamp" we have SQLite fill the timestamp column
+    # automatically.
+    cur.executescript("""
+    create table test(id integer primary key, data, created timestamp default current_timestamp);
+    """)
+    with con:
+        for i in range(3):
+            cur.execute("insert into test(data) values ('foo')")
+            time.sleep(1)
+
+    # Delete older than certain interval
+    # SQLite uses UTC time, so we need to create these timestamps in Python, too.
+    with con:
+        delete_before = datetime.utcnow() - timedelta(seconds=2)
+        cur.execute("delete from test where created < ?", (delete_before,))
+
+def modify_insert():
+    # Use a unique index and the REPLACE command to have the "insert if not
+    # there, but modify if it is there" pattern. Race conditions are taken care
+    # of by transactions.
+    con = sqlite3.connect(":memory:")
+    cur = con.cursor()
+    cur.executescript("""
+    create table test(id integer primary key, name, age);
+    insert into test(name, age) values ('Adam', 18);
+    insert into test(name, age) values ('Eve', 21);
+    create unique index idx_test_data_unique on test(name);
+    """)
+
+    with con:
+        # Make Adam age 19
+        cur.execute("replace into test(name, age) values ('Adam', 19)")
+
+        # Create new entry
+        cur.execute("replace into test(name, age) values ('Abel', 3)")
+
+if __name__ == "__main__":
+    read_modify_write()
+    delete_older_than()
+    modify_insert()
diff --git a/mkwin32.py b/mkwin32.py
new file mode 100755 (executable)
index 0000000..ac5dea4
--- /dev/null
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+#
+# Cross-compile and build pysqlite installers for win32 on Linux or Mac OS X.
+#
+# The way this works is very ugly, but hey, it *works*!  And I didn't have to
+# reinvent the wheel using NSIS.
+
+import os
+import sys
+import urllib
+import zipfile
+
+from setup import get_amalgamation
+
+# Cross-compiler
+if sys.platform == "darwin":
+    CC = "/usr/local/i386-mingw32-4.3.0/bin/i386-mingw32-gcc"
+    LIBDIR = "lib.macosx-10.6-i386-2.5"
+    STRIP = "/usr/local/i386-mingw32-4.3.0/bin/i386-mingw32-gcc --strip-all"
+else:
+    CC = "/usr/bin/i586-mingw32msvc-gcc"
+    LIBDIR = "lib.linux-i686-2.5"
+    STRIP = "strip --strip-all"
+
+# Optimization settings
+OPT = "-O2"
+
+# pysqlite sources + SQLite amalgamation
+SRC = "src/module.c src/connection.c src/cursor.c src/cache.c src/microprotocols.c src/prepare_protocol.c src/statement.c src/util.c src/row.c amalgamation/sqlite3.c"
+
+# You will need to fetch these from
+# https://pyext-cross.pysqlite.googlecode.com/hg/
+CROSS_TOOLS = "../pysqlite-pyext-cross"
+
+def execute(cmd):
+    print cmd
+    return os.system(cmd)
+
+def compile_module(pyver):
+    VER = pyver.replace(".", "")
+    INC = "%s/python%s/include" % (CROSS_TOOLS, VER)
+    vars = locals()
+    vars.update(globals())
+    cmd = '%(CC)s -mno-cygwin %(OPT)s -mdll -DMODULE_NAME=\\"pysqlite2._sqlite\\" -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_FTS3=1 -I amalgamation -I %(INC)s -I . %(SRC)s -L %(CROSS_TOOLS)s/python%(VER)s/libs -lpython%(VER)s -o build/%(LIBDIR)s/pysqlite2/_sqlite.pyd' % vars
+    execute(cmd)
+    execute("%(STRIP)s build/%(LIBDIR)s/pysqlite2/_sqlite.pyd" % vars)
+
+def main():
+    vars = locals()
+    vars.update(globals())
+    get_amalgamation()
+    for ver in ["2.5", "2.6", "2.7"]:
+        execute("rm -rf build")
+        # First, compile the host version. This is just to get the .py files in place.
+        execute("python2.5 setup.py build")
+        # Yes, now delete the host extension module. What a waste of time.
+        os.unlink("build/%(LIBDIR)s/pysqlite2/_sqlite.so" % vars)
+        # Cross-compile win32 extension module.
+        compile_module(ver)
+        # Prepare for target Python version.
+        libdir_ver = LIBDIR[:-3] + ver
+        os.rename("build/%(LIBDIR)s" % vars, "build/" + libdir_ver)
+        # And create the installer!
+        os.putenv("PYEXT_CROSS", CROSS_TOOLS)
+        execute("python2.5 setup.py cross_bdist_wininst --skip-build --target-version=" + ver)
+
+if __name__ == "__main__":
+    main()
diff --git a/scripts/stress.py b/scripts/stress.py
new file mode 100644 (file)
index 0000000..d8bd50a
--- /dev/null
@@ -0,0 +1,80 @@
+from pysqlite2 import dbapi2 as sqlite
+import os, threading
+
+def getcon():
+    #con = sqlite.connect("db", isolation_level=None, timeout=5.0)
+    con = sqlite.connect(":memory:")
+    cur = con.cursor()
+    cur.execute("create table test(i, s)")
+    for i in range(10):
+        cur.execute("insert into test(i, s) values (?, 'asfd')", (i,))
+    con.commit()
+    cur.close()
+    return con
+
+def reader(what):
+    con = getcon()
+    while 1:
+        cur = con.cursor()
+        cur.execute("select i, s from test where i % 1000=?", (what,))
+        res = cur.fetchall()
+        cur.close()
+    con.close()
+
+def appender():
+    con = getcon()
+    counter = 0
+    while 1:
+        cur = con.cursor()
+        cur.execute("insert into test(i, s) values (?, ?)", (counter, "foosadfasfasfsfafs"))
+        #cur.execute("insert into test(foo) values (?)", (counter,))
+        counter += 1
+        if counter % 100 == 0:
+            #print "appender committing", counter
+            con.commit()
+        cur.close()
+    con.close()
+
+
+def updater():
+    con = getcon()
+    counter = 0
+    while 1:
+        cur = con.cursor()
+        counter += 1
+        if counter % 5 == 0:
+            cur.execute("update test set s='foo' where i % 50=0")
+            #print "updater committing", counter
+            con.commit()
+        cur.close()
+    con.close()
+
+
+def deleter():
+    con = getcon()
+    counter = 0
+    while 1:
+        cur = con.cursor()
+        counter += 1
+        if counter % 5 == 0:
+            #print "deleter committing", counter
+            cur.execute("delete from  test where i % 20=0")
+            con.commit()
+        cur.close()
+    con.close()
+
+threads = []
+
+for i in range(10):
+    continue
+    threads.append(threading.Thread(target=lambda: reader(i)))
+
+for i in range(5):
+    threads.append(threading.Thread(target=appender))
+    #threads.append(threading.Thread(target=updater))
+    #threads.append(threading.Thread(target=deleter))
+
+for t in threads:
+    t.start()
+
+
diff --git a/scripts/test-pysqlite b/scripts/test-pysqlite
new file mode 100755 (executable)
index 0000000..fe23001
--- /dev/null
@@ -0,0 +1,3 @@
+#!/usr/bin/env python
+from pysqlite2.test import test
+test()
index 607fda4..2d965a7 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,3 @@
 [build_ext]
-#define=
-#include_dirs=/usr/local/include
-#library_dirs=/usr/local/lib
 libraries=sqlite3
-define=SQLITE_OMIT_LOAD_EXTENSION
+define=SQLITE_OMIT_LOAD_EXTENSION
index 4e9ad3d..ea3de9f 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # setup.py: the distutils script
 #
-# Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2004-2015 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
 #    misrepresented as being the original software.
 # 3. This notice may not be removed or altered from any source distribution.
 
-import glob, os, re, sys
-import urllib
-import zipfile
+import commands
+import glob
+import os
+import re
+import shutil
+import sys
 
 from distutils.core import setup, Extension, Command
 from distutils.command.build import build
@@ -63,6 +66,22 @@ if sys.platform != "win32":
 else:
     define_macros.append(('MODULE_NAME', '\\"pysqlite2.dbapi2\\"'))
 
+class TestRunner(Command):
+    description = "Runs the unit tests"
+    user_options = []
+
+    def initialize_options(self):
+        pass
+
+    def finalize_options(self):
+        pass
+
+    def run(self):
+        build_dir = "build/lib.linux-x86_64-%i.%i" % sys.version_info[:2]
+        sys.path.append(build_dir)
+        from pysqlite2 import test
+        test.test()
+
 class DocBuilder(Command):
     description = "Builds the documentation"
     user_options = []
@@ -74,7 +93,6 @@ class DocBuilder(Command):
         pass
 
     def run(self):
-        import os, shutil
         try:
             shutil.rmtree("build/doc")
         except OSError:
@@ -82,36 +100,7 @@ class DocBuilder(Command):
         os.makedirs("build/doc")
         rc = os.system("sphinx-build doc/sphinx build/doc")
         if rc != 0:
-            print "Is sphinx installed? If not, try 'sudo easy_install sphinx'."
-
-AMALGAMATION_ROOT = "amalgamation"
-
-def get_amalgamation():
-    """Download the SQLite amalgamation if it isn't there, already."""
-    if os.path.exists(AMALGAMATION_ROOT):
-        return
-    os.mkdir(AMALGAMATION_ROOT)
-    print "Downloading amalgation."
-
-    # find out what's current amalgamation ZIP file
-    download_page = urllib.urlopen("http://sqlite.org/download.html").read()
-    pattern = re.compile("(sqlite-amalgamation.*?\.zip)")
-    download_file = pattern.findall(download_page)[0]
-    amalgamation_url = "http://sqlite.org/" + download_file
-
-    # and download it
-    urllib.urlretrieve(amalgamation_url, "tmp.zip")
-
-    zf = zipfile.ZipFile("tmp.zip")
-    files = ["sqlite3.c", "sqlite3.h"]
-    directory = zf.namelist()[0]
-    for fn in files:
-        print "Extracting", fn
-        outf = open(AMALGAMATION_ROOT + os.sep + fn, "wb")
-        outf.write(zf.read(directory + fn))
-        outf.close()
-    zf.close()
-    os.unlink("tmp.zip")
+            print "Is sphinx installed? If not, try 'sudo pip sphinx'."
 
 class AmalgamationBuilder(build):
     description = "Build a statically built pysqlite using the amalgamtion."
@@ -123,13 +112,32 @@ class AmalgamationBuilder(build):
 class MyBuildExt(build_ext):
     amalgamation = False
 
+    def _pkgconfig(self, flag, package):
+        status, output = commands.getstatusoutput("pkg-config %s %s" % (flag, package))
+        return output
+
+    def _pkgconfig_include_dirs(self, package):
+        return [x.strip() for x in 
+                self._pkgconfig("--cflags-only-I",
+                                package).replace("-I", " ").split()]
+
+    def _pkgconfig_library_dirs(self, package):
+        return [x.strip() for x in 
+                self._pkgconfig("--libs-only-L",
+                                package).replace("-L", " ").split()]
+
+
     def build_extension(self, ext):
         if self.amalgamation:
-            get_amalgamation()
-            ext.define_macros.append(("SQLITE_ENABLE_FTS3", "1"))   # build with fulltext search enabled
-            ext.define_macros.append(("SQLITE_ENABLE_RTREE", "1"))   # build with fulltext search enabled
-            ext.sources.append(os.path.join(AMALGAMATION_ROOT, "sqlite3.c"))
-            ext.include_dirs.append(AMALGAMATION_ROOT)
+            ext.define_macros += [
+                    ("SQLITE_ENABLE_FTS5", "1"),
+                    ("SQLITE_ENABLE_RTREE", "1")]
+            ext.sources.append("sqlite3.c")
+        try:
+            ext.include_dirs = self._pkgconfig_include_dirs("sqlite3")
+            ext.library_dirs = self._pkgconfig_library_dirs("sqlite3")
+        except OSError:
+            pass # no pkg_config installed
         build_ext.build_extension(self, ext)
 
     def __setattr__(self, k, v):
@@ -173,8 +181,7 @@ def get_setup_args():
             author_email = "gh@ghaering.de",
             license = "zlib/libpng license",
             platforms = "ALL",
-            url = "http://pysqlite.googlecode.com/",
-            download_url = "http://code.google.com/p/pysqlite/downloads/list",
+            url = "http://github.com/ghaering/pysqlite",
 
             # Description of the modules and packages in the distribution
             package_dir = {"pysqlite2": "lib"},
@@ -200,13 +207,20 @@ def get_setup_args():
             "Operating System :: Microsoft :: Windows",
             "Operating System :: POSIX",
             "Programming Language :: C",
-            "Programming Language :: Python",
+            "Programming Language :: Python :: 2 :: Only",
             "Topic :: Database :: Database Engines/Servers",
-            "Topic :: Software Development :: Libraries :: Python Modules"],
+            "Topic :: Software Development :: Libraries :: Python Modules",
+            ],
             cmdclass = {"build_docs": DocBuilder}
             )
 
-    setup_args["cmdclass"].update({"build_docs": DocBuilder, "build_ext": MyBuildExt, "build_static": AmalgamationBuilder, "cross_bdist_wininst": cross_bdist_wininst.bdist_wininst})
+    setup_args["cmdclass"].update({
+        "build_docs": DocBuilder,
+        "test": TestRunner,
+        "build_ext": MyBuildExt,
+        "build_static": AmalgamationBuilder,
+        "cross_bdist_wininst": cross_bdist_wininst.bdist_wininst
+    })
     return setup_args
 
 def main():
diff --git a/src/backup.c b/src/backup.c
new file mode 100644 (file)
index 0000000..21cb67f
--- /dev/null
@@ -0,0 +1,134 @@
+/* backup.c - the backup type
+ *
+ * Copyright (C) 2010-2015 Gerhard Häring <gh@ghaering.de>
+ *
+ * This file is part of pysqlite.
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#include "module.h"
+#include "backup.h"
+#include "sqlitecompat.h"
+
+void pysqlite_backup_dealloc(pysqlite_Backup* self)
+{
+    int rc;
+
+    if (self->backup) {
+        Py_BEGIN_ALLOW_THREADS
+        rc = sqlite3_backup_finish(self->backup);
+        Py_END_ALLOW_THREADS
+
+        Py_DECREF(self->source_con);
+        Py_DECREF(self->dest_con);
+
+        self->backup = NULL;
+    }
+
+    Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+PyObject* pysqlite_backup_step(pysqlite_Backup* self, PyObject* args, PyObject* kwargs)
+{
+    int npages;
+
+    if (!PyArg_ParseTuple(args, "i", &npages)) {
+        return NULL;
+    }
+
+    int rc = sqlite3_backup_step(self->backup, npages);
+
+    if (rc == SQLITE_DONE) {
+        Py_RETURN_TRUE;
+    } else if (rc == SQLITE_OK) {
+        Py_RETURN_FALSE;
+    } else {
+        PyErr_SetString(pysqlite_OperationalError, sqlite3_errmsg(self->source_con->db));
+        return NULL;
+    }
+}
+
+static PyObject* pysqlite_backup_get_remaining(pysqlite_Backup* self, void* unused)
+{
+    return Py_BuildValue("i", sqlite3_backup_remaining(self->backup));
+}
+
+static PyObject* pysqlite_backup_get_pagecount(pysqlite_Backup* self, void* unused)
+{
+    return Py_BuildValue("i", sqlite3_backup_remaining(self->backup));
+}
+
+static PyGetSetDef pysqlite_backup_getset[] = {
+    {"remaining",  (getter)pysqlite_backup_get_remaining, (setter)0},
+    {"pagecount",  (getter)pysqlite_backup_get_pagecount, (setter)0},
+    {NULL}
+};
+
+static PyMethodDef pysqlite_backup_methods[] = {
+    {"step", (PyCFunction)pysqlite_backup_step, METH_VARARGS,
+        PyDoc_STR("Copy pages to backup database.")},
+    {NULL, NULL}
+};
+
+PyTypeObject pysqlite_BackupType = {
+        PyVarObject_HEAD_INIT(NULL, 0)
+        MODULE_NAME ".Backup",                          /* tp_name */
+        sizeof(pysqlite_Backup),                        /* tp_basicsize */
+        0,                                              /* tp_itemsize */
+        (destructor)pysqlite_backup_dealloc,            /* tp_dealloc */
+        0,                                              /* tp_print */
+        0,                                              /* tp_getattr */
+        0,                                              /* tp_setattr */
+        0,                                              /* tp_compare */
+        0,                                              /* tp_repr */
+        0,                                              /* tp_as_number */
+        0,                                              /* tp_as_sequence */
+        0,                                              /* tp_as_mapping */
+        0,                                              /* tp_hash */
+        0,                                              /* tp_call */
+        0,                                              /* tp_str */
+        0,                                              /* tp_getattro */
+        0,                                              /* tp_setattro */
+        0,                                              /* tp_as_buffer */
+        Py_TPFLAGS_DEFAULT,                             /* tp_flags */
+        0,                                              /* tp_doc */
+        0,                                              /* tp_traverse */
+        0,                                              /* tp_clear */
+        0,                                              /* tp_richcompare */
+        0,                                              /* tp_weaklistoffset */
+        0,                                              /* tp_iter */
+        0,                                              /* tp_iternext */
+        pysqlite_backup_methods,                        /* tp_methods */
+        0,                                              /* tp_members */
+        pysqlite_backup_getset,                         /* tp_getset */
+        0,                                              /* tp_base */
+        0,                                              /* tp_dict */
+        0,                                              /* tp_descr_get */
+        0,                                              /* tp_descr_set */
+        0,                                              /* tp_dictoffset */
+        (initproc)0,                                    /* tp_init */
+        0,                                              /* tp_alloc */
+        0,                                              /* tp_new */
+        0                                               /* tp_free */
+};
+
+extern int pysqlite_backup_setup_types(void)
+{
+    pysqlite_BackupType.tp_new = PyType_GenericNew;
+    return PyType_Ready(&pysqlite_BackupType);
+}
index 10720f0..9be4e21 100644 (file)
@@ -1,6 +1,6 @@
 /* backup.h - definitions for the backup type
  *
- * Copyright (C) 2010 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2010-2015 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
index 0653367..bcb00e8 100644 (file)
@@ -1,6 +1,6 @@
 /* cache .c - a LRU cache
  *
- * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2015 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
index b09517c..06f957a 100644 (file)
@@ -1,6 +1,6 @@
 /* cache.h - definitions for the LRU cache
  *
- * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2015 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
index 481b9b5..8b96c6d 100644 (file)
@@ -1,6 +1,6 @@
 /* connection.c - the connection type
  *
- * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2015 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  * 
@@ -1018,6 +1018,48 @@ static int _progress_handler(void* user_arg)
     return rc;
 }
 
+static PyObject* pysqlite_connection_get_limit(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
+{
+    int limit_id, new_val;
+
+    static char *kwlist[] = { "limit_id", NULL };
+    int retval;
+
+    if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
+        return NULL;
+    }
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:get_limit",
+                                      kwlist, &limit_id)) {
+        return NULL;
+    }
+
+    retval = sqlite3_limit(self->db, limit_id, -1);
+
+    return PyInt_FromLong(retval);
+}
+
+static PyObject* pysqlite_connection_set_limit(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
+{
+    int limit_id, new_val;
+
+    static char *kwlist[] = { "limit_id", "new_val", NULL };
+    int retval;
+
+    if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
+        return NULL;
+    }
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:set_limit",
+                                      kwlist, &limit_id, &new_val)) {
+        return NULL;
+    }
+
+    retval = sqlite3_limit(self->db, limit_id, new_val);
+
+    return PyInt_FromLong(retval);
+}
+
 static PyObject* pysqlite_connection_set_authorizer(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
 {
     PyObject* authorizer_cb;
@@ -1609,6 +1651,10 @@ static PyMethodDef connection_methods[] = {
         PyDoc_STR("Creates a new function. Non-standard.")},
     {"create_aggregate", (PyCFunction)pysqlite_connection_create_aggregate, METH_VARARGS|METH_KEYWORDS,
         PyDoc_STR("Creates a new aggregate. Non-standard.")},
+    {"set_limit", (PyCFunction)pysqlite_connection_set_limit, METH_VARARGS|METH_KEYWORDS,
+        PyDoc_STR("Sets SQLite limit. Non-standard.")},
+    {"get_limit", (PyCFunction)pysqlite_connection_get_limit, METH_VARARGS|METH_KEYWORDS,
+        PyDoc_STR("Gets SQLite limit. Non-standard.")},
     {"set_authorizer", (PyCFunction)pysqlite_connection_set_authorizer, METH_VARARGS|METH_KEYWORDS,
         PyDoc_STR("Sets authorizer callback. Non-standard.")},
     #ifdef HAVE_LOAD_EXTENSION
index 3fc5a70..58db8cd 100644 (file)
@@ -1,6 +1,6 @@
 /* connection.h - definitions for the connection type
  *
- * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2015 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
index 26e3307..0e065f3 100644 (file)
@@ -1,6 +1,6 @@
 /* cursor.c - the cursor type
  *
- * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2015 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
@@ -268,29 +268,26 @@ PyObject* _pysqlite_build_column_name(const char* colname)
     }
 }
 
-PyObject* pysqlite_unicode_from_string(const char* val_str, int optimize)
+static PyObject* pysqlite_unicode_from_string(const char* val_str, Py_ssize_t nbytes, int optimize)
 {
-    const char* check;
     int is_ascii = 0;
+    int i;
 
     if (optimize) {
         is_ascii = 1;
 
-        check = val_str;
-        while (*check) {
-            if (*check & 0x80) {
+        for (i = 0; i < nbytes; i++) {
+            if (val_str[i] & 0x80) {
                 is_ascii = 0;
                 break;
             }
-
-            check++;
         }
     }
 
     if (is_ascii) {
-        return PyString_FromString(val_str);
+        return PyString_FromStringAndSize(val_str, nbytes);
     } else {
-        return PyUnicode_DecodeUTF8(val_str, strlen(val_str), NULL);
+        return PyUnicode_DecodeUTF8(val_str, nbytes, NULL);
     }
 }
 
@@ -331,6 +328,8 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
     }
 
     for (i = 0; i < numcols; i++) {
+        nbytes = sqlite3_column_bytes(self->statement->st, i);
+
         if (self->connection->detect_types) {
             converter = PyList_GetItem(self->row_cast_map, i);
             if (!converter) {
@@ -341,20 +340,24 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
         }
 
         if (converter != Py_None) {
-            nbytes = sqlite3_column_bytes(self->statement->st, i);
-            val_str = (const char*)sqlite3_column_blob(self->statement->st, i);
-            if (!val_str) {
+            if (sqlite3_column_type(self->statement->st, i) == SQLITE_NULL) {
                 Py_INCREF(Py_None);
                 converted = Py_None;
             } else {
-                item = PyString_FromStringAndSize(val_str, nbytes);
-                if (!item) {
-                    return NULL;
-                }
-                converted = PyObject_CallFunction(converter, "O", item);
-                Py_DECREF(item);
-                if (!converted) {
-                    break;
+                val_str = (const char*)sqlite3_column_blob(self->statement->st, i);
+                if (!val_str) {
+                    Py_INCREF(Py_None);
+                    converted = Py_None;
+                } else {
+                    item = PyString_FromStringAndSize(val_str, nbytes);
+                    if (!item) {
+                        return NULL;
+                    }
+                    converted = PyObject_CallFunction(converter, "O", item);
+                    Py_DECREF(item);
+                    if (!converted) {
+                        break;
+                    }
                 }
             }
         } else {
@@ -378,7 +381,7 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
                 if ((self->connection->text_factory == (PyObject*)&PyUnicode_Type)
                     || (self->connection->text_factory == pysqlite_OptimizedUnicode)) {
 
-                    converted = pysqlite_unicode_from_string(val_str,
+                    converted = pysqlite_unicode_from_string(val_str, nbytes,
                         self->connection->text_factory == pysqlite_OptimizedUnicode ? 1 : 0);
 
                     if (!converted) {
@@ -391,7 +394,7 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
                         PyErr_SetString(pysqlite_OperationalError, buf);
                     }
                 } else if (self->connection->text_factory == (PyObject*)&PyString_Type) {
-                    converted = PyString_FromString(val_str);
+                    converted = PyString_FromStringAndSize(val_str, nbytes);
                 } else {
                     converted = PyObject_CallFunction(self->connection->text_factory, "s", val_str);
                 }
@@ -441,9 +444,14 @@ static int check_cursor(pysqlite_Cursor* cur)
     if (cur->closed) {
         PyErr_SetString(pysqlite_ProgrammingError, "Cannot operate on a closed cursor.");
         return 0;
-    } else {
-        return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection);
     }
+
+    if (cur->locked) {
+        PyErr_SetString(pysqlite_ProgrammingError, "Recursive use of cursors not allowed.");
+        return 0;
+    }
+
+    return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection);
 }
 
 PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args)
@@ -466,9 +474,10 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
     int allow_8bit_chars;
 
     if (!check_cursor(self)) {
-        return NULL;
+        goto error;
     }
 
+    self->locked = 1;
     self->reset = 0;
 
     /* Make shooting yourself in the foot with not utf-8 decodable 8-bit-strings harder */
@@ -481,12 +490,12 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
     if (multiple) {
         /* executemany() */
         if (!PyArg_ParseTuple(args, "OO", &operation, &second_argument)) {
-            return NULL;
+            goto error;
         }
 
         if (!PyString_Check(operation) && !PyUnicode_Check(operation)) {
             PyErr_SetString(PyExc_ValueError, "operation parameter must be str or unicode");
-            return NULL;
+            goto error;
         }
 
         if (PyIter_Check(second_argument)) {
@@ -497,23 +506,23 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
             /* sequence */
             parameters_iter = PyObject_GetIter(second_argument);
             if (!parameters_iter) {
-                return NULL;
+                goto error;
             }
         }
     } else {
         /* execute() */
         if (!PyArg_ParseTuple(args, "O|O", &operation, &second_argument)) {
-            return NULL;
+            goto error;
         }
 
         if (!PyString_Check(operation) && !PyUnicode_Check(operation)) {
             PyErr_SetString(PyExc_ValueError, "operation parameter must be str or unicode");
-            return NULL;
+            goto error;
         }
 
         parameters_list = PyList_New(0);
         if (!parameters_list) {
-            return NULL;
+            goto error;
         }
 
         if (second_argument == NULL) {
@@ -759,7 +768,8 @@ error:
      * ROLLBACK could have happened */
     #ifdef SQLITE_VERSION_NUMBER
     #if SQLITE_VERSION_NUMBER >= 3002002
-    self->connection->inTransaction = !sqlite3_get_autocommit(self->connection->db);
+    if (self->connection && self->connection->db)
+        self->connection->inTransaction = !sqlite3_get_autocommit(self->connection->db);
     #endif
     #endif
 
@@ -768,6 +778,8 @@ error:
     Py_XDECREF(parameters_iter);
     Py_XDECREF(parameters_list);
 
+    self->locked = 0;
+
     if (PyErr_Occurred()) {
         self->rowcount = -1L;
         return NULL;
index 82f5972..03f6d71 100644 (file)
@@ -1,6 +1,6 @@
 /* cursor.h - definitions for the cursor type
  *
- * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2015 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
@@ -42,6 +42,7 @@ typedef struct
     pysqlite_Statement* statement;
     int closed;
     int reset;
+    int locked;
     int initialized;
 
     /* the next row to be returned, NULL if no next row available */
index c0e6aa8..25152e4 100644 (file)
@@ -1,6 +1,6 @@
 /* module.c - the module itself
  *
- * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2015 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
@@ -266,41 +266,8 @@ static IntConstantPair _int_constants[] = {
     {"PARSE_DECLTYPES", PARSE_DECLTYPES},
     {"PARSE_COLNAMES", PARSE_COLNAMES},
 
-    {"SQLITE_OK", SQLITE_OK},
-    {"SQLITE_DENY", SQLITE_DENY},
-    {"SQLITE_IGNORE", SQLITE_IGNORE},
-    {"SQLITE_CREATE_INDEX", SQLITE_CREATE_INDEX},
-    {"SQLITE_CREATE_TABLE", SQLITE_CREATE_TABLE},
-    {"SQLITE_CREATE_TEMP_INDEX", SQLITE_CREATE_TEMP_INDEX},
-    {"SQLITE_CREATE_TEMP_TABLE", SQLITE_CREATE_TEMP_TABLE},
-    {"SQLITE_CREATE_TEMP_TRIGGER", SQLITE_CREATE_TEMP_TRIGGER},
-    {"SQLITE_CREATE_TEMP_VIEW", SQLITE_CREATE_TEMP_VIEW},
-    {"SQLITE_CREATE_TRIGGER", SQLITE_CREATE_TRIGGER},
-    {"SQLITE_CREATE_VIEW", SQLITE_CREATE_VIEW},
-    {"SQLITE_DELETE", SQLITE_DELETE},
-    {"SQLITE_DROP_INDEX", SQLITE_DROP_INDEX},
-    {"SQLITE_DROP_TABLE", SQLITE_DROP_TABLE},
-    {"SQLITE_DROP_TEMP_INDEX", SQLITE_DROP_TEMP_INDEX},
-    {"SQLITE_DROP_TEMP_TABLE", SQLITE_DROP_TEMP_TABLE},
-    {"SQLITE_DROP_TEMP_TRIGGER", SQLITE_DROP_TEMP_TRIGGER},
-    {"SQLITE_DROP_TEMP_VIEW", SQLITE_DROP_TEMP_VIEW},
-    {"SQLITE_DROP_TRIGGER", SQLITE_DROP_TRIGGER},
-    {"SQLITE_DROP_VIEW", SQLITE_DROP_VIEW},
-    {"SQLITE_INSERT", SQLITE_INSERT},
-    {"SQLITE_PRAGMA", SQLITE_PRAGMA},
-    {"SQLITE_READ", SQLITE_READ},
-    {"SQLITE_SELECT", SQLITE_SELECT},
-    {"SQLITE_TRANSACTION", SQLITE_TRANSACTION},
-    {"SQLITE_UPDATE", SQLITE_UPDATE},
-    {"SQLITE_ATTACH", SQLITE_ATTACH},
-    {"SQLITE_DETACH", SQLITE_DETACH},
-#if SQLITE_VERSION_NUMBER >= 3002001
-    {"SQLITE_ALTER_TABLE", SQLITE_ALTER_TABLE},
-    {"SQLITE_REINDEX", SQLITE_REINDEX},
-#endif
-#if SQLITE_VERSION_NUMBER >= 3003000
-    {"SQLITE_ANALYZE", SQLITE_ANALYZE},
-#endif
+#include "sqlite_constants.h"
+
     {(char*)NULL, 0}
 };
 
index 0b1dab3..b662b7e 100644 (file)
@@ -1,6 +1,6 @@
 /* module.h - definitions for the module
  *
- * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2015 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
@@ -25,7 +25,7 @@
 #define PYSQLITE_MODULE_H
 #include "Python.h"
 
-#define PYSQLITE_VERSION "2.6.3"
+#define PYSQLITE_VERSION "2.7.0"
 
 extern PyObject* pysqlite_Error;
 extern PyObject* pysqlite_Warning;
index 9ed25e1..62ac901 100644 (file)
@@ -1,6 +1,6 @@
 /* prepare_protocol.c - the protocol for preparing values for SQLite
  *
- * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2015 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
index 1cdf708..15ab4bc 100644 (file)
@@ -1,6 +1,6 @@
 /* prepare_protocol.h - the protocol for preparing values for SQLite
  *
- * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2015 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
index 480b482..92829f1 100644 (file)
--- a/src/row.c
+++ b/src/row.c
@@ -1,6 +1,6 @@
 /* row.c - an enhanced tuple for database rows
  *
- * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2015 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
index dd9b0c3..8ad5f83 100644 (file)
--- a/src/row.h
+++ b/src/row.h
@@ -1,6 +1,6 @@
 /* row.h - an enhanced tuple for database rows
  *
- * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2015 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
diff --git a/src/sqlite_constants.h b/src/sqlite_constants.h
new file mode 100644 (file)
index 0000000..79e98e7
--- /dev/null
@@ -0,0 +1,1002 @@
+#ifdef SQLITE_VERSION_NUMBER
+{"SQLITE_VERSION_NUMBER", SQLITE_VERSION_NUMBER},
+#endif
+#ifdef SQLITE_ABORT
+{"SQLITE_ABORT", SQLITE_ABORT},
+#endif
+#ifdef SQLITE_AUTH
+{"SQLITE_AUTH", SQLITE_AUTH},
+#endif
+#ifdef SQLITE_BUSY
+{"SQLITE_BUSY", SQLITE_BUSY},
+#endif
+#ifdef SQLITE_CANTOPEN
+{"SQLITE_CANTOPEN", SQLITE_CANTOPEN},
+#endif
+#ifdef SQLITE_CONSTRAINT
+{"SQLITE_CONSTRAINT", SQLITE_CONSTRAINT},
+#endif
+#ifdef SQLITE_CORRUPT
+{"SQLITE_CORRUPT", SQLITE_CORRUPT},
+#endif
+#ifdef SQLITE_DONE
+{"SQLITE_DONE", SQLITE_DONE},
+#endif
+#ifdef SQLITE_EMPTY
+{"SQLITE_EMPTY", SQLITE_EMPTY},
+#endif
+#ifdef SQLITE_ERROR
+{"SQLITE_ERROR", SQLITE_ERROR},
+#endif
+#ifdef SQLITE_FORMAT
+{"SQLITE_FORMAT", SQLITE_FORMAT},
+#endif
+#ifdef SQLITE_FULL
+{"SQLITE_FULL", SQLITE_FULL},
+#endif
+#ifdef SQLITE_INTERNAL
+{"SQLITE_INTERNAL", SQLITE_INTERNAL},
+#endif
+#ifdef SQLITE_INTERRUPT
+{"SQLITE_INTERRUPT", SQLITE_INTERRUPT},
+#endif
+#ifdef SQLITE_IOERR
+{"SQLITE_IOERR", SQLITE_IOERR},
+#endif
+#ifdef SQLITE_LOCKED
+{"SQLITE_LOCKED", SQLITE_LOCKED},
+#endif
+#ifdef SQLITE_MISMATCH
+{"SQLITE_MISMATCH", SQLITE_MISMATCH},
+#endif
+#ifdef SQLITE_MISUSE
+{"SQLITE_MISUSE", SQLITE_MISUSE},
+#endif
+#ifdef SQLITE_NOLFS
+{"SQLITE_NOLFS", SQLITE_NOLFS},
+#endif
+#ifdef SQLITE_NOMEM
+{"SQLITE_NOMEM", SQLITE_NOMEM},
+#endif
+#ifdef SQLITE_NOTADB
+{"SQLITE_NOTADB", SQLITE_NOTADB},
+#endif
+#ifdef SQLITE_NOTFOUND
+{"SQLITE_NOTFOUND", SQLITE_NOTFOUND},
+#endif
+#ifdef SQLITE_NOTICE
+{"SQLITE_NOTICE", SQLITE_NOTICE},
+#endif
+#ifdef SQLITE_OK
+{"SQLITE_OK", SQLITE_OK},
+#endif
+#ifdef SQLITE_PERM
+{"SQLITE_PERM", SQLITE_PERM},
+#endif
+#ifdef SQLITE_PROTOCOL
+{"SQLITE_PROTOCOL", SQLITE_PROTOCOL},
+#endif
+#ifdef SQLITE_RANGE
+{"SQLITE_RANGE", SQLITE_RANGE},
+#endif
+#ifdef SQLITE_READONLY
+{"SQLITE_READONLY", SQLITE_READONLY},
+#endif
+#ifdef SQLITE_ROW
+{"SQLITE_ROW", SQLITE_ROW},
+#endif
+#ifdef SQLITE_SCHEMA
+{"SQLITE_SCHEMA", SQLITE_SCHEMA},
+#endif
+#ifdef SQLITE_TOOBIG
+{"SQLITE_TOOBIG", SQLITE_TOOBIG},
+#endif
+#ifdef SQLITE_WARNING
+{"SQLITE_WARNING", SQLITE_WARNING},
+#endif
+#ifdef SQLITE_ABORT_ROLLBACK
+{"SQLITE_ABORT_ROLLBACK", SQLITE_ABORT_ROLLBACK},
+#endif
+#ifdef SQLITE_AUTH_USER
+{"SQLITE_AUTH_USER", SQLITE_AUTH_USER},
+#endif
+#ifdef SQLITE_BUSY_RECOVERY
+{"SQLITE_BUSY_RECOVERY", SQLITE_BUSY_RECOVERY},
+#endif
+#ifdef SQLITE_BUSY_SNAPSHOT
+{"SQLITE_BUSY_SNAPSHOT", SQLITE_BUSY_SNAPSHOT},
+#endif
+#ifdef SQLITE_CANTOPEN_CONVPATH
+{"SQLITE_CANTOPEN_CONVPATH", SQLITE_CANTOPEN_CONVPATH},
+#endif
+#ifdef SQLITE_CANTOPEN_FULLPATH
+{"SQLITE_CANTOPEN_FULLPATH", SQLITE_CANTOPEN_FULLPATH},
+#endif
+#ifdef SQLITE_CANTOPEN_ISDIR
+{"SQLITE_CANTOPEN_ISDIR", SQLITE_CANTOPEN_ISDIR},
+#endif
+#ifdef SQLITE_CANTOPEN_NOTEMPDIR
+{"SQLITE_CANTOPEN_NOTEMPDIR", SQLITE_CANTOPEN_NOTEMPDIR},
+#endif
+#ifdef SQLITE_CONSTRAINT_CHECK
+{"SQLITE_CONSTRAINT_CHECK", SQLITE_CONSTRAINT_CHECK},
+#endif
+#ifdef SQLITE_CONSTRAINT_COMMITHOOK
+{"SQLITE_CONSTRAINT_COMMITHOOK", SQLITE_CONSTRAINT_COMMITHOOK},
+#endif
+#ifdef SQLITE_CONSTRAINT_FOREIGNKEY
+{"SQLITE_CONSTRAINT_FOREIGNKEY", SQLITE_CONSTRAINT_FOREIGNKEY},
+#endif
+#ifdef SQLITE_CONSTRAINT_FUNCTION
+{"SQLITE_CONSTRAINT_FUNCTION", SQLITE_CONSTRAINT_FUNCTION},
+#endif
+#ifdef SQLITE_CONSTRAINT_NOTNULL
+{"SQLITE_CONSTRAINT_NOTNULL", SQLITE_CONSTRAINT_NOTNULL},
+#endif
+#ifdef SQLITE_CONSTRAINT_PRIMARYKEY
+{"SQLITE_CONSTRAINT_PRIMARYKEY", SQLITE_CONSTRAINT_PRIMARYKEY},
+#endif
+#ifdef SQLITE_CONSTRAINT_ROWID
+{"SQLITE_CONSTRAINT_ROWID", SQLITE_CONSTRAINT_ROWID},
+#endif
+#ifdef SQLITE_CONSTRAINT_TRIGGER
+{"SQLITE_CONSTRAINT_TRIGGER", SQLITE_CONSTRAINT_TRIGGER},
+#endif
+#ifdef SQLITE_CONSTRAINT_UNIQUE
+{"SQLITE_CONSTRAINT_UNIQUE", SQLITE_CONSTRAINT_UNIQUE},
+#endif
+#ifdef SQLITE_CONSTRAINT_VTAB
+{"SQLITE_CONSTRAINT_VTAB", SQLITE_CONSTRAINT_VTAB},
+#endif
+#ifdef SQLITE_CORRUPT_VTAB
+{"SQLITE_CORRUPT_VTAB", SQLITE_CORRUPT_VTAB},
+#endif
+#ifdef SQLITE_IOERR_ACCESS
+{"SQLITE_IOERR_ACCESS", SQLITE_IOERR_ACCESS},
+#endif
+#ifdef SQLITE_IOERR_BLOCKED
+{"SQLITE_IOERR_BLOCKED", SQLITE_IOERR_BLOCKED},
+#endif
+#ifdef SQLITE_IOERR_CHECKRESERVEDLOCK
+{"SQLITE_IOERR_CHECKRESERVEDLOCK", SQLITE_IOERR_CHECKRESERVEDLOCK},
+#endif
+#ifdef SQLITE_IOERR_CLOSE
+{"SQLITE_IOERR_CLOSE", SQLITE_IOERR_CLOSE},
+#endif
+#ifdef SQLITE_IOERR_CONVPATH
+{"SQLITE_IOERR_CONVPATH", SQLITE_IOERR_CONVPATH},
+#endif
+#ifdef SQLITE_IOERR_DELETE
+{"SQLITE_IOERR_DELETE", SQLITE_IOERR_DELETE},
+#endif
+#ifdef SQLITE_IOERR_DELETE_NOENT
+{"SQLITE_IOERR_DELETE_NOENT", SQLITE_IOERR_DELETE_NOENT},
+#endif
+#ifdef SQLITE_IOERR_DIR_CLOSE
+{"SQLITE_IOERR_DIR_CLOSE", SQLITE_IOERR_DIR_CLOSE},
+#endif
+#ifdef SQLITE_IOERR_DIR_FSYNC
+{"SQLITE_IOERR_DIR_FSYNC", SQLITE_IOERR_DIR_FSYNC},
+#endif
+#ifdef SQLITE_IOERR_FSTAT
+{"SQLITE_IOERR_FSTAT", SQLITE_IOERR_FSTAT},
+#endif
+#ifdef SQLITE_IOERR_FSYNC
+{"SQLITE_IOERR_FSYNC", SQLITE_IOERR_FSYNC},
+#endif
+#ifdef SQLITE_IOERR_GETTEMPPATH
+{"SQLITE_IOERR_GETTEMPPATH", SQLITE_IOERR_GETTEMPPATH},
+#endif
+#ifdef SQLITE_IOERR_LOCK
+{"SQLITE_IOERR_LOCK", SQLITE_IOERR_LOCK},
+#endif
+#ifdef SQLITE_IOERR_MMAP
+{"SQLITE_IOERR_MMAP", SQLITE_IOERR_MMAP},
+#endif
+#ifdef SQLITE_IOERR_NOMEM
+{"SQLITE_IOERR_NOMEM", SQLITE_IOERR_NOMEM},
+#endif
+#ifdef SQLITE_IOERR_RDLOCK
+{"SQLITE_IOERR_RDLOCK", SQLITE_IOERR_RDLOCK},
+#endif
+#ifdef SQLITE_IOERR_READ
+{"SQLITE_IOERR_READ", SQLITE_IOERR_READ},
+#endif
+#ifdef SQLITE_IOERR_SEEK
+{"SQLITE_IOERR_SEEK", SQLITE_IOERR_SEEK},
+#endif
+#ifdef SQLITE_IOERR_SHMLOCK
+{"SQLITE_IOERR_SHMLOCK", SQLITE_IOERR_SHMLOCK},
+#endif
+#ifdef SQLITE_IOERR_SHMMAP
+{"SQLITE_IOERR_SHMMAP", SQLITE_IOERR_SHMMAP},
+#endif
+#ifdef SQLITE_IOERR_SHMOPEN
+{"SQLITE_IOERR_SHMOPEN", SQLITE_IOERR_SHMOPEN},
+#endif
+#ifdef SQLITE_IOERR_SHMSIZE
+{"SQLITE_IOERR_SHMSIZE", SQLITE_IOERR_SHMSIZE},
+#endif
+#ifdef SQLITE_IOERR_SHORT_READ
+{"SQLITE_IOERR_SHORT_READ", SQLITE_IOERR_SHORT_READ},
+#endif
+#ifdef SQLITE_IOERR_TRUNCATE
+{"SQLITE_IOERR_TRUNCATE", SQLITE_IOERR_TRUNCATE},
+#endif
+#ifdef SQLITE_IOERR_UNLOCK
+{"SQLITE_IOERR_UNLOCK", SQLITE_IOERR_UNLOCK},
+#endif
+#ifdef SQLITE_IOERR_WRITE
+{"SQLITE_IOERR_WRITE", SQLITE_IOERR_WRITE},
+#endif
+#ifdef SQLITE_LOCKED_SHAREDCACHE
+{"SQLITE_LOCKED_SHAREDCACHE", SQLITE_LOCKED_SHAREDCACHE},
+#endif
+#ifdef SQLITE_NOTICE_RECOVER_ROLLBACK
+{"SQLITE_NOTICE_RECOVER_ROLLBACK", SQLITE_NOTICE_RECOVER_ROLLBACK},
+#endif
+#ifdef SQLITE_NOTICE_RECOVER_WAL
+{"SQLITE_NOTICE_RECOVER_WAL", SQLITE_NOTICE_RECOVER_WAL},
+#endif
+#ifdef SQLITE_READONLY_CANTLOCK
+{"SQLITE_READONLY_CANTLOCK", SQLITE_READONLY_CANTLOCK},
+#endif
+#ifdef SQLITE_READONLY_DBMOVED
+{"SQLITE_READONLY_DBMOVED", SQLITE_READONLY_DBMOVED},
+#endif
+#ifdef SQLITE_READONLY_RECOVERY
+{"SQLITE_READONLY_RECOVERY", SQLITE_READONLY_RECOVERY},
+#endif
+#ifdef SQLITE_READONLY_ROLLBACK
+{"SQLITE_READONLY_ROLLBACK", SQLITE_READONLY_ROLLBACK},
+#endif
+#ifdef SQLITE_WARNING_AUTOINDEX
+{"SQLITE_WARNING_AUTOINDEX", SQLITE_WARNING_AUTOINDEX},
+#endif
+#ifdef SQLITE_OPEN_AUTOPROXY
+{"SQLITE_OPEN_AUTOPROXY", SQLITE_OPEN_AUTOPROXY},
+#endif
+#ifdef SQLITE_OPEN_CREATE
+{"SQLITE_OPEN_CREATE", SQLITE_OPEN_CREATE},
+#endif
+#ifdef SQLITE_OPEN_DELETEONCLOSE
+{"SQLITE_OPEN_DELETEONCLOSE", SQLITE_OPEN_DELETEONCLOSE},
+#endif
+#ifdef SQLITE_OPEN_EXCLUSIVE
+{"SQLITE_OPEN_EXCLUSIVE", SQLITE_OPEN_EXCLUSIVE},
+#endif
+#ifdef SQLITE_OPEN_FULLMUTEX
+{"SQLITE_OPEN_FULLMUTEX", SQLITE_OPEN_FULLMUTEX},
+#endif
+#ifdef SQLITE_OPEN_MAIN_DB
+{"SQLITE_OPEN_MAIN_DB", SQLITE_OPEN_MAIN_DB},
+#endif
+#ifdef SQLITE_OPEN_MAIN_JOURNAL
+{"SQLITE_OPEN_MAIN_JOURNAL", SQLITE_OPEN_MAIN_JOURNAL},
+#endif
+#ifdef SQLITE_OPEN_MASTER_JOURNAL
+{"SQLITE_OPEN_MASTER_JOURNAL", SQLITE_OPEN_MASTER_JOURNAL},
+#endif
+#ifdef SQLITE_OPEN_MEMORY
+{"SQLITE_OPEN_MEMORY", SQLITE_OPEN_MEMORY},
+#endif
+#ifdef SQLITE_OPEN_NOMUTEX
+{"SQLITE_OPEN_NOMUTEX", SQLITE_OPEN_NOMUTEX},
+#endif
+#ifdef SQLITE_OPEN_PRIVATECACHE
+{"SQLITE_OPEN_PRIVATECACHE", SQLITE_OPEN_PRIVATECACHE},
+#endif
+#ifdef SQLITE_OPEN_READONLY
+{"SQLITE_OPEN_READONLY", SQLITE_OPEN_READONLY},
+#endif
+#ifdef SQLITE_OPEN_READWRITE
+{"SQLITE_OPEN_READWRITE", SQLITE_OPEN_READWRITE},
+#endif
+#ifdef SQLITE_OPEN_SHAREDCACHE
+{"SQLITE_OPEN_SHAREDCACHE", SQLITE_OPEN_SHAREDCACHE},
+#endif
+#ifdef SQLITE_OPEN_SUBJOURNAL
+{"SQLITE_OPEN_SUBJOURNAL", SQLITE_OPEN_SUBJOURNAL},
+#endif
+#ifdef SQLITE_OPEN_TEMP_DB
+{"SQLITE_OPEN_TEMP_DB", SQLITE_OPEN_TEMP_DB},
+#endif
+#ifdef SQLITE_OPEN_TEMP_JOURNAL
+{"SQLITE_OPEN_TEMP_JOURNAL", SQLITE_OPEN_TEMP_JOURNAL},
+#endif
+#ifdef SQLITE_OPEN_TRANSIENT_DB
+{"SQLITE_OPEN_TRANSIENT_DB", SQLITE_OPEN_TRANSIENT_DB},
+#endif
+#ifdef SQLITE_OPEN_URI
+{"SQLITE_OPEN_URI", SQLITE_OPEN_URI},
+#endif
+#ifdef SQLITE_OPEN_WAL
+{"SQLITE_OPEN_WAL", SQLITE_OPEN_WAL},
+#endif
+#ifdef SQLITE_IOCAP_ATOMIC
+{"SQLITE_IOCAP_ATOMIC", SQLITE_IOCAP_ATOMIC},
+#endif
+#ifdef SQLITE_IOCAP_ATOMIC16K
+{"SQLITE_IOCAP_ATOMIC16K", SQLITE_IOCAP_ATOMIC16K},
+#endif
+#ifdef SQLITE_IOCAP_ATOMIC1K
+{"SQLITE_IOCAP_ATOMIC1K", SQLITE_IOCAP_ATOMIC1K},
+#endif
+#ifdef SQLITE_IOCAP_ATOMIC2K
+{"SQLITE_IOCAP_ATOMIC2K", SQLITE_IOCAP_ATOMIC2K},
+#endif
+#ifdef SQLITE_IOCAP_ATOMIC32K
+{"SQLITE_IOCAP_ATOMIC32K", SQLITE_IOCAP_ATOMIC32K},
+#endif
+#ifdef SQLITE_IOCAP_ATOMIC4K
+{"SQLITE_IOCAP_ATOMIC4K", SQLITE_IOCAP_ATOMIC4K},
+#endif
+#ifdef SQLITE_IOCAP_ATOMIC512
+{"SQLITE_IOCAP_ATOMIC512", SQLITE_IOCAP_ATOMIC512},
+#endif
+#ifdef SQLITE_IOCAP_ATOMIC64K
+{"SQLITE_IOCAP_ATOMIC64K", SQLITE_IOCAP_ATOMIC64K},
+#endif
+#ifdef SQLITE_IOCAP_ATOMIC8K
+{"SQLITE_IOCAP_ATOMIC8K", SQLITE_IOCAP_ATOMIC8K},
+#endif
+#ifdef SQLITE_IOCAP_IMMUTABLE
+{"SQLITE_IOCAP_IMMUTABLE", SQLITE_IOCAP_IMMUTABLE},
+#endif
+#ifdef SQLITE_IOCAP_POWERSAFE_OVERWRITE
+{"SQLITE_IOCAP_POWERSAFE_OVERWRITE", SQLITE_IOCAP_POWERSAFE_OVERWRITE},
+#endif
+#ifdef SQLITE_IOCAP_SAFE_APPEND
+{"SQLITE_IOCAP_SAFE_APPEND", SQLITE_IOCAP_SAFE_APPEND},
+#endif
+#ifdef SQLITE_IOCAP_SEQUENTIAL
+{"SQLITE_IOCAP_SEQUENTIAL", SQLITE_IOCAP_SEQUENTIAL},
+#endif
+#ifdef SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
+{"SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN", SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN},
+#endif
+#ifdef SQLITE_LOCK_EXCLUSIVE
+{"SQLITE_LOCK_EXCLUSIVE", SQLITE_LOCK_EXCLUSIVE},
+#endif
+#ifdef SQLITE_LOCK_NONE
+{"SQLITE_LOCK_NONE", SQLITE_LOCK_NONE},
+#endif
+#ifdef SQLITE_LOCK_PENDING
+{"SQLITE_LOCK_PENDING", SQLITE_LOCK_PENDING},
+#endif
+#ifdef SQLITE_LOCK_RESERVED
+{"SQLITE_LOCK_RESERVED", SQLITE_LOCK_RESERVED},
+#endif
+#ifdef SQLITE_LOCK_SHARED
+{"SQLITE_LOCK_SHARED", SQLITE_LOCK_SHARED},
+#endif
+#ifdef SQLITE_SYNC_DATAONLY
+{"SQLITE_SYNC_DATAONLY", SQLITE_SYNC_DATAONLY},
+#endif
+#ifdef SQLITE_SYNC_FULL
+{"SQLITE_SYNC_FULL", SQLITE_SYNC_FULL},
+#endif
+#ifdef SQLITE_SYNC_NORMAL
+{"SQLITE_SYNC_NORMAL", SQLITE_SYNC_NORMAL},
+#endif
+#ifdef SQLITE_FCNTL_BUSYHANDLER
+{"SQLITE_FCNTL_BUSYHANDLER", SQLITE_FCNTL_BUSYHANDLER},
+#endif
+#ifdef SQLITE_FCNTL_CHUNK_SIZE
+{"SQLITE_FCNTL_CHUNK_SIZE", SQLITE_FCNTL_CHUNK_SIZE},
+#endif
+#ifdef SQLITE_FCNTL_COMMIT_PHASETWO
+{"SQLITE_FCNTL_COMMIT_PHASETWO", SQLITE_FCNTL_COMMIT_PHASETWO},
+#endif
+#ifdef SQLITE_FCNTL_FILE_POINTER
+{"SQLITE_FCNTL_FILE_POINTER", SQLITE_FCNTL_FILE_POINTER},
+#endif
+#ifdef SQLITE_FCNTL_GET_LOCKPROXYFILE
+{"SQLITE_FCNTL_GET_LOCKPROXYFILE", SQLITE_FCNTL_GET_LOCKPROXYFILE},
+#endif
+#ifdef SQLITE_FCNTL_HAS_MOVED
+{"SQLITE_FCNTL_HAS_MOVED", SQLITE_FCNTL_HAS_MOVED},
+#endif
+#ifdef SQLITE_FCNTL_LAST_ERRNO
+{"SQLITE_FCNTL_LAST_ERRNO", SQLITE_FCNTL_LAST_ERRNO},
+#endif
+#ifdef SQLITE_FCNTL_LOCKSTATE
+{"SQLITE_FCNTL_LOCKSTATE", SQLITE_FCNTL_LOCKSTATE},
+#endif
+#ifdef SQLITE_FCNTL_MMAP_SIZE
+{"SQLITE_FCNTL_MMAP_SIZE", SQLITE_FCNTL_MMAP_SIZE},
+#endif
+#ifdef SQLITE_FCNTL_OVERWRITE
+{"SQLITE_FCNTL_OVERWRITE", SQLITE_FCNTL_OVERWRITE},
+#endif
+#ifdef SQLITE_FCNTL_PERSIST_WAL
+{"SQLITE_FCNTL_PERSIST_WAL", SQLITE_FCNTL_PERSIST_WAL},
+#endif
+#ifdef SQLITE_FCNTL_POWERSAFE_OVERWRITE
+{"SQLITE_FCNTL_POWERSAFE_OVERWRITE", SQLITE_FCNTL_POWERSAFE_OVERWRITE},
+#endif
+#ifdef SQLITE_FCNTL_PRAGMA
+{"SQLITE_FCNTL_PRAGMA", SQLITE_FCNTL_PRAGMA},
+#endif
+#ifdef SQLITE_FCNTL_RBU
+{"SQLITE_FCNTL_RBU", SQLITE_FCNTL_RBU},
+#endif
+#ifdef SQLITE_FCNTL_SET_LOCKPROXYFILE
+{"SQLITE_FCNTL_SET_LOCKPROXYFILE", SQLITE_FCNTL_SET_LOCKPROXYFILE},
+#endif
+#ifdef SQLITE_FCNTL_SIZE_HINT
+{"SQLITE_FCNTL_SIZE_HINT", SQLITE_FCNTL_SIZE_HINT},
+#endif
+#ifdef SQLITE_FCNTL_SYNC
+{"SQLITE_FCNTL_SYNC", SQLITE_FCNTL_SYNC},
+#endif
+#ifdef SQLITE_FCNTL_SYNC_OMITTED
+{"SQLITE_FCNTL_SYNC_OMITTED", SQLITE_FCNTL_SYNC_OMITTED},
+#endif
+#ifdef SQLITE_FCNTL_TEMPFILENAME
+{"SQLITE_FCNTL_TEMPFILENAME", SQLITE_FCNTL_TEMPFILENAME},
+#endif
+#ifdef SQLITE_FCNTL_TRACE
+{"SQLITE_FCNTL_TRACE", SQLITE_FCNTL_TRACE},
+#endif
+#ifdef SQLITE_FCNTL_VFSNAME
+{"SQLITE_FCNTL_VFSNAME", SQLITE_FCNTL_VFSNAME},
+#endif
+#ifdef SQLITE_FCNTL_WAL_BLOCK
+{"SQLITE_FCNTL_WAL_BLOCK", SQLITE_FCNTL_WAL_BLOCK},
+#endif
+#ifdef SQLITE_FCNTL_WIN32_AV_RETRY
+{"SQLITE_FCNTL_WIN32_AV_RETRY", SQLITE_FCNTL_WIN32_AV_RETRY},
+#endif
+#ifdef SQLITE_FCNTL_WIN32_SET_HANDLE
+{"SQLITE_FCNTL_WIN32_SET_HANDLE", SQLITE_FCNTL_WIN32_SET_HANDLE},
+#endif
+#ifdef SQLITE_FCNTL_ZIPVFS
+{"SQLITE_FCNTL_ZIPVFS", SQLITE_FCNTL_ZIPVFS},
+#endif
+#ifdef SQLITE_ACCESS_EXISTS
+{"SQLITE_ACCESS_EXISTS", SQLITE_ACCESS_EXISTS},
+#endif
+#ifdef SQLITE_ACCESS_READ
+{"SQLITE_ACCESS_READ", SQLITE_ACCESS_READ},
+#endif
+#ifdef SQLITE_ACCESS_READWRITE
+{"SQLITE_ACCESS_READWRITE", SQLITE_ACCESS_READWRITE},
+#endif
+#ifdef SQLITE_SHM_EXCLUSIVE
+{"SQLITE_SHM_EXCLUSIVE", SQLITE_SHM_EXCLUSIVE},
+#endif
+#ifdef SQLITE_SHM_LOCK
+{"SQLITE_SHM_LOCK", SQLITE_SHM_LOCK},
+#endif
+#ifdef SQLITE_SHM_SHARED
+{"SQLITE_SHM_SHARED", SQLITE_SHM_SHARED},
+#endif
+#ifdef SQLITE_SHM_UNLOCK
+{"SQLITE_SHM_UNLOCK", SQLITE_SHM_UNLOCK},
+#endif
+#ifdef SQLITE_SHM_NLOCK
+{"SQLITE_SHM_NLOCK", SQLITE_SHM_NLOCK},
+#endif
+#ifdef SQLITE_CONFIG_COVERING_INDEX_SCAN
+{"SQLITE_CONFIG_COVERING_INDEX_SCAN", SQLITE_CONFIG_COVERING_INDEX_SCAN},
+#endif
+#ifdef SQLITE_CONFIG_GETMALLOC
+{"SQLITE_CONFIG_GETMALLOC", SQLITE_CONFIG_GETMALLOC},
+#endif
+#ifdef SQLITE_CONFIG_GETMUTEX
+{"SQLITE_CONFIG_GETMUTEX", SQLITE_CONFIG_GETMUTEX},
+#endif
+#ifdef SQLITE_CONFIG_GETPCACHE
+{"SQLITE_CONFIG_GETPCACHE", SQLITE_CONFIG_GETPCACHE},
+#endif
+#ifdef SQLITE_CONFIG_GETPCACHE2
+{"SQLITE_CONFIG_GETPCACHE2", SQLITE_CONFIG_GETPCACHE2},
+#endif
+#ifdef SQLITE_CONFIG_HEAP
+{"SQLITE_CONFIG_HEAP", SQLITE_CONFIG_HEAP},
+#endif
+#ifdef SQLITE_CONFIG_LOG
+{"SQLITE_CONFIG_LOG", SQLITE_CONFIG_LOG},
+#endif
+#ifdef SQLITE_CONFIG_LOOKASIDE
+{"SQLITE_CONFIG_LOOKASIDE", SQLITE_CONFIG_LOOKASIDE},
+#endif
+#ifdef SQLITE_CONFIG_MALLOC
+{"SQLITE_CONFIG_MALLOC", SQLITE_CONFIG_MALLOC},
+#endif
+#ifdef SQLITE_CONFIG_MEMSTATUS
+{"SQLITE_CONFIG_MEMSTATUS", SQLITE_CONFIG_MEMSTATUS},
+#endif
+#ifdef SQLITE_CONFIG_MMAP_SIZE
+{"SQLITE_CONFIG_MMAP_SIZE", SQLITE_CONFIG_MMAP_SIZE},
+#endif
+#ifdef SQLITE_CONFIG_MULTITHREAD
+{"SQLITE_CONFIG_MULTITHREAD", SQLITE_CONFIG_MULTITHREAD},
+#endif
+#ifdef SQLITE_CONFIG_MUTEX
+{"SQLITE_CONFIG_MUTEX", SQLITE_CONFIG_MUTEX},
+#endif
+#ifdef SQLITE_CONFIG_PAGECACHE
+{"SQLITE_CONFIG_PAGECACHE", SQLITE_CONFIG_PAGECACHE},
+#endif
+#ifdef SQLITE_CONFIG_PCACHE
+{"SQLITE_CONFIG_PCACHE", SQLITE_CONFIG_PCACHE},
+#endif
+#ifdef SQLITE_CONFIG_PCACHE2
+{"SQLITE_CONFIG_PCACHE2", SQLITE_CONFIG_PCACHE2},
+#endif
+#ifdef SQLITE_CONFIG_PCACHE_HDRSZ
+{"SQLITE_CONFIG_PCACHE_HDRSZ", SQLITE_CONFIG_PCACHE_HDRSZ},
+#endif
+#ifdef SQLITE_CONFIG_PMASZ
+{"SQLITE_CONFIG_PMASZ", SQLITE_CONFIG_PMASZ},
+#endif
+#ifdef SQLITE_CONFIG_SCRATCH
+{"SQLITE_CONFIG_SCRATCH", SQLITE_CONFIG_SCRATCH},
+#endif
+#ifdef SQLITE_CONFIG_SERIALIZED
+{"SQLITE_CONFIG_SERIALIZED", SQLITE_CONFIG_SERIALIZED},
+#endif
+#ifdef SQLITE_CONFIG_SINGLETHREAD
+{"SQLITE_CONFIG_SINGLETHREAD", SQLITE_CONFIG_SINGLETHREAD},
+#endif
+#ifdef SQLITE_CONFIG_SQLLOG
+{"SQLITE_CONFIG_SQLLOG", SQLITE_CONFIG_SQLLOG},
+#endif
+#ifdef SQLITE_CONFIG_URI
+{"SQLITE_CONFIG_URI", SQLITE_CONFIG_URI},
+#endif
+#ifdef SQLITE_CONFIG_WIN32_HEAPSIZE
+{"SQLITE_CONFIG_WIN32_HEAPSIZE", SQLITE_CONFIG_WIN32_HEAPSIZE},
+#endif
+#ifdef SQLITE_DBCONFIG_ENABLE_FKEY
+{"SQLITE_DBCONFIG_ENABLE_FKEY", SQLITE_DBCONFIG_ENABLE_FKEY},
+#endif
+#ifdef SQLITE_DBCONFIG_ENABLE_TRIGGER
+{"SQLITE_DBCONFIG_ENABLE_TRIGGER", SQLITE_DBCONFIG_ENABLE_TRIGGER},
+#endif
+#ifdef SQLITE_DBCONFIG_LOOKASIDE
+{"SQLITE_DBCONFIG_LOOKASIDE", SQLITE_DBCONFIG_LOOKASIDE},
+#endif
+#ifdef SQLITE_DENY
+{"SQLITE_DENY", SQLITE_DENY},
+#endif
+#ifdef SQLITE_IGNORE
+{"SQLITE_IGNORE", SQLITE_IGNORE},
+#endif
+#ifdef SQLITE_ALTER_TABLE
+{"SQLITE_ALTER_TABLE", SQLITE_ALTER_TABLE},
+#endif
+#ifdef SQLITE_ANALYZE
+{"SQLITE_ANALYZE", SQLITE_ANALYZE},
+#endif
+#ifdef SQLITE_ATTACH
+{"SQLITE_ATTACH", SQLITE_ATTACH},
+#endif
+#ifdef SQLITE_COPY
+{"SQLITE_COPY", SQLITE_COPY},
+#endif
+#ifdef SQLITE_CREATE_INDEX
+{"SQLITE_CREATE_INDEX", SQLITE_CREATE_INDEX},
+#endif
+#ifdef SQLITE_CREATE_TABLE
+{"SQLITE_CREATE_TABLE", SQLITE_CREATE_TABLE},
+#endif
+#ifdef SQLITE_CREATE_TEMP_INDEX
+{"SQLITE_CREATE_TEMP_INDEX", SQLITE_CREATE_TEMP_INDEX},
+#endif
+#ifdef SQLITE_CREATE_TEMP_TABLE
+{"SQLITE_CREATE_TEMP_TABLE", SQLITE_CREATE_TEMP_TABLE},
+#endif
+#ifdef SQLITE_CREATE_TEMP_TRIGGER
+{"SQLITE_CREATE_TEMP_TRIGGER", SQLITE_CREATE_TEMP_TRIGGER},
+#endif
+#ifdef SQLITE_CREATE_TEMP_VIEW
+{"SQLITE_CREATE_TEMP_VIEW", SQLITE_CREATE_TEMP_VIEW},
+#endif
+#ifdef SQLITE_CREATE_TRIGGER
+{"SQLITE_CREATE_TRIGGER", SQLITE_CREATE_TRIGGER},
+#endif
+#ifdef SQLITE_CREATE_VIEW
+{"SQLITE_CREATE_VIEW", SQLITE_CREATE_VIEW},
+#endif
+#ifdef SQLITE_CREATE_VTABLE
+{"SQLITE_CREATE_VTABLE", SQLITE_CREATE_VTABLE},
+#endif
+#ifdef SQLITE_DELETE
+{"SQLITE_DELETE", SQLITE_DELETE},
+#endif
+#ifdef SQLITE_DETACH
+{"SQLITE_DETACH", SQLITE_DETACH},
+#endif
+#ifdef SQLITE_DROP_INDEX
+{"SQLITE_DROP_INDEX", SQLITE_DROP_INDEX},
+#endif
+#ifdef SQLITE_DROP_TABLE
+{"SQLITE_DROP_TABLE", SQLITE_DROP_TABLE},
+#endif
+#ifdef SQLITE_DROP_TEMP_INDEX
+{"SQLITE_DROP_TEMP_INDEX", SQLITE_DROP_TEMP_INDEX},
+#endif
+#ifdef SQLITE_DROP_TEMP_TABLE
+{"SQLITE_DROP_TEMP_TABLE", SQLITE_DROP_TEMP_TABLE},
+#endif
+#ifdef SQLITE_DROP_TEMP_TRIGGER
+{"SQLITE_DROP_TEMP_TRIGGER", SQLITE_DROP_TEMP_TRIGGER},
+#endif
+#ifdef SQLITE_DROP_TEMP_VIEW
+{"SQLITE_DROP_TEMP_VIEW", SQLITE_DROP_TEMP_VIEW},
+#endif
+#ifdef SQLITE_DROP_TRIGGER
+{"SQLITE_DROP_TRIGGER", SQLITE_DROP_TRIGGER},
+#endif
+#ifdef SQLITE_DROP_VIEW
+{"SQLITE_DROP_VIEW", SQLITE_DROP_VIEW},
+#endif
+#ifdef SQLITE_DROP_VTABLE
+{"SQLITE_DROP_VTABLE", SQLITE_DROP_VTABLE},
+#endif
+#ifdef SQLITE_FUNCTION
+{"SQLITE_FUNCTION", SQLITE_FUNCTION},
+#endif
+#ifdef SQLITE_INSERT
+{"SQLITE_INSERT", SQLITE_INSERT},
+#endif
+#ifdef SQLITE_PRAGMA
+{"SQLITE_PRAGMA", SQLITE_PRAGMA},
+#endif
+#ifdef SQLITE_READ
+{"SQLITE_READ", SQLITE_READ},
+#endif
+#ifdef SQLITE_RECURSIVE
+{"SQLITE_RECURSIVE", SQLITE_RECURSIVE},
+#endif
+#ifdef SQLITE_REINDEX
+{"SQLITE_REINDEX", SQLITE_REINDEX},
+#endif
+#ifdef SQLITE_SAVEPOINT
+{"SQLITE_SAVEPOINT", SQLITE_SAVEPOINT},
+#endif
+#ifdef SQLITE_SELECT
+{"SQLITE_SELECT", SQLITE_SELECT},
+#endif
+#ifdef SQLITE_TRANSACTION
+{"SQLITE_TRANSACTION", SQLITE_TRANSACTION},
+#endif
+#ifdef SQLITE_UPDATE
+{"SQLITE_UPDATE", SQLITE_UPDATE},
+#endif
+#ifdef SQLITE_LIMIT_ATTACHED
+{"SQLITE_LIMIT_ATTACHED", SQLITE_LIMIT_ATTACHED},
+#endif
+#ifdef SQLITE_LIMIT_COLUMN
+{"SQLITE_LIMIT_COLUMN", SQLITE_LIMIT_COLUMN},
+#endif
+#ifdef SQLITE_LIMIT_COMPOUND_SELECT
+{"SQLITE_LIMIT_COMPOUND_SELECT", SQLITE_LIMIT_COMPOUND_SELECT},
+#endif
+#ifdef SQLITE_LIMIT_EXPR_DEPTH
+{"SQLITE_LIMIT_EXPR_DEPTH", SQLITE_LIMIT_EXPR_DEPTH},
+#endif
+#ifdef SQLITE_LIMIT_FUNCTION_ARG
+{"SQLITE_LIMIT_FUNCTION_ARG", SQLITE_LIMIT_FUNCTION_ARG},
+#endif
+#ifdef SQLITE_LIMIT_LENGTH
+{"SQLITE_LIMIT_LENGTH", SQLITE_LIMIT_LENGTH},
+#endif
+#ifdef SQLITE_LIMIT_LIKE_PATTERN_LENGTH
+{"SQLITE_LIMIT_LIKE_PATTERN_LENGTH", SQLITE_LIMIT_LIKE_PATTERN_LENGTH},
+#endif
+#ifdef SQLITE_LIMIT_SQL_LENGTH
+{"SQLITE_LIMIT_SQL_LENGTH", SQLITE_LIMIT_SQL_LENGTH},
+#endif
+#ifdef SQLITE_LIMIT_TRIGGER_DEPTH
+{"SQLITE_LIMIT_TRIGGER_DEPTH", SQLITE_LIMIT_TRIGGER_DEPTH},
+#endif
+#ifdef SQLITE_LIMIT_VARIABLE_NUMBER
+{"SQLITE_LIMIT_VARIABLE_NUMBER", SQLITE_LIMIT_VARIABLE_NUMBER},
+#endif
+#ifdef SQLITE_LIMIT_VDBE_OP
+{"SQLITE_LIMIT_VDBE_OP", SQLITE_LIMIT_VDBE_OP},
+#endif
+#ifdef SQLITE_LIMIT_WORKER_THREADS
+{"SQLITE_LIMIT_WORKER_THREADS", SQLITE_LIMIT_WORKER_THREADS},
+#endif
+#ifdef SQLITE_BLOB
+{"SQLITE_BLOB", SQLITE_BLOB},
+#endif
+#ifdef SQLITE_FLOAT
+{"SQLITE_FLOAT", SQLITE_FLOAT},
+#endif
+#ifdef SQLITE_INTEGER
+{"SQLITE_INTEGER", SQLITE_INTEGER},
+#endif
+#ifdef SQLITE_NULL
+{"SQLITE_NULL", SQLITE_NULL},
+#endif
+#ifdef SQLITE_TEXT
+{"SQLITE_TEXT", SQLITE_TEXT},
+#endif
+#ifdef SQLITE_ANY
+{"SQLITE_ANY", SQLITE_ANY},
+#endif
+#ifdef SQLITE_UTF16
+{"SQLITE_UTF16", SQLITE_UTF16},
+#endif
+#ifdef SQLITE_UTF16BE
+{"SQLITE_UTF16BE", SQLITE_UTF16BE},
+#endif
+#ifdef SQLITE_UTF16LE
+{"SQLITE_UTF16LE", SQLITE_UTF16LE},
+#endif
+#ifdef SQLITE_UTF16_ALIGNED
+{"SQLITE_UTF16_ALIGNED", SQLITE_UTF16_ALIGNED},
+#endif
+#ifdef SQLITE_UTF8
+{"SQLITE_UTF8", SQLITE_UTF8},
+#endif
+#ifdef SQLITE_DETERMINISTIC
+{"SQLITE_DETERMINISTIC", SQLITE_DETERMINISTIC},
+#endif
+#ifdef SQLITE_STATIC
+{"SQLITE_STATIC", SQLITE_STATIC},
+#endif
+#ifdef SQLITE_TRANSIENT
+{"SQLITE_TRANSIENT", SQLITE_TRANSIENT},
+#endif
+#ifdef SQLITE_INDEX_CONSTRAINT_EQ
+{"SQLITE_INDEX_CONSTRAINT_EQ", SQLITE_INDEX_CONSTRAINT_EQ},
+#endif
+#ifdef SQLITE_INDEX_CONSTRAINT_GE
+{"SQLITE_INDEX_CONSTRAINT_GE", SQLITE_INDEX_CONSTRAINT_GE},
+#endif
+#ifdef SQLITE_INDEX_CONSTRAINT_GT
+{"SQLITE_INDEX_CONSTRAINT_GT", SQLITE_INDEX_CONSTRAINT_GT},
+#endif
+#ifdef SQLITE_INDEX_CONSTRAINT_LE
+{"SQLITE_INDEX_CONSTRAINT_LE", SQLITE_INDEX_CONSTRAINT_LE},
+#endif
+#ifdef SQLITE_INDEX_CONSTRAINT_LT
+{"SQLITE_INDEX_CONSTRAINT_LT", SQLITE_INDEX_CONSTRAINT_LT},
+#endif
+#ifdef SQLITE_INDEX_CONSTRAINT_MATCH
+{"SQLITE_INDEX_CONSTRAINT_MATCH", SQLITE_INDEX_CONSTRAINT_MATCH},
+#endif
+#ifdef SQLITE_MUTEX_FAST
+{"SQLITE_MUTEX_FAST", SQLITE_MUTEX_FAST},
+#endif
+#ifdef SQLITE_MUTEX_RECURSIVE
+{"SQLITE_MUTEX_RECURSIVE", SQLITE_MUTEX_RECURSIVE},
+#endif
+#ifdef SQLITE_MUTEX_STATIC_APP1
+{"SQLITE_MUTEX_STATIC_APP1", SQLITE_MUTEX_STATIC_APP1},
+#endif
+#ifdef SQLITE_MUTEX_STATIC_APP2
+{"SQLITE_MUTEX_STATIC_APP2", SQLITE_MUTEX_STATIC_APP2},
+#endif
+#ifdef SQLITE_MUTEX_STATIC_APP3
+{"SQLITE_MUTEX_STATIC_APP3", SQLITE_MUTEX_STATIC_APP3},
+#endif
+#ifdef SQLITE_MUTEX_STATIC_LRU
+{"SQLITE_MUTEX_STATIC_LRU", SQLITE_MUTEX_STATIC_LRU},
+#endif
+#ifdef SQLITE_MUTEX_STATIC_LRU2
+{"SQLITE_MUTEX_STATIC_LRU2", SQLITE_MUTEX_STATIC_LRU2},
+#endif
+#ifdef SQLITE_MUTEX_STATIC_MASTER
+{"SQLITE_MUTEX_STATIC_MASTER", SQLITE_MUTEX_STATIC_MASTER},
+#endif
+#ifdef SQLITE_MUTEX_STATIC_MEM
+{"SQLITE_MUTEX_STATIC_MEM", SQLITE_MUTEX_STATIC_MEM},
+#endif
+#ifdef SQLITE_MUTEX_STATIC_MEM2
+{"SQLITE_MUTEX_STATIC_MEM2", SQLITE_MUTEX_STATIC_MEM2},
+#endif
+#ifdef SQLITE_MUTEX_STATIC_OPEN
+{"SQLITE_MUTEX_STATIC_OPEN", SQLITE_MUTEX_STATIC_OPEN},
+#endif
+#ifdef SQLITE_MUTEX_STATIC_PMEM
+{"SQLITE_MUTEX_STATIC_PMEM", SQLITE_MUTEX_STATIC_PMEM},
+#endif
+#ifdef SQLITE_MUTEX_STATIC_PRNG
+{"SQLITE_MUTEX_STATIC_PRNG", SQLITE_MUTEX_STATIC_PRNG},
+#endif
+#ifdef SQLITE_MUTEX_STATIC_VFS1
+{"SQLITE_MUTEX_STATIC_VFS1", SQLITE_MUTEX_STATIC_VFS1},
+#endif
+#ifdef SQLITE_MUTEX_STATIC_VFS2
+{"SQLITE_MUTEX_STATIC_VFS2", SQLITE_MUTEX_STATIC_VFS2},
+#endif
+#ifdef SQLITE_MUTEX_STATIC_VFS3
+{"SQLITE_MUTEX_STATIC_VFS3", SQLITE_MUTEX_STATIC_VFS3},
+#endif
+#ifdef SQLITE_TESTCTRL_ALWAYS
+{"SQLITE_TESTCTRL_ALWAYS", SQLITE_TESTCTRL_ALWAYS},
+#endif
+#ifdef SQLITE_TESTCTRL_ASSERT
+{"SQLITE_TESTCTRL_ASSERT", SQLITE_TESTCTRL_ASSERT},
+#endif
+#ifdef SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS
+{"SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS", SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS},
+#endif
+#ifdef SQLITE_TESTCTRL_BITVEC_TEST
+{"SQLITE_TESTCTRL_BITVEC_TEST", SQLITE_TESTCTRL_BITVEC_TEST},
+#endif
+#ifdef SQLITE_TESTCTRL_BYTEORDER
+{"SQLITE_TESTCTRL_BYTEORDER", SQLITE_TESTCTRL_BYTEORDER},
+#endif
+#ifdef SQLITE_TESTCTRL_EXPLAIN_STMT
+{"SQLITE_TESTCTRL_EXPLAIN_STMT", SQLITE_TESTCTRL_EXPLAIN_STMT},
+#endif
+#ifdef SQLITE_TESTCTRL_FAULT_INSTALL
+{"SQLITE_TESTCTRL_FAULT_INSTALL", SQLITE_TESTCTRL_FAULT_INSTALL},
+#endif
+#ifdef SQLITE_TESTCTRL_FIRST
+{"SQLITE_TESTCTRL_FIRST", SQLITE_TESTCTRL_FIRST},
+#endif
+#ifdef SQLITE_TESTCTRL_IMPOSTER
+{"SQLITE_TESTCTRL_IMPOSTER", SQLITE_TESTCTRL_IMPOSTER},
+#endif
+#ifdef SQLITE_TESTCTRL_ISINIT
+{"SQLITE_TESTCTRL_ISINIT", SQLITE_TESTCTRL_ISINIT},
+#endif
+#ifdef SQLITE_TESTCTRL_ISKEYWORD
+{"SQLITE_TESTCTRL_ISKEYWORD", SQLITE_TESTCTRL_ISKEYWORD},
+#endif
+#ifdef SQLITE_TESTCTRL_LAST
+{"SQLITE_TESTCTRL_LAST", SQLITE_TESTCTRL_LAST},
+#endif
+#ifdef SQLITE_TESTCTRL_LOCALTIME_FAULT
+{"SQLITE_TESTCTRL_LOCALTIME_FAULT", SQLITE_TESTCTRL_LOCALTIME_FAULT},
+#endif
+#ifdef SQLITE_TESTCTRL_NEVER_CORRUPT
+{"SQLITE_TESTCTRL_NEVER_CORRUPT", SQLITE_TESTCTRL_NEVER_CORRUPT},
+#endif
+#ifdef SQLITE_TESTCTRL_OPTIMIZATIONS
+{"SQLITE_TESTCTRL_OPTIMIZATIONS", SQLITE_TESTCTRL_OPTIMIZATIONS},
+#endif
+#ifdef SQLITE_TESTCTRL_PENDING_BYTE
+{"SQLITE_TESTCTRL_PENDING_BYTE", SQLITE_TESTCTRL_PENDING_BYTE},
+#endif
+#ifdef SQLITE_TESTCTRL_PRNG_RESET
+{"SQLITE_TESTCTRL_PRNG_RESET", SQLITE_TESTCTRL_PRNG_RESET},
+#endif
+#ifdef SQLITE_TESTCTRL_PRNG_RESTORE
+{"SQLITE_TESTCTRL_PRNG_RESTORE", SQLITE_TESTCTRL_PRNG_RESTORE},
+#endif
+#ifdef SQLITE_TESTCTRL_PRNG_SAVE
+{"SQLITE_TESTCTRL_PRNG_SAVE", SQLITE_TESTCTRL_PRNG_SAVE},
+#endif
+#ifdef SQLITE_TESTCTRL_RESERVE
+{"SQLITE_TESTCTRL_RESERVE", SQLITE_TESTCTRL_RESERVE},
+#endif
+#ifdef SQLITE_TESTCTRL_SCRATCHMALLOC
+{"SQLITE_TESTCTRL_SCRATCHMALLOC", SQLITE_TESTCTRL_SCRATCHMALLOC},
+#endif
+#ifdef SQLITE_TESTCTRL_SORTER_MMAP
+{"SQLITE_TESTCTRL_SORTER_MMAP", SQLITE_TESTCTRL_SORTER_MMAP},
+#endif
+#ifdef SQLITE_TESTCTRL_VDBE_COVERAGE
+{"SQLITE_TESTCTRL_VDBE_COVERAGE", SQLITE_TESTCTRL_VDBE_COVERAGE},
+#endif
+#ifdef SQLITE_STATUS_MALLOC_COUNT
+{"SQLITE_STATUS_MALLOC_COUNT", SQLITE_STATUS_MALLOC_COUNT},
+#endif
+#ifdef SQLITE_STATUS_MALLOC_SIZE
+{"SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE},
+#endif
+#ifdef SQLITE_STATUS_MEMORY_USED
+{"SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED},
+#endif
+#ifdef SQLITE_STATUS_PAGECACHE_OVERFLOW
+{"SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW},
+#endif
+#ifdef SQLITE_STATUS_PAGECACHE_SIZE
+{"SQLITE_STATUS_PAGECACHE_SIZE", SQLITE_STATUS_PAGECACHE_SIZE},
+#endif
+#ifdef SQLITE_STATUS_PAGECACHE_USED
+{"SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED},
+#endif
+#ifdef SQLITE_STATUS_PARSER_STACK
+{"SQLITE_STATUS_PARSER_STACK", SQLITE_STATUS_PARSER_STACK},
+#endif
+#ifdef SQLITE_STATUS_SCRATCH_OVERFLOW
+{"SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW},
+#endif
+#ifdef SQLITE_STATUS_SCRATCH_SIZE
+{"SQLITE_STATUS_SCRATCH_SIZE", SQLITE_STATUS_SCRATCH_SIZE},
+#endif
+#ifdef SQLITE_STATUS_SCRATCH_USED
+{"SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED},
+#endif
+#ifdef SQLITE_DBSTATUS_CACHE_HIT
+{"SQLITE_DBSTATUS_CACHE_HIT", SQLITE_DBSTATUS_CACHE_HIT},
+#endif
+#ifdef SQLITE_DBSTATUS_CACHE_MISS
+{"SQLITE_DBSTATUS_CACHE_MISS", SQLITE_DBSTATUS_CACHE_MISS},
+#endif
+#ifdef SQLITE_DBSTATUS_CACHE_USED
+{"SQLITE_DBSTATUS_CACHE_USED", SQLITE_DBSTATUS_CACHE_USED},
+#endif
+#ifdef SQLITE_DBSTATUS_CACHE_WRITE
+{"SQLITE_DBSTATUS_CACHE_WRITE", SQLITE_DBSTATUS_CACHE_WRITE},
+#endif
+#ifdef SQLITE_DBSTATUS_DEFERRED_FKS
+{"SQLITE_DBSTATUS_DEFERRED_FKS", SQLITE_DBSTATUS_DEFERRED_FKS},
+#endif
+#ifdef SQLITE_DBSTATUS_LOOKASIDE_HIT
+{"SQLITE_DBSTATUS_LOOKASIDE_HIT", SQLITE_DBSTATUS_LOOKASIDE_HIT},
+#endif
+#ifdef SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL
+{"SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL},
+#endif
+#ifdef SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE
+{"SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE", SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE},
+#endif
+#ifdef SQLITE_DBSTATUS_LOOKASIDE_USED
+{"SQLITE_DBSTATUS_LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED},
+#endif
+#ifdef SQLITE_DBSTATUS_MAX
+{"SQLITE_DBSTATUS_MAX", SQLITE_DBSTATUS_MAX},
+#endif
+#ifdef SQLITE_DBSTATUS_SCHEMA_USED
+{"SQLITE_DBSTATUS_SCHEMA_USED", SQLITE_DBSTATUS_SCHEMA_USED},
+#endif
+#ifdef SQLITE_DBSTATUS_STMT_USED
+{"SQLITE_DBSTATUS_STMT_USED", SQLITE_DBSTATUS_STMT_USED},
+#endif
+#ifdef SQLITE_STMTSTATUS_AUTOINDEX
+{"SQLITE_STMTSTATUS_AUTOINDEX", SQLITE_STMTSTATUS_AUTOINDEX},
+#endif
+#ifdef SQLITE_STMTSTATUS_FULLSCAN_STEP
+{"SQLITE_STMTSTATUS_FULLSCAN_STEP", SQLITE_STMTSTATUS_FULLSCAN_STEP},
+#endif
+#ifdef SQLITE_STMTSTATUS_SORT
+{"SQLITE_STMTSTATUS_SORT", SQLITE_STMTSTATUS_SORT},
+#endif
+#ifdef SQLITE_STMTSTATUS_VM_STEP
+{"SQLITE_STMTSTATUS_VM_STEP", SQLITE_STMTSTATUS_VM_STEP},
+#endif
+#ifdef SQLITE_CHECKPOINT_FULL
+{"SQLITE_CHECKPOINT_FULL", SQLITE_CHECKPOINT_FULL},
+#endif
+#ifdef SQLITE_CHECKPOINT_PASSIVE
+{"SQLITE_CHECKPOINT_PASSIVE", SQLITE_CHECKPOINT_PASSIVE},
+#endif
+#ifdef SQLITE_CHECKPOINT_RESTART
+{"SQLITE_CHECKPOINT_RESTART", SQLITE_CHECKPOINT_RESTART},
+#endif
+#ifdef SQLITE_CHECKPOINT_TRUNCATE
+{"SQLITE_CHECKPOINT_TRUNCATE", SQLITE_CHECKPOINT_TRUNCATE},
+#endif
+#ifdef SQLITE_VTAB_CONSTRAINT_SUPPORT
+{"SQLITE_VTAB_CONSTRAINT_SUPPORT", SQLITE_VTAB_CONSTRAINT_SUPPORT},
+#endif
+#ifdef SQLITE_FAIL
+{"SQLITE_FAIL", SQLITE_FAIL},
+#endif
+#ifdef SQLITE_REPLACE
+{"SQLITE_REPLACE", SQLITE_REPLACE},
+#endif
+#ifdef SQLITE_ROLLBACK
+{"SQLITE_ROLLBACK", SQLITE_ROLLBACK},
+#endif
+#ifdef SQLITE_SCANSTAT_EST
+{"SQLITE_SCANSTAT_EST", SQLITE_SCANSTAT_EST},
+#endif
+#ifdef SQLITE_SCANSTAT_EXPLAIN
+{"SQLITE_SCANSTAT_EXPLAIN", SQLITE_SCANSTAT_EXPLAIN},
+#endif
+#ifdef SQLITE_SCANSTAT_NAME
+{"SQLITE_SCANSTAT_NAME", SQLITE_SCANSTAT_NAME},
+#endif
+#ifdef SQLITE_SCANSTAT_NLOOP
+{"SQLITE_SCANSTAT_NLOOP", SQLITE_SCANSTAT_NLOOP},
+#endif
+#ifdef SQLITE_SCANSTAT_NVISIT
+{"SQLITE_SCANSTAT_NVISIT", SQLITE_SCANSTAT_NVISIT},
+#endif
+#ifdef SQLITE_SCANSTAT_SELECTID
+{"SQLITE_SCANSTAT_SELECTID", SQLITE_SCANSTAT_SELECTID},
+#endif
index 3408fc2..6e14d44 100644 (file)
@@ -1,6 +1,6 @@
 /* sqlitecompat.h - compatibility macros
  *
- * Copyright (C) 2006-2010 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2006-2015 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
index 9d08f2b..a253ade 100644 (file)
@@ -1,6 +1,6 @@
 /* statement.c - the statement type
  *
- * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2015 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
@@ -167,12 +167,14 @@ int pysqlite_statement_bind_parameter(pysqlite_Statement* self, int pos, PyObjec
             break;
         case TYPE_STRING:
             string = PyString_AS_STRING(parameter);
-            rc = sqlite3_bind_text(self->st, pos, string, -1, SQLITE_TRANSIENT);
+            buflen = PyString_Size(parameter);
+            rc = sqlite3_bind_text(self->st, pos, string, buflen, SQLITE_TRANSIENT);
             break;
         case TYPE_UNICODE:
             stringval = PyUnicode_AsUTF8String(parameter);
             string = PyString_AsString(stringval);
-            rc = sqlite3_bind_text(self->st, pos, string, -1, SQLITE_TRANSIENT);
+            buflen = PyString_Size(stringval);
+            rc = sqlite3_bind_text(self->st, pos, string, buflen, SQLITE_TRANSIENT);
             Py_DECREF(stringval);
             break;
         case TYPE_BUFFER:
@@ -185,9 +187,22 @@ int pysqlite_statement_bind_parameter(pysqlite_Statement* self, int pos, PyObjec
             break;
         case TYPE_UNKNOWN:
             rc = -1;
+            PyErr_Format(pysqlite_InterfaceError, "Parameter %d is of no supported type", pos);
     }
 
 final:
+    switch (rc) {
+        case SQLITE_TOOBIG:
+            PyErr_Format(pysqlite_DatabaseError, "Parameter %d is too big", pos);
+            break;
+        case SQLITE_RANGE:
+            PyErr_Format(pysqlite_DatabaseError, "Parameter index %d is out of range", pos);
+            break;
+        case SQLITE_NOMEM:
+            PyErr_Format(pysqlite_DatabaseError, "SQlite is out of memory for parameter %d", pos);
+            break;
+    }
+
     return rc;
 }
 
@@ -266,7 +281,7 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
 
             if (rc != SQLITE_OK) {
                 if (!PyErr_Occurred()) {
-                    PyErr_Format(pysqlite_InterfaceError, "Error binding parameter %d - probably unsupported type.", i);
+                    PyErr_Format(pysqlite_InterfaceError, "Unknown error binding parameter %d.", i);
                 }
                 return;
             }
@@ -311,7 +326,7 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
 
             if (rc != SQLITE_OK) {
                 if (!PyErr_Occurred()) {
-                    PyErr_Format(pysqlite_InterfaceError, "Error binding parameter :%s - probably unsupported type.", binding_name);
+                    PyErr_Format(pysqlite_InterfaceError, "Unknown error binding parameter %s.", binding_name);
                 }
                 return;
            }
index 05fd5ff..e109e28 100644 (file)
@@ -1,6 +1,6 @@
 /* statement.h - definitions for the statement type
  *
- * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2015 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
index 6b57b76..9456ea5 100644 (file)
@@ -1,6 +1,6 @@
 /* util.c - various utility functions
  *
- * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2015 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
index 4269003..ffe46fe 100644 (file)
@@ -1,6 +1,6 @@
 /* util.h - various utility functions
  *
- * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2015 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
diff --git a/test.sh b/test.sh
new file mode 100755 (executable)
index 0000000..070a25a
--- /dev/null
+++ b/test.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+python2.7 setup.py build
+(cd build/lib.linux-x86_64-2.7 && python2.7 -c "from pysqlite2 import test; test.test()" )
+
diff --git a/tox.ini b/tox.ini
new file mode 100644 (file)
index 0000000..90e3ee7
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,12 @@
+# Tox (http://tox.testrun.org/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+envlist = py27,py26
+
+[testenv]
+commands = {envpython} setup.py test
+deps =
+
diff --git a/update_sqlite_constants.py b/update_sqlite_constants.py
new file mode 100644 (file)
index 0000000..34b64a0
--- /dev/null
@@ -0,0 +1,19 @@
+import sqlite3
+
+import urllib
+
+FILENAME = "/tmp/toc.db"
+
+stream = urllib.urlopen("https://sqlite.org/toc.db")
+with open(FILENAME, "wb") as f:
+    f.write(stream.read())
+
+con = sqlite3.connect("/tmp/toc.db")
+cur = con.cursor()
+cur.execute("select name from toc where type='constant' and name not in ('SQLITE_SOURCE_ID', 'SQLITE_VERSION')")
+with open("src/sqlite_constants.h", "w") as out:
+    for row in cur:
+        constant = row[0]
+        out.write("#ifdef %s\n" % constant)
+        out.write('{"%s", %s},\n' % (constant, constant))
+        out.write("#endif\n")