Imported Upstream version 2.2.2 upstream/2.2.2
authorJoel Rosdahl <joel@debian.org>
Mon, 11 Jan 2010 20:37:32 +0000 (21:37 +0100)
committerJoel Rosdahl <joel@debian.org>
Mon, 11 Jan 2010 20:37:32 +0000 (21:37 +0100)
73 files changed:
LICENSE [new file with mode: 0644]
MANIFEST.in [new file with mode: 0644]
PKG-INFO [new file with mode: 0644]
doc/code/adapter_datetime.py [new file with mode: 0644]
doc/code/adapter_point_1.py [new file with mode: 0644]
doc/code/adapter_point_2.py [new file with mode: 0644]
doc/code/collation_reverse.py [new file with mode: 0644]
doc/code/complete_statement.py [new file with mode: 0644]
doc/code/connect_db_1.py [new file with mode: 0644]
doc/code/connect_db_2.py [new file with mode: 0644]
doc/code/converter_point.py [new file with mode: 0644]
doc/code/countcursors.py [new file with mode: 0644]
doc/code/createdb.py [new file with mode: 0644]
doc/code/execsql_fetchonerow.py [new file with mode: 0644]
doc/code/execsql_printall_1.py [new file with mode: 0644]
doc/code/execute_1.py [new file with mode: 0644]
doc/code/execute_2.py [new file with mode: 0644]
doc/code/execute_3.py [new file with mode: 0644]
doc/code/executemany_1.py [new file with mode: 0644]
doc/code/executemany_2.py [new file with mode: 0644]
doc/code/executescript.py [new file with mode: 0644]
doc/code/insert_more_people.py [new file with mode: 0644]
doc/code/md5func.py [new file with mode: 0644]
doc/code/mysumaggr.py [new file with mode: 0644]
doc/code/parse_colnames.py [new file with mode: 0644]
doc/code/pysqlite_datetime.py [new file with mode: 0644]
doc/code/row_factory.py [new file with mode: 0644]
doc/code/rowclass.py [new file with mode: 0644]
doc/code/shared_cache.py [new file with mode: 0644]
doc/code/shortcut_methods.py [new file with mode: 0644]
doc/code/simple_tableprinter.py [new file with mode: 0644]
doc/code/text_factory.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-win32.html [new file with mode: 0644]
doc/install-source-win32.txt [new file with mode: 0644]
doc/install-source.html [new file with mode: 0644]
doc/install-source.txt [new file with mode: 0644]
doc/silvercity.css [new file with mode: 0644]
doc/usage-guide.html [new file with mode: 0644]
doc/usage-guide.txt [new file with mode: 0644]
docutilsupport.py [new file with mode: 0644]
pysqlite2/__init__.py [new file with mode: 0644]
pysqlite2/dbapi2.py [new file with mode: 0644]
pysqlite2/test/__init__.py [new file with mode: 0644]
pysqlite2/test/dbapi.py [new file with mode: 0644]
pysqlite2/test/factory.py [new file with mode: 0644]
pysqlite2/test/hooks.py [new file with mode: 0644]
pysqlite2/test/regression.py [new file with mode: 0644]
pysqlite2/test/transactions.py [new file with mode: 0644]
pysqlite2/test/types.py [new file with mode: 0644]
pysqlite2/test/userfunctions.py [new file with mode: 0644]
setup.cfg [new file with mode: 0644]
setup.py [new file with mode: 0644]
src/cache.c [new file with mode: 0644]
src/cache.h [new file with mode: 0644]
src/compat.h [new file with mode: 0644]
src/connection.c [new file with mode: 0644]
src/connection.h [new file with mode: 0644]
src/cursor.c [new file with mode: 0644]
src/cursor.h [new file with mode: 0644]
src/microprotocols.c [new file with mode: 0644]
src/microprotocols.h [new file with mode: 0644]
src/module.c [new file with mode: 0644]
src/module.h [new file with mode: 0644]
src/prepare_protocol.c [new file with mode: 0644]
src/prepare_protocol.h [new file with mode: 0644]
src/row.c [new file with mode: 0644]
src/row.h [new file with mode: 0644]
src/statement.c [new file with mode: 0644]
src/statement.h [new file with mode: 0644]
src/util.c [new file with mode: 0644]
src/util.h [new file with mode: 0644]

diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..a5b9fd2
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2004 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
+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.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644 (file)
index 0000000..4a50054
--- /dev/null
@@ -0,0 +1,8 @@
+include MANIFEST.in
+include LICENSE
+include docutilsupport.py
+include src/*.h
+include doc/*.html
+include doc/*.txt
+include doc/*.css
+include doc/code/*.py
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644 (file)
index 0000000..272e496
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,25 @@
+Metadata-Version: 1.0
+Name: pysqlite
+Version: 2.2.2
+Summary: DB-API 2.0 interface for SQLite 3.x
+Home-page: http://pysqlite.org/
+Author: Gerhard Haering
+Author-email: gh@ghaering.de
+License: zlib/libpng license
+Download-URL: http://initd.org/tracker/pysqlite/wiki/PysqliteDownloads
+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/doc/code/adapter_datetime.py b/doc/code/adapter_datetime.py
new file mode 100644 (file)
index 0000000..bf91997
--- /dev/null
@@ -0,0 +1,14 @@
+from pysqlite2 import dbapi2 as sqlite\r
+import datetime, time\r
+\r
+def adapt_datetime(ts):\r
+    return time.mktime(ts.timetuple())\r
+\r
+sqlite.register_adapter(datetime.datetime, adapt_datetime)\r
+\r
+con = sqlite.connect(":memory:")\r
+cur = con.cursor()\r
+\r
+now = datetime.datetime.now()\r
+cur.execute("select ?", (now,))\r
+print cur.fetchone()[0]\r
diff --git a/doc/code/adapter_point_1.py b/doc/code/adapter_point_1.py
new file mode 100644 (file)
index 0000000..9731c44
--- /dev/null
@@ -0,0 +1,17 @@
+from pysqlite2 import dbapi2 as sqlite\r
+\r
+class Point(object):\r
+    def __init__(self, x, y):\r
+        self.x, self.y = x, y\r
+\r
+    def __conform__(self, protocol):\r
+        if protocol is sqlite.PrepareProtocol:\r
+            return "%f;%f" % (self.x, self.y)\r
+\r
+con = sqlite.connect(":memory:")\r
+cur = con.cursor()\r
+\r
+p = Point(4.0, -3.2)\r
+cur.execute("select ?", (p,))\r
+print cur.fetchone()[0]\r
+\r
diff --git a/doc/code/adapter_point_2.py b/doc/code/adapter_point_2.py
new file mode 100644 (file)
index 0000000..e170343
--- /dev/null
@@ -0,0 +1,18 @@
+from pysqlite2 import dbapi2 as sqlite\r
+\r
+class Point(object):\r
+    def __init__(self, x, y):\r
+        self.x, self.y = x, y\r
+\r
+def adapt_point(point):\r
+    return "%f;%f" % (point.x, point.y)\r
+\r
+sqlite.register_adapter(Point, adapt_point)\r
+\r
+con = sqlite.connect(":memory:")\r
+cur = con.cursor()\r
+\r
+p = Point(4.0, -3.2)\r
+cur.execute("select ?", (p,))\r
+print cur.fetchone()[0]\r
+\r
diff --git a/doc/code/collation_reverse.py b/doc/code/collation_reverse.py
new file mode 100644 (file)
index 0000000..40f7a5f
--- /dev/null
@@ -0,0 +1,15 @@
+from pysqlite2 import dbapi2 as sqlite\r
+\r
+def collate_reverse(string1, string2):\r
+    return -cmp(string1, string2)\r
+\r
+con = sqlite.connect(":memory:")\r
+con.create_collation("reverse", collate_reverse)\r
+\r
+cur = con.cursor()\r
+cur.execute("create table test(x)")\r
+cur.executemany("insert into test(x) values (?)", [("a",), ("b",)])\r
+cur.execute("select x from test order by x collate reverse")\r
+for row in cur:\r
+    print row\r
+con.close()\r
diff --git a/doc/code/complete_statement.py b/doc/code/complete_statement.py
new file mode 100644 (file)
index 0000000..3a5ef34
--- /dev/null
@@ -0,0 +1,30 @@
+# A minimal SQLite shell for experiments
+
+from pysqlite2 import dbapi2 as sqlite
+
+con = sqlite.connect(":memory:")
+con.isolation_level = None
+cur = con.cursor()
+
+buffer = ""
+
+print "Enter your SQL commands to execute in SQLite."
+print "Enter a blank line to exit."
+
+while True:
+    line = raw_input()
+    if line == "":
+        break
+    buffer += line
+    if sqlite.complete_statement(buffer):
+        try:
+            buffer = buffer.strip()
+            cur.execute(buffer)
+
+            if buffer.lstrip().upper().startswith("SELECT"):
+                print cur.fetchall()
+        except sqlite.Error, e:
+            print "An error occured:", e.args[0]
+        buffer = ""
+
+con.close()
diff --git a/doc/code/connect_db_1.py b/doc/code/connect_db_1.py
new file mode 100644 (file)
index 0000000..cf13825
--- /dev/null
@@ -0,0 +1,3 @@
+from pysqlite2 import dbapi2 as sqlite\r
+\r
+con = sqlite.connect("mydb")\r
diff --git a/doc/code/connect_db_2.py b/doc/code/connect_db_2.py
new file mode 100644 (file)
index 0000000..c9c853a
--- /dev/null
@@ -0,0 +1,3 @@
+from pysqlite2 import dbapi2 as sqlite\r
+\r
+con = sqlite.connect(":memory:")\r
diff --git a/doc/code/converter_point.py b/doc/code/converter_point.py
new file mode 100644 (file)
index 0000000..47467f4
--- /dev/null
@@ -0,0 +1,47 @@
+from pysqlite2 import dbapi2 as sqlite\r
+\r
+class Point(object):\r
+    def __init__(self, x, y):\r
+        self.x, self.y = x, y\r
+\r
+    def __repr__(self):\r
+        return "(%f;%f)" % (self.x, self.y)\r
+\r
+def adapt_point(point):\r
+    return "%f;%f" % (point.x, point.y)\r
+\r
+def convert_point(s):\r
+    x, y = map(float, s.split(";"))\r
+    return Point(x, y)\r
+\r
+# Register the adapter\r
+sqlite.register_adapter(Point, adapt_point)\r
+\r
+# Register the converter\r
+sqlite.register_converter("point", convert_point)\r
+\r
+p = Point(4.0, -3.2)\r
+\r
+#########################\r
+# 1) Using declared types\r
+con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES)\r
+cur = con.cursor()\r
+cur.execute("create table test(p point)")\r
+\r
+cur.execute("insert into test(p) values (?)", (p,))\r
+cur.execute("select p from test")\r
+print "with declared types:", cur.fetchone()[0]\r
+cur.close()\r
+con.close()\r
+\r
+#######################\r
+# 1) Using column names\r
+con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_COLNAMES)\r
+cur = con.cursor()\r
+cur.execute("create table test(p)")\r
+\r
+cur.execute("insert into test(p) values (?)", (p,))\r
+cur.execute('select p as "p [point]" from test')\r
+print "with column names:", cur.fetchone()[0]\r
+cur.close()\r
+con.close()\r
diff --git a/doc/code/countcursors.py b/doc/code/countcursors.py
new file mode 100644 (file)
index 0000000..e8f64d5
--- /dev/null
@@ -0,0 +1,15 @@
+from pysqlite2 import dbapi2 as sqlite\r
+\r
+class CountCursorsConnection(sqlite.Connection):\r
+    def __init__(self, *args, **kwargs):\r
+        sqlite.Connection.__init__(self, *args, **kwargs)\r
+        self.numcursors = 0\r
+\r
+    def cursor(self, *args, **kwargs):\r
+        self.numcursors += 1\r
+        return sqlite.Connection.cursor(self, *args, **kwargs)\r
+\r
+con = sqlite.connect(":memory:", factory=CountCursorsConnection)\r
+cur1 = con.cursor()\r
+cur2 = con.cursor()\r
+print con.numcursors\r
diff --git a/doc/code/createdb.py b/doc/code/createdb.py
new file mode 100644 (file)
index 0000000..59766b1
--- /dev/null
@@ -0,0 +1,28 @@
+# Not referenced from the documentation, but builds the database file the other\r
+# code snippets expect.\r
+\r
+from pysqlite2 import dbapi2 as sqlite\r
+import os\r
+\r
+DB_FILE = "mydb"\r
+\r
+if os.path.exists(DB_FILE):\r
+    os.remove(DB_FILE)\r
+\r
+con = sqlite.connect(DB_FILE)\r
+cur = con.cursor()\r
+cur.execute("""\r
+        create table people\r
+        (\r
+          name_last      varchar(20),\r
+          age            integer\r
+        )\r
+        """)\r
+\r
+cur.execute("insert into people (name_last, age) values ('Yeltsin',   72)")\r
+cur.execute("insert into people (name_last, age) values ('Putin',     51)")\r
+\r
+con.commit()\r
+\r
+cur.close()\r
+con.close()\r
diff --git a/doc/code/execsql_fetchonerow.py b/doc/code/execsql_fetchonerow.py
new file mode 100644 (file)
index 0000000..6a33067
--- /dev/null
@@ -0,0 +1,17 @@
+from pysqlite2 import dbapi2 as sqlite\r
+\r
+con = sqlite.connect("mydb")\r
+\r
+cur = con.cursor()\r
+SELECT = "select name_last, age from people order by age, name_last"\r
+\r
+# 1. Iterate over the rows available from the cursor, unpacking the\r
+# resulting sequences to yield their elements (name_last, age):\r
+cur.execute(SELECT)\r
+for (name_last, age) in cur:\r
+    print '%s is %d years old.' % (name_last, age)\r
+\r
+# 2. Equivalently:\r
+cur.execute(SELECT)\r
+for row in cur:\r
+    print '%s is %d years old.' % (row[0], row[1])\r
diff --git a/doc/code/execsql_printall_1.py b/doc/code/execsql_printall_1.py
new file mode 100644 (file)
index 0000000..436fc6d
--- /dev/null
@@ -0,0 +1,13 @@
+from pysqlite2 import dbapi2 as sqlite\r
+\r
+# Create a connection to the database file "mydb":\r
+con = sqlite.connect("mydb")\r
+\r
+# Get a Cursor object that operates in the context of Connection con:\r
+cur = con.cursor()\r
+\r
+# Execute the SELECT statement:\r
+cur.execute("select * from people order by age")\r
+\r
+# Retrieve all rows as a sequence and print that sequence:\r
+print cur.fetchall()\r
diff --git a/doc/code/execute_1.py b/doc/code/execute_1.py
new file mode 100644 (file)
index 0000000..b9799ce
--- /dev/null
@@ -0,0 +1,11 @@
+from pysqlite2 import dbapi2 as sqlite\r
+\r
+con = sqlite.connect("mydb")\r
+\r
+cur = con.cursor()\r
+\r
+who = "Yeltsin"\r
+age = 72\r
+\r
+cur.execute("select name_last, age from people where name_last=? and age=?", (who, age))\r
+print cur.fetchone()\r
diff --git a/doc/code/execute_2.py b/doc/code/execute_2.py
new file mode 100644 (file)
index 0000000..4dd0a67
--- /dev/null
@@ -0,0 +1,13 @@
+from pysqlite2 import dbapi2 as sqlite\r
+\r
+con = sqlite.connect("mydb")\r
+\r
+cur = con.cursor()\r
+\r
+who = "Yeltsin"\r
+age = 72\r
+\r
+cur.execute("select name_last, age from people where name_last=:who and age=:age",\r
+    {"who": who, "age": age})\r
+print cur.fetchone()\r
+\r
diff --git a/doc/code/execute_3.py b/doc/code/execute_3.py
new file mode 100644 (file)
index 0000000..46be8a9
--- /dev/null
@@ -0,0 +1,14 @@
+from pysqlite2 import dbapi2 as sqlite\r
+\r
+con = sqlite.connect("mydb")\r
+\r
+cur = con.cursor()\r
+\r
+who = "Yeltsin"\r
+age = 72\r
+\r
+cur.execute("select name_last, age from people where name_last=:who and age=:age",\r
+    locals())\r
+print cur.fetchone()\r
+\r
+\r
diff --git a/doc/code/executemany_1.py b/doc/code/executemany_1.py
new file mode 100644 (file)
index 0000000..3f0be35
--- /dev/null
@@ -0,0 +1,24 @@
+from pysqlite2 import dbapi2 as sqlite\r
+\r
+class IterChars:\r
+    def __init__(self):\r
+        self.count = ord('a')\r
+\r
+    def __iter__(self):\r
+        return self\r
+\r
+    def next(self):\r
+        if self.count > ord('z'):\r
+            raise StopIteration\r
+        self.count += 1\r
+        return (chr(self.count - 1),) # this is a 1-tuple\r
+\r
+con = sqlite.connect(":memory:")\r
+cur = con.cursor()\r
+cur.execute("create table characters(c)")\r
+\r
+theIter = IterChars()\r
+cur.executemany("insert into characters(c) values (?)", theIter)\r
+\r
+cur.execute("select c from characters")\r
+print cur.fetchall()\r
diff --git a/doc/code/executemany_2.py b/doc/code/executemany_2.py
new file mode 100644 (file)
index 0000000..49d4855
--- /dev/null
@@ -0,0 +1,15 @@
+from pysqlite2 import dbapi2 as sqlite\r
+\r
+def char_generator():\r
+    import string\r
+    for c in string.letters[:26]:\r
+        yield (c,)\r
+\r
+con = sqlite.connect(":memory:")\r
+cur = con.cursor()\r
+cur.execute("create table characters(c)")\r
+\r
+cur.executemany("insert into characters(c) values (?)", char_generator())\r
+\r
+cur.execute("select c from characters")\r
+print cur.fetchall()\r
diff --git a/doc/code/executescript.py b/doc/code/executescript.py
new file mode 100644 (file)
index 0000000..4ec04aa
--- /dev/null
@@ -0,0 +1,24 @@
+from pysqlite2 import dbapi2 as sqlite\r
+\r
+con = sqlite.connect(":memory:")\r
+cur = con.cursor()\r
+cur.executescript("""\r
+    create table person(\r
+        firstname,\r
+        lastname,\r
+        age\r
+    );\r
+\r
+    create table book(\r
+        title,\r
+        author,\r
+        published\r
+    );\r
+\r
+    insert into book(title, author, published)\r
+    values (\r
+        'Dirk Gently''s Holistic Detective Agency\r
+        'Douglas Adams',\r
+        1987\r
+    );\r
+    """)\r
diff --git a/doc/code/insert_more_people.py b/doc/code/insert_more_people.py
new file mode 100644 (file)
index 0000000..6d2ae77
--- /dev/null
@@ -0,0 +1,17 @@
+from pysqlite2 import dbapi2 as sqlite\r
+\r
+con = sqlite.connect("mydb")\r
+\r
+cur = con.cursor()\r
+\r
+newPeople = (\r
+    ('Lebed'       , 53),\r
+    ('Zhirinovsky' , 57),\r
+  )\r
+\r
+for person in newPeople:\r
+    cur.execute("insert into people (name_last, age) values (?, ?)", person)\r
+\r
+# The changes will not be saved unless the transaction is committed explicitly:\r
+con.commit()\r
+\r
diff --git a/doc/code/md5func.py b/doc/code/md5func.py
new file mode 100644 (file)
index 0000000..d0ebd02
--- /dev/null
@@ -0,0 +1,11 @@
+from pysqlite2 import dbapi2 as sqlite\r
+import md5\r
+\r
+def md5sum(t):\r
+    return md5.md5(t).hexdigest()\r
+\r
+con = sqlite.connect(":memory:")\r
+con.create_function("md5", 1, md5sum)\r
+cur = con.cursor()\r
+cur.execute("select md5(?)", ("foo",))\r
+print cur.fetchone()[0]\r
diff --git a/doc/code/mysumaggr.py b/doc/code/mysumaggr.py
new file mode 100644 (file)
index 0000000..46abdda
--- /dev/null
@@ -0,0 +1,20 @@
+from pysqlite2 import dbapi2 as sqlite\r
+\r
+class MySum:\r
+    def __init__(self):\r
+        self.count = 0\r
+\r
+    def step(self, value):\r
+        self.count += value\r
+\r
+    def finalize(self):\r
+        return self.count\r
+\r
+con = sqlite.connect(":memory:")\r
+con.create_aggregate("mysum", 1, MySum)\r
+cur = con.cursor()\r
+cur.execute("create table test(i)")\r
+cur.execute("insert into test(i) values (1)")\r
+cur.execute("insert into test(i) values (2)")\r
+cur.execute("select mysum(i) from test")\r
+print cur.fetchone()[0]\r
diff --git a/doc/code/parse_colnames.py b/doc/code/parse_colnames.py
new file mode 100644 (file)
index 0000000..eedd79e
--- /dev/null
@@ -0,0 +1,8 @@
+from pysqlite2 import dbapi2 as sqlite\r
+import datetime\r
+\r
+con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_COLNAMES)\r
+cur = con.cursor()\r
+cur.execute('select ? as "x [timestamp]"', (datetime.datetime.now(),))\r
+dt = cur.fetchone()[0]\r
+print dt, type(dt)\r
diff --git a/doc/code/pysqlite_datetime.py b/doc/code/pysqlite_datetime.py
new file mode 100644 (file)
index 0000000..b077856
--- /dev/null
@@ -0,0 +1,20 @@
+from pysqlite2 import dbapi2 as sqlite\r
+import datetime\r
+\r
+con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES|sqlite.PARSE_COLNAMES)\r
+cur = con.cursor()\r
+cur.execute("create table test(d date, ts timestamp)")\r
+\r
+today = datetime.date.today()\r
+now = datetime.datetime.now()\r
+\r
+cur.execute("insert into test(d, ts) values (?, ?)", (today, now))\r
+cur.execute("select d, ts from test")\r
+row = cur.fetchone()\r
+print today, "=>", row[0], type(row[0])\r
+print now, "=>", row[1], type(row[1])\r
+\r
+cur.execute('select current_date as "d [date]", current_timestamp as "ts [timestamp]"')\r
+row = cur.fetchone()\r
+print "current_date", row[0], type(row[0])\r
+print "current_timestamp", row[1], type(row[1])\r
diff --git a/doc/code/row_factory.py b/doc/code/row_factory.py
new file mode 100644 (file)
index 0000000..79fd5d3
--- /dev/null
@@ -0,0 +1,13 @@
+from pysqlite2 import dbapi2 as 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
+con = sqlite.connect(":memory:")\r
+con.row_factory = dict_factory\r
+cur = con.cursor()\r
+cur.execute("select 1 as a")\r
+print cur.fetchone()["a"]\r
diff --git a/doc/code/rowclass.py b/doc/code/rowclass.py
new file mode 100644 (file)
index 0000000..4d85f40
--- /dev/null
@@ -0,0 +1,12 @@
+from pysqlite2 import dbapi2 as sqlite
+
+con = sqlite.connect("mydb")
+con.row_factory = sqlite.Row
+
+cur = con.cursor()
+cur.execute("select name_last, age from people")
+for row in cur:
+    assert row[0] == row["name_last"]
+    assert row["name_last"] == row["nAmE_lAsT"]
+    assert row[1] == row["age"]
+    assert row[1] == row["AgE"]
diff --git a/doc/code/shared_cache.py b/doc/code/shared_cache.py
new file mode 100644 (file)
index 0000000..f6cde80
--- /dev/null
@@ -0,0 +1,6 @@
+from pysqlite2 import dbapi2 as sqlite
+
+# The shared cache is only available in SQLite versions 3.3.3 or later
+# See the SQLite documentaton for details.
+
+sqlite.enable_shared_cache(True)
diff --git a/doc/code/shortcut_methods.py b/doc/code/shortcut_methods.py
new file mode 100644 (file)
index 0000000..f3be82f
--- /dev/null
@@ -0,0 +1,22 @@
+from pysqlite2 import dbapi2 as sqlite
+
+persons = [
+    ("Hugo", "Boss"),
+    ("Calvin", "Klein")
+    ]
+
+con = sqlite.connect(":memory:")
+
+# Create the table
+con.execute("create table person(firstname, lastname)")
+
+# Fill the table
+con.executemany("insert into person(firstname, lastname) values (?, ?)", persons)
+
+# Print the table contents
+for row in con.execute("select firstname, lastname from person"):
+    print row
+
+# Using a dummy WHERE clause to not let SQLite take the shortcut table deletes.
+print "I just deleted", con.execute("delete from person where 1=1").rowcount, "rows"
+
diff --git a/doc/code/simple_tableprinter.py b/doc/code/simple_tableprinter.py
new file mode 100644 (file)
index 0000000..223cb11
--- /dev/null
@@ -0,0 +1,26 @@
+from pysqlite2 import dbapi2 as sqlite\r
+\r
+FIELD_MAX_WIDTH = 20\r
+TABLE_NAME = 'people'\r
+SELECT = 'select * from %s order by age, name_last' % TABLE_NAME\r
+\r
+con = sqlite.connect("mydb")\r
+\r
+cur = con.cursor()\r
+cur.execute(SELECT)\r
+\r
+# Print a header.\r
+for fieldDesc in cur.description:\r
+    print fieldDesc[0].ljust(FIELD_MAX_WIDTH) ,\r
+print # Finish the header with a newline.\r
+print '-' * 78\r
+\r
+# For each row, print the value of each field left-justified within\r
+# the maximum possible width of that field.\r
+fieldIndices = range(len(cur.description))\r
+for row in cur:\r
+    for fieldIndex in fieldIndices:\r
+        fieldValue = str(row[fieldIndex])\r
+        print fieldValue.ljust(FIELD_MAX_WIDTH) ,\r
+\r
+    print # Finish the row with a newline.\r
diff --git a/doc/code/text_factory.py b/doc/code/text_factory.py
new file mode 100644 (file)
index 0000000..0916e88
--- /dev/null
@@ -0,0 +1,43 @@
+from pysqlite2 import dbapi2 as sqlite
+
+con = sqlite.connect(":memory:")
+cur = con.cursor()
+
+# Create the table
+con.execute("create table person(lastname, firstname)")
+
+AUSTRIA = u"\xd6sterreich"
+
+# by default, rows are returned as Unicode
+cur.execute("select ?", (AUSTRIA,))
+row = cur.fetchone()
+assert row[0] == AUSTRIA
+
+# but we can make pysqlite always return bytestrings ...
+con.text_factory = str
+cur.execute("select ?", (AUSTRIA,))
+row = cur.fetchone()
+assert type(row[0]) == str
+# the bytestrings will be encoded in UTF-8, unless you stored garbage in the
+# database ...
+assert row[0] == AUSTRIA.encode("utf-8")
+
+# we can also implement a custom text_factory ...
+# here we implement one that will ignore Unicode characters that cannot be
+# decoded from UTF-8
+con.text_factory = lambda x: unicode(x, "utf-8", "ignore")
+cur.execute("select ?", ("this is latin1 and would normally create errors" + u"\xe4\xf6\xfc".encode("latin1"),))
+row = cur.fetchone()
+assert type(row[0]) == unicode
+
+# pysqlite offers a builtin optimized text_factory that will return bytestring
+# objects, if the data is in ASCII only, and otherwise return unicode objects
+con.text_factory = sqlite.OptimizedUnicode
+cur.execute("select ?", (AUSTRIA,))
+row = cur.fetchone()
+assert type(row[0]) == unicode
+
+cur.execute("select ?", ("Germany",))
+row = cur.fetchone()
+assert type(row[0]) == str
+
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-win32.html b/doc/install-source-win32.html
new file mode 100644 (file)
index 0000000..d3b4c3c
--- /dev/null
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.4: http://docutils.sourceforge.net/" />
+<title>pysqlite installation guide - installing from source on Windows</title>
+<style type="text/css">
+
+@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;
+}
+
+</style>
+</head>
+<body>
+<div class="document" id="pysqlite-installation-guide-installing-from-source-on-windows">
+<h1 class="title">pysqlite installation guide - installing from source on Windows</h1>
+<p>(c) 2005 Gerhard Häring</p>
+<p>Steps:</p>
+<blockquote>
+<ul class="simple">
+<li><a class="reference" href="#step-1-download-and-install-required-tools">Step 1: Download and install required tools</a></li>
+<li><a class="reference" href="#step-2-download-and-compile-sqlite">Step 2: Download and compile SQLite</a></li>
+<li><a class="reference" href="#step-3-compile-pysqlite">Step 3: Compile pysqlite</a></li>
+<li><a class="reference" href="#step-4-install-pysqlite-or-create-an-installer">Step 4: Install pysqlite or create an installer</a></li>
+<li><a class="reference" href="#step-5-test-your-pysqlite-installation">Step 5: Test your pysqlite installation</a></li>
+</ul>
+</blockquote>
+<div class="section">
+<h1><a id="step-1-download-and-install-required-tools" name="step-1-download-and-install-required-tools">Step 1: Download and install required tools</a></h1>
+<p>This guide explains how to build SQLite and pysqlite with free and commercial
+Microsoft compilers for Python 2.4 and later. Other compilers might work, too,
+and MINGW is known to work well for Python 2.3, but in order to keep this
+document to the point, only one obvious way to do it is documented.</p>
+<p>First we need to have a working compiler. These two work fine:</p>
+<blockquote>
+<ul class="simple">
+<li>Microsoft Visual Studio .NET 2003</li>
+<li>MS Toolkit Compiler (<a class="reference" href="http://www.vrplumber.com/programming/mstoolkit/">http://www.vrplumber.com/programming/mstoolkit/</a>)</li>
+</ul>
+</blockquote>
+<p>Then, we need GNU make. Download a Windows version from
+<a class="reference" href="http://mingw.sourceforge.net/download.shtml">http://mingw.sourceforge.net/download.shtml</a> and extract it.</p>
+<p>Make sure your PATH is set up correctly, so that the make.exe you just
+downloaded is in the PATH and that your compiler's environment is set up
+correctly. For MS Visual Studio .NET 2003, just execute
+Start/Programs/Microsoft Visual Studio .NET/Visual Studio .NET Tools/Visual
+Studio .NET 2003 Command Prompt. For the MS Toolkit Compiler write yourself a
+batch file that sets up the environment as neccessary.</p>
+</div>
+<div class="section">
+<h1><a id="step-2-download-and-compile-sqlite" name="step-2-download-and-compile-sqlite">Step 2: Download and compile SQLite</a></h1>
+<p>From now on, let's suppose you do all your development work in $SRCDIR.</p>
+<p>Now download the latest versions of the SQLite 3.x Windows sources from <a class="reference" href="http://sqlite.org/download.html">http://sqlite.org/download.html</a>.</p>
+<p>Pick the download that looks like this:</p>
+<p>sqlite-source-3_{major}_{minor}.zip</p>
+<p>Extract this file in $SRCDIR/sqlite</p>
+<p>Now copy this file into your $SRCDIR/sqlite directory:
+<a class="reference" href="http://initd.org/svn/pysqlite/pysqlite/trunk/misc/Makefile">http://initd.org/svn/pysqlite/pysqlite/trunk/misc/Makefile</a></p>
+<p>Then on a Windows command prompt, change into the $SRCDIR/sqlite directory and
+issue a &quot;make&quot;. This should build a statically linked SQLite library now:</p>
+<pre class="literal-block">
+Setting environment for using Microsoft Visual Studio .NET 2003 tools.
+(If you have another version of Visual Studio or Visual C++ installed and wish
+to use its tools from the command line, run vcvars32.bat for that version.)
+
+C:\Documents and Settings\Gerhard&gt;set path=c:\msys\1.0\bin;%PATH%
+
+C:\Documents and Settings\Gerhard&gt;d:
+
+D:\&gt;cd src\sqlite
+
+D:\src\sqlite&gt;make
+cl -c -O2 -Og -G7 -Foalter.o alter.c
+Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
+Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
+
+alter.c
+cl -c -O2 -Og -G7 -Foanalyze.o analyze.c
+Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
+Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
+
+[...]
+
+utf.c
+cl -c -O2 -Og -G7 -Folegacy.o legacy.c
+Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
+Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
+
+legacy.c
+link -LIB -OUT:sqlite3.lib alter.o analyze.o attach.o auth.o btree.o build.o cal
+lback.o complete.o date.o delete.o expr.o func.o hash.o insert.o main.o opcodes.
+o os_unix.o os_win.o pager.o parse.o pragma.o prepare.o printf.o random.o select
+.o table.o tokenize.o trigger.o update.o util.o vacuum.o vdbe.o vdbeapi.o vdbeau
+x.o vdbefifo.o vdbemem.o where.o utf.o legacy.o
+Microsoft (R) Library Manager Version 7.10.3077
+Copyright (C) Microsoft Corporation.  All rights reserved.
+
+done
+
+D:\src\sqlite&gt;
+</pre>
+</div>
+<div class="section">
+<h1><a id="step-3-compile-pysqlite" name="step-3-compile-pysqlite">Step 3: Compile pysqlite</a></h1>
+<p>Unpack the latest pysqlite sources in $SRCDIR/pysqlite</p>
+<p>Now change the include_dirs and library_dirs settings in <tt class="docutils literal"><span class="pre">setup.cfg</span></tt> like
+this:</p>
+<pre class="literal-block">
+[build_ext]
+define=
+include_dirs=../sqlite
+library_dirs=../sqlite
+libraries=sqlite3
+</pre>
+<p>Now open a command prompt, change to the directory where you decompressed the
+pysqlite source distribution, and type:</p>
+<pre class="literal-block">
+python setup.py build
+</pre>
+<p>If setup.py raises no errors and its output concludes with something like
+&quot;Creating library...&quot;, then you are ready to proceed to the next step.</p>
+<p>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).</p>
+</div>
+<div class="section">
+<h1><a id="step-4-install-pysqlite-or-create-an-installer" name="step-4-install-pysqlite-or-create-an-installer">Step 4: Install pysqlite or create an installer</a></h1>
+<p>To install pysqlite now, invoke:</p>
+<pre class="literal-block">
+python setup.py install
+</pre>
+<p>from the commandline. In order to create an installer executable, invoke:</p>
+<pre class="literal-block">
+python setup.py bdist_wininst
+</pre>
+<p>from the commandline.</p>
+</div>
+<div class="section">
+<h1><a id="step-5-test-your-pysqlite-installation" name="step-5-test-your-pysqlite-installation">Step 5: Test Your pysqlite Installation</a></h1>
+<p>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:</p>
+<pre class="literal-block">
+&gt;&gt;&gt; from pysqlite2 import test
+&gt;&gt;&gt; test.test()
+......................................................................
+......................................................................
+...........
+----------------------------------------------------------------------
+Ran 151 tests in 1.059s
+
+OK
+&gt;&gt;&gt;
+</pre>
+<p>If the test suite runs without any errors, you are finished.</p>
+<p>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 <a class="reference" href="http://initd.org/tracker/pysqlite">pysqlite bug tracker</a> or the <a class="reference" href="http://lists.initd.org/mailman/listinfo/pysqlite">pysqlite mailing
+list</a>.</p>
+</div>
+</div>
+</body>
+</html>
diff --git a/doc/install-source-win32.txt b/doc/install-source-win32.txt
new file mode 100644 (file)
index 0000000..ed9260b
--- /dev/null
@@ -0,0 +1,168 @@
+---------------------------------------------------------------
+pysqlite installation guide - installing from source on Windows
+---------------------------------------------------------------
+
+\(c\) 2005 Gerhard Häring
+
+Steps:
+
+  - `Step 1: Download and install required tools`_
+  - `Step 2: Download and compile SQLite`_
+  - `Step 3: Compile pysqlite`_
+  - `Step 4: Install pysqlite or create an installer`_
+  - `Step 5: Test your pysqlite installation`_
+
+Step 1: Download and install required tools
+===========================================
+
+This guide explains how to build SQLite and pysqlite with free and commercial
+Microsoft compilers for Python 2.4 and later. Other compilers might work, too,
+and MINGW is known to work well for Python 2.3, but in order to keep this
+document to the point, only one obvious way to do it is documented.
+
+First we need to have a working compiler. These two work fine:
+
+    * Microsoft Visual Studio .NET 2003
+    * MS Toolkit Compiler (http://www.vrplumber.com/programming/mstoolkit/)
+
+Then, we need GNU make. Download a Windows version from
+http://mingw.sourceforge.net/download.shtml and extract it.
+
+Make sure your PATH is set up correctly, so that the make.exe you just
+downloaded is in the PATH and that your compiler's environment is set up
+correctly. For MS Visual Studio .NET 2003, just execute
+Start/Programs/Microsoft Visual Studio .NET/Visual Studio .NET Tools/Visual
+Studio .NET 2003 Command Prompt. For the MS Toolkit Compiler write yourself a
+batch file that sets up the environment as neccessary.
+
+Step 2: Download and compile SQLite
+===================================
+
+From now on, let's suppose you do all your development work in $SRCDIR.
+
+Now download the latest versions of the SQLite 3.x Windows sources from http://sqlite.org/download.html.
+
+Pick the download that looks like this:
+
+sqlite-source-3_{major}_{minor}.zip
+
+Extract this file in $SRCDIR/sqlite
+
+Now copy this file into your $SRCDIR/sqlite directory:
+http://initd.org/svn/pysqlite/pysqlite/trunk/misc/Makefile
+
+Then on a Windows command prompt, change into the $SRCDIR/sqlite directory and
+issue a "make". This should build a statically linked SQLite library now::
+
+    Setting environment for using Microsoft Visual Studio .NET 2003 tools.
+    (If you have another version of Visual Studio or Visual C++ installed and wish
+    to use its tools from the command line, run vcvars32.bat for that version.)
+
+    C:\Documents and Settings\Gerhard>set path=c:\msys\1.0\bin;%PATH%
+
+    C:\Documents and Settings\Gerhard>d:
+
+    D:\>cd src\sqlite
+
+    D:\src\sqlite>make
+    cl -c -O2 -Og -G7 -Foalter.o alter.c
+    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
+    Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
+
+    alter.c
+    cl -c -O2 -Og -G7 -Foanalyze.o analyze.c
+    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
+    Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
+
+    [...]
+
+    utf.c
+    cl -c -O2 -Og -G7 -Folegacy.o legacy.c
+    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
+    Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
+
+    legacy.c
+    link -LIB -OUT:sqlite3.lib alter.o analyze.o attach.o auth.o btree.o build.o cal
+    lback.o complete.o date.o delete.o expr.o func.o hash.o insert.o main.o opcodes.
+    o os_unix.o os_win.o pager.o parse.o pragma.o prepare.o printf.o random.o select
+    .o table.o tokenize.o trigger.o update.o util.o vacuum.o vdbe.o vdbeapi.o vdbeau
+    x.o vdbefifo.o vdbemem.o where.o utf.o legacy.o
+    Microsoft (R) Library Manager Version 7.10.3077
+    Copyright (C) Microsoft Corporation.  All rights reserved.
+
+    done
+
+    D:\src\sqlite>
+
+
+Step 3: Compile pysqlite
+========================
+
+Unpack the latest pysqlite sources in $SRCDIR/pysqlite
+
+Now change the include_dirs and library_dirs settings in ``setup.cfg`` like
+this::
+
+    [build_ext]
+    define=
+    include_dirs=../sqlite
+    library_dirs=../sqlite
+    libraries=sqlite3
+
+Now open a command prompt, change to the directory where you decompressed the
+pysqlite source distribution, and type::
+
+  python setup.py build
+
+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 4: Install pysqlite or create an installer
+===============================================
+
+To install pysqlite now, invoke::
+
+    python setup.py install
+
+from the commandline. In order to create an installer executable, invoke::
+
+    python setup.py bdist_wininst
+
+from the commandline.
+
+Step 5: 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 151 tests in 1.059s
+
+    OK
+    >>>
+
+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/
+.. _pysqlite bug tracker: http://initd.org/tracker/pysqlite
+.. _pysqlite mailing list: http://lists.initd.org/mailman/listinfo/pysqlite
diff --git a/doc/install-source.html b/doc/install-source.html
new file mode 100644 (file)
index 0000000..36a9452
--- /dev/null
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.4: http://docutils.sourceforge.net/" />
+<title>pysqlite installation guide - source distribution</title>
+<style type="text/css">
+
+@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;
+}
+
+</style>
+</head>
+<body>
+<div class="document" id="pysqlite-installation-guide-source-distribution">
+<h1 class="title">pysqlite installation guide - source distribution</h1>
+<p>(c) 2005 Gerhard Häring</p>
+<dl class="docutils">
+<dt>Note: For Windows users, it is recommended that you use the win32 binary</dt>
+<dd>distribution of pysqlite!</dd>
+</dl>
+<p>Steps:</p>
+<blockquote>
+<ul class="simple">
+<li><a class="reference" href="#step-1-satisfy-the-dependencies">Step 1: Satisfy the dependencies</a></li>
+<li><a class="reference" href="#step-2-compile-pysqlite">Step 2: Compile pysqlite</a></li>
+<li><a class="reference" href="#step-3-install-pysqlite">Step 3: Install pysqlite</a></li>
+<li><a class="reference" href="#step-4-test-your-pysqlite-installation">Step 4: Test your pysqlite installation</a></li>
+</ul>
+</blockquote>
+<div class="section">
+<h1><a id="step-1-satisfy-the-dependencies" name="step-1-satisfy-the-dependencies">Step 1: Satisfy The Dependencies</a></h1>
+<p>pysqlite requires a valid combination of the dependencies in the list below.</p>
+<p>Detailed instructions on how to install each dependency are beyond the scope of
+this document; consult the dependency distributor for installation
+instructions.</p>
+<p>Dependencies:</p>
+<blockquote>
+<ol class="arabic simple">
+<li>Operating System and C Compiler - one of:<ul>
+<li>Linux/FreeBSD/NetBSD/OpenBSD and GCC</li>
+<li>Other POSIX-compliant operating system and a C compiler</li>
+</ul>
+</li>
+<li>SQLite:<ul>
+<li>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.</li>
+</ul>
+</li>
+<li>Python:<ul>
+<li>Python 2.3 or later</li>
+</ul>
+</li>
+</ol>
+</blockquote>
+</div>
+<div class="section">
+<h1><a id="step-2-compile-pysqlite" name="step-2-compile-pysqlite">Step 2: Compile pysqlite</a></h1>
+<p>Once you have successfully installed the dependencies, you may proceed with the
+installation of pysqlite itself.</p>
+<p>pysqlite has full support for the <a class="reference" href="http://www.python.org/sigs/distutils-sig/">distutils</a>, the standard facility for Python
+package distribution and installation. Full instructions for using the
+distutils are available in <a class="reference" href="http://www.python.org/doc/current/inst/inst.html">this section of the Python documentation</a>, but you
+can skip them unless you have an otherwise insoluble problem.</p>
+<p>Open a command prompt, change to the directory where you decompressed the
+pysqlite source distribution, and type:</p>
+<pre class="literal-block">
+python setup.py build
+</pre>
+<p>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.</p>
+<p>Otherwise you will have to customize the build process. That's what the file
+<em>setup.cfg</em> 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.</p>
+<p>After you've customized <em>setup.cfg</em> apprporiately, try invoking <tt class="docutils literal"><span class="pre">python</span>
+<span class="pre">setup.py</span> <span class="pre">build</span></tt> again.</p>
+<p>If setup.py raises no errors and its output concludes with something like
+&quot;Creating library...&quot;, then you are ready to proceed to the next step.</p>
+<p>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).</p>
+</div>
+<div class="section">
+<h1><a id="step-3-install-pysqlite" name="step-3-install-pysqlite">Step 3: Install pysqlite</a></h1>
+<p>During this step, the setup script moves the <em>pysqlite2</em> 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.</p>
+<p>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.</p>
+<p>Run the following command:</p>
+<pre class="literal-block">
+python setup.py install
+</pre>
+<p>The setup script will install pysqlite, listing each file it installs.</p>
+<p>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:</p>
+<ul class="simple">
+<li>Log in as a user who has the required file system permissions and repeat the
+installation step.</li>
+<li>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.</li>
+</ul>
+</div>
+<div class="section">
+<h1><a id="step-4-test-your-pysqlite-installation" name="step-4-test-your-pysqlite-installation">Step 4: Test Your pysqlite Installation</a></h1>
+<p>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:</p>
+<pre class="literal-block">
+&gt;&gt;&gt; from pysqlite2 import test
+&gt;&gt;&gt; test.test()
+.....................................................................................................
+----------------------------------------------------------------------
+Ran 101 tests in 0.182s
+</pre>
+<p>If the test suite runs without any errors, you are finished.</p>
+<p>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 <a class="reference" href="http://initd.org/tracker/pysqlite">pysqlite bug tracker</a> or the <a class="reference" href="http://lists.initd.org/mailman/listinfo/pysqlite">pysqlite mailing
+list</a>.</p>
+</div>
+</div>
+</body>
+</html>
diff --git a/doc/install-source.txt b/doc/install-source.txt
new file mode 100644 (file)
index 0000000..090209c
--- /dev/null
@@ -0,0 +1,147 @@
+-------------------------------------------------
+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* apprporiately, 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://initd.org/tracker/pysqlite
+.. _pysqlite mailing list: http://lists.initd.org/mailman/listinfo/pysqlite
diff --git a/doc/silvercity.css b/doc/silvercity.css
new file mode 100644 (file)
index 0000000..aa54711
--- /dev/null
@@ -0,0 +1,542 @@
+\r
+.code_default\r
+{\r
+    FONT-FAMILY: "Courier New", Courier, monospace;\r
+    FONT-SIZE: 10pt;\r
+}\r
+\r
+.css_class\r
+{\r
+    color: #900000;\r
+}\r
+\r
+.css_comment\r
+{\r
+       color: green;\r
+       font-style: italic;\r
+}\r
+\r
+.css_default\r
+{\r
+}\r
+\r
+.css_directive\r
+{\r
+    color: #009000;\r
+       font-weight: bold;\r
+}\r
+\r
+.css_doublestring\r
+{\r
+       color: navy;\r
+}\r
+\r
+.css_id\r
+{\r
+    color: #900000;\r
+}\r
+\r
+.css_identifier\r
+{\r
+       color: black;\r
+}\r
+\r
+.css_important\r
+{\r
+       color: blue;\r
+}\r
+\r
+.css_operator\r
+{\r
+    color: #000090;\r
+       font-weight: bold;\r
+}\r
+\r
+.css_pseudoclass\r
+{\r
+    color: #900000;\r
+}\r
+\r
+.css_singlestring\r
+{\r
+       color: navy;\r
+}\r
+\r
+.css_tag\r
+{\r
+    color: #900000;\r
+       font-weight: bold;\r
+}\r
+\r
+.css_unknown_identifier\r
+{\r
+       color: red;\r
+}\r
+\r
+.css_unknown_pseudoclass\r
+{\r
+    color: #ff0000;\r
+}\r
+\r
+.css_value\r
+{\r
+       color: navy;\r
+}\r
+\r
+.c_character\r
+{\r
+       color: olive;\r
+}\r
+\r
+.c_comment\r
+{\r
+       color: green;\r
+       font-style: italic;\r
+}\r
+\r
+.c_commentdoc\r
+{\r
+       color: green;\r
+       font-style: italic;\r
+}\r
+\r
+.c_commentdockeyword\r
+{\r
+       color: navy;\r
+       font-weight: bold;\r
+}\r
+\r
+.c_commentdockeyworderror\r
+{\r
+       color: red;\r
+       font-weight: bold;\r
+}\r
+\r
+.c_commentline\r
+{\r
+       color: green;\r
+       font-style: italic;\r
+}\r
+\r
+.c_commentlinedoc\r
+{\r
+       color: green;\r
+       font-style: italic;\r
+}\r
+\r
+.c_default\r
+{\r
+}\r
+\r
+.c_identifier\r
+{\r
+       color: black;\r
+}\r
+\r
+.c_number\r
+{\r
+    color: #009999;\r
+}\r
+\r
+.c_operator\r
+{\r
+       color: black;\r
+}\r
+\r
+.c_preprocessor\r
+{\r
+       color: navy;\r
+       font-weight: bold;\r
+}\r
+\r
+.c_regex\r
+{\r
+       color: olive;\r
+}\r
+\r
+.c_string\r
+{\r
+       color: olive;\r
+}\r
+\r
+.c_stringeol\r
+{\r
+       color: olive;\r
+}\r
+\r
+.c_uuid\r
+{\r
+       color: olive;\r
+}\r
+\r
+.c_verbatim\r
+{\r
+       color: olive;\r
+}\r
+\r
+.c_word\r
+{\r
+       color: navy;\r
+       font-weight: bold;\r
+}\r
+\r
+.c_word2\r
+{\r
+       color: navy;\r
+       font-weight: bold;\r
+}\r
+\r
+.h_asp\r
+{\r
+    color: #ffff00;\r
+}\r
+\r
+.h_aspat\r
+{\r
+    color: #ffdf00;\r
+}\r
+\r
+.h_attribute\r
+{\r
+    color: #008080;\r
+}\r
+\r
+.h_attributeunknown\r
+{\r
+    color: #ff0000;\r
+}\r
+\r
+.h_cdata\r
+{\r
+    color: #ffdf00;\r
+}\r
+\r
+.h_comment\r
+{\r
+    color: #808000;\r
+}\r
+\r
+.h_default\r
+{\r
+}\r
+\r
+.h_doublestring\r
+{\r
+       color: olive;\r
+}\r
+\r
+.h_entity\r
+{\r
+    color: #800080;\r
+}\r
+\r
+.h_number\r
+{\r
+    color: #009999;\r
+}\r
+\r
+.h_other\r
+{\r
+    color: #800080;\r
+}\r
+\r
+.h_script\r
+{\r
+    color: #000080;\r
+}\r
+\r
+.h_singlestring\r
+{\r
+       color: olive;\r
+}\r
+\r
+.h_tag\r
+{\r
+    color: #000080;\r
+}\r
+\r
+.h_tagend\r
+{\r
+    color: #000080;\r
+}\r
+\r
+.h_tagunknown\r
+{\r
+    color: #ff0000;\r
+}\r
+\r
+.h_xmlend\r
+{\r
+    color: #0000ff;\r
+}\r
+\r
+.h_xmlstart\r
+{\r
+    color: #0000ff;\r
+}\r
+\r
+.pl_array\r
+{\r
+       color: black;\r
+}\r
+\r
+.pl_backticks\r
+{\r
+       color: olive;\r
+}\r
+\r
+.pl_character\r
+{\r
+       color: olive;\r
+}\r
+\r
+.pl_commentline\r
+{\r
+       color: green;\r
+       font-style: italic;\r
+}\r
+\r
+.pl_datasection\r
+{\r
+       color: olive;\r
+}\r
+\r
+.pl_default\r
+{\r
+}\r
+\r
+.pl_error\r
+{\r
+       color: red;\r
+       font-style: bold;\r
+}\r
+\r
+.pl_hash\r
+{\r
+       color: black;\r
+}\r
+\r
+.pl_here_delim\r
+{\r
+       color: olive;\r
+}\r
+\r
+.pl_here_q\r
+{\r
+       color: olive;\r
+}\r
+\r
+.pl_here_qq\r
+{\r
+       color: olive;\r
+}\r
+\r
+.pl_here_qx\r
+{\r
+       color: olive;\r
+}\r
+\r
+.pl_identifier\r
+{\r
+       color: black;\r
+}\r
+\r
+.pl_longquote\r
+{\r
+       color: olive;\r
+}\r
+\r
+.pl_number\r
+{\r
+    color: #009999;\r
+}\r
+\r
+.pl_operator\r
+{\r
+       color: black;\r
+}\r
+\r
+.pl_pod\r
+{\r
+       color: black;\r
+       font-style: italic;\r
+}\r
+\r
+.pl_preprocessor\r
+{\r
+       color: navy;\r
+       font-weight: bold;\r
+}\r
+\r
+.pl_punctuation\r
+{\r
+       color: black;\r
+}\r
+\r
+.pl_regex\r
+{\r
+       color: olive;\r
+}\r
+\r
+.pl_regsubst\r
+{\r
+       color: olive;\r
+}\r
+\r
+.pl_scalar\r
+{\r
+       color: black;\r
+}\r
+\r
+.pl_string\r
+{\r
+       color: olive;\r
+}\r
+\r
+.pl_string_q\r
+{\r
+       color: olive;\r
+}\r
+\r
+.pl_string_qq\r
+{\r
+       color: olive;\r
+}\r
+\r
+.pl_string_qr\r
+{\r
+       color: olive;\r
+}\r
+\r
+.pl_string_qw\r
+{\r
+       color: olive;\r
+}\r
+\r
+.pl_string_qx\r
+{\r
+       color: olive;\r
+}\r
+\r
+.pl_symboltable\r
+{\r
+       color: black;\r
+}\r
+\r
+.pl_word\r
+{\r
+       color: navy;\r
+       font-weight: bold;\r
+}\r
+\r
+.p_character\r
+{\r
+       color: olive;\r
+}\r
+\r
+.p_classname\r
+{\r
+       color: blue;\r
+       font-weight: bold;\r
+}\r
+\r
+.p_commentblock\r
+{\r
+       color: gray;\r
+       font-style: italic;\r
+}\r
+\r
+.p_commentline\r
+{\r
+       color: green;\r
+       font-style: italic;\r
+}\r
+\r
+.p_default\r
+{\r
+}\r
+\r
+.p_defname\r
+{\r
+    color: #009999;\r
+       font-weight: bold;\r
+}\r
+\r
+.p_identifier\r
+{\r
+       color: black;\r
+}\r
+\r
+.p_number\r
+{\r
+    color: #009999;\r
+}\r
+\r
+.p_operator\r
+{\r
+       color: black;\r
+}\r
+\r
+.p_string\r
+{\r
+       color: olive;\r
+}\r
+\r
+.p_stringeol\r
+{\r
+       color: olive;\r
+}\r
+\r
+.p_triple\r
+{\r
+       color: olive;\r
+}\r
+\r
+.p_tripledouble\r
+{\r
+       color: olive;\r
+}\r
+\r
+.p_word\r
+{\r
+       color: navy;\r
+       font-weight: bold;\r
+}\r
+\r
+.yaml_comment\r
+{\r
+    color: #008800;\r
+       font-style: italic;\r
+}\r
+\r
+.yaml_default\r
+{\r
+}\r
+\r
+.yaml_document\r
+{\r
+    color: #808080;\r
+       font-style: italic;\r
+}\r
+\r
+.yaml_identifier\r
+{\r
+       color: navy;\r
+       font-weight: bold;\r
+}\r
+\r
+.yaml_keyword\r
+{\r
+    color: #880088;\r
+}\r
+\r
+.yaml_number\r
+{\r
+    color: #880000;\r
+}\r
+\r
+.yaml_reference\r
+{\r
+    color: #008888;\r
+}\r
+\r
diff --git a/doc/usage-guide.html b/doc/usage-guide.html
new file mode 100644 (file)
index 0000000..8ca7ba0
--- /dev/null
@@ -0,0 +1,1328 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.4: http://docutils.sourceforge.net/" />
+<title>pysqlite usage guide</title>
+<style type="text/css">
+
+@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;
+}
+
+</style>
+</head>
+<body>
+<div class="document" id="pysqlite-usage-guide">
+<h1 class="title">pysqlite usage guide</h1>
+<div class="line-block">
+<div class="line">(c) 2004-2005 David Rushby</div>
+<div class="line">(c) 2005-2006 Gerhard Häring</div>
+</div>
+<p>Last updated for pysqlite 2.2.1</p>
+<div class="section">
+<h1><a id="table-of-contents" name="table-of-contents">Table Of Contents</a></h1>
+<div class="line-block">
+<div class="line"><a class="reference" href="#introduction">0. Introduction</a></div>
+<div class="line"><a class="reference" href="#python-database-api-2-0-compliance">1. Python Database API 2.0 Compliance</a></div>
+<div class="line-block">
+<div class="line"><a class="reference" href="#incompatibilities">1.1 Incompatibilities</a></div>
+<div class="line"><a class="reference" href="#unsupported-optional-features">1.2 Unsupported Optional Features</a></div>
+<div class="line"><a class="reference" href="#nominally-supported-optional-features">1.3 Nominally Supported Optional Features</a></div>
+<div class="line"><a class="reference" href="#extensions-and-caveats">1.4 Extensions and Caveats</a></div>
+</div>
+<div class="line"><a class="reference" href="#brief-tutorial">2. Brief Tutorial</a></div>
+<div class="line-block">
+<div class="line"><a class="reference" href="#connecting-to-a-database">2.1 Connecting to a Database</a></div>
+<div class="line"><a class="reference" href="#executing-sql-statements">2.2 Executing SQL statements</a></div>
+</div>
+<div class="line"><a class="reference" href="#native-database-engine-features-and-extensions-beyond-the-python-db-api">3. Native Database Engine Features and Extensions Beyond the Python DB API</a></div>
+<div class="line-block">
+<div class="line"><a class="reference" href="#creating-user-defined-functions">3.1 Creating user-defined functions</a></div>
+<div class="line"><a class="reference" href="#creating-user-defined-aggregates">3.2 Creating user-defined aggregates</a></div>
+<div class="line"><a class="reference" href="#creating-and-using-collations">3.3 Creating and using collations</a></div>
+<div class="line"><a class="reference" href="#checking-for-complete-statements">3.4 Checking for complete statements</a></div>
+<div class="line"><a class="reference" href="#enabling-sqlite-s-shared-cache">3.5 Enabling SQLite's shared cache</a></div>
+</div>
+<div class="line"><a class="reference" href="#sqlite-and-python-types">4. SQLite and Python types</a></div>
+<div class="line-block">
+<div class="line"><a class="reference" href="#id1">4.1 Introduction</a></div>
+<div class="line"><a class="reference" href="#using-adapters-to-store-additional-python-types-in-sqlite-databases">4.2 Using adapters to store additional Python types in SQLite databases</a></div>
+<div class="line-block">
+<div class="line"><a class="reference" href="#letting-your-object-adapt-itself">4.2.1 Letting your object adapt itself</a></div>
+<div class="line"><a class="reference" href="#registering-an-adapter-callable">4.2.2 Registering an adapter callable</a></div>
+</div>
+<div class="line"><a class="reference" href="#converting-sqlite-values-to-custom-python-types">4.3 Converting SQLite values to custom Python types</a></div>
+<div class="line"><a class="reference" href="#default-pysqlite-adapters-and-converters">4.4 Default pysqlite adapters and converters</a></div>
+</div>
+<div class="line"><a class="reference" href="#controlling-transactions">5. Controlling Transactions</a></div>
+<div class="line"><a class="reference" href="#using-pysqlite-efficiently">6. Using pysqlite efficiently</a></div>
+<div class="line-block">
+<div class="line"><a class="reference" href="#using-shortcut-methods">6.1 Using shortcut methods</a></div>
+<div class="line"><a class="reference" href="#accessing-columns-by-name-instead-of-by-index">6.2 Accessing columns by name instead of by index</a></div>
+</div>
+</div>
+</div>
+<div class="section">
+<h1><a id="introduction" name="introduction">0. Introduction</a></h1>
+<p>This Usage Guide is not a tutorial on Python, SQL, or SQLite; rather, it is a
+topical presentation of pysqlite's feature set, with example code to
+demonstrate basic usage patterns. This guide is meant to be consumed in
+conjunction with the Python Database API Specification and the SQLite
+documentation.</p>
+<p>It was originally written by David Rushby for kinterbasdb. He kindly gave the
+permission to adapt it for pysqlite.</p>
+</div>
+<div class="section">
+<h1><a id="python-database-api-2-0-compliance" name="python-database-api-2-0-compliance">1. Python Database API 2.0 Compliance</a></h1>
+<div class="section">
+<h2><a id="incompatibilities" name="incompatibilities">1.1 Incompatibilities</a></h2>
+<ul>
+<li><p class="first">No type information in cursor.description</p>
+<p><em>cursor.description</em> has a tuple with the fields (<em>name</em>, <em>type_code</em>,
+<em>display_size</em>, <em>internal_size</em>, <em>precision</em>, <em>scale</em>, <em>null_ok</em>) for each
+column that a query returns. The DB-API spec requires that at least <em>name</em>
+and <em>type_code</em> are filled, but at the time cursor.description is built,
+pysqlite cannot determine any types, yet. So, the only field of
+<em>cursor.description</em> that pysqlite fills is <em>name</em>. All other fields are set to
+None.</p>
+</li>
+<li><p class="first">No type objects</p>
+<p>Consequently, there are also no type objects STRING, BINARY, NUMBER,
+DATETIME, ROWID at module-level. They would be useless.</p>
+</li>
+</ul>
+</div>
+<div class="section">
+<h2><a id="unsupported-optional-features" name="unsupported-optional-features">1.2 Unsupported Optional Features</a></h2>
+<ul>
+<li><p class="first"><strong>Cursor</strong> class</p>
+<ul>
+<li><p class="first"><strong>nextset</strong> method</p>
+<p>This method is not implemented because the database engine does not
+support opening multiple result sets simultaneously with a single
+cursor.</p>
+</li>
+</ul>
+</li>
+</ul>
+</div>
+<div class="section">
+<h2><a id="nominally-supported-optional-features" name="nominally-supported-optional-features">1.3 Nominally Supported Optional Features</a></h2>
+<ul>
+<li><p class="first"><strong>Cursor</strong> class</p>
+<ul>
+<li><p class="first"><strong>arraysize</strong> attribute</p>
+<p>As required by the spec, the value of this attribute is observed
+with respect to the fetchmany method. However, changing the value
+of this attribute does not make any difference in fetch efficiency
+because the database engine only supports fetching a single row at
+a time.</p>
+</li>
+<li><p class="first"><strong>setinputsizes</strong> method</p>
+<p>Although this method is present, it does nothing, as allowed by the
+spec.</p>
+</li>
+<li><p class="first"><strong>setoutputsize</strong> method</p>
+<p>Although this method is present, it does nothing, as allowed by the
+spec.</p>
+</li>
+</ul>
+</li>
+</ul>
+</div>
+<div class="section">
+<h2><a id="extensions-and-caveats" name="extensions-and-caveats">1.4 Extensions and Caveats</a></h2>
+<p>pysqlite offers a large feature set beyond the minimal requirements of the
+Python DB API. Most of these extensions are documented in the section of this
+document entitled Native Database Engine Features and Extensions Beyond the
+Python DB API.</p>
+<ul>
+<li><p class="first"><strong>connect</strong> function</p>
+<p>The parameter <em>database</em> refers to the database file for the SQLite
+database. It's a normal filesystem path and you can use absolute or
+relative path names.</p>
+<p>The connect function supports the following optional keyword arguments
+in addition to those required by the spec:</p>
+<ul>
+<li><p class="first"><strong>timeout</strong> - When a database is accessed by multiple connections, and</p>
+<p>one of the processes modifies the database, the SQLite database is
+locked until that transaction is committed. The timeout parameter
+specifies how long the connection should wait for the lock to go away
+until raising an exception. The default for the timeout parameter is
+5.0 (five seconds).</p>
+<dl class="docutils">
+<dt>Example:</dt>
+<dd><div class="first last"><div class="code-block">
+<span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_identifier">database</span><span class="p_operator">=</span><span class="p_string">"mydb"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">timeout</span><span class="p_operator">=</span><span class="p_number">10.0</span><span class="p_operator">)</span>
+</div>
+</div></dd>
+</dl>
+</li>
+<li><p class="first"><strong>isolation_level</strong> - pysqlite will by default open transactions with a
+&quot;BEGIN&quot; statement, when it encounters a DML statement like
+INSERT/UPDATE/DELETE/REPLACE. Some users don't want pysqlite to implicitly
+open transactions for them - they want an autocommit mode. Other users want
+pysqlite to open different kinds of transactions, like with &quot;BEGIN
+IMMEDIATE&quot;. See <a class="reference" href="#controlling-transactions">5. Controlling Transactions</a>  for a more detailed
+explanation.</p>
+<p>Note that you can also switch to a different isolation level by setting the
+<strong>isolation_level</strong> property of connections.</p>
+<dl class="docutils">
+<dt>Example:</dt>
+<dd><div class="first last"><div class="code-block">
+<span class="p_commentline">#&nbsp;Turn&nbsp;on&nbsp;autocommit&nbsp;mode</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">"mydb"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">isolation_level</span><span class="p_operator">=</span><span class="p_word">None</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;Set&nbsp;isolation_level&nbsp;to&nbsp;"IMMEDIATE"</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">isolation_level</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_string">"IMMEDIATE"</span>
+</div>
+</div></dd>
+</dl>
+</li>
+<li><p class="first"><strong>detect_types</strong> - SQLite natively supports only the types TEXT,
+INTEGER, FLOAT, BLOB and NULL. If you want to use other types, like you
+have to add support for them yourself.  The <em>detect_types</em> parameter and
+using custom <em>converters</em> registered with the module-level
+<em>register_converter</em> function allow you to easily do that.</p>
+<p><em>detect_types</em> defaults to 0 (i. e. off, no type detection), you can
+set it to any combination of <em>PARSE_DECLTYPES</em> and <em>PARSE_COLNAMES</em> to turn
+type detection on.</p>
+<p>Consult the section <a class="reference" href="#sqlite-and-python-types">4. SQLite and Python types</a> of this manual for
+details.</p>
+<ul>
+<li><p class="first"><strong>sqlite.PARSE_DECLTYPES</strong> - This makes pysqlite parse the declared
+type for each column it returns. It will parse out the first word of the
+declared type, i. e. for &quot;integer primary key&quot;, it will parse out
+&quot;integer&quot;. Then for that column, it will look into pysqlite's converters
+dictionary and use the converter function registered for that type there.
+Converter names are case-sensitive!</p>
+</li>
+<li><p class="first"><strong>sqlite.PARSE_COLNAMES</strong> - This makes pysqlite parse the column name
+for each column it returns. It will look for a string formed
+[mytype] in there, and then decide that 'mytype' is the type of
+the column. It will try to find an entry of 'mytype' in the
+converters dictionary and then use the converter function found
+there to return the value. The column name found in
+cursor.description is only the first word of the column name, i.
+e. if you use something like 'as &quot;x [datetime]&quot;' in your SQL,
+then pysqlite will parse out everything until the first blank for
+the column name: the column name would simply be &quot;x&quot;.</p>
+<p>The following example uses the column name <em>timestamp</em>, which is already
+registered by default in the converters dictionary with an appropriate
+converter! Note that converter names are case-sensitive!</p>
+<p>Example:</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">datetime</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">detect_types</span><span class="p_operator">=</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">PARSE_COLNAMES</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_character">'select&nbsp;?&nbsp;as&nbsp;"x&nbsp;[timestamp]"'</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">datetime</span><span class="p_operator">.</span><span class="p_identifier">datetime</span><span class="p_operator">.</span><span class="p_identifier">now</span><span class="p_operator">(),))</span><span class="p_default"><br/>
+</span><span class="p_identifier">dt</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()[</span><span class="p_number">0</span><span class="p_operator">]</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">dt</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">type</span><span class="p_operator">(</span><span class="p_identifier">dt</span><span class="p_operator">)</span>
+</div>
+</li>
+</ul>
+</li>
+<li><p class="first"><strong>check_same_thread</strong> - SQLite connections/cursors can only safely be
+used in the same thread they were created in. pysqlite checks for
+this each time it would do a call to the SQLite engine. If you are
+confident that you are ensuring safety otherwise, you can disable
+that checks by setting check_same_thread to False.</p>
+</li>
+<li><p class="first"><strong>factory</strong> - By default, pysqlite uses the Connection class for the
+connect call. You can, however, subclass the Connection class and
+make .connect() use your class instead by providing your class for
+the factory parameter.</p>
+<p>Example:</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">class</span><span class="p_default">&nbsp;</span><span class="p_classname">CountCursorsConnection</span><span class="p_operator">(</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">Connection</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">__init__</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">*</span><span class="p_identifier">args</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">**</span><span class="p_identifier">kwargs</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">Connection</span><span class="p_operator">.</span><span class="p_identifier">__init__</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">*</span><span class="p_identifier">args</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">**</span><span class="p_identifier">kwargs</span><span class="p_operator">)</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">numcursors</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_number">0</span><span class="p_default"><br/>
+<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">cursor</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">*</span><span class="p_identifier">args</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">**</span><span class="p_identifier">kwargs</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">numcursors</span><span class="p_default">&nbsp;</span><span class="p_operator">+=</span><span class="p_default">&nbsp;</span><span class="p_number">1</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">return</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">Connection</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">*</span><span class="p_identifier">args</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">**</span><span class="p_identifier">kwargs</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">factory</span><span class="p_operator">=</span><span class="p_identifier">CountCursorsConnection</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur1</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur2</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">numcursors</span>
+</div>
+</li>
+<li><p class="first"><strong>cached_statements</strong> - pysqlite internally uses a statement cache to avoid
+SQL parsing overhead. If you want to explicitly set the number of
+statements that are cached for the connection, you can set this parameter.
+The currently implemented default is to cache 100 statements.</p>
+</li>
+</ul>
+<div class="line-block">
+<div class="line"><br /></div>
+<div class="line"><br /></div>
+</div>
+</li>
+<li><p class="first"><strong>register_converter</strong> function - <tt class="docutils literal"><span class="pre">register_converter(typename,</span> <span class="pre">callable)</span></tt>
+registers a callable to convert a bytestring from the database into a custom
+Python type. The converter will be invoked for all database values that are
+of the type <tt class="docutils literal"><span class="pre">typename</span></tt>. Confer the parameter <strong>detect_types</strong> of the
+<strong>connect</strong> method for how the type detection works. Note that the case
+<tt class="docutils literal"><span class="pre">typename</span></tt> and the name of the type in your query must match!</p>
+</li>
+<li><p class="first"><strong>register_adapter</strong> function - <tt class="docutils literal"><span class="pre">register_adapter(type,</span> <span class="pre">callable)</span></tt>
+registers a callable to convert the custom Python <strong>type</strong> into one of
+SQLite's supported types. The callable accepts as single parameter the Python
+value, and must return a value of the following types: int, long, float, str
+(UTF-8 encoded), unicode or buffer.</p>
+</li>
+<li><p class="first"><strong>Connection</strong> class</p>
+<ul>
+<li><p class="first"><strong>isolation_level</strong> attribute (read-write)</p>
+<p>Get or set the current <em>isolation level</em>: None for autocommit mode or one
+of &quot;DEFERRED&quot;, &quot;IMMEDIATE&quot; or &quot;EXLUSIVE&quot;. See <a class="reference" href="#controlling-transactions">5. Controlling
+Transactions</a> for a more detailed explanation.</p>
+</li>
+<li><p class="first"><strong>cursor method</strong> - The cursor method accepts a single optional parameter:
+a custom cursor class extending pysqlite's <em>Cursor</em> class that you can
+adapt to your needs. Note that it is required that your custom cursor class
+extends pysqlite's <em>Cursor</em> class.</p>
+</li>
+<li><p class="first"><strong>execute method</strong> - Nonstandard - this works as a shortcut for not having
+to create a cursor object and is implemented like this:</p>
+<blockquote>
+<div class="code-block">
+<span class="p_word">class</span><span class="p_default">&nbsp;</span><span class="p_classname">Connection</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">execute</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">*</span><span class="p_identifier">args</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(*</span><span class="p_identifier">args</span><span class="p_operator">)</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">return</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span>
+</div>
+</blockquote>
+</li>
+<li><p class="first"><strong>executemany method</strong> - Nonstandard - The same shortcut as the nonstandard
+<tt class="docutils literal"><span class="pre">execute</span></tt> method.</p>
+</li>
+<li><p class="first"><strong>executesript method</strong> - Nonstandard - The same shortcut as the nonstandard
+<tt class="docutils literal"><span class="pre">execute</span></tt> method.</p>
+</li>
+<li><p class="first"><strong>row_factory</strong> attribute (read-write)</p>
+<p>You can change this attribute to a callable that accepts the cursor and
+the original row as tuple and will return the real result row.  This
+way, you can implement more advanced ways of returning results, like
+ones that can also access columns by name.</p>
+<p>Example:</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">dict_factory</span><span class="p_operator">(</span><span class="p_identifier">cursor</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">d</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_operator">{}</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">for</span><span class="p_default">&nbsp;</span><span class="p_identifier">idx</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">col</span><span class="p_default">&nbsp;</span><span class="p_word">in</span><span class="p_default">&nbsp;</span><span class="p_identifier">enumerate</span><span class="p_operator">(</span><span class="p_identifier">cursor</span><span class="p_operator">.</span><span class="p_identifier">description</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">d</span><span class="p_operator">[</span><span class="p_identifier">col</span><span class="p_operator">[</span><span class="p_number">0</span><span class="p_operator">]]</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_identifier">idx</span><span class="p_operator">]</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">return</span><span class="p_default">&nbsp;</span><span class="p_identifier">d</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">row_factory</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">dict_factory</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;1&nbsp;as&nbsp;a"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()[</span><span class="p_string">"a"</span><span class="p_operator">]</span>
+</div>
+<p>If the standard tuple types don't suffice for you, and you want name-based
+access to columns, you should consider setting <tt class="docutils literal"><span class="pre">row_factory</span></tt> to the
+highly-optimized <tt class="docutils literal"><span class="pre">pysqlite2.dbapi2.Row</span></tt> type. It provides both
+index-based and case-insensitive name-based access to columns with almost
+no memory overhead. Much better than your own custom dictionary-based
+approach or even a <tt class="docutils literal"><span class="pre">db_row</span></tt> based solution.</p>
+</li>
+<li><p class="first"><strong>text_factory</strong> attribute (read-write)</p>
+<p>Using this attribute you can control what objects pysqlite returns for the
+TEXT data type. By default, this attribute is set to <tt class="docutils literal"><span class="pre">unicode</span></tt> and
+pysqlite will return Unicode objects for TEXT. If you want to return
+bytestrings instead, you can set it to <tt class="docutils literal"><span class="pre">str</span></tt>.</p>
+<p>For efficiency reasons, there's also a way to return Unicode objects only
+for non-ASCII data, and bytestrings otherwise. To activate it, set this
+attribute to <tt class="docutils literal"><span class="pre">pysqlite2.dbapi2.OptimizedUnicode</span></tt>.</p>
+<p>You can also set it to any other callable that accepts a single bytestring
+parameter and returns the result object.</p>
+<p>See the following example code for illustration:</p>
+<blockquote>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;Create&nbsp;the&nbsp;table</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"create&nbsp;table&nbsp;person(lastname,&nbsp;firstname)"</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">AUSTRIA</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_string">u"\xd6sterreich"</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;by&nbsp;default,&nbsp;rows&nbsp;are&nbsp;returned&nbsp;as&nbsp;Unicode</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;?"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">AUSTRIA</span><span class="p_operator">,))</span><span class="p_default"><br/>
+</span><span class="p_identifier">row</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_word">assert</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">0</span><span class="p_operator">]</span><span class="p_default">&nbsp;</span><span class="p_operator">==</span><span class="p_default">&nbsp;</span><span class="p_identifier">AUSTRIA</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;but&nbsp;we&nbsp;can&nbsp;make&nbsp;pysqlite&nbsp;always&nbsp;return&nbsp;bytestrings&nbsp;...</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">text_factory</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">str</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;?"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">AUSTRIA</span><span class="p_operator">,))</span><span class="p_default"><br/>
+</span><span class="p_identifier">row</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_word">assert</span><span class="p_default">&nbsp;</span><span class="p_identifier">type</span><span class="p_operator">(</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">0</span><span class="p_operator">])</span><span class="p_default">&nbsp;</span><span class="p_operator">==</span><span class="p_default">&nbsp;</span><span class="p_identifier">str</span><span class="p_default"><br/>
+</span><span class="p_commentline">#&nbsp;the&nbsp;bytestrings&nbsp;will&nbsp;be&nbsp;encoded&nbsp;in&nbsp;UTF-8,&nbsp;unless&nbsp;you&nbsp;stored&nbsp;garbage&nbsp;in&nbsp;the</span><span class="p_default"><br/>
+</span><span class="p_commentline">#&nbsp;database&nbsp;...</span><span class="p_default"><br/>
+</span><span class="p_word">assert</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">0</span><span class="p_operator">]</span><span class="p_default">&nbsp;</span><span class="p_operator">==</span><span class="p_default">&nbsp;</span><span class="p_identifier">AUSTRIA</span><span class="p_operator">.</span><span class="p_identifier">encode</span><span class="p_operator">(</span><span class="p_string">"utf-8"</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;we&nbsp;can&nbsp;also&nbsp;implement&nbsp;a&nbsp;custom&nbsp;text_factory&nbsp;...</span><span class="p_default"><br/>
+</span><span class="p_commentline">#&nbsp;here&nbsp;we&nbsp;implement&nbsp;one&nbsp;that&nbsp;will&nbsp;ignore&nbsp;Unicode&nbsp;characters&nbsp;that&nbsp;cannot&nbsp;be</span><span class="p_default"><br/>
+</span><span class="p_commentline">#&nbsp;decoded&nbsp;from&nbsp;UTF-8</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">text_factory</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_word">lambda</span><span class="p_default">&nbsp;</span><span class="p_identifier">x</span><span class="p_operator">:</span><span class="p_default">&nbsp;</span><span class="p_identifier">unicode</span><span class="p_operator">(</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_string">"utf-8"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_string">"ignore"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;?"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_string">"this&nbsp;is&nbsp;latin1&nbsp;and&nbsp;would&nbsp;normally&nbsp;create&nbsp;errors"</span><span class="p_default">&nbsp;</span><span class="p_operator">+</span><span class="p_default">&nbsp;</span><span class="p_string">u"\xe4\xf6\xfc"</span><span class="p_operator">.</span><span class="p_identifier">encode</span><span class="p_operator">(</span><span class="p_string">"latin1"</span><span class="p_operator">),))</span><span class="p_default"><br/>
+</span><span class="p_identifier">row</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_word">assert</span><span class="p_default">&nbsp;</span><span class="p_identifier">type</span><span class="p_operator">(</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">0</span><span class="p_operator">])</span><span class="p_default">&nbsp;</span><span class="p_operator">==</span><span class="p_default">&nbsp;</span><span class="p_identifier">unicode</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;pysqlite&nbsp;offers&nbsp;a&nbsp;builtin&nbsp;optimized&nbsp;text_factory&nbsp;that&nbsp;will&nbsp;return&nbsp;bytestring</span><span class="p_default"><br/>
+</span><span class="p_commentline">#&nbsp;objects,&nbsp;if&nbsp;the&nbsp;data&nbsp;is&nbsp;in&nbsp;ASCII&nbsp;only,&nbsp;and&nbsp;otherwise&nbsp;return&nbsp;unicode&nbsp;objects</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">text_factory</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">OptimizedUnicode</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;?"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">AUSTRIA</span><span class="p_operator">,))</span><span class="p_default"><br/>
+</span><span class="p_identifier">row</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_word">assert</span><span class="p_default">&nbsp;</span><span class="p_identifier">type</span><span class="p_operator">(</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">0</span><span class="p_operator">])</span><span class="p_default">&nbsp;</span><span class="p_operator">==</span><span class="p_default">&nbsp;</span><span class="p_identifier">unicode</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;?"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_string">"Germany"</span><span class="p_operator">,))</span><span class="p_default"><br/>
+</span><span class="p_identifier">row</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_word">assert</span><span class="p_default">&nbsp;</span><span class="p_identifier">type</span><span class="p_operator">(</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">0</span><span class="p_operator">])</span><span class="p_default">&nbsp;</span><span class="p_operator">==</span><span class="p_default">&nbsp;</span><span class="p_identifier">str</span><span class="p_default"><br/>
+</span>
+</div>
+</blockquote>
+</li>
+<li><p class="first"><strong>total_changes</strong> attribute (read-only)</p>
+<p>Returns the total number of database rows that have be modified, inserted,
+or deleted since the database connection was opened.</p>
+</li>
+</ul>
+<div class="line-block">
+<div class="line"><br /></div>
+</div>
+</li>
+<li><p class="first"><strong>Cursor</strong> class</p>
+<ul>
+<li><p class="first"><strong>execute</strong> method</p>
+<p>pysqlite uses <em>paramstyle = &quot;qmark&quot;</em>. That means if you use parametrized
+statements, you use the question mark as placeholder.</p>
+<p>This is a basic example showing the use of question marks as placeholders
+and a parameter tuple:</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">"mydb"</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">who</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_string">"Yeltsin"</span><span class="p_default"><br/>
+</span><span class="p_identifier">age</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_number">72</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;name_last,&nbsp;age&nbsp;from&nbsp;people&nbsp;where&nbsp;name_last=?&nbsp;and&nbsp;age=?"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">who</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">age</span><span class="p_operator">))</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()</span>
+</div>
+<p>pysqlite also supports <em>paramstyle = &quot;named&quot;</em>. That means you can use named
+placeholders in the format &quot;:name&quot;, i. e. a colon followed by the parameter
+name. As parameters, you then supply a mapping instead of a sequence. In
+the simplest case, a dictionary instead of a tuple.</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">"mydb"</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">who</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_string">"Yeltsin"</span><span class="p_default"><br/>
+</span><span class="p_identifier">age</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_number">72</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;name_last,&nbsp;age&nbsp;from&nbsp;people&nbsp;where&nbsp;name_last=:who&nbsp;and&nbsp;age=:age"</span><span class="p_operator">,</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_operator">{</span><span class="p_string">"who"</span><span class="p_operator">:</span><span class="p_default">&nbsp;</span><span class="p_identifier">who</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_string">"age"</span><span class="p_operator">:</span><span class="p_default">&nbsp;</span><span class="p_identifier">age</span><span class="p_operator">})</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span>
+</div>
+<p>The following example shows a shortcut that you can often use when using
+named parameters. It exploits the fact that locals() is a dictionary, too.
+So you can also use it as parameter for <em>execute</em>:</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">"mydb"</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">who</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_string">"Yeltsin"</span><span class="p_default"><br/>
+</span><span class="p_identifier">age</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_number">72</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;name_last,&nbsp;age&nbsp;from&nbsp;people&nbsp;where&nbsp;name_last=:who&nbsp;and&nbsp;age=:age"</span><span class="p_operator">,</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">locals</span><span class="p_operator">())</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()</span><span class="p_default"><br/>
+<br/>
+</span>
+</div>
+<p><em>execute</em> will only execute a single SQL statement. If you try to execute
+more than one statement with it, it will raise a Warning. Use
+<em>executescript</em> if want to execute multiple SQL statements with one call.</p>
+</li>
+<li><p class="first"><strong>executemany</strong> method</p>
+<p>The DB-API specifies the executemany method like this:</p>
+<div class="code-block">
+<span class="p_operator">.</span><span class="p_identifier">executemany</span><span class="p_operator">(</span><span class="p_identifier">operation</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">seq_of_parameters</span><span class="p_operator">)</span>
+</div>
+<p>pysqlite, however, extends <em>executemany</em> so it can be used more efficiently
+for inserting bulk data. The second parameter to <em>executemany</em> can be a
+<em>sequence of parameters</em>, but it can also be an <em>iterator</em> returning
+parameters.</p>
+<p>Example:</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">class</span><span class="p_default">&nbsp;</span><span class="p_classname">IterChars</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">__init__</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">count</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">ord</span><span class="p_operator">(</span><span class="p_character">'a'</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">__iter__</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">return</span><span class="p_default">&nbsp;</span><span class="p_identifier">self</span><span class="p_default"><br/>
+<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">next</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">if</span><span class="p_default">&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">count</span><span class="p_default">&nbsp;</span><span class="p_operator">&gt;</span><span class="p_default">&nbsp;</span><span class="p_identifier">ord</span><span class="p_operator">(</span><span class="p_character">'z'</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">raise</span><span class="p_default">&nbsp;</span><span class="p_identifier">StopIteration</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">count</span><span class="p_default">&nbsp;</span><span class="p_operator">+=</span><span class="p_default">&nbsp;</span><span class="p_number">1</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">return</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">chr</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">count</span><span class="p_default">&nbsp;</span><span class="p_operator">-</span><span class="p_default">&nbsp;</span><span class="p_number">1</span><span class="p_operator">),)</span><span class="p_default">&nbsp;</span><span class="p_commentline">#&nbsp;this&nbsp;is&nbsp;a&nbsp;1-tuple</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"create&nbsp;table&nbsp;characters(c)"</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">theIter</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">IterChars</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">executemany</span><span class="p_operator">(</span><span class="p_string">"insert&nbsp;into&nbsp;characters(c)&nbsp;values&nbsp;(?)"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">theIter</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;c&nbsp;from&nbsp;characters"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchall</span><span class="p_operator">()</span>
+</div>
+<p>As generators are iterators, too, here's a much simpler, equivalent example
+using a generator:</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">char_generator</span><span class="p_operator">():</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">string</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">for</span><span class="p_default">&nbsp;</span><span class="p_identifier">c</span><span class="p_default">&nbsp;</span><span class="p_word">in</span><span class="p_default">&nbsp;</span><span class="p_identifier">string</span><span class="p_operator">.</span><span class="p_identifier">letters</span><span class="p_operator">[:</span><span class="p_number">26</span><span class="p_operator">]:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">yield</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">c</span><span class="p_operator">,)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"create&nbsp;table&nbsp;characters(c)"</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">executemany</span><span class="p_operator">(</span><span class="p_string">"insert&nbsp;into&nbsp;characters(c)&nbsp;values&nbsp;(?)"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">char_generator</span><span class="p_operator">())</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;c&nbsp;from&nbsp;characters"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchall</span><span class="p_operator">()</span>
+</div>
+<p><em>executemany</em> will only execute a single SQL statement. If you try to
+execute more than one statement with it, it will raise a Warning. Use
+<em>executescript</em> if want to execute multiple SQL statements with one call.</p>
+</li>
+</ul>
+</li>
+<li><p class="first"><strong>executescript</strong> method</p>
+<blockquote>
+<div class="code-block">
+<span class="p_operator">.</span><span class="p_identifier">executemany</span><span class="p_operator">(</span><span class="p_identifier">sqlscript</span><span class="p_operator">)</span>
+</div>
+<p>This is a nonstandard convenience method for executing multiple SQL
+statements at once. It issues a COMMIT statement before, then executes the
+SQL script it gets as a parameter.</p>
+<p>The SQL script <tt class="docutils literal"><span class="pre">sqlscript</span></tt> can be a bytestring or a Unicode string.</p>
+<p>Example:</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">executescript</span><span class="p_operator">(</span><span class="p_tripledouble">"""<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;create&nbsp;table&nbsp;person(<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;firstname,<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lastname,<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;age<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;);<br/>
+<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;create&nbsp;table&nbsp;book(<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;title,<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;author,<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;published<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;);<br/>
+<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;insert&nbsp;into&nbsp;book(title,&nbsp;author,&nbsp;published)<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;values&nbsp;(<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'Dirk&nbsp;Gently''s&nbsp;Holistic&nbsp;Detective&nbsp;Agency<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'Douglas&nbsp;Adams',<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1987<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;);<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;"""</span><span class="p_operator">)</span>
+</div>
+</blockquote>
+<ul>
+<li><p class="first"><strong>rowcount</strong> attribute</p>
+<p>Although pysqlite's Cursors implement this attribute, the database
+engine's own support for the determination of &quot;rows affected&quot;/&quot;rows
+selected&quot; is quirky.</p>
+<p>For <tt class="docutils literal"><span class="pre">SELECT</span></tt> statements, <em>rowcount</em> is always None because pysqlite
+cannot determine the number of rows a query produced until all rows
+were fetched.</p>
+<p>For <tt class="docutils literal"><span class="pre">DELETE</span></tt> statements, SQLite reports <em>rowcount</em> as 0 if you make a
+<tt class="docutils literal"><span class="pre">DELETE</span> <span class="pre">FROM</span> <span class="pre">table</span></tt> without any condition.</p>
+<p>For <em>executemany</em> statements, pysqlite sums up the number of
+modifications into <em>rowcount</em>.</p>
+<p>As required by the Python DB API Spec, the <em>rowcount</em> attribute &quot;is -1
+in case no executeXX() has been performed on the cursor or the rowcount
+of the last operation is not determinable by the interface&quot;.</p>
+</li>
+</ul>
+</li>
+</ul>
+<div class="line-block">
+<div class="line"><br /></div>
+</div>
+<hr class="docutils" />
+<div class="line-block">
+<div class="line"><br /></div>
+</div>
+</div>
+</div>
+<div class="section">
+<h1><a id="brief-tutorial" name="brief-tutorial">2. Brief Tutorial</a></h1>
+<p>This brief tutorial aims to get the reader started by demonstrating elementary
+usage of pysqlite. It is not a comprehensive Python Database API tutorial, nor
+is it comprehensive in its coverage of anything else.</p>
+<div class="section">
+<h2><a id="connecting-to-a-database" name="connecting-to-a-database">2.1 Connecting to a Database</a></h2>
+<blockquote>
+<p><strong>Example 1</strong></p>
+<p>Connecting to a database file <em>mydb</em>:</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">"mydb"</span><span class="p_operator">)</span>
+</div>
+<p><strong>Example 2</strong></p>
+<p>Creating an in-memory database:</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">)</span>
+</div>
+</blockquote>
+</div>
+<div class="section">
+<h2><a id="executing-sql-statements" name="executing-sql-statements">2.2 Executing SQL statements</a></h2>
+<p>For this section, we have a database <em>mydb</em> defined and populated by the
+following SQL code:</p>
+<blockquote>
+<div class="code-block">
+<span class="c_identifier">create</span><span class="c_default">&nbsp;</span><span class="c_identifier">table</span><span class="c_default">&nbsp;</span><span class="c_identifier">people</span><span class="c_default"><br/>
+</span><span class="c_operator">(</span><span class="c_default"><br/>
+&nbsp;&nbsp;</span><span class="c_identifier">name_last</span><span class="c_default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="c_identifier">varchar</span><span class="c_operator">(</span><span class="c_number">20</span><span class="c_operator">),</span><span class="c_default"><br/>
+&nbsp;&nbsp;</span><span class="c_identifier">age</span><span class="c_default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="c_identifier">integer</span><span class="c_default"><br/>
+</span><span class="c_operator">);</span><span class="c_default"><br/>
+<br/>
+</span><span class="c_identifier">insert</span><span class="c_default">&nbsp;</span><span class="c_identifier">into</span><span class="c_default">&nbsp;</span><span class="c_identifier">people</span><span class="c_default">&nbsp;</span><span class="c_operator">(</span><span class="c_identifier">name_last</span><span class="c_operator">,</span><span class="c_default">&nbsp;</span><span class="c_identifier">age</span><span class="c_operator">)</span><span class="c_default">&nbsp;</span><span class="c_identifier">values</span><span class="c_default">&nbsp;</span><span class="c_operator">(</span><span class="c_character">'Yeltsin'</span><span class="c_operator">,</span><span class="c_default">&nbsp;&nbsp;&nbsp;</span><span class="c_number">72</span><span class="c_operator">);</span><span class="c_default"><br/>
+</span><span class="c_identifier">insert</span><span class="c_default">&nbsp;</span><span class="c_identifier">into</span><span class="c_default">&nbsp;</span><span class="c_identifier">people</span><span class="c_default">&nbsp;</span><span class="c_operator">(</span><span class="c_identifier">name_last</span><span class="c_operator">,</span><span class="c_default">&nbsp;</span><span class="c_identifier">age</span><span class="c_operator">)</span><span class="c_default">&nbsp;</span><span class="c_identifier">values</span><span class="c_default">&nbsp;</span><span class="c_operator">(</span><span class="c_character">'Putin'</span><span class="c_operator">,</span><span class="c_default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="c_number">51</span><span class="c_operator">);</span>
+</div>
+</blockquote>
+<p><em>Example 1</em></p>
+<p>This example shows the simplest way to print the entire contents of the <tt class="docutils literal"><span class="pre">people</span></tt> table:</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;Create&nbsp;a&nbsp;connection&nbsp;to&nbsp;the&nbsp;database&nbsp;file&nbsp;"mydb":</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">"mydb"</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;Get&nbsp;a&nbsp;Cursor&nbsp;object&nbsp;that&nbsp;operates&nbsp;in&nbsp;the&nbsp;context&nbsp;of&nbsp;Connection&nbsp;con:</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;Execute&nbsp;the&nbsp;SELECT&nbsp;statement:</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;*&nbsp;from&nbsp;people&nbsp;order&nbsp;by&nbsp;age"</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;Retrieve&nbsp;all&nbsp;rows&nbsp;as&nbsp;a&nbsp;sequence&nbsp;and&nbsp;print&nbsp;that&nbsp;sequence:</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchall</span><span class="p_operator">()</span>
+</div>
+<p>Sample output:</p>
+<pre class="literal-block">
+[(u'Putin', 51), (u'Yeltsin', 72)]
+</pre>
+<p><em>Example 2</em></p>
+<p>Here's another trivial example that demonstrates various ways of fetching a
+single row at a time from a SELECT-cursor:</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">"mydb"</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">SELECT</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_string">"select&nbsp;name_last,&nbsp;age&nbsp;from&nbsp;people&nbsp;order&nbsp;by&nbsp;age,&nbsp;name_last"</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;1.&nbsp;Iterate&nbsp;over&nbsp;the&nbsp;rows&nbsp;available&nbsp;from&nbsp;the&nbsp;cursor,&nbsp;unpacking&nbsp;the</span><span class="p_default"><br/>
+</span><span class="p_commentline">#&nbsp;resulting&nbsp;sequences&nbsp;to&nbsp;yield&nbsp;their&nbsp;elements&nbsp;(name_last,&nbsp;age):</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_identifier">SELECT</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_word">for</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">name_last</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">age</span><span class="p_operator">)</span><span class="p_default">&nbsp;</span><span class="p_word">in</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_character">'%s&nbsp;is&nbsp;%d&nbsp;years&nbsp;old.'</span><span class="p_default">&nbsp;</span><span class="p_operator">%</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">name_last</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">age</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;2.&nbsp;Equivalently:</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_identifier">SELECT</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_word">for</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_default">&nbsp;</span><span class="p_word">in</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_character">'%s&nbsp;is&nbsp;%d&nbsp;years&nbsp;old.'</span><span class="p_default">&nbsp;</span><span class="p_operator">%</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">0</span><span class="p_operator">],</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">1</span><span class="p_operator">])</span>
+</div>
+<p>Sample output:</p>
+<pre class="literal-block">
+Putin is 51 years old.
+Yeltsin is 72 years old.
+Putin is 51 years old.
+Yeltsin is 72 years old.
+</pre>
+<p><em>Example 3</em></p>
+<p>The following program is a simplistic table printer (applied in this example to
+people)</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">FIELD_MAX_WIDTH</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_number">20</span><span class="p_default"><br/>
+</span><span class="p_identifier">TABLE_NAME</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_character">'people'</span><span class="p_default"><br/>
+</span><span class="p_identifier">SELECT</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_character">'select&nbsp;*&nbsp;from&nbsp;%s&nbsp;order&nbsp;by&nbsp;age,&nbsp;name_last'</span><span class="p_default">&nbsp;</span><span class="p_operator">%</span><span class="p_default">&nbsp;</span><span class="p_identifier">TABLE_NAME</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">"mydb"</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_identifier">SELECT</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;Print&nbsp;a&nbsp;header.</span><span class="p_default"><br/>
+</span><span class="p_word">for</span><span class="p_default">&nbsp;</span><span class="p_identifier">fieldDesc</span><span class="p_default">&nbsp;</span><span class="p_word">in</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">description</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">fieldDesc</span><span class="p_operator">[</span><span class="p_number">0</span><span class="p_operator">].</span><span class="p_identifier">ljust</span><span class="p_operator">(</span><span class="p_identifier">FIELD_MAX_WIDTH</span><span class="p_operator">)</span><span class="p_default">&nbsp;</span><span class="p_operator">,</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_commentline">#&nbsp;Finish&nbsp;the&nbsp;header&nbsp;with&nbsp;a&nbsp;newline.</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_character">'-'</span><span class="p_default">&nbsp;</span><span class="p_operator">*</span><span class="p_default">&nbsp;</span><span class="p_number">78</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;For&nbsp;each&nbsp;row,&nbsp;print&nbsp;the&nbsp;value&nbsp;of&nbsp;each&nbsp;field&nbsp;left-justified&nbsp;within</span><span class="p_default"><br/>
+</span><span class="p_commentline">#&nbsp;the&nbsp;maximum&nbsp;possible&nbsp;width&nbsp;of&nbsp;that&nbsp;field.</span><span class="p_default"><br/>
+</span><span class="p_identifier">fieldIndices</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">range</span><span class="p_operator">(</span><span class="p_identifier">len</span><span class="p_operator">(</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">description</span><span class="p_operator">))</span><span class="p_default"><br/>
+</span><span class="p_word">for</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_default">&nbsp;</span><span class="p_word">in</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">for</span><span class="p_default">&nbsp;</span><span class="p_identifier">fieldIndex</span><span class="p_default">&nbsp;</span><span class="p_word">in</span><span class="p_default">&nbsp;</span><span class="p_identifier">fieldIndices</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">fieldValue</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">str</span><span class="p_operator">(</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_identifier">fieldIndex</span><span class="p_operator">])</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">fieldValue</span><span class="p_operator">.</span><span class="p_identifier">ljust</span><span class="p_operator">(</span><span class="p_identifier">FIELD_MAX_WIDTH</span><span class="p_operator">)</span><span class="p_default">&nbsp;</span><span class="p_operator">,</span><span class="p_default"><br/>
+<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_commentline">#&nbsp;Finish&nbsp;the&nbsp;row&nbsp;with&nbsp;a&nbsp;newline.</span>
+</div>
+<p>Sample output:</p>
+<pre class="literal-block">
+name_last            age
+------------------------------------------------------------------------------
+Putin                51
+Yeltsin              72
+</pre>
+<p><em>Example 4</em></p>
+<p>Let's insert more people into the people table:</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">"mydb"</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">newPeople</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_operator">(</span><span class="p_character">'Lebed'</span><span class="p_default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_number">53</span><span class="p_operator">),</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_operator">(</span><span class="p_character">'Zhirinovsky'</span><span class="p_default">&nbsp;</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_number">57</span><span class="p_operator">),</span><span class="p_default"><br/>
+&nbsp;&nbsp;</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">for</span><span class="p_default">&nbsp;</span><span class="p_identifier">person</span><span class="p_default">&nbsp;</span><span class="p_word">in</span><span class="p_default">&nbsp;</span><span class="p_identifier">newPeople</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"insert&nbsp;into&nbsp;people&nbsp;(name_last,&nbsp;age)&nbsp;values&nbsp;(?,&nbsp;?)"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">person</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;The&nbsp;changes&nbsp;will&nbsp;not&nbsp;be&nbsp;saved&nbsp;unless&nbsp;the&nbsp;transaction&nbsp;is&nbsp;committed&nbsp;explicitly:</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">commit</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span>
+</div>
+<p>Note the use of a parameterized SQL statement above. When dealing with
+repetitive statements, this is much faster and less error-prone than assembling
+each SQL statement manually.</p>
+<p>It's also worth noting that in the example above, the code:</p>
+<p>It's also worth noting that in the example above, the code:</p>
+<div class="code-block">
+<span class="p_word">for</span><span class="p_default">&nbsp;</span><span class="p_identifier">person</span><span class="p_default">&nbsp;</span><span class="p_word">in</span><span class="p_default">&nbsp;</span><span class="p_identifier">newPeople</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"insert&nbsp;into&nbsp;people&nbsp;(name_last,&nbsp;age)&nbsp;values&nbsp;(?,&nbsp;?)"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">person</span><span class="p_operator">)</span>
+</div>
+<p>could be rewritten as:</p>
+<div class="code-block">
+<span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">executemany</span><span class="p_operator">(</span><span class="p_string">"insert&nbsp;into&nbsp;people&nbsp;(name_last,&nbsp;age)&nbsp;values&nbsp;(?,&nbsp;?)"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">newPeople</span><span class="p_operator">)</span>
+</div>
+<p>After running Example 4, the table printer from Example 3 would print:</p>
+<pre class="literal-block">
+name_last            age
+------------------------------------------------------------------------------
+Putin                51
+Lebed                53
+Zhirinovsky          57
+Yeltsin              72
+</pre>
+<div class="line-block">
+<div class="line"><br /></div>
+</div>
+<hr class="docutils" />
+<div class="line-block">
+<div class="line"><br /></div>
+</div>
+</div>
+</div>
+<div class="section">
+<h1><a id="native-database-engine-features-and-extensions-beyond-the-python-db-api" name="native-database-engine-features-and-extensions-beyond-the-python-db-api">3. Native Database Engine Features and Extensions Beyond the Python DB API</a></h1>
+<div class="section">
+<h2><a id="creating-user-defined-functions" name="creating-user-defined-functions">3.1 Creating user-defined functions</a></h2>
+<p>SQLite supports user-defined functions.  Using pysqlite, you can create new
+functions with the connection's <strong>create_function</strong> method:</p>
+<blockquote>
+<div class="code-block">
+<span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">create_function</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">name</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">numparams</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">func</span><span class="p_operator">)</span>
+</div>
+<dl class="docutils">
+<dt><em>name</em></dt>
+<dd>the name of your function in SQL</dd>
+<dt><em>numparams</em></dt>
+<dd>the number of parameters your function accepts, -1 if it accepts any
+number of parameters</dd>
+<dt><em>func</em></dt>
+<dd>the Python function</dd>
+</dl>
+<p>The function can return any of pysqlite's supported SQLite types: unicode,
+str, int, long, float, buffer and None.  The function should never raise an
+exception.</p>
+<p>Example:</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">md5</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">md5sum</span><span class="p_operator">(</span><span class="p_identifier">t</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">return</span><span class="p_default">&nbsp;</span><span class="p_identifier">md5</span><span class="p_operator">.</span><span class="p_identifier">md5</span><span class="p_operator">(</span><span class="p_identifier">t</span><span class="p_operator">).</span><span class="p_identifier">hexdigest</span><span class="p_operator">()</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">create_function</span><span class="p_operator">(</span><span class="p_string">"md5"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_number">1</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">md5sum</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;md5(?)"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_string">"foo"</span><span class="p_operator">,))</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()[</span><span class="p_number">0</span><span class="p_operator">]</span>
+</div>
+</blockquote>
+</div>
+<div class="section">
+<h2><a id="creating-user-defined-aggregates" name="creating-user-defined-aggregates">3.2 Creating user-defined aggregates</a></h2>
+<p>SQLite supports user-defined aggregate functions. Using pysqlite, you can
+create new aggregate functions with the connection's <em>create_aggregate</em> method.</p>
+<blockquote>
+<div class="code-block">
+<span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">create_aggregate</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">name</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">numparams</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">aggregate_class</span><span class="p_operator">)</span>
+</div>
+<p>The aggregate class must implement a <em>step</em> method, which accepts the
+number of parameters defined in <em>create_aggregate</em>, and a <em>finalize</em>
+method which will return the final result of the aggregate.</p>
+<p>The <em>finalize</em> method can return any of pysqlite's supported SQLite types:
+unicode, str, int, long, float, buffer and None. The aggregate class's
+methods should never raise any exception.</p>
+<p>Example:</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">class</span><span class="p_default">&nbsp;</span><span class="p_classname">MySum</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">__init__</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">count</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_number">0</span><span class="p_default"><br/>
+<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">step</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">value</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">count</span><span class="p_default">&nbsp;</span><span class="p_operator">+=</span><span class="p_default">&nbsp;</span><span class="p_identifier">value</span><span class="p_default"><br/>
+<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">finalize</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">return</span><span class="p_default">&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">count</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">create_aggregate</span><span class="p_operator">(</span><span class="p_string">"mysum"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_number">1</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">MySum</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"create&nbsp;table&nbsp;test(i)"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"insert&nbsp;into&nbsp;test(i)&nbsp;values&nbsp;(1)"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"insert&nbsp;into&nbsp;test(i)&nbsp;values&nbsp;(2)"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;mysum(i)&nbsp;from&nbsp;test"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()[</span><span class="p_number">0</span><span class="p_operator">]</span>
+</div>
+</blockquote>
+</div>
+<div class="section">
+<h2><a id="creating-and-using-collations" name="creating-and-using-collations">3.3 Creating and using collations</a></h2>
+<blockquote>
+<div class="code-block">
+<span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">create_collation</span><span class="p_operator">(</span><span class="p_identifier">name</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">callable</span><span class="p_operator">)</span>
+</div>
+</blockquote>
+<p>Creates a collation with the specified name and callable. The callable will be
+passed two string arguments. It should return -1 if the first is less than the
+second, 0 if they are equal and 1 and if the first is greater than the second.
+Note that this controls sorting (ORDER BY in SQL) so your comparisons don't
+affect other SQL operations. Read more about SQLite's handling of collations.
+(This calls sqlite3_create_collation.) If there is an error in your Python code
+then 0 (ie items are equal) is returned.</p>
+<p>Note that the callable will get its parameters as Python bytestrings, which
+will normally be encoded in UTF-8.</p>
+<p>The following example shows a custom collation that sorts &quot;the wrong way&quot;:</p>
+<blockquote>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">collate_reverse</span><span class="p_operator">(</span><span class="p_identifier">string1</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">string2</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">return</span><span class="p_default">&nbsp;</span><span class="p_operator">-</span><span class="p_identifier">cmp</span><span class="p_operator">(</span><span class="p_identifier">string1</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">string2</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">create_collation</span><span class="p_operator">(</span><span class="p_string">"reverse"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">collate_reverse</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"create&nbsp;table&nbsp;test(x)"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">executemany</span><span class="p_operator">(</span><span class="p_string">"insert&nbsp;into&nbsp;test(x)&nbsp;values&nbsp;(?)"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">[(</span><span class="p_string">"a"</span><span class="p_operator">,),</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_string">"b"</span><span class="p_operator">,)])</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;x&nbsp;from&nbsp;test&nbsp;order&nbsp;by&nbsp;x&nbsp;collate&nbsp;reverse"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_word">for</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_default">&nbsp;</span><span class="p_word">in</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">close</span><span class="p_operator">()</span>
+</div>
+</blockquote>
+<p>To remove a collation, call <cite>create_collation</cite> with None as callable:</p>
+<blockquote>
+<div class="code-block">
+<span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">create_collation</span><span class="p_operator">(</span><span class="p_string">"reverse"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_word">None</span><span class="p_operator">)</span>
+</div>
+</blockquote>
+</div>
+<div class="section">
+<h2><a id="checking-for-complete-statements" name="checking-for-complete-statements">3.4 Checking for complete statements</a></h2>
+<p>The module-level function <em>complete_statement(sql)</em> can be used to check if a
+string contains a complete SQL statement or is still incomplete. The given
+string could still contain invalid SQL, but be parsable as a &quot;complete&quot;
+statement!</p>
+<p>This can be used to build a shell for SQLite, like in the following example:</p>
+<blockquote>
+<div class="code-block">
+<span class="p_commentline">#&nbsp;A&nbsp;minimal&nbsp;SQLite&nbsp;shell&nbsp;for&nbsp;experiments</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">isolation_level</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_word">None</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">buffer</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_string">""</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_string">"Enter&nbsp;your&nbsp;SQL&nbsp;commands&nbsp;to&nbsp;execute&nbsp;in&nbsp;SQLite."</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_string">"Enter&nbsp;a&nbsp;blank&nbsp;line&nbsp;to&nbsp;exit."</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">while</span><span class="p_default">&nbsp;</span><span class="p_identifier">True</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">line</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">raw_input</span><span class="p_operator">()</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">if</span><span class="p_default">&nbsp;</span><span class="p_identifier">line</span><span class="p_default">&nbsp;</span><span class="p_operator">==</span><span class="p_default">&nbsp;</span><span class="p_string">""</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">break</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">buffer</span><span class="p_default">&nbsp;</span><span class="p_operator">+=</span><span class="p_default">&nbsp;</span><span class="p_identifier">line</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">if</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">complete_statement</span><span class="p_operator">(</span><span class="p_identifier">buffer</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">try</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">buffer</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">buffer</span><span class="p_operator">.</span><span class="p_identifier">strip</span><span class="p_operator">()</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_identifier">buffer</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">if</span><span class="p_default">&nbsp;</span><span class="p_identifier">buffer</span><span class="p_operator">.</span><span class="p_identifier">lstrip</span><span class="p_operator">().</span><span class="p_identifier">upper</span><span class="p_operator">().</span><span class="p_identifier">startswith</span><span class="p_operator">(</span><span class="p_string">"SELECT"</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchall</span><span class="p_operator">()</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">except</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">Error</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">e</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_string">"An&nbsp;error&nbsp;occured:"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">e</span><span class="p_operator">.</span><span class="p_identifier">args</span><span class="p_operator">[</span><span class="p_number">0</span><span class="p_operator">]</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">buffer</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_string">""</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">close</span><span class="p_operator">()</span>
+</div>
+</blockquote>
+</div>
+<div class="section">
+<h2><a id="enabling-sqlite-s-shared-cache" name="enabling-sqlite-s-shared-cache">3.5 Enabling SQLite's shared cache</a></h2>
+<p>To enable SQLite's shared cache for the calling thread, call the function
+<em>enable_shared_cache</em>.</p>
+<blockquote>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;The&nbsp;shared&nbsp;cache&nbsp;is&nbsp;only&nbsp;available&nbsp;in&nbsp;SQLite&nbsp;versions&nbsp;3.3.3&nbsp;or&nbsp;later</span><span class="p_default"><br/>
+</span><span class="p_commentline">#&nbsp;See&nbsp;the&nbsp;SQLite&nbsp;documentaton&nbsp;for&nbsp;details.</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">enable_shared_cache</span><span class="p_operator">(</span><span class="p_identifier">True</span><span class="p_operator">)</span>
+</div>
+</blockquote>
+</div>
+</div>
+<div class="section">
+<h1><a id="sqlite-and-python-types" name="sqlite-and-python-types">4. SQLite and Python types</a></h1>
+<div class="section">
+<h2><a id="id1" name="id1">4.1 Introduction</a></h2>
+<p><a class="reference" href="http://sqlite.org/datatype3.html">http://sqlite.org/datatype3.html</a></p>
+<p>SQLite natively supports the following types: NULL, INTEGER, REAL, TEXT, BLOB.</p>
+<p>The following Python types can thus be sent to SQLite without any problem:</p>
+<table border="1" class="docutils">
+<colgroup>
+<col width="67%" />
+<col width="33%" />
+</colgroup>
+<thead valign="bottom">
+<tr><th class="head">Python type</th>
+<th class="head">SQLite type</th>
+</tr>
+</thead>
+<tbody valign="top">
+<tr><td>NoneType</td>
+<td>NULL</td>
+</tr>
+<tr><td>int</td>
+<td>INTEGER</td>
+</tr>
+<tr><td>long</td>
+<td>INTEGER</td>
+</tr>
+<tr><td>float</td>
+<td>REAL</td>
+</tr>
+<tr><td>str (utf-8 encoded)</td>
+<td>TEXT</td>
+</tr>
+<tr><td>unicode</td>
+<td>TEXT</td>
+</tr>
+<tr><td>buffer</td>
+<td>BLOB</td>
+</tr>
+</tbody>
+</table>
+<p>This is how SQLite types are converted to Python types by default:</p>
+<table border="1" class="docutils">
+<colgroup>
+<col width="27%" />
+<col width="73%" />
+</colgroup>
+<thead valign="bottom">
+<tr><th class="head">SQLite type</th>
+<th class="head">Python type</th>
+</tr>
+</thead>
+<tbody valign="top">
+<tr><td>NULL</td>
+<td>NoneType</td>
+</tr>
+<tr><td>INTEGER</td>
+<td>int or long, depending on size</td>
+</tr>
+<tr><td>REAL</td>
+<td>float</td>
+</tr>
+<tr><td>TEXT</td>
+<td>unicode</td>
+</tr>
+<tr><td>BLOB</td>
+<td>buffer</td>
+</tr>
+</tbody>
+</table>
+<p>pysqlite's type system is extensible in both ways: you can store additional
+Python types in a SQLite database via object adaptation, and you can let
+pysqlite convert SQLite types to different Python types via pysqlite's
+converters.</p>
+</div>
+<div class="section">
+<h2><a id="using-adapters-to-store-additional-python-types-in-sqlite-databases" name="using-adapters-to-store-additional-python-types-in-sqlite-databases">4.2 Using adapters to store additional Python types in SQLite databases</a></h2>
+<p>Like described before, SQLite supports only a limited set of types natively. To
+use other Python types with SQLite, you must <em>adapt</em> them to one of pysqlite's
+supported types for SQLite. So, one of NoneType, int, long, float, str,
+unicode, buffer.</p>
+<p>pysqlite uses the Python object adaptation, like described in PEP 246 for this.
+The protocol to use is <tt class="docutils literal"><span class="pre">PrepareProtocol</span></tt>.</p>
+<p>There are two ways to enable pysqlite to adapt a custom Python type to one of
+the supported ones.</p>
+</div>
+<div class="section">
+<h2><a id="letting-your-object-adapt-itself" name="letting-your-object-adapt-itself">4.2.1 Letting your object adapt itself</a></h2>
+<p>This is a good approach if you write the class yourself. Let's suppose you have
+a class like this:</p>
+<blockquote>
+<div class="code-block">
+<span class="p_word">class</span><span class="p_default">&nbsp;</span><span class="p_classname">Point</span><span class="p_operator">(</span><span class="p_identifier">object</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">__init__</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">y</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">y</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">y</span>
+</div>
+</blockquote>
+<p>Now you want to store the point in a single SQLite column. You'll have to
+choose one of the supported types first that you use to represent the point in.
+Let's just use str and separate the coordinates using a semicolon. Then you
+need to give your class a method <tt class="docutils literal"><span class="pre">__conform__(self,</span> <span class="pre">protocol)</span></tt> which must
+return the converted value. The parameter <tt class="docutils literal"><span class="pre">protocol</span></tt> will be
+<tt class="docutils literal"><span class="pre">PrepareProtocol</span></tt>.</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">class</span><span class="p_default">&nbsp;</span><span class="p_classname">Point</span><span class="p_operator">(</span><span class="p_identifier">object</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">__init__</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">y</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">y</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">y</span><span class="p_default"><br/>
+<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">__conform__</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">protocol</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">if</span><span class="p_default">&nbsp;</span><span class="p_identifier">protocol</span><span class="p_default">&nbsp;</span><span class="p_word">is</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">PrepareProtocol</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">return</span><span class="p_default">&nbsp;</span><span class="p_string">"%f;%f"</span><span class="p_default">&nbsp;</span><span class="p_operator">%</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">y</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">p</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">Point</span><span class="p_operator">(</span><span class="p_number">4.0</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">-</span><span class="p_number">3.2</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;?"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">p</span><span class="p_operator">,))</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()[</span><span class="p_number">0</span><span class="p_operator">]</span><span class="p_default"><br/>
+</span>
+</div>
+</div>
+<div class="section">
+<h2><a id="registering-an-adapter-callable" name="registering-an-adapter-callable">4.2.2 Registering an adapter callable</a></h2>
+<p>The other possibility is to create a function that converts the type to the
+string representation and register the function with <tt class="docutils literal"><span class="pre">register_adapter</span></tt>.</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">class</span><span class="p_default">&nbsp;</span><span class="p_classname">Point</span><span class="p_operator">(</span><span class="p_identifier">object</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">__init__</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">y</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">y</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">y</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">adapt_point</span><span class="p_operator">(</span><span class="p_identifier">point</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">return</span><span class="p_default">&nbsp;</span><span class="p_string">"%f;%f"</span><span class="p_default">&nbsp;</span><span class="p_operator">%</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">point</span><span class="p_operator">.</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">point</span><span class="p_operator">.</span><span class="p_identifier">y</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">register_adapter</span><span class="p_operator">(</span><span class="p_identifier">Point</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">adapt_point</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">p</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">Point</span><span class="p_operator">(</span><span class="p_number">4.0</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">-</span><span class="p_number">3.2</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;?"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">p</span><span class="p_operator">,))</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()[</span><span class="p_number">0</span><span class="p_operator">]</span><span class="p_default"><br/>
+</span>
+</div>
+<p>The type/class to adapt must be a new-style class, i. e. it must have
+<tt class="docutils literal"><span class="pre">object</span></tt> as one of its bases!!!</p>
+<p>pysqlite has two default adapters for Python's builtin <em>date</em> and <em>datetime</em>
+types. Now let's suppose we want to store <em>datetime</em> objects not in ISO
+representation, but as Unix timestamp.</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">datetime</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">time</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">adapt_datetime</span><span class="p_operator">(</span><span class="p_identifier">ts</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">return</span><span class="p_default">&nbsp;</span><span class="p_identifier">time</span><span class="p_operator">.</span><span class="p_identifier">mktime</span><span class="p_operator">(</span><span class="p_identifier">ts</span><span class="p_operator">.</span><span class="p_identifier">timetuple</span><span class="p_operator">())</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">register_adapter</span><span class="p_operator">(</span><span class="p_identifier">datetime</span><span class="p_operator">.</span><span class="p_identifier">datetime</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">adapt_datetime</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">now</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">datetime</span><span class="p_operator">.</span><span class="p_identifier">datetime</span><span class="p_operator">.</span><span class="p_identifier">now</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;?"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">now</span><span class="p_operator">,))</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()[</span><span class="p_number">0</span><span class="p_operator">]</span>
+</div>
+</div>
+<div class="section">
+<h2><a id="converting-sqlite-values-to-custom-python-types" name="converting-sqlite-values-to-custom-python-types">4.3 Converting SQLite values to custom Python types</a></h2>
+<p>Now that's all nice and dandy that you can send custom Python types to SQLite.
+But to make it really useful we need to make the Python to SQLite to Python
+roundtrip work.</p>
+<p>Enter pysqlite converters.</p>
+<p>Let's go back to the Point class. We stored the x and y coordinates separated
+via semicolons as strings in SQLite.</p>
+<p>Let's first define a converter function that accepts the string as a parameter and constructs a Point object from it.</p>
+<p>!!! Note that converter functions <em>always</em> get called with a string, no matter
+under which data type you sent the value to SQLite !!!</p>
+<p>!!! Also note that converter names are looked up in a case-sensitive manner !!!</p>
+<blockquote>
+<div class="code-block">
+<span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">convert_point</span><span class="p_operator">(</span><span class="p_identifier">s</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">y</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">map</span><span class="p_operator">(</span><span class="p_identifier">float</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">s</span><span class="p_operator">.</span><span class="p_identifier">split</span><span class="p_operator">(</span><span class="p_string">";"</span><span class="p_operator">))</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">return</span><span class="p_default">&nbsp;</span><span class="p_identifier">Point</span><span class="p_operator">(</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">y</span><span class="p_operator">)</span>
+</div>
+</blockquote>
+<p>Now you need to make pysqlite know that what you select from the database is
+actually a point. There are two ways of doing this:</p>
+<blockquote>
+<ul class="simple">
+<li>Implicitly via the declared type</li>
+<li>Explicitly via the column name</li>
+</ul>
+</blockquote>
+<p>Both ways are described in section <a class="reference" href="#extensions-and-caveats">1.4 Extensions and Caveats</a> in the
+paragraphs describing the connect function, and specifically the meaning of the
+<em>detect_types</em> parameter.</p>
+<p>The following example illustrates both ways.</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">class</span><span class="p_default">&nbsp;</span><span class="p_classname">Point</span><span class="p_operator">(</span><span class="p_identifier">object</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">__init__</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">y</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">y</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">y</span><span class="p_default"><br/>
+<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">__repr__</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">return</span><span class="p_default">&nbsp;</span><span class="p_string">"(%f;%f)"</span><span class="p_default">&nbsp;</span><span class="p_operator">%</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">self</span><span class="p_operator">.</span><span class="p_identifier">y</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">adapt_point</span><span class="p_operator">(</span><span class="p_identifier">point</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">return</span><span class="p_default">&nbsp;</span><span class="p_string">"%f;%f"</span><span class="p_default">&nbsp;</span><span class="p_operator">%</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">point</span><span class="p_operator">.</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">point</span><span class="p_operator">.</span><span class="p_identifier">y</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">convert_point</span><span class="p_operator">(</span><span class="p_identifier">s</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">y</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">map</span><span class="p_operator">(</span><span class="p_identifier">float</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">s</span><span class="p_operator">.</span><span class="p_identifier">split</span><span class="p_operator">(</span><span class="p_string">";"</span><span class="p_operator">))</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">return</span><span class="p_default">&nbsp;</span><span class="p_identifier">Point</span><span class="p_operator">(</span><span class="p_identifier">x</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">y</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;Register&nbsp;the&nbsp;adapter</span><span class="p_default"><br/>
+</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">register_adapter</span><span class="p_operator">(</span><span class="p_identifier">Point</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">adapt_point</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;Register&nbsp;the&nbsp;converter</span><span class="p_default"><br/>
+</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">register_converter</span><span class="p_operator">(</span><span class="p_string">"point"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">convert_point</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">p</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">Point</span><span class="p_operator">(</span><span class="p_number">4.0</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">-</span><span class="p_number">3.2</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentblock">#########################</span><span class="p_default"><br/>
+</span><span class="p_commentline">#&nbsp;1)&nbsp;Using&nbsp;declared&nbsp;types</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">detect_types</span><span class="p_operator">=</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">PARSE_DECLTYPES</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"create&nbsp;table&nbsp;test(p&nbsp;point)"</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"insert&nbsp;into&nbsp;test(p)&nbsp;values&nbsp;(?)"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">p</span><span class="p_operator">,))</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;p&nbsp;from&nbsp;test"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_string">"with&nbsp;declared&nbsp;types:"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()[</span><span class="p_number">0</span><span class="p_operator">]</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">close</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">close</span><span class="p_operator">()</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentblock">#######################</span><span class="p_default"><br/>
+</span><span class="p_commentline">#&nbsp;1)&nbsp;Using&nbsp;column&nbsp;names</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">detect_types</span><span class="p_operator">=</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">PARSE_COLNAMES</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"create&nbsp;table&nbsp;test(p)"</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"insert&nbsp;into&nbsp;test(p)&nbsp;values&nbsp;(?)"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">p</span><span class="p_operator">,))</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_character">'select&nbsp;p&nbsp;as&nbsp;"p&nbsp;[point]"&nbsp;from&nbsp;test'</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_string">"with&nbsp;column&nbsp;names:"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()[</span><span class="p_number">0</span><span class="p_operator">]</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">close</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">close</span><span class="p_operator">()</span>
+</div>
+</div>
+<div class="section">
+<h2><a id="default-pysqlite-adapters-and-converters" name="default-pysqlite-adapters-and-converters">4.4 Default pysqlite adapters and converters</a></h2>
+<p>pysqlite has default adapters for the date and datetime types in the datetime
+module. They will be sent as ISO dates/ISO timestamps to SQLite.</p>
+<p>pysqlite has default converters registered under the name &quot;date&quot; for
+datetime.date and under the name &quot;timestamp&quot; for datetime.datetime.</p>
+<p>This way, you can use date/timestamps from pysqlite without any additional
+fiddling in most cases. The format of the adapters is also compatible with the
+experimental SQLite date/time functions.</p>
+<p>The following example demonstrates this.</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">datetime</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">detect_types</span><span class="p_operator">=</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">PARSE_DECLTYPES</span><span class="p_operator">|</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">PARSE_COLNAMES</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"create&nbsp;table&nbsp;test(d&nbsp;date,&nbsp;ts&nbsp;timestamp)"</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">today</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">datetime</span><span class="p_operator">.</span><span class="p_identifier">date</span><span class="p_operator">.</span><span class="p_identifier">today</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">now</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">datetime</span><span class="p_operator">.</span><span class="p_identifier">datetime</span><span class="p_operator">.</span><span class="p_identifier">now</span><span class="p_operator">()</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"insert&nbsp;into&nbsp;test(d,&nbsp;ts)&nbsp;values&nbsp;(?,&nbsp;?)"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_identifier">today</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">now</span><span class="p_operator">))</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;d,&nbsp;ts&nbsp;from&nbsp;test"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">row</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">today</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_string">"=&gt;"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">0</span><span class="p_operator">],</span><span class="p_default">&nbsp;</span><span class="p_identifier">type</span><span class="p_operator">(</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">0</span><span class="p_operator">])</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">now</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_string">"=&gt;"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">1</span><span class="p_operator">],</span><span class="p_default">&nbsp;</span><span class="p_identifier">type</span><span class="p_operator">(</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">1</span><span class="p_operator">])</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_character">'select&nbsp;current_date&nbsp;as&nbsp;"d&nbsp;[date]",&nbsp;current_timestamp&nbsp;as&nbsp;"ts&nbsp;[timestamp]"'</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">row</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">fetchone</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_string">"current_date"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">0</span><span class="p_operator">],</span><span class="p_default">&nbsp;</span><span class="p_identifier">type</span><span class="p_operator">(</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">0</span><span class="p_operator">])</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_string">"current_timestamp"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">1</span><span class="p_operator">],</span><span class="p_default">&nbsp;</span><span class="p_identifier">type</span><span class="p_operator">(</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">1</span><span class="p_operator">])</span>
+</div>
+</div>
+<div class="section">
+<h2><a id="controlling-transactions" name="controlling-transactions">5. Controlling Transactions</a></h2>
+<p>By default, pysqlite opens transactions implicitly before a DML statement
+(<em>INSERT/UPDATE/DELETE/REPLACE</em>), and commits transactions implicitly before a
+non-DML, non-DQL statement (i. e. anything other than
+<em>SELECT/INSERT/UPDATE/DELETE/REPLACE</em>).</p>
+<p>So if you are within a transaction, and issue a command like <tt class="docutils literal"><span class="pre">CREATE</span> <span class="pre">TABLE</span>
+<span class="pre">...</span></tt>, <tt class="docutils literal"><span class="pre">VACUUM</span></tt>, <tt class="docutils literal"><span class="pre">PRAGMA</span></tt>, pysqlite will commit implicitly before executing
+that command. There are two reasons for doing that. The first is that most of
+these commands don't work within transactions. The other reason is that
+pysqlite needs to keep track of the transaction state (if a transaction is
+active or not).</p>
+<p>You can control which kind of &quot;BEGIN&quot; statements pysqlite implicitly executes
+(or none at all) via the <strong>isolation_level</strong> parameter to the <em>connect</em> call,
+or via the <strong>isolation_level</strong> property of connections.</p>
+<p>If you want <em>autocommit mode</em>, then set <strong>isolation_level</strong> to None.</p>
+<p>Otherwise leave it at it's default, which will result in a plain &quot;BEGIN&quot;
+statement, or set it to one of SQLite's supported isolation levels: DEFERRED,
+IMMEDIATE or EXCLUSIVE.</p>
+<p>As pysqlite needs to keep track of the transaction state, you should not use
+<tt class="docutils literal"><span class="pre">OR</span> <span class="pre">ROLLBACK</span></tt> or <tt class="docutils literal"><span class="pre">ON</span> <span class="pre">CONFLICT</span> <span class="pre">ROLLBACK</span></tt>. Instead, catch the
+<tt class="docutils literal"><span class="pre">IntegrityError</span></tt> and call the <tt class="docutils literal"><span class="pre">rollback</span></tt> method of the connection yourself.</p>
+</div>
+<div class="section">
+<h2><a id="using-pysqlite-efficiently" name="using-pysqlite-efficiently">6. Using pysqlite efficiently</a></h2>
+</div>
+<div class="section">
+<h2><a id="using-shortcut-methods" name="using-shortcut-methods">6.1 Using shortcut methods</a></h2>
+<p>Using the nonstandard <tt class="docutils literal"><span class="pre">execute()</span></tt>, <tt class="docutils literal"><span class="pre">executemany()</span></tt> and <tt class="docutils literal"><span class="pre">executescript()</span></tt>
+methods of the Connection object, your code can be written more concisely,
+because you don't have to create the - often superfluous Cursor objects
+explicitly. Instead, the Cursor objects are created implicitly and
+these shortcut methods return the cursor objects. This way, you can for
+example execute a SELECT statement and iterate over it directly using
+only a single call on the Connection object.</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">persons</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_operator">[</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_operator">(</span><span class="p_string">"Hugo"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_string">"Boss"</span><span class="p_operator">),</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_operator">(</span><span class="p_string">"Calvin"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_string">"Klein"</span><span class="p_operator">)</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_operator">]</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">":memory:"</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;Create&nbsp;the&nbsp;table</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"create&nbsp;table&nbsp;person(firstname,&nbsp;lastname)"</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;Fill&nbsp;the&nbsp;table</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">executemany</span><span class="p_operator">(</span><span class="p_string">"insert&nbsp;into&nbsp;person(firstname,&nbsp;lastname)&nbsp;values&nbsp;(?,&nbsp;?)"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">persons</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;Print&nbsp;the&nbsp;table&nbsp;contents</span><span class="p_default"><br/>
+</span><span class="p_word">for</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_default">&nbsp;</span><span class="p_word">in</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;firstname,&nbsp;lastname&nbsp;from&nbsp;person"</span><span class="p_operator">):</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;Using&nbsp;a&nbsp;dummy&nbsp;WHERE&nbsp;clause&nbsp;to&nbsp;not&nbsp;let&nbsp;SQLite&nbsp;take&nbsp;the&nbsp;shortcut&nbsp;table&nbsp;deletes.</span><span class="p_default"><br/>
+</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_string">"I&nbsp;just&nbsp;deleted"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"delete&nbsp;from&nbsp;person&nbsp;where&nbsp;1=1"</span><span class="p_operator">).</span><span class="p_identifier">rowcount</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_string">"rows"</span><span class="p_default"><br/>
+</span>
+</div>
+</div>
+<div class="section">
+<h2><a id="accessing-columns-by-name-instead-of-by-index" name="accessing-columns-by-name-instead-of-by-index">6.2 Accessing columns by name instead of by index</a></h2>
+<p>A cool new feature of pysqlite 2.1.0 is the new builtin sqlite.Row class
+designed to be used as a row factory.</p>
+<p>Rows wrapped with this class can be accessed both by index (like tuples) and
+case-insensitively by name:</p>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">pysqlite2</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbapi2</span><span class="p_default">&nbsp;</span><span class="p_word">as</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">connect</span><span class="p_operator">(</span><span class="p_string">"mydb"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">row_factory</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">sqlite</span><span class="p_operator">.</span><span class="p_identifier">Row</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">cur</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">cursor</span><span class="p_operator">()</span><span class="p_default"><br/>
+</span><span class="p_identifier">cur</span><span class="p_operator">.</span><span class="p_identifier">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;name_last,&nbsp;age&nbsp;from&nbsp;people"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_word">for</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_default">&nbsp;</span><span class="p_word">in</span><span class="p_default">&nbsp;</span><span class="p_identifier">cur</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">assert</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">0</span><span class="p_operator">]</span><span class="p_default">&nbsp;</span><span class="p_operator">==</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_string">"name_last"</span><span class="p_operator">]</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">assert</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_string">"name_last"</span><span class="p_operator">]</span><span class="p_default">&nbsp;</span><span class="p_operator">==</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_string">"nAmE_lAsT"</span><span class="p_operator">]</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">assert</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">1</span><span class="p_operator">]</span><span class="p_default">&nbsp;</span><span class="p_operator">==</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_string">"age"</span><span class="p_operator">]</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_word">assert</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_number">1</span><span class="p_operator">]</span><span class="p_default">&nbsp;</span><span class="p_operator">==</span><span class="p_default">&nbsp;</span><span class="p_identifier">row</span><span class="p_operator">[</span><span class="p_string">"AgE"</span><span class="p_operator">]</span>
+</div>
+</div>
+</div>
+</div>
+</body>
+</html>
diff --git a/doc/usage-guide.txt b/doc/usage-guide.txt
new file mode 100644 (file)
index 0000000..135cf4c
--- /dev/null
@@ -0,0 +1,881 @@
+--------------------
+pysqlite usage guide
+--------------------
+
+| (c) 2004-2005 David Rushby
+| (c) 2005-2006 Gerhard Häring
+
+Last updated for pysqlite 2.2.1
+
+Table Of Contents
+=================
+
+| `0. Introduction`_
+| `1. Python Database API 2.0 Compliance`_
+|   `1.1 Incompatibilities`_
+|   `1.2 Unsupported Optional Features`_
+|   `1.3 Nominally Supported Optional Features`_
+|   `1.4 Extensions and Caveats`_
+| `2. Brief Tutorial`_
+|   `2.1 Connecting to a Database`_
+|   `2.2 Executing SQL statements`_
+| `3. Native Database Engine Features and Extensions Beyond the Python DB API`_
+|   `3.1 Creating user-defined functions`_
+|   `3.2 Creating user-defined aggregates`_
+|   `3.3 Creating and using collations`_
+|   `3.4 Checking for complete statements`_
+|   `3.5 Enabling SQLite's shared cache`_
+| `4. SQLite and Python types`_
+|   `4.1 Introduction`_
+|   `4.2 Using adapters to store additional Python types in SQLite databases`_
+|     `4.2.1 Letting your object adapt itself`_
+|     `4.2.2 Registering an adapter callable`_
+|   `4.3 Converting SQLite values to custom Python types`_
+|   `4.4 Default pysqlite adapters and converters`_
+| `5. Controlling Transactions`_
+| `6. Using pysqlite efficiently`_
+|   `6.1 Using shortcut methods`_
+|   `6.2 Accessing columns by name instead of by index`_
+
+0. Introduction
+===============
+
+This Usage Guide is not a tutorial on Python, SQL, or SQLite; rather, it is a
+topical presentation of pysqlite's feature set, with example code to
+demonstrate basic usage patterns. This guide is meant to be consumed in
+conjunction with the Python Database API Specification and the SQLite
+documentation.
+
+It was originally written by David Rushby for kinterbasdb. He kindly gave the
+permission to adapt it for pysqlite.
+
+1. Python Database API 2.0 Compliance
+=====================================
+
+1.1 Incompatibilities
+---------------------
+
+* No type information in cursor.description
+
+  *cursor.description* has a tuple with the fields (*name*, *type_code*,
+  *display_size*, *internal_size*, *precision*, *scale*, *null_ok*) for each
+  column that a query returns. The DB-API spec requires that at least *name*
+  and *type_code* are filled, but at the time cursor.description is built,
+  pysqlite cannot determine any types, yet. So, the only field of
+  *cursor.description* that pysqlite fills is *name*. All other fields are set to
+  None.
+
+* No type objects
+
+  Consequently, there are also no type objects STRING, BINARY, NUMBER,
+  DATETIME, ROWID at module-level. They would be useless.
+
+1.2 Unsupported Optional Features
+---------------------------------
+
+* **Cursor** class
+
+  * **nextset** method
+
+    This method is not implemented because the database engine does not
+    support opening multiple result sets simultaneously with a single
+    cursor.
+
+1.3 Nominally Supported Optional Features
+-----------------------------------------
+
+* **Cursor** class
+
+  * **arraysize** attribute
+
+    As required by the spec, the value of this attribute is observed
+    with respect to the fetchmany method. However, changing the value
+    of this attribute does not make any difference in fetch efficiency
+    because the database engine only supports fetching a single row at
+    a time.
+
+  * **setinputsizes** method
+
+    Although this method is present, it does nothing, as allowed by the
+    spec.
+
+  * **setoutputsize** method
+
+    Although this method is present, it does nothing, as allowed by the
+    spec.
+
+1.4 Extensions and Caveats
+--------------------------
+
+pysqlite offers a large feature set beyond the minimal requirements of the
+Python DB API. Most of these extensions are documented in the section of this
+document entitled Native Database Engine Features and Extensions Beyond the
+Python DB API.
+
+* **connect** function
+
+  The parameter *database* refers to the database file for the SQLite
+  database. It's a normal filesystem path and you can use absolute or
+  relative path names.
+
+  The connect function supports the following optional keyword arguments
+  in addition to those required by the spec:
+
+  * **timeout** - When a database is accessed by multiple connections, and
+
+    one of the processes modifies the database, the SQLite database is
+    locked until that transaction is committed. The timeout parameter
+    specifies how long the connection should wait for the lock to go away
+    until raising an exception. The default for the timeout parameter is
+    5.0 (five seconds).
+
+    Example:
+     .. code-block:: Python
+
+      sqlite.connect(database="mydb", timeout=10.0)
+
+
+  * **isolation_level** - pysqlite will by default open transactions with a
+    "BEGIN" statement, when it encounters a DML statement like
+    INSERT/UPDATE/DELETE/REPLACE. Some users don't want pysqlite to implicitly
+    open transactions for them - they want an autocommit mode. Other users want
+    pysqlite to open different kinds of transactions, like with "BEGIN
+    IMMEDIATE". See `5. Controlling Transactions`_  for a more detailed
+    explanation.
+
+    Note that you can also switch to a different isolation level by setting the
+    **isolation_level** property of connections.
+
+    Example:
+     .. code-block:: Python
+
+      # Turn on autocommit mode
+      con = sqlite.connect("mydb", isolation_level=None)
+
+      # Set isolation_level to "IMMEDIATE"
+      con.isolation_level = "IMMEDIATE"
+
+  * **detect_types** - SQLite natively supports only the types TEXT,
+    INTEGER, FLOAT, BLOB and NULL. If you want to use other types, like you
+    have to add support for them yourself.  The *detect_types* parameter and
+    using custom *converters* registered with the module-level
+    *register_converter* function allow you to easily do that.
+
+    *detect_types* defaults to 0 (i. e. off, no type detection), you can
+    set it to any combination of *PARSE_DECLTYPES* and *PARSE_COLNAMES* to turn
+    type detection on.
+
+    Consult the section `4. SQLite and Python types`_ of this manual for
+    details.
+
+    * **sqlite.PARSE_DECLTYPES** - This makes pysqlite parse the declared
+      type for each column it returns. It will parse out the first word of the
+      declared type, i. e. for "integer primary key", it will parse out
+      "integer". Then for that column, it will look into pysqlite's converters
+      dictionary and use the converter function registered for that type there.
+      Converter names are case-sensitive!
+
+    * **sqlite.PARSE_COLNAMES** - This makes pysqlite parse the column name
+      for each column it returns. It will look for a string formed
+      [mytype] in there, and then decide that 'mytype' is the type of
+      the column. It will try to find an entry of 'mytype' in the
+      converters dictionary and then use the converter function found
+      there to return the value. The column name found in
+      cursor.description is only the first word of the column name, i.
+      e. if you use something like 'as "x [datetime]"' in your SQL,
+      then pysqlite will parse out everything until the first blank for
+      the column name: the column name would simply be "x".
+
+      The following example uses the column name *timestamp*, which is already
+      registered by default in the converters dictionary with an appropriate
+      converter! Note that converter names are case-sensitive!
+
+      Example:
+
+      .. code-block::
+       :language: Python
+       :source-file: code/parse_colnames.py
+
+  * **check_same_thread** - SQLite connections/cursors can only safely be
+    used in the same thread they were created in. pysqlite checks for
+    this each time it would do a call to the SQLite engine. If you are
+    confident that you are ensuring safety otherwise, you can disable
+    that checks by setting check_same_thread to False.
+
+  * **factory** - By default, pysqlite uses the Connection class for the
+    connect call. You can, however, subclass the Connection class and
+    make .connect() use your class instead by providing your class for
+    the factory parameter.
+
+    Example:
+
+    .. code-block::
+     :language: Python
+     :source-file: code/countcursors.py
+
+  * **cached_statements** - pysqlite internally uses a statement cache to avoid
+    SQL parsing overhead. If you want to explicitly set the number of
+    statements that are cached for the connection, you can set this parameter.
+    The currently implemented default is to cache 100 statements.
+
+  |
+  |
+
+* **register_converter** function - ``register_converter(typename, callable)``
+  registers a callable to convert a bytestring from the database into a custom
+  Python type. The converter will be invoked for all database values that are
+  of the type ``typename``. Confer the parameter **detect_types** of the
+  **connect** method for how the type detection works. Note that the case
+  ``typename`` and the name of the type in your query must match!
+
+* **register_adapter** function - ``register_adapter(type, callable)``
+  registers a callable to convert the custom Python **type** into one of
+  SQLite's supported types. The callable accepts as single parameter the Python
+  value, and must return a value of the following types: int, long, float, str
+  (UTF-8 encoded), unicode or buffer.
+
+* **Connection** class
+
+  * **isolation_level** attribute (read-write)
+
+    Get or set the current *isolation level*: None for autocommit mode or one
+    of "DEFERRED", "IMMEDIATE" or "EXLUSIVE". See `5. Controlling
+    Transactions`_ for a more detailed explanation.
+
+  * **cursor method** - The cursor method accepts a single optional parameter:
+    a custom cursor class extending pysqlite's *Cursor* class that you can
+    adapt to your needs. Note that it is required that your custom cursor class
+    extends pysqlite's *Cursor* class.
+
+  * **execute method** - Nonstandard - this works as a shortcut for not having
+    to create a cursor object and is implemented like this:
+
+     .. code-block:: Python
+
+      class Connection:
+        def execute(self, *args):
+          cur = self.cursor()
+          cur.execute(*args)
+          return cur
+
+  * **executemany method** - Nonstandard - The same shortcut as the nonstandard
+    ``execute`` method.
+
+  * **executesript method** - Nonstandard - The same shortcut as the nonstandard
+    ``execute`` method.
+
+  * **row_factory** attribute (read-write)
+
+    You can change this attribute to a callable that accepts the cursor and
+    the original row as tuple and will return the real result row.  This
+    way, you can implement more advanced ways of returning results, like
+    ones that can also access columns by name.
+
+    Example:
+
+    .. code-block::
+     :language: Python
+     :source-file: code/row_factory.py
+
+    If the standard tuple types don't suffice for you, and you want name-based
+    access to columns, you should consider setting ``row_factory`` to the
+    highly-optimized ``pysqlite2.dbapi2.Row`` type. It provides both
+    index-based and case-insensitive name-based access to columns with almost
+    no memory overhead. Much better than your own custom dictionary-based
+    approach or even a ``db_row`` based solution.
+
+  * **text_factory** attribute (read-write)
+
+    Using this attribute you can control what objects pysqlite returns for the
+    TEXT data type. By default, this attribute is set to ``unicode`` and
+    pysqlite will return Unicode objects for TEXT. If you want to return
+    bytestrings instead, you can set it to ``str``.
+
+    For efficiency reasons, there's also a way to return Unicode objects only
+    for non-ASCII data, and bytestrings otherwise. To activate it, set this
+    attribute to ``pysqlite2.dbapi2.OptimizedUnicode``.
+
+    You can also set it to any other callable that accepts a single bytestring
+    parameter and returns the result object.
+
+    See the following example code for illustration:
+
+     .. code-block::
+      :language: Python
+      :source-file: code/text_factory.py
+
+  * **total_changes** attribute (read-only)
+
+    Returns the total number of database rows that have be modified, inserted,
+    or deleted since the database connection was opened.
+
+  |
+* **Cursor** class
+
+  * **execute** method
+
+    pysqlite uses *paramstyle = "qmark"*. That means if you use parametrized
+    statements, you use the question mark as placeholder.
+
+    This is a basic example showing the use of question marks as placeholders
+    and a parameter tuple:
+
+    .. code-block::
+     :language: Python
+     :source-file: code/execute_1.py
+
+    pysqlite also supports *paramstyle = "named"*. That means you can use named
+    placeholders in the format ":name", i. e. a colon followed by the parameter
+    name. As parameters, you then supply a mapping instead of a sequence. In
+    the simplest case, a dictionary instead of a tuple.
+
+    .. code-block::
+     :language: Python
+     :source-file: code/execute_2.py
+
+    The following example shows a shortcut that you can often use when using
+    named parameters. It exploits the fact that locals() is a dictionary, too.
+    So you can also use it as parameter for *execute*:
+
+    .. code-block::
+     :language: Python
+     :source-file: code/execute_3.py
+
+    *execute* will only execute a single SQL statement. If you try to execute
+    more than one statement with it, it will raise a Warning. Use
+    *executescript* if want to execute multiple SQL statements with one call.
+
+
+  * **executemany** method
+
+    The DB-API specifies the executemany method like this:
+
+    .. code-block:: Python
+
+      .executemany(operation, seq_of_parameters)
+
+    pysqlite, however, extends *executemany* so it can be used more efficiently
+    for inserting bulk data. The second parameter to *executemany* can be a
+    *sequence of parameters*, but it can also be an *iterator* returning
+    parameters.
+
+    Example:
+
+    .. code-block::
+     :language: Python
+     :source-file: code/executemany_1.py
+
+    As generators are iterators, too, here's a much simpler, equivalent example
+    using a generator:
+
+    .. code-block::
+     :language: Python
+     :source-file: code/executemany_2.py
+
+    *executemany* will only execute a single SQL statement. If you try to
+    execute more than one statement with it, it will raise a Warning. Use
+    *executescript* if want to execute multiple SQL statements with one call.
+
+* **executescript** method
+
+    .. code-block:: Python
+
+        .executemany(sqlscript)
+
+    This is a nonstandard convenience method for executing multiple SQL
+    statements at once. It issues a COMMIT statement before, then executes the
+    SQL script it gets as a parameter.
+
+    The SQL script ``sqlscript`` can be a bytestring or a Unicode string.
+
+    Example:
+
+    .. code-block::
+     :language: Python
+     :source-file: code/executescript.py
+
+  * **rowcount** attribute
+
+    Although pysqlite's Cursors implement this attribute, the database
+    engine's own support for the determination of "rows affected"/"rows
+    selected" is quirky.
+
+    For ``SELECT`` statements, *rowcount* is always None because pysqlite
+    cannot determine the number of rows a query produced until all rows
+    were fetched.
+
+    For ``DELETE`` statements, SQLite reports *rowcount* as 0 if you make a
+    ``DELETE FROM table`` without any condition.
+
+    For *executemany* statements, pysqlite sums up the number of
+    modifications into *rowcount*.
+
+    As required by the Python DB API Spec, the *rowcount* attribute "is -1
+    in case no executeXX() has been performed on the cursor or the rowcount
+    of the last operation is not determinable by the interface".
+
+|
+
+----
+
+|
+
+2. Brief Tutorial
+=================
+
+This brief tutorial aims to get the reader started by demonstrating elementary
+usage of pysqlite. It is not a comprehensive Python Database API tutorial, nor
+is it comprehensive in its coverage of anything else.
+
+2.1 Connecting to a Database
+----------------------------
+
+    **Example 1**
+
+    Connecting to a database file *mydb*:
+
+    .. code-block::
+     :language: Python
+     :source-file: code/connect_db_1.py
+
+
+    **Example 2**
+
+    Creating an in-memory database:
+
+    .. code-block::
+     :language: Python
+     :source-file: code/connect_db_2.py
+
+
+2.2 Executing SQL statements
+----------------------------
+
+For this section, we have a database *mydb* defined and populated by the
+following SQL code:
+
+  .. code-block:: SQL
+
+    create table people
+    (
+      name_last      varchar(20),
+      age            integer
+    );
+
+    insert into people (name_last, age) values ('Yeltsin',   72);
+    insert into people (name_last, age) values ('Putin',     51);
+
+*Example 1*
+
+This example shows the simplest way to print the entire contents of the ``people`` table:
+
+.. code-block::
+ :language: Python
+ :source-file: code/execsql_printall_1.py
+
+Sample output::
+
+  [(u'Putin', 51), (u'Yeltsin', 72)]
+
+*Example 2*
+
+Here's another trivial example that demonstrates various ways of fetching a
+single row at a time from a SELECT-cursor:
+
+.. code-block::
+ :language: Python
+ :source-file: code/execsql_fetchonerow.py
+
+Sample output::
+
+  Putin is 51 years old.
+  Yeltsin is 72 years old.
+  Putin is 51 years old.
+  Yeltsin is 72 years old.
+
+*Example 3*
+
+The following program is a simplistic table printer (applied in this example to
+people)
+
+.. code-block::
+ :language: Python
+ :source-file: code/simple_tableprinter.py
+
+Sample output::
+
+  name_last            age
+  ------------------------------------------------------------------------------
+  Putin                51
+  Yeltsin              72
+
+*Example 4*
+
+Let's insert more people into the people table: 
+
+.. code-block::
+ :language: Python
+ :source-file: code/insert_more_people.py
+
+Note the use of a parameterized SQL statement above. When dealing with
+repetitive statements, this is much faster and less error-prone than assembling
+each SQL statement manually.
+
+It's also worth noting that in the example above, the code: 
+
+It's also worth noting that in the example above, the code:
+
+.. code-block:: Python
+
+  for person in newPeople:
+      cur.execute("insert into people (name_last, age) values (?, ?)", person)
+
+could be rewritten as:
+
+.. code-block:: Python
+
+  cur.executemany("insert into people (name_last, age) values (?, ?)", newPeople)
+
+After running Example 4, the table printer from Example 3 would print::
+
+  name_last            age
+  ------------------------------------------------------------------------------
+  Putin                51
+  Lebed                53
+  Zhirinovsky          57
+  Yeltsin              72
+
+|
+
+----
+
+|
+
+3. Native Database Engine Features and Extensions Beyond the Python DB API
+==========================================================================
+
+3.1 Creating user-defined functions
+-----------------------------------
+
+SQLite supports user-defined functions.  Using pysqlite, you can create new
+functions with the connection's **create_function** method:
+
+  .. code-block:: Python
+
+    def create_function(self, name, numparams, func)
+
+  *name*
+    the name of your function in SQL
+  *numparams*
+    the number of parameters your function accepts, -1 if it accepts any
+    number of parameters
+  *func*
+    the Python function
+
+  The function can return any of pysqlite's supported SQLite types: unicode,
+  str, int, long, float, buffer and None.  The function should never raise an
+  exception.
+
+  Example:
+
+  .. code-block::
+   :language: Python
+   :source-file: code/md5func.py
+
+3.2 Creating user-defined aggregates
+------------------------------------
+
+SQLite supports user-defined aggregate functions. Using pysqlite, you can
+create new aggregate functions with the connection's *create_aggregate* method.
+
+  .. code-block:: Python
+
+    def create_aggregate(self, name, numparams, aggregate_class)
+
+  The aggregate class must implement a *step* method, which accepts the
+  number of parameters defined in *create_aggregate*, and a *finalize*
+  method which will return the final result of the aggregate.
+
+  The *finalize* method can return any of pysqlite's supported SQLite types:
+  unicode, str, int, long, float, buffer and None. The aggregate class's
+  methods should never raise any exception.
+
+  Example:
+
+  .. code-block::
+   :language: Python
+   :source-file: code/mysumaggr.py
+
+3.3 Creating and using collations
+---------------------------------
+
+  .. code-block:: Python
+
+    def create_collation(name, callable)
+
+Creates a collation with the specified name and callable. The callable will be
+passed two string arguments. It should return -1 if the first is less than the
+second, 0 if they are equal and 1 and if the first is greater than the second.
+Note that this controls sorting (ORDER BY in SQL) so your comparisons don't
+affect other SQL operations. Read more about SQLite's handling of collations.
+(This calls sqlite3_create_collation.) If there is an error in your Python code
+then 0 (ie items are equal) is returned.
+
+Note that the callable will get its parameters as Python bytestrings, which
+will normally be encoded in UTF-8.
+
+The following example shows a custom collation that sorts "the wrong way":
+
+  .. code-block::
+   :language: Python
+   :source-file: code/collation_reverse.py
+
+To remove a collation, call `create_collation` with None as callable:
+
+  .. code-block:: Python
+
+    con.create_collation("reverse", None)
+
+3.4 Checking for complete statements
+------------------------------------
+
+The module-level function *complete_statement(sql)* can be used to check if a
+string contains a complete SQL statement or is still incomplete. The given
+string could still contain invalid SQL, but be parsable as a "complete"
+statement!
+
+This can be used to build a shell for SQLite, like in the following example:
+
+  .. code-block::
+   :language: Python
+   :source-file: code/complete_statement.py
+
+3.5 Enabling SQLite's shared cache
+----------------------------------
+
+To enable SQLite's shared cache for the calling thread, call the function
+*enable_shared_cache*.
+
+  .. code-block::
+   :language: Python
+   :source-file: code/shared_cache.py
+
+4. SQLite and Python types
+==========================
+
+4.1 Introduction
+----------------
+
+http://sqlite.org/datatype3.html
+
+SQLite natively supports the following types: NULL, INTEGER, REAL, TEXT, BLOB.
+
+The following Python types can thus be sent to SQLite without any problem:
+
+======================  ===========
+Python type             SQLite type
+======================  ===========
+NoneType                NULL
+int                     INTEGER
+long                    INTEGER
+float                   REAL
+str (utf-8 encoded)     TEXT
+unicode                 TEXT
+buffer                  BLOB
+======================  ===========
+
+This is how SQLite types are converted to Python types by default:
+
+===========  ==============================
+SQLite type  Python type
+===========  ==============================
+NULL         NoneType
+INTEGER      int or long, depending on size
+REAL         float
+TEXT         unicode
+BLOB         buffer
+===========  ==============================
+
+pysqlite's type system is extensible in both ways: you can store additional
+Python types in a SQLite database via object adaptation, and you can let
+pysqlite convert SQLite types to different Python types via pysqlite's
+converters.
+
+4.2 Using adapters to store additional Python types in SQLite databases
+-----------------------------------------------------------------------
+
+Like described before, SQLite supports only a limited set of types natively. To
+use other Python types with SQLite, you must *adapt* them to one of pysqlite's
+supported types for SQLite. So, one of NoneType, int, long, float, str,
+unicode, buffer.
+
+pysqlite uses the Python object adaptation, like described in PEP 246 for this.
+The protocol to use is ``PrepareProtocol``.
+
+There are two ways to enable pysqlite to adapt a custom Python type to one of
+the supported ones.
+
+4.2.1 Letting your object adapt itself
+--------------------------------------
+
+This is a good approach if you write the class yourself. Let's suppose you have
+a class like this:
+
+  .. code-block:: Python
+
+    class Point(object):
+        def __init__(self, x, y):
+            self.x, self.y = x, y
+
+Now you want to store the point in a single SQLite column. You'll have to
+choose one of the supported types first that you use to represent the point in.
+Let's just use str and separate the coordinates using a semicolon. Then you
+need to give your class a method ``__conform__(self, protocol)`` which must
+return the converted value. The parameter ``protocol`` will be
+``PrepareProtocol``.
+
+.. code-block::
+ :language: Python
+ :source-file: code/adapter_point_1.py
+
+4.2.2 Registering an adapter callable
+-------------------------------------
+
+The other possibility is to create a function that converts the type to the
+string representation and register the function with ``register_adapter``.
+
+.. code-block::
+ :language: Python
+ :source-file: code/adapter_point_2.py
+
+The type/class to adapt must be a new-style class, i. e. it must have
+``object`` as one of its bases!!!
+
+pysqlite has two default adapters for Python's builtin *date* and *datetime*
+types. Now let's suppose we want to store *datetime* objects not in ISO
+representation, but as Unix timestamp.
+
+.. code-block::
+ :language: Python
+ :source-file: code/adapter_datetime.py
+
+4.3 Converting SQLite values to custom Python types
+---------------------------------------------------
+
+Now that's all nice and dandy that you can send custom Python types to SQLite.
+But to make it really useful we need to make the Python to SQLite to Python
+roundtrip work.
+
+Enter pysqlite converters.
+
+Let's go back to the Point class. We stored the x and y coordinates separated
+via semicolons as strings in SQLite.
+
+Let's first define a converter function that accepts the string as a parameter and constructs a Point object from it.
+
+!!! Note that converter functions *always* get called with a string, no matter
+under which data type you sent the value to SQLite !!!
+
+!!! Also note that converter names are looked up in a case-sensitive manner !!!
+
+  .. code-block:: Python
+
+    def convert_point(s):
+        x, y = map(float, s.split(";"))
+        return Point(x, y)
+
+Now you need to make pysqlite know that what you select from the database is
+actually a point. There are two ways of doing this:
+
+ * Implicitly via the declared type
+ * Explicitly via the column name
+
+Both ways are described in section `1.4 Extensions and Caveats`_ in the
+paragraphs describing the connect function, and specifically the meaning of the
+*detect_types* parameter.
+
+The following example illustrates both ways.
+
+.. code-block::
+ :language: Python
+ :source-file: code/converter_point.py
+
+4.4 Default pysqlite adapters and converters
+--------------------------------------------
+
+pysqlite has default adapters for the date and datetime types in the datetime
+module. They will be sent as ISO dates/ISO timestamps to SQLite.
+
+pysqlite has default converters registered under the name "date" for
+datetime.date and under the name "timestamp" for datetime.datetime.
+
+This way, you can use date/timestamps from pysqlite without any additional
+fiddling in most cases. The format of the adapters is also compatible with the
+experimental SQLite date/time functions.
+
+The following example demonstrates this.
+
+.. code-block::
+ :language: Python
+ :source-file: code/pysqlite_datetime.py
+
+5. Controlling Transactions
+---------------------------
+
+By default, pysqlite opens transactions implicitly before a DML statement
+(*INSERT/UPDATE/DELETE/REPLACE*), and commits transactions implicitly before a
+non-DML, non-DQL statement (i. e. anything other than
+*SELECT/INSERT/UPDATE/DELETE/REPLACE*).
+
+So if you are within a transaction, and issue a command like ``CREATE TABLE
+...``, ``VACUUM``, ``PRAGMA``, pysqlite will commit implicitly before executing
+that command. There are two reasons for doing that. The first is that most of
+these commands don't work within transactions. The other reason is that
+pysqlite needs to keep track of the transaction state (if a transaction is
+active or not).
+
+You can control which kind of "BEGIN" statements pysqlite implicitly executes
+(or none at all) via the **isolation_level** parameter to the *connect* call,
+or via the **isolation_level** property of connections.
+
+If you want *autocommit mode*, then set **isolation_level** to None.
+
+Otherwise leave it at it's default, which will result in a plain "BEGIN"
+statement, or set it to one of SQLite's supported isolation levels: DEFERRED,
+IMMEDIATE or EXCLUSIVE.
+
+As pysqlite needs to keep track of the transaction state, you should not use
+``OR ROLLBACK`` or ``ON CONFLICT ROLLBACK``. Instead, catch the
+``IntegrityError`` and call the ``rollback`` method of the connection yourself.
+
+6. Using pysqlite efficiently
+-----------------------------
+
+6.1 Using shortcut methods
+--------------------------
+
+Using the nonstandard ``execute()``, ``executemany()`` and ``executescript()``
+methods of the Connection object, your code can be written more concisely,
+because you don't have to create the - often superfluous Cursor objects
+explicitly. Instead, the Cursor objects are created implicitly and
+these shortcut methods return the cursor objects. This way, you can for
+example execute a SELECT statement and iterate over it directly using
+only a single call on the Connection object.
+
+.. code-block::
+ :language: Python
+ :source-file: code/shortcut_methods.py
+
+6.2 Accessing columns by name instead of by index
+-------------------------------------------------
+
+A cool new feature of pysqlite 2.1.0 is the new builtin sqlite.Row class
+designed to be used as a row factory.
+
+Rows wrapped with this class can be accessed both by index (like tuples) and
+case-insensitively by name:
+
+.. code-block::
+ :language: Python
+ :source-file: code/rowclass.py
+
diff --git a/docutilsupport.py b/docutilsupport.py
new file mode 100644 (file)
index 0000000..e79842a
--- /dev/null
@@ -0,0 +1,82 @@
+#!/usr/bin/env python\r
+\r
+import SilverCity\r
+import docutils.parsers.rst\r
+import StringIO\r
+\r
+def code_block( name, arguments, options, content, lineno,\r
+             content_offset, block_text, state, state_machine ):\r
+  """\r
+  The code-block directive provides syntax highlighting for blocks\r
+  of code.  It is used with the the following syntax::\r
+  \r
+  .. code-block:: CPP\r
+     \r
+    #include <iostream>\r
+    \r
+    int main( int argc, char* argv[] )\r
+    {\r
+      std::cout << "Hello world" << std::endl;\r
+    }\r
+    \r
+  The directive requires the name of a language supported by SilverCity\r
+  as its only argument.  All code in the indented block following\r
+  the directive will be colourized.  Note that this directive is only\r
+  supported for HTML writers.\r
+\r
+  The directive can also be told to include a source file directly::\r
+\r
+  .. code-block::\r
+     :language: Python\r
+     :source-file: ../myfile.py\r
+\r
+  You cannot both specify a source-file and include code directly.\r
+  """\r
+\r
+  try:\r
+    language = arguments[0]\r
+  except IndexError:\r
+    language = options['language']\r
+\r
+  if content and 'source-file' in options:\r
+    error = state_machine.reporter.error( "You cannot both specify a source-file and include code directly.",\r
+                                          docutils.nodes.literal_block(block_text,block_text), line=lineno)\r
+    return [error]\r
+\r
+  if not content:\r
+    try:\r
+      content = [line.rstrip() for line in file(options['source-file'])]\r
+    except KeyError:\r
+      # source-file was not specified\r
+      pass\r
+    except IOError:\r
+      error = state_machine.reporter.error( "Could not read file %s."%options['source-file'],\r
+                                            docutils.nodes.literal_block(block_text,block_text), line=lineno)\r
+      return [error]\r
+  try:\r
+    module = getattr(SilverCity, language)\r
+    generator = getattr(module, language+"HTMLGenerator")\r
+  except AttributeError:\r
+    error = state_machine.reporter.error( "No SilverCity lexer found "\r
+      "for language '%s'." % language, \r
+      docutils.nodes.literal_block(block_text, block_text), line=lineno )\r
+    return [error]\r
+  io = StringIO.StringIO()\r
+  generator().generate_html( io, '\n'.join(content) )\r
+  html = '<div class="code-block">\n%s\n</div>\n' % io.getvalue()\r
+  raw = docutils.nodes.raw('',html, format = 'html')\r
+  return [raw]\r
+\r
+#code_block.arguments = (1,0,0)\r
+code_block.arguments = (0,2,1)\r
+code_block.options = {'language' : docutils.parsers.rst.directives.unchanged,\r
+                      'source-file' : docutils.parsers.rst.directives.path,}\r
+code_block.content = 1\r
+  \r
+# Simply importing this module will make the directive available.\r
+docutils.parsers.rst.directives.register_directive( 'code-block', code_block )\r
+\r
+if __name__ == "__main__":\r
+  import docutils.core\r
+  docutils.core.publish_cmdline(writer_name='html')\r
+\r
diff --git a/pysqlite2/__init__.py b/pysqlite2/__init__.py
new file mode 100644 (file)
index 0000000..f6c5eff
--- /dev/null
@@ -0,0 +1,22 @@
+#-*- coding: ISO-8859-1 -*-
+# pysqlite2/__init__.py: the pysqlite2 package.
+#
+# Copyright (C) 2005 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.
diff --git a/pysqlite2/dbapi2.py b/pysqlite2/dbapi2.py
new file mode 100644 (file)
index 0000000..4170e86
--- /dev/null
@@ -0,0 +1,88 @@
+#-*- coding: ISO-8859-1 -*-
+# pysqlite2/dbapi2.py: the DB-API 2.0 interface
+#
+# Copyright (C) 2004-2005 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.
+
+import datetime
+import time
+
+from pysqlite2._sqlite import *
+
+paramstyle = "qmark"
+
+threadsafety = 1
+
+apilevel = "2.0"
+
+Date = datetime.date
+
+Time = datetime.time
+
+Timestamp = datetime.datetime
+
+def DateFromTicks(ticks):
+    return apply(Date, time.localtime(ticks)[:3])
+
+def TimeFromTicks(ticks):
+    return apply(Time, time.localtime(ticks)[3:6])
+
+def TimestampFromTicks(ticks):
+    return apply(Timestamp, time.localtime(ticks)[:6])
+
+version_info = tuple([int(x) for x in version.split(".")])
+sqlite_version_info = tuple([int(x) for x in sqlite_version.split(".")]) 
+
+Binary = buffer
+
+def register_adapters_and_converters():
+    def adapt_date(val):
+        return val.isoformat()
+
+    def adapt_datetime(val):
+        return val.isoformat(" ")
+
+    def convert_date(val):
+        return datetime.date(*map(int, val.split("-")))
+
+    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(float("0." + timepart_full[1]) * 1000000)
+        else:
+            microseconds = 0
+
+        val = datetime.datetime(year, month, day, hours, minutes, seconds, microseconds)
+        return val
+
+
+    register_adapter(datetime.date, adapt_date)
+    register_adapter(datetime.datetime, adapt_datetime)
+    register_converter("date", convert_date)
+    register_converter("timestamp", convert_timestamp)
+
+register_adapters_and_converters()
+
+# Clean up namespace
+
+del(register_adapters_and_converters)
diff --git a/pysqlite2/test/__init__.py b/pysqlite2/test/__init__.py
new file mode 100644 (file)
index 0000000..f07ad15
--- /dev/null
@@ -0,0 +1,35 @@
+#-*- coding: ISO-8859-1 -*-
+# pysqlite2/test/__init__.py: the package containing the test suite
+#
+# Copyright (C) 2004-2006 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.
+
+import unittest
+from pysqlite2.test import dbapi, types, userfunctions, factory, transactions,\
+    hooks, regression
+
+def suite():
+    return unittest.TestSuite(
+        (dbapi.suite(), types.suite(), userfunctions.suite(), factory.suite(),\
+         transactions.suite(), hooks.suite(), regression.suite()))
+
+def test():
+    runner = unittest.TextTestRunner()
+    runner.run(suite())
diff --git a/pysqlite2/test/dbapi.py b/pysqlite2/test/dbapi.py
new file mode 100644 (file)
index 0000000..408836a
--- /dev/null
@@ -0,0 +1,732 @@
+#-*- coding: ISO-8859-1 -*-
+# pysqlite2/test/dbapi.py: tests for DB-API compliance
+#
+# Copyright (C) 2004-2005 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.
+
+import unittest
+import threading
+import pysqlite2.dbapi2 as sqlite
+
+class ModuleTests(unittest.TestCase):
+    def CheckAPILevel(self):
+        self.assertEqual(sqlite.apilevel, "2.0",
+                         "apilevel is %s, should be 2.0" % sqlite.apilevel)
+
+    def CheckThreadSafety(self):
+        self.assertEqual(sqlite.threadsafety, 1,
+                         "threadsafety is %d, should be 1" % sqlite.threadsafety)
+
+    def CheckParamStyle(self):
+        self.assertEqual(sqlite.paramstyle, "qmark",
+                         "paramstyle is '%s', should be 'qmark'" %
+                         sqlite.paramstyle)
+
+    def CheckWarning(self):
+        self.assert_(issubclass(sqlite.Warning, StandardError),
+                     "Warning is not a subclass of StandardError")
+
+    def CheckError(self):
+        self.failUnless(issubclass(sqlite.Error, StandardError),
+                        "Error is not a subclass of StandardError")
+
+    def CheckInterfaceError(self):
+        self.failUnless(issubclass(sqlite.InterfaceError, sqlite.Error),
+                        "InterfaceError is not a subclass of Error")
+
+    def CheckDatabaseError(self):
+        self.failUnless(issubclass(sqlite.DatabaseError, sqlite.Error),
+                        "DatabaseError is not a subclass of Error")
+
+    def CheckDataError(self):
+        self.failUnless(issubclass(sqlite.DataError, sqlite.DatabaseError),
+                        "DataError is not a subclass of DatabaseError")
+
+    def CheckOperationalError(self):
+        self.failUnless(issubclass(sqlite.OperationalError, sqlite.DatabaseError),
+                        "OperationalError is not a subclass of DatabaseError")
+
+    def CheckIntegrityError(self):
+        self.failUnless(issubclass(sqlite.IntegrityError, sqlite.DatabaseError),
+                        "IntegrityError is not a subclass of DatabaseError")
+
+    def CheckInternalError(self):
+        self.failUnless(issubclass(sqlite.InternalError, sqlite.DatabaseError),
+                        "InternalError is not a subclass of DatabaseError")
+
+    def CheckProgrammingError(self):
+        self.failUnless(issubclass(sqlite.ProgrammingError, sqlite.DatabaseError),
+                        "ProgrammingError is not a subclass of DatabaseError")
+
+    def CheckNotSupportedError(self):
+        self.failUnless(issubclass(sqlite.NotSupportedError,
+                                   sqlite.DatabaseError),
+                        "NotSupportedError is not a subclass of DatabaseError")
+
+class ConnectionTests(unittest.TestCase):
+    def setUp(self):
+        self.cx = sqlite.connect(":memory:")
+        cu = self.cx.cursor()
+        cu.execute("create table test(id integer primary key, name text)")
+        cu.execute("insert into test(name) values (?)", ("foo",))
+
+    def tearDown(self):
+        self.cx.close()
+
+    def CheckCommit(self):
+        self.cx.commit()
+
+    def CheckCommitAfterNoChanges(self):
+        """
+        A commit should also work when no changes were made to the database.
+        """
+        self.cx.commit()
+        self.cx.commit()
+
+    def CheckRollback(self):
+        self.cx.rollback()
+
+    def CheckRollbackAfterNoChanges(self):
+        """
+        A rollback should also work when no changes were made to the database.
+        """
+        self.cx.rollback()
+        self.cx.rollback()
+
+    def CheckCursor(self):
+        cu = self.cx.cursor()
+
+    def CheckFailedOpen(self):
+        YOU_CANNOT_OPEN_THIS = "/foo/bar/bla/23534/mydb.db"
+        try:
+            con = sqlite.connect(YOU_CANNOT_OPEN_THIS)
+        except sqlite.OperationalError:
+            return
+        self.fail("should have raised an OperationalError")
+
+    def CheckClose(self):
+        self.cx.close()
+
+    def CheckExceptions(self):
+        # Optional DB-API extension.
+        self.failUnlessEqual(self.cx.Warning, sqlite.Warning)
+        self.failUnlessEqual(self.cx.Error, sqlite.Error)
+        self.failUnlessEqual(self.cx.InterfaceError, sqlite.InterfaceError)
+        self.failUnlessEqual(self.cx.DatabaseError, sqlite.DatabaseError)
+        self.failUnlessEqual(self.cx.DataError, sqlite.DataError)
+        self.failUnlessEqual(self.cx.OperationalError, sqlite.OperationalError)
+        self.failUnlessEqual(self.cx.IntegrityError, sqlite.IntegrityError)
+        self.failUnlessEqual(self.cx.InternalError, sqlite.InternalError)
+        self.failUnlessEqual(self.cx.ProgrammingError, sqlite.ProgrammingError)
+        self.failUnlessEqual(self.cx.NotSupportedError, sqlite.NotSupportedError)
+
+class CursorTests(unittest.TestCase):
+    def setUp(self):
+        self.cx = sqlite.connect(":memory:")
+        self.cu = self.cx.cursor()
+        self.cu.execute("create table test(id integer primary key, name text, income number)")
+        self.cu.execute("insert into test(name) values (?)", ("foo",))
+
+    def tearDown(self):
+        self.cu.close()
+        self.cx.close()
+
+    def CheckExecuteNoArgs(self):
+        self.cu.execute("delete from test")
+
+    def CheckExecuteIllegalSql(self):
+        try:
+            self.cu.execute("select asdf")
+            self.fail("should have raised an OperationalError")
+        except sqlite.OperationalError:
+            return
+        except:
+            self.fail("raised wrong exception")
+
+    def CheckExecuteTooMuchSql(self):
+        try:
+            self.cu.execute("select 5+4; select 4+5")
+            self.fail("should have raised a Warning")
+        except sqlite.Warning:
+            return
+        except:
+            self.fail("raised wrong exception")
+
+    def CheckExecuteTooMuchSql2(self):
+        self.cu.execute("select 5+4; -- foo bar")
+
+    def CheckExecuteTooMuchSql3(self):
+        self.cu.execute("""
+            select 5+4;
+
+            /*
+            foo
+            */
+            """)
+
+    def CheckExecuteWrongSqlArg(self):
+        try:
+            self.cu.execute(42)
+            self.fail("should have raised a ValueError")
+        except ValueError:
+            return
+        except:
+            self.fail("raised wrong exception.")
+
+    def CheckExecuteArgInt(self):
+        self.cu.execute("insert into test(id) values (?)", (42,))
+
+    def CheckExecuteArgFloat(self):
+        self.cu.execute("insert into test(income) values (?)", (2500.32,))
+
+    def CheckExecuteArgString(self):
+        self.cu.execute("insert into test(name) values (?)", ("Hugo",))
+
+    def CheckExecuteWrongNoOfArgs1(self):
+        # too many parameters
+        try:
+            self.cu.execute("insert into test(id) values (?)", (17, "Egon"))
+            self.fail("should have raised ProgrammingError")
+        except sqlite.ProgrammingError:
+            pass
+
+    def CheckExecuteWrongNoOfArgs2(self):
+        # too little parameters
+        try:
+            self.cu.execute("insert into test(id) values (?)")
+            self.fail("should have raised ProgrammingError")
+        except sqlite.ProgrammingError:
+            pass
+
+    def CheckExecuteWrongNoOfArgs3(self):
+        # no parameters, parameters are needed
+        try:
+            self.cu.execute("insert into test(id) values (?)")
+            self.fail("should have raised ProgrammingError")
+        except sqlite.ProgrammingError:
+            pass
+
+    def CheckExecuteDictMapping(self):
+        self.cu.execute("insert into test(name) values ('foo')")
+        self.cu.execute("select name from test where name=:name", {"name": "foo"})
+        row = self.cu.fetchone()
+        self.failUnlessEqual(row[0], "foo")
+
+    def CheckExecuteDictMappingTooLittleArgs(self):
+        self.cu.execute("insert into test(name) values ('foo')")
+        try:
+            self.cu.execute("select name from test where name=:name and id=:id", {"name": "foo"})
+            self.fail("should have raised ProgrammingError")
+        except sqlite.ProgrammingError:
+            pass
+
+    def CheckExecuteDictMappingNoArgs(self):
+        self.cu.execute("insert into test(name) values ('foo')")
+        try:
+            self.cu.execute("select name from test where name=:name")
+            self.fail("should have raised ProgrammingError")
+        except sqlite.ProgrammingError:
+            pass
+
+    def CheckExecuteDictMappingUnnamed(self):
+        self.cu.execute("insert into test(name) values ('foo')")
+        try:
+            self.cu.execute("select name from test where name=?", {"name": "foo"})
+            self.fail("should have raised ProgrammingError")
+        except sqlite.ProgrammingError:
+            pass
+
+    def CheckClose(self):
+        self.cu.close()
+
+    def CheckRowcountExecute(self):
+        self.cu.execute("delete from test")
+        self.cu.execute("insert into test(name) values ('foo')")
+        self.cu.execute("insert into test(name) values ('foo')")
+        self.cu.execute("update test set name='bar'")
+        self.failUnlessEqual(self.cu.rowcount, 2)
+
+    def CheckRowcountExecutemany(self):
+        self.cu.execute("delete from test")
+        self.cu.executemany("insert into test(name) values (?)", [(1,), (2,), (3,)])
+        self.failUnlessEqual(self.cu.rowcount, 3)
+
+    def CheckTotalChanges(self):
+        self.cu.execute("insert into test(name) values ('foo')")
+        self.cu.execute("insert into test(name) values ('foo')")
+        if self.cx.total_changes < 2:
+            self.fail("total changes reported wrong value")
+
+    # Checks for executemany:
+    # Sequences are required by the DB-API, iterators
+    # enhancements in pysqlite.
+
+    def CheckExecuteManySequence(self):
+        self.cu.executemany("insert into test(income) values (?)", [(x,) for x in range(100, 110)])
+
+    def CheckExecuteManyIterator(self):
+        class MyIter:
+            def __init__(self):
+                self.value = 5
+
+            def next(self):
+                if self.value == 10:
+                    raise StopIteration
+                else:
+                    self.value += 1
+                    return (self.value,)
+
+        self.cu.executemany("insert into test(income) values (?)", MyIter())
+
+    def CheckExecuteManyGenerator(self):
+        def mygen():
+            for i in range(5):
+                yield (i,)
+
+        self.cu.executemany("insert into test(income) values (?)", mygen())
+
+    def CheckExecuteManyWrongSqlArg(self):
+        try:
+            self.cu.executemany(42, [(3,)])
+            self.fail("should have raised a ValueError")
+        except ValueError:
+            return
+        except:
+            self.fail("raised wrong exception.")
+
+    def CheckExecuteManySelect(self):
+        try:
+            self.cu.executemany("select ?", [(3,)])
+            self.fail("should have raised a ProgrammingError")
+        except sqlite.ProgrammingError:
+            return
+        except:
+            self.fail("raised wrong exception.")
+
+    def CheckExecuteManyNotIterable(self):
+        try:
+            self.cu.executemany("insert into test(income) values (?)", 42)
+            self.fail("should have raised a TypeError")
+        except TypeError:
+            return
+        except Exception, e:
+            print "raised", e.__class__
+            self.fail("raised wrong exception.")
+
+    def CheckFetchIter(self):
+        # Optional DB-API extension.
+        self.cu.execute("delete from test")
+        self.cu.execute("insert into test(id) values (?)", (5,))
+        self.cu.execute("insert into test(id) values (?)", (6,))
+        self.cu.execute("select id from test order by id")
+        lst = []
+        for row in self.cu:
+            lst.append(row[0])
+        self.failUnlessEqual(lst[0], 5)
+        self.failUnlessEqual(lst[1], 6)
+
+    def CheckFetchone(self):
+        self.cu.execute("select name from test")
+        row = self.cu.fetchone()
+        self.failUnlessEqual(row[0], "foo")
+        row = self.cu.fetchone()
+        self.failUnlessEqual(row, None)
+
+    def CheckFetchoneNoStatement(self):
+        cur = self.cx.cursor()
+        row = cur.fetchone()
+        self.failUnlessEqual(row, None)
+
+    def CheckArraySize(self):
+        # must default ot 1
+        self.failUnlessEqual(self.cu.arraysize, 1)
+
+        # now set to 2
+        self.cu.arraysize = 2
+
+        # now make the query return 3 rows
+        self.cu.execute("delete from test")
+        self.cu.execute("insert into test(name) values ('A')")
+        self.cu.execute("insert into test(name) values ('B')")
+        self.cu.execute("insert into test(name) values ('C')")
+        self.cu.execute("select name from test")
+        res = self.cu.fetchmany()
+
+        self.failUnlessEqual(len(res), 2)
+
+    def CheckFetchmany(self):
+        self.cu.execute("select name from test")
+        res = self.cu.fetchmany(100)
+        self.failUnlessEqual(len(res), 1)
+        res = self.cu.fetchmany(100)
+        self.failUnlessEqual(res, [])
+
+    def CheckFetchall(self):
+        self.cu.execute("select name from test")
+        res = self.cu.fetchall()
+        self.failUnlessEqual(len(res), 1)
+        res = self.cu.fetchall()
+        self.failUnlessEqual(res, [])
+
+    def CheckSetinputsizes(self):
+        self.cu.setinputsizes([3, 4, 5])
+
+    def CheckSetoutputsize(self):
+        self.cu.setoutputsize(5, 0)
+
+    def CheckSetoutputsizeNoColumn(self):
+        self.cu.setoutputsize(42)
+
+    def CheckCursorConnection(self):
+        # Optional DB-API extension.
+        self.failUnlessEqual(self.cu.connection, self.cx)
+
+    def CheckWrongCursorCallable(self):
+        try:
+            def f(): pass
+            cur = self.cx.cursor(f)
+            self.fail("should have raised a TypeError")
+        except TypeError:
+            return
+        self.fail("should have raised a ValueError")
+
+    def CheckCursorWrongClass(self):
+        class Foo: pass
+        foo = Foo()
+        try:
+            cur = sqlite.Cursor(foo)
+            self.fail("should have raised a ValueError")
+        except TypeError:
+            pass
+
+class ThreadTests(unittest.TestCase):
+    def setUp(self):
+        self.con = sqlite.connect(":memory:")
+        self.cur = self.con.cursor()
+        self.cur.execute("create table test(id integer primary key, name text, bin binary, ratio number, ts timestamp)")
+
+    def tearDown(self):
+        self.cur.close()
+        self.con.close()
+
+    def CheckConCursor(self):
+        def run(con, errors):
+            try:
+                cur = con.cursor()
+                errors.append("did not raise ProgrammingError")
+                return
+            except sqlite.ProgrammingError:
+                return
+            except:
+                errors.append("raised wrong exception")
+
+        errors = []
+        t = threading.Thread(target=run, kwargs={"con": self.con, "errors": errors})
+        t.start()
+        t.join()
+        if len(errors) > 0:
+            self.fail("\n".join(errors))
+
+    def CheckConCommit(self):
+        def run(con, errors):
+            try:
+                con.commit()
+                errors.append("did not raise ProgrammingError")
+                return
+            except sqlite.ProgrammingError:
+                return
+            except:
+                errors.append("raised wrong exception")
+
+        errors = []
+        t = threading.Thread(target=run, kwargs={"con": self.con, "errors": errors})
+        t.start()
+        t.join()
+        if len(errors) > 0:
+            self.fail("\n".join(errors))
+
+    def CheckConRollback(self):
+        def run(con, errors):
+            try:
+                con.rollback()
+                errors.append("did not raise ProgrammingError")
+                return
+            except sqlite.ProgrammingError:
+                return
+            except:
+                errors.append("raised wrong exception")
+
+        errors = []
+        t = threading.Thread(target=run, kwargs={"con": self.con, "errors": errors})
+        t.start()
+        t.join()
+        if len(errors) > 0:
+            self.fail("\n".join(errors))
+
+    def CheckConClose(self):
+        def run(con, errors):
+            try:
+                con.close()
+                errors.append("did not raise ProgrammingError")
+                return
+            except sqlite.ProgrammingError:
+                return
+            except:
+                errors.append("raised wrong exception")
+
+        errors = []
+        t = threading.Thread(target=run, kwargs={"con": self.con, "errors": errors})
+        t.start()
+        t.join()
+        if len(errors) > 0:
+            self.fail("\n".join(errors))
+
+    def CheckCurImplicitBegin(self):
+        def run(cur, errors):
+            try:
+                cur.execute("insert into test(name) values ('a')")
+                errors.append("did not raise ProgrammingError")
+                return
+            except sqlite.ProgrammingError:
+                return
+            except:
+                errors.append("raised wrong exception")
+
+        errors = []
+        t = threading.Thread(target=run, kwargs={"cur": self.cur, "errors": errors})
+        t.start()
+        t.join()
+        if len(errors) > 0:
+            self.fail("\n".join(errors))
+
+    def CheckCurClose(self):
+        def run(cur, errors):
+            try:
+                cur.close()
+                errors.append("did not raise ProgrammingError")
+                return
+            except sqlite.ProgrammingError:
+                return
+            except:
+                errors.append("raised wrong exception")
+
+        errors = []
+        t = threading.Thread(target=run, kwargs={"cur": self.cur, "errors": errors})
+        t.start()
+        t.join()
+        if len(errors) > 0:
+            self.fail("\n".join(errors))
+
+    def CheckCurExecute(self):
+        def run(cur, errors):
+            try:
+                cur.execute("select name from test")
+                errors.append("did not raise ProgrammingError")
+                return
+            except sqlite.ProgrammingError:
+                return
+            except:
+                errors.append("raised wrong exception")
+
+        errors = []
+        self.cur.execute("insert into test(name) values ('a')")
+        t = threading.Thread(target=run, kwargs={"cur": self.cur, "errors": errors})
+        t.start()
+        t.join()
+        if len(errors) > 0:
+            self.fail("\n".join(errors))
+
+    def CheckCurIterNext(self):
+        def run(cur, errors):
+            try:
+                row = cur.fetchone()
+                errors.append("did not raise ProgrammingError")
+                return
+            except sqlite.ProgrammingError:
+                return
+            except:
+                errors.append("raised wrong exception")
+
+        errors = []
+        self.cur.execute("insert into test(name) values ('a')")
+        self.cur.execute("select name from test")
+        t = threading.Thread(target=run, kwargs={"cur": self.cur, "errors": errors})
+        t.start()
+        t.join()
+        if len(errors) > 0:
+            self.fail("\n".join(errors))
+
+class ConstructorTests(unittest.TestCase):
+    def CheckDate(self):
+        d = sqlite.Date(2004, 10, 28)
+
+    def CheckTime(self):
+        t = sqlite.Time(12, 39, 35)
+
+    def CheckTimestamp(self):
+        ts = sqlite.Timestamp(2004, 10, 28, 12, 39, 35)
+
+    def CheckDateFromTicks(self):
+        d = sqlite.DateFromTicks(42)
+
+    def CheckTimeFromTicks(self):
+        t = sqlite.TimeFromTicks(42)
+
+    def CheckTimestampFromTicks(self):
+        ts = sqlite.TimestampFromTicks(42)
+
+    def CheckBinary(self):
+        b = sqlite.Binary(chr(0) + "'")
+
+class ExtensionTests(unittest.TestCase):
+    def CheckScriptStringSql(self):
+        con = sqlite.connect(":memory:")
+        cur = con.cursor()
+        cur.executescript("""
+            -- bla bla
+            /* a stupid comment */
+            create table a(i);
+            insert into a(i) values (5);
+            """)
+        cur.execute("select i from a")
+        res = cur.fetchone()[0]
+        self.failUnlessEqual(res, 5)
+
+    def CheckScriptStringUnicode(self):
+        con = sqlite.connect(":memory:")
+        cur = con.cursor()
+        cur.executescript(u"""
+            create table a(i);
+            insert into a(i) values (5);
+            select i from a;
+            delete from a;
+            insert into a(i) values (6);
+            """)
+        cur.execute("select i from a")
+        res = cur.fetchone()[0]
+        self.failUnlessEqual(res, 6)
+
+    def CheckScriptErrorIncomplete(self):
+        con = sqlite.connect(":memory:")
+        cur = con.cursor()
+        raised = False
+        try:
+            cur.executescript("create table test(sadfsadfdsa")
+        except sqlite.ProgrammingError:
+            raised = True
+        self.failUnlessEqual(raised, True, "should have raised an exception")
+
+    def CheckScriptErrorNormal(self):
+        con = sqlite.connect(":memory:")
+        cur = con.cursor()
+        raised = False
+        try:
+            cur.executescript("create table test(sadfsadfdsa); select foo from hurz;")
+        except sqlite.OperationalError:
+            raised = True
+        self.failUnlessEqual(raised, True, "should have raised an exception")
+
+    def CheckConnectionExecute(self):
+        con = sqlite.connect(":memory:")
+        result = con.execute("select 5").fetchone()[0]
+        self.failUnlessEqual(result, 5, "Basic test of Connection.execute")
+
+    def CheckConnectionExecutemany(self):
+        con = sqlite.connect(":memory:")
+        con.execute("create table test(foo)")
+        con.executemany("insert into test(foo) values (?)", [(3,), (4,)])
+        result = con.execute("select foo from test order by foo").fetchall()
+        self.failUnlessEqual(result[0][0], 3, "Basic test of Connection.executemany")
+        self.failUnlessEqual(result[1][0], 4, "Basic test of Connection.executemany")
+
+    def CheckConnectionExecutescript(self):
+        con = sqlite.connect(":memory:")
+        con.executescript("create table test(foo); insert into test(foo) values (5);")
+        result = con.execute("select foo from test").fetchone()[0]
+        self.failUnlessEqual(result, 5, "Basic test of Connection.executescript")
+
+class ClosedTests(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def CheckClosedConCursor(self):
+        con = sqlite.connect(":memory:")
+        con.close()
+        try:
+            cur = con.cursor()
+            self.fail("Should have raised a ProgrammingError")
+        except sqlite.ProgrammingError:
+            pass
+        except:
+            self.fail("Should have raised a ProgrammingError")
+
+    def CheckClosedConCommit(self):
+        con = sqlite.connect(":memory:")
+        con.close()
+        try:
+            con.commit()
+            self.fail("Should have raised a ProgrammingError")
+        except sqlite.ProgrammingError:
+            pass
+        except:
+            self.fail("Should have raised a ProgrammingError")
+
+    def CheckClosedConRollback(self):
+        con = sqlite.connect(":memory:")
+        con.close()
+        try:
+            con.rollback()
+            self.fail("Should have raised a ProgrammingError")
+        except sqlite.ProgrammingError:
+            pass
+        except:
+            self.fail("Should have raised a ProgrammingError")
+
+    def CheckClosedCurExecute(self):
+        con = sqlite.connect(":memory:")
+        cur = con.cursor()
+        con.close()
+        try:
+            cur.execute("select 4")
+            self.fail("Should have raised a ProgrammingError")
+        except sqlite.ProgrammingError:
+            pass
+        except:
+            self.fail("Should have raised a ProgrammingError")
+
+def suite():
+    module_suite = unittest.makeSuite(ModuleTests, "Check")
+    connection_suite = unittest.makeSuite(ConnectionTests, "Check")
+    cursor_suite = unittest.makeSuite(CursorTests, "Check")
+    thread_suite = unittest.makeSuite(ThreadTests, "Check")
+    constructor_suite = unittest.makeSuite(ConstructorTests, "Check")
+    ext_suite = unittest.makeSuite(ExtensionTests, "Check")
+    closed_suite = unittest.makeSuite(ClosedTests, "Check")
+    return unittest.TestSuite((module_suite, connection_suite, cursor_suite, thread_suite, constructor_suite, ext_suite, closed_suite))
+
+def test():
+    runner = unittest.TextTestRunner()
+    runner.run(suite())
+
+if __name__ == "__main__":
+    test()
diff --git a/pysqlite2/test/factory.py b/pysqlite2/test/factory.py
new file mode 100644 (file)
index 0000000..60bd528
--- /dev/null
@@ -0,0 +1,164 @@
+#-*- coding: ISO-8859-1 -*-
+# pysqlite2/test/factory.py: tests for the various factories in pysqlite
+#
+# Copyright (C) 2005 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.
+
+import unittest
+import pysqlite2.dbapi2 as sqlite
+
+class MyConnection(sqlite.Connection):
+    def __init__(self, *args, **kwargs):
+        sqlite.Connection.__init__(self, *args, **kwargs)
+
+def dict_factory(cursor, row):
+    d = {}
+    for idx, col in enumerate(cursor.description):
+        d[col[0]] = row[idx]
+    return d
+
+class MyCursor(sqlite.Cursor):
+    def __init__(self, *args, **kwargs):
+        sqlite.Cursor.__init__(self, *args, **kwargs)
+        self.row_factory = dict_factory
+
+class ConnectionFactoryTests(unittest.TestCase):
+    def setUp(self):
+        self.con = sqlite.connect(":memory:", factory=MyConnection)
+
+    def tearDown(self):
+        self.con.close()
+
+    def CheckIsInstance(self):
+        self.failUnless(isinstance(self.con,
+                                   MyConnection),
+                        "connection is not instance of MyConnection")
+
+class CursorFactoryTests(unittest.TestCase):
+    def setUp(self):
+        self.con = sqlite.connect(":memory:")
+
+    def tearDown(self):
+        self.con.close()
+
+    def CheckIsInstance(self):
+        cur = self.con.cursor(factory=MyCursor)
+        self.failUnless(isinstance(cur,
+                                   MyCursor),
+                        "cursor is not instance of MyCursor")
+
+class RowFactoryTestsBackwardsCompat(unittest.TestCase):
+    def setUp(self):
+        self.con = sqlite.connect(":memory:")
+
+    def CheckIsProducedByFactory(self):
+        cur = self.con.cursor(factory=MyCursor)
+        cur.execute("select 4+5 as foo")
+        row = cur.fetchone()
+        self.failUnless(isinstance(row,
+                                   dict),
+                        "row is not instance of dict")
+        cur.close()
+
+    def tearDown(self):
+        self.con.close()
+
+class RowFactoryTests(unittest.TestCase):
+    def setUp(self):
+        self.con = sqlite.connect(":memory:")
+
+    def CheckCustomFactory(self):
+        self.con.row_factory = lambda cur, row: list(row)
+        row = self.con.execute("select 1, 2").fetchone()
+        self.failUnless(isinstance(row,
+                                   list),
+                        "row is not instance of list")
+
+    def CheckSqliteRow(self):
+        self.con.row_factory = sqlite.Row
+        row = self.con.execute("select 1 as a, 2 as b").fetchone()
+        self.failUnless(isinstance(row,
+                                   sqlite.Row),
+                        "row is not instance of sqlite.Row")
+
+        col1, col2 = row["a"], row["b"]
+        self.failUnless(col1 == 1, "by name: wrong result for column 'a'")
+        self.failUnless(col2 == 2, "by name: wrong result for column 'a'")
+
+        col1, col2 = row["A"], row["B"]
+        self.failUnless(col1 == 1, "by name: wrong result for column 'A'")
+        self.failUnless(col2 == 2, "by name: wrong result for column 'B'")
+
+        col1, col2 = row[0], row[1]
+        self.failUnless(col1 == 1, "by index: wrong result for column 0")
+        self.failUnless(col2 == 2, "by index: wrong result for column 1")
+
+    def tearDown(self):
+        self.con.close()
+
+class TextFactoryTests(unittest.TestCase):
+    def setUp(self):
+        self.con = sqlite.connect(":memory:")
+
+    def CheckUnicode(self):
+        austria = unicode("Österreich", "latin1")
+        row = self.con.execute("select ?", (austria,)).fetchone()
+        self.failUnless(type(row[0]) == unicode, "type of row[0] must be unicode")
+
+    def CheckString(self):
+        self.con.text_factory = str
+        austria = unicode("Österreich", "latin1")
+        row = self.con.execute("select ?", (austria,)).fetchone()
+        self.failUnless(type(row[0]) == str, "type of row[0] must be str")
+        self.failUnless(row[0] == austria.encode("utf-8"), "column must equal original data in UTF-8")
+
+    def CheckCustom(self):
+        self.con.text_factory = lambda x: unicode(x, "utf-8", "ignore")
+        austria = unicode("Österreich", "latin1")
+        row = self.con.execute("select ?", (austria.encode("latin1"),)).fetchone()
+        self.failUnless(type(row[0]) == unicode, "type of row[0] must be unicode")
+        self.failUnless(row[0].endswith(u"reich"), "column must contain original data")
+
+    def CheckOptimizedUnicode(self):
+        self.con.text_factory = sqlite.OptimizedUnicode
+        austria = unicode("Österreich", "latin1")
+        germany = unicode("Deutchland")
+        a_row = self.con.execute("select ?", (austria,)).fetchone()
+        d_row = self.con.execute("select ?", (germany,)).fetchone()
+        self.failUnless(type(a_row[0]) == unicode, "type of non-ASCII row must be unicode")
+        self.failUnless(type(d_row[0]) == str, "type of ASCII-only row must be str")
+
+    def tearDown(self):
+        self.con.close()
+
+def suite():
+    connection_suite = unittest.makeSuite(ConnectionFactoryTests, "Check")
+    cursor_suite = unittest.makeSuite(CursorFactoryTests, "Check")
+    row_suite_compat = unittest.makeSuite(RowFactoryTestsBackwardsCompat, "Check")
+    row_suite = unittest.makeSuite(RowFactoryTests, "Check")
+    text_suite = unittest.makeSuite(TextFactoryTests, "Check")
+    return unittest.TestSuite((connection_suite, cursor_suite, row_suite_compat, row_suite, text_suite))
+
+def test():
+    runner = unittest.TextTestRunner()
+    runner.run(suite())
+
+if __name__ == "__main__":
+    test()
diff --git a/pysqlite2/test/hooks.py b/pysqlite2/test/hooks.py
new file mode 100644 (file)
index 0000000..7dd61c6
--- /dev/null
@@ -0,0 +1,115 @@
+#-*- coding: ISO-8859-1 -*-
+# pysqlite2/test/hooks.py: tests for various SQLite-specific hooks
+#
+# Copyright (C) 2006 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.
+
+import os, unittest
+import pysqlite2.dbapi2 as sqlite
+
+class CollationTests(unittest.TestCase):
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def CheckCreateCollationNotCallable(self):
+        con = sqlite.connect(":memory:")
+        try:
+            con.create_collation("X", 42)
+            self.fail("should have raised a TypeError")
+        except TypeError, e:
+            self.failUnlessEqual(e.args[0], "parameter must be callable")
+
+    def CheckCreateCollationNotAscii(self):
+        con = sqlite.connect(":memory:")
+        try:
+            con.create_collation("collä", cmp)
+            self.fail("should have raised a ProgrammingError")
+        except sqlite.ProgrammingError, e:
+            pass
+
+    def CheckCollationIsUsed(self):
+        def mycoll(x, y):
+            # reverse order
+            return -cmp(x, y)
+
+        con = sqlite.connect(":memory:")
+        con.create_collation("mycoll", mycoll)
+        sql = """
+            select x from (
+            select 'a' as x
+            union
+            select 'b' as x
+            union
+            select 'c' as x
+            ) order by x collate mycoll
+            """
+        result = con.execute(sql).fetchall()
+        if result[0][0] != "c" or result[1][0] != "b" or result[2][0] != "a":
+            self.fail("the expected order was not returned")
+
+        con.create_collation("mycoll", None)
+        try:
+            result = con.execute(sql).fetchall()
+            self.fail("should have raised an OperationalError")
+        except sqlite.OperationalError, e:
+            self.failUnlessEqual(e.args[0].lower(), "no such collation sequence: mycoll")
+
+    def CheckCollationRegisterTwice(self):
+        """
+        Register two different collation functions under the same name.
+        Verify that the last one is actually used.
+        """
+        con = sqlite.connect(":memory:")
+        con.create_collation("mycoll", cmp)
+        con.create_collation("mycoll", lambda x, y: -cmp(x, y))
+        result = con.execute("""
+            select x from (select 'a' as x union select 'b' as x) order by x collate mycoll
+            """).fetchall()
+        if result[0][0] != 'b' or result[1][0] != 'a':
+            self.fail("wrong collation function is used")
+
+    def CheckDeregisterCollation(self):
+        """
+        Register a collation, then deregister it. Make sure an error is raised if we try
+        to use it.
+        """
+        con = sqlite.connect(":memory:")
+        con.create_collation("mycoll", cmp)
+        con.create_collation("mycoll", None)
+        try:
+            con.execute("select 'a' as x union select 'b' as x order by x collate mycoll")
+            self.fail("should have raised an OperationalError")
+        except sqlite.OperationalError, e:
+            if not e.args[0].startswith("no such collation sequence"):
+                self.fail("wrong OperationalError raised")
+
+def suite():
+    collation_suite = unittest.makeSuite(CollationTests, "Check")
+    return unittest.TestSuite((collation_suite,))
+
+def test():
+    runner = unittest.TextTestRunner()
+    runner.run(suite())
+
+if __name__ == "__main__":
+    test()
diff --git a/pysqlite2/test/regression.py b/pysqlite2/test/regression.py
new file mode 100644 (file)
index 0000000..6cc3015
--- /dev/null
@@ -0,0 +1,73 @@
+#-*- coding: ISO-8859-1 -*-
+# pysqlite2/test/regression.py: pysqlite regression tests
+#
+# Copyright (C) 2006 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.
+
+import unittest
+import pysqlite2.dbapi2 as sqlite
+
+class RegressionTests(unittest.TestCase):
+    def setUp(self):
+        self.con = sqlite.connect(":memory:")
+
+    def tearDown(self):
+        self.con.close()
+
+    def CheckPragmaUserVersion(self):
+        # This used to crash pysqlite because this pragma command returns NULL for the column name
+        cur = self.con.cursor()
+        cur.execute("pragma user_version")
+
+    def CheckPragmaSchemaVersion(self):
+        # This still crashed pysqlite <= 2.2.1
+        con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_COLNAMES)
+        try:
+            cur = self.con.cursor()
+            cur.execute("pragma schema_version")
+        finally:
+            cur.close()
+            con.close()
+
+    def CheckStatementReset(self):
+        # pysqlite 2.1.0 to 2.2.0 have the problem that not all statements are
+        # reset before a rollback, but only those that are still in the
+        # statement cache. The others are not accessible from the connection object.
+        con = sqlite.connect(":memory:", cached_statements=5)
+        cursors = [con.cursor() for x in xrange(5)]
+        cursors[0].execute("create table test(x)")
+        for i in range(10):
+            cursors[0].executemany("insert into test(x) values (?)", [(x,) for x in xrange(10)])
+
+        for i in range(5):
+            cursors[i].execute(" " * i + "select x from test")
+
+        con.rollback()
+
+def suite():
+    regression_suite = unittest.makeSuite(RegressionTests, "Check")
+    return unittest.TestSuite((regression_suite,))
+
+def test():
+    runner = unittest.TextTestRunner()
+    runner.run(suite())
+
+if __name__ == "__main__":
+    test()
diff --git a/pysqlite2/test/transactions.py b/pysqlite2/test/transactions.py
new file mode 100644 (file)
index 0000000..4452b54
--- /dev/null
@@ -0,0 +1,156 @@
+#-*- coding: ISO-8859-1 -*-
+# pysqlite2/test/transactions.py: tests transactions
+#
+# Copyright (C) 2005 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.
+
+import os, unittest
+import pysqlite2.dbapi2 as sqlite
+
+def get_db_path():
+    return "sqlite_testdb"
+
+class TransactionTests(unittest.TestCase):
+    def setUp(self):
+        try:
+            os.remove(get_db_path())
+        except:
+            pass
+
+        self.con1 = sqlite.connect(get_db_path(), timeout=0.1)
+        self.cur1 = self.con1.cursor()
+
+        self.con2 = sqlite.connect(get_db_path(), timeout=0.1)
+        self.cur2 = self.con2.cursor()
+
+    def tearDown(self):
+        self.cur1.close()
+        self.con1.close()
+
+        self.cur2.close()
+        self.con2.close()
+
+        os.unlink(get_db_path())
+
+    def CheckDMLdoesAutoCommitBefore(self):
+        self.cur1.execute("create table test(i)")
+        self.cur1.execute("insert into test(i) values (5)")
+        self.cur1.execute("create table test2(j)")
+        self.cur2.execute("select i from test")
+        res = self.cur2.fetchall()
+        self.failUnlessEqual(len(res), 1)
+
+    def CheckInsertStartsTransaction(self):
+        self.cur1.execute("create table test(i)")
+        self.cur1.execute("insert into test(i) values (5)")
+        self.cur2.execute("select i from test")
+        res = self.cur2.fetchall()
+        self.failUnlessEqual(len(res), 0)
+
+    def CheckUpdateStartsTransaction(self):
+        self.cur1.execute("create table test(i)")
+        self.cur1.execute("insert into test(i) values (5)")
+        self.con1.commit()
+        self.cur1.execute("update test set i=6")
+        self.cur2.execute("select i from test")
+        res = self.cur2.fetchone()[0]
+        self.failUnlessEqual(res, 5)
+
+    def CheckDeleteStartsTransaction(self):
+        self.cur1.execute("create table test(i)")
+        self.cur1.execute("insert into test(i) values (5)")
+        self.con1.commit()
+        self.cur1.execute("delete from test")
+        self.cur2.execute("select i from test")
+        res = self.cur2.fetchall()
+        self.failUnlessEqual(len(res), 1)
+
+    def CheckReplaceStartsTransaction(self):
+        self.cur1.execute("create table test(i)")
+        self.cur1.execute("insert into test(i) values (5)")
+        self.con1.commit()
+        self.cur1.execute("replace into test(i) values (6)")
+        self.cur2.execute("select i from test")
+        res = self.cur2.fetchall()
+        self.failUnlessEqual(len(res), 1)
+        self.failUnlessEqual(res[0][0], 5)
+
+    def CheckToggleAutoCommit(self):
+        self.cur1.execute("create table test(i)")
+        self.cur1.execute("insert into test(i) values (5)")
+        self.con1.isolation_level = None
+        self.failUnlessEqual(self.con1.isolation_level, None)
+        self.cur2.execute("select i from test")
+        res = self.cur2.fetchall()
+        self.failUnlessEqual(len(res), 1)
+
+        self.con1.isolation_level = "DEFERRED"
+        self.failUnlessEqual(self.con1.isolation_level , "DEFERRED")
+        self.cur1.execute("insert into test(i) values (5)")
+        self.cur2.execute("select i from test")
+        res = self.cur2.fetchall()
+        self.failUnlessEqual(len(res), 1)
+
+    def CheckRaiseTimeout(self):
+        self.cur1.execute("create table test(i)")
+        self.cur1.execute("insert into test(i) values (5)")
+        try:
+            self.cur2.execute("insert into test(i) values (5)")
+            self.fail("should have raised an OperationalError")
+        except sqlite.OperationalError:
+            pass
+        except:
+            self.fail("should have raised an OperationalError")
+
+class SpecialCommandTests(unittest.TestCase):
+    def setUp(self):
+        self.con = sqlite.connect(":memory:")
+        self.cur = self.con.cursor()
+
+    def CheckVacuum(self):
+        self.cur.execute("create table test(i)")
+        self.cur.execute("insert into test(i) values (5)")
+        self.cur.execute("vacuum")
+
+    def CheckDropTable(self):
+        self.cur.execute("create table test(i)")
+        self.cur.execute("insert into test(i) values (5)")
+        self.cur.execute("drop table test")
+
+    def CheckPragma(self):
+        self.cur.execute("create table test(i)")
+        self.cur.execute("insert into test(i) values (5)")
+        self.cur.execute("pragma count_changes=1")
+
+    def tearDown(self):
+        self.cur.close()
+        self.con.close()
+
+def suite():
+    default_suite = unittest.makeSuite(TransactionTests, "Check")
+    special_command_suite = unittest.makeSuite(SpecialCommandTests, "Check")
+    return unittest.TestSuite((default_suite, special_command_suite))
+
+def test():
+    runner = unittest.TextTestRunner()
+    runner.run(suite())
+
+if __name__ == "__main__":
+    test()
diff --git a/pysqlite2/test/types.py b/pysqlite2/test/types.py
new file mode 100644 (file)
index 0000000..977044b
--- /dev/null
@@ -0,0 +1,339 @@
+#-*- coding: ISO-8859-1 -*-
+# pysqlite2/test/types.py: tests for type conversion and detection
+#
+# Copyright (C) 2005 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.
+
+import datetime
+import unittest
+import pysqlite2.dbapi2 as sqlite
+
+class SqliteTypeTests(unittest.TestCase):
+    def setUp(self):
+        self.con = sqlite.connect(":memory:")
+        self.cur = self.con.cursor()
+        self.cur.execute("create table test(i integer, s varchar, f number, b blob)")
+
+    def tearDown(self):
+        self.cur.close()
+        self.con.close()
+
+    def CheckString(self):
+        self.cur.execute("insert into test(s) values (?)", (u"Österreich",))
+        self.cur.execute("select s from test")
+        row = self.cur.fetchone()
+        self.failUnlessEqual(row[0], u"Österreich")
+
+    def CheckSmallInt(self):
+        self.cur.execute("insert into test(i) values (?)", (42,))
+        self.cur.execute("select i from test")
+        row = self.cur.fetchone()
+        self.failUnlessEqual(row[0], 42)
+
+    def CheckLargeInt(self):
+        num = 2**40
+        self.cur.execute("insert into test(i) values (?)", (num,))
+        self.cur.execute("select i from test")
+        row = self.cur.fetchone()
+        self.failUnlessEqual(row[0], num)
+
+    def CheckFloat(self):
+        val = 3.14
+        self.cur.execute("insert into test(f) values (?)", (val,))
+        self.cur.execute("select f from test")
+        row = self.cur.fetchone()
+        self.failUnlessEqual(row[0], val)
+
+    def CheckBlob(self):
+        val = buffer("Guglhupf")
+        self.cur.execute("insert into test(b) values (?)", (val,))
+        self.cur.execute("select b from test")
+        row = self.cur.fetchone()
+        self.failUnlessEqual(row[0], val)
+
+    def CheckUnicodeExecute(self):
+        self.cur.execute(u"select 'Österreich'")
+        row = self.cur.fetchone()
+        self.failUnlessEqual(row[0], u"Österreich")
+
+class DeclTypesTests(unittest.TestCase):
+    class Foo:
+        def __init__(self, _val):
+            self.val = _val
+
+        def __cmp__(self, other):
+            if not isinstance(other, DeclTypesTests.Foo):
+                raise ValueError
+            if self.val == other.val:
+                return 0
+            else:
+                return 1
+
+        def __conform__(self, protocol):
+            if protocol is sqlite.PrepareProtocol:
+                return self.val
+            else:
+                return None
+
+        def __str__(self):
+            return "<%s>" % self.val
+
+    def setUp(self):
+        self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES)
+        self.cur = self.con.cursor()
+        self.cur.execute("create table test(i int, s str, f float, b bool, u unicode, foo foo, bin blob)")
+
+        # override float, make them always return the same number
+        sqlite.converters["float"] = lambda x: 47.2
+
+        # and implement two custom ones
+        sqlite.converters["bool"] = lambda x: bool(int(x))
+        sqlite.converters["foo"] = DeclTypesTests.Foo
+
+    def tearDown(self):
+        del sqlite.converters["float"]
+        del sqlite.converters["bool"]
+        del sqlite.converters["foo"]
+        self.cur.close()
+        self.con.close()
+
+    def CheckString(self):
+        # default
+        self.cur.execute("insert into test(s) values (?)", ("foo",))
+        self.cur.execute("select s from test")
+        row = self.cur.fetchone()
+        self.failUnlessEqual(row[0], "foo")
+
+    def CheckSmallInt(self):
+        # default
+        self.cur.execute("insert into test(i) values (?)", (42,))
+        self.cur.execute("select i from test")
+        row = self.cur.fetchone()
+        self.failUnlessEqual(row[0], 42)
+
+    def CheckLargeInt(self):
+        # default
+        num = 2**40
+        self.cur.execute("insert into test(i) values (?)", (num,))
+        self.cur.execute("select i from test")
+        row = self.cur.fetchone()
+        self.failUnlessEqual(row[0], num)
+
+    def CheckFloat(self):
+        # custom
+        val = 3.14
+        self.cur.execute("insert into test(f) values (?)", (val,))
+        self.cur.execute("select f from test")
+        row = self.cur.fetchone()
+        self.failUnlessEqual(row[0], 47.2)
+
+    def CheckBool(self):
+        # custom
+        self.cur.execute("insert into test(b) values (?)", (False,))
+        self.cur.execute("select b from test")
+        row = self.cur.fetchone()
+        self.failUnlessEqual(row[0], False)
+
+        self.cur.execute("delete from test")
+        self.cur.execute("insert into test(b) values (?)", (True,))
+        self.cur.execute("select b from test")
+        row = self.cur.fetchone()
+        self.failUnlessEqual(row[0], True)
+
+    def CheckUnicode(self):
+        # default
+        val = u"\xd6sterreich"
+        self.cur.execute("insert into test(u) values (?)", (val,))
+        self.cur.execute("select u from test")
+        row = self.cur.fetchone()
+        self.failUnlessEqual(row[0], val)
+
+    def CheckFoo(self):
+        val = DeclTypesTests.Foo("bla")
+        self.cur.execute("insert into test(foo) values (?)", (val,))
+        self.cur.execute("select foo from test")
+        row = self.cur.fetchone()
+        self.failUnlessEqual(row[0], val)
+
+    def CheckUnsupportedSeq(self):
+        class Bar: pass
+        val = Bar()
+        try:
+            self.cur.execute("insert into test(f) values (?)", (val,))
+            self.fail("should have raised an InterfaceError")
+        except sqlite.InterfaceError:
+            pass
+        except:
+            self.fail("should have raised an InterfaceError")
+
+    def CheckUnsupportedDict(self):
+        class Bar: pass
+        val = Bar()
+        try:
+            self.cur.execute("insert into test(f) values (:val)", {"val": val})
+            self.fail("should have raised an InterfaceError")
+        except sqlite.InterfaceError:
+            pass
+        except:
+            self.fail("should have raised an InterfaceError")
+
+    def CheckBlob(self):
+        # default
+        val = buffer("Guglhupf")
+        self.cur.execute("insert into test(bin) values (?)", (val,))
+        self.cur.execute("select bin from test")
+        row = self.cur.fetchone()
+        self.failUnlessEqual(row[0], val)
+
+class ColNamesTests(unittest.TestCase):
+    def setUp(self):
+        self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_COLNAMES|sqlite.PARSE_DECLTYPES)
+        self.cur = self.con.cursor()
+        self.cur.execute("create table test(x foo)")
+
+        sqlite.converters["foo"] = lambda x: "[%s]" % x
+        sqlite.converters["bar"] = lambda x: "<%s>" % x
+        sqlite.converters["exc"] = lambda x: 5/0
+
+    def tearDown(self):
+        del sqlite.converters["foo"]
+        del sqlite.converters["bar"]
+        del sqlite.converters["exc"]
+        self.cur.close()
+        self.con.close()
+
+    def CheckDeclType(self):
+        self.cur.execute("insert into test(x) values (?)", ("xxx",))
+        self.cur.execute("select x from test")
+        val = self.cur.fetchone()[0]
+        self.failUnlessEqual(val, "[xxx]")
+
+    def CheckNone(self):
+        self.cur.execute("insert into test(x) values (?)", (None,))
+        self.cur.execute("select x from test")
+        val = self.cur.fetchone()[0]
+        self.failUnlessEqual(val, None)
+
+    def CheckExc(self):
+        # Exceptions in type converters result in returned Nones
+        self.cur.execute('select 5 as "x [exc]"')
+        val = self.cur.fetchone()[0]
+        self.failUnlessEqual(val, None)
+
+    def CheckColName(self):
+        self.cur.execute("insert into test(x) values (?)", ("xxx",))
+        self.cur.execute('select x as "x [bar]" from test')
+        val = self.cur.fetchone()[0]
+        self.failUnlessEqual(val, "<xxx>")
+
+        # Check if the stripping of colnames works. Everything after the first
+        # whitespace should be stripped.
+        self.failUnlessEqual(self.cur.description[0][0], "x")
+
+    def CheckCursorDescriptionNoRow(self):
+        """
+        cursor.description should at least provide the column name(s), even if
+        no row returned.
+        """
+        self.cur.execute("select * from test where 0 = 1")
+        self.assert_(self.cur.description[0][0] == "x")
+
+class ObjectAdaptationTests(unittest.TestCase):
+    def cast(obj):
+        return float(obj)
+    cast = staticmethod(cast)
+
+    def setUp(self):
+        self.con = sqlite.connect(":memory:")
+        try:
+            del sqlite.adapters[int]
+        except:
+            pass
+        sqlite.register_adapter(int, ObjectAdaptationTests.cast)
+        self.cur = self.con.cursor()
+
+    def tearDown(self):
+        del sqlite.adapters[(int, sqlite.PrepareProtocol)]
+        self.cur.close()
+        self.con.close()
+
+    def CheckCasterIsUsed(self):
+        self.cur.execute("select ?", (4,))
+        val = self.cur.fetchone()[0]
+        self.failUnlessEqual(type(val), float)
+
+class DateTimeTests(unittest.TestCase):
+    def setUp(self):
+        self.con = sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES)
+        self.cur = self.con.cursor()
+        self.cur.execute("create table test(d date, ts timestamp)")
+
+    def tearDown(self):
+        self.cur.close()
+        self.con.close()
+
+    def CheckSqliteDate(self):
+        d = sqlite.Date(2004, 2, 14)
+        self.cur.execute("insert into test(d) values (?)", (d,))
+        self.cur.execute("select d from test")
+        d2 = self.cur.fetchone()[0]
+        self.failUnlessEqual(d, d2)
+
+    def CheckSqliteTimestamp(self):
+        ts = sqlite.Timestamp(2004, 2, 14, 7, 15, 0)
+        self.cur.execute("insert into test(ts) values (?)", (ts,))
+        self.cur.execute("select ts from test")
+        ts2 = self.cur.fetchone()[0]
+        self.failUnlessEqual(ts, ts2)
+
+    def CheckSqlTimestamp(self):
+        # The date functions are only available in SQLite version 3.1 or later
+        if sqlite.sqlite_version_info < (3, 1):
+            return
+
+        # SQLite's current_timestamp uses UTC time, while datetime.datetime.now() uses local time.
+        now = datetime.datetime.now()
+        self.cur.execute("insert into test(ts) values (current_timestamp)")
+        self.cur.execute("select ts from test")
+        ts = self.cur.fetchone()[0]
+        self.failUnlessEqual(type(ts), datetime.datetime)
+        self.failUnlessEqual(ts.year, now.year)
+
+    def CheckDateTimeSubSeconds(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.failUnlessEqual(ts, ts2)
+
+def suite():
+    sqlite_type_suite = unittest.makeSuite(SqliteTypeTests, "Check")
+    decltypes_type_suite = unittest.makeSuite(DeclTypesTests, "Check")
+    colnames_type_suite = unittest.makeSuite(ColNamesTests, "Check")
+    adaptation_suite = unittest.makeSuite(ObjectAdaptationTests, "Check")
+    date_suite = unittest.makeSuite(DateTimeTests, "Check")
+    return unittest.TestSuite((sqlite_type_suite, decltypes_type_suite, colnames_type_suite, adaptation_suite, date_suite))
+
+def test():
+    runner = unittest.TextTestRunner()
+    runner.run(suite())
+
+if __name__ == "__main__":
+    test()
diff --git a/pysqlite2/test/userfunctions.py b/pysqlite2/test/userfunctions.py
new file mode 100644 (file)
index 0000000..7982147
--- /dev/null
@@ -0,0 +1,344 @@
+#-*- coding: ISO-8859-1 -*-
+# pysqlite2/test/userfunctions.py: tests for user-defined functions and
+#                                  aggregates.
+#
+# Copyright (C) 2005 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.
+
+import unittest
+import pysqlite2.dbapi2 as sqlite
+
+def func_returntext():
+    return "foo"
+def func_returnunicode():
+    return u"bar"
+def func_returnint():
+    return 42
+def func_returnfloat():
+    return 3.14
+def func_returnnull():
+    return None
+def func_returnblob():
+    return buffer("blob")
+def func_raiseexception():
+    5/0
+
+def func_isstring(v):
+    return type(v) is unicode
+def func_isint(v):
+    return type(v) is int
+def func_isfloat(v):
+    return type(v) is float
+def func_isnone(v):
+    return type(v) is type(None)
+def func_isblob(v):
+    return type(v) is buffer
+
+class AggrNoStep:
+    def __init__(self):
+        pass
+
+class AggrNoFinalize:
+    def __init__(self):
+        pass
+
+    def step(self, x):
+        pass
+
+class AggrExceptionInInit:
+    def __init__(self):
+        5/0
+
+    def step(self, x):
+        pass
+
+    def finalize(self):
+        pass
+
+class AggrExceptionInStep:
+    def __init__(self):
+        pass
+
+    def step(self, x):
+        5/0
+
+    def finalize(self):
+        return 42
+
+class AggrExceptionInFinalize:
+    def __init__(self):
+        pass
+
+    def step(self, x):
+        pass
+
+    def finalize(self):
+        5/0
+
+class AggrCheckType:
+    def __init__(self):
+        self.val = None
+
+    def step(self, whichType, val):
+        theType = {"str": unicode, "int": int, "float": float, "None": type(None), "blob": buffer}
+        self.val = int(theType[whichType] is type(val))
+
+    def finalize(self):
+        return self.val
+
+class AggrSum:
+    def __init__(self):
+        self.val = 0.0
+
+    def step(self, val):
+        self.val += val
+
+    def finalize(self):
+        return self.val
+
+class FunctionTests(unittest.TestCase):
+    def setUp(self):
+        self.con = sqlite.connect(":memory:")
+
+        self.con.create_function("returntext", 0, func_returntext)
+        self.con.create_function("returnunicode", 0, func_returnunicode)
+        self.con.create_function("returnint", 0, func_returnint)
+        self.con.create_function("returnfloat", 0, func_returnfloat)
+        self.con.create_function("returnnull", 0, func_returnnull)
+        self.con.create_function("returnblob", 0, func_returnblob)
+        self.con.create_function("raiseexception", 0, func_raiseexception)
+
+        self.con.create_function("isstring", 1, func_isstring)
+        self.con.create_function("isint", 1, func_isint)
+        self.con.create_function("isfloat", 1, func_isfloat)
+        self.con.create_function("isnone", 1, func_isnone)
+        self.con.create_function("isblob", 1, func_isblob)
+
+    def tearDown(self):
+        self.con.close()
+
+    def CheckFuncErrorOnCreate(self):
+        try:
+            self.con.create_function("bla", -100, lambda x: 2*x)
+            self.fail("should have raised an OperationalError")
+        except sqlite.OperationalError:
+            pass
+
+    def CheckFuncRefCount(self):
+        def getfunc():
+            def f():
+                return val
+            return f
+        self.con.create_function("reftest", 0, getfunc())
+        cur = self.con.cursor()
+        cur.execute("select reftest()")
+
+    def CheckFuncReturnText(self):
+        cur = self.con.cursor()
+        cur.execute("select returntext()")
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(type(val), unicode)
+        self.failUnlessEqual(val, "foo")
+
+    def CheckFuncReturnUnicode(self):
+        cur = self.con.cursor()
+        cur.execute("select returnunicode()")
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(type(val), unicode)
+        self.failUnlessEqual(val, u"bar")
+
+    def CheckFuncReturnInt(self):
+        cur = self.con.cursor()
+        cur.execute("select returnint()")
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(type(val), int)
+        self.failUnlessEqual(val, 42)
+
+    def CheckFuncReturnFloat(self):
+        cur = self.con.cursor()
+        cur.execute("select returnfloat()")
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(type(val), float)
+        if val < 3.139 or val > 3.141:
+            self.fail("wrong value")
+
+    def CheckFuncReturnNull(self):
+        cur = self.con.cursor()
+        cur.execute("select returnnull()")
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(type(val), type(None))
+        self.failUnlessEqual(val, None)
+
+    def CheckFuncReturnBlob(self):
+        cur = self.con.cursor()
+        cur.execute("select returnblob()")
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(type(val), buffer)
+        self.failUnlessEqual(val, buffer("blob"))
+
+    def CheckFuncException(self):
+        cur = self.con.cursor()
+        cur.execute("select raiseexception()")
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(val, None)
+
+    def CheckParamString(self):
+        cur = self.con.cursor()
+        cur.execute("select isstring(?)", ("foo",))
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(val, 1)
+
+    def CheckParamInt(self):
+        cur = self.con.cursor()
+        cur.execute("select isint(?)", (42,))
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(val, 1)
+
+    def CheckParamFloat(self):
+        cur = self.con.cursor()
+        cur.execute("select isfloat(?)", (3.14,))
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(val, 1)
+
+    def CheckParamNone(self):
+        cur = self.con.cursor()
+        cur.execute("select isnone(?)", (None,))
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(val, 1)
+
+    def CheckParamBlob(self):
+        cur = self.con.cursor()
+        cur.execute("select isblob(?)", (buffer("blob"),))
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(val, 1)
+
+class AggregateTests(unittest.TestCase):
+    def setUp(self):
+        self.con = sqlite.connect(":memory:")
+        cur = self.con.cursor()
+        cur.execute("""
+            create table test(
+                t text,
+                i integer,
+                f float,
+                n,
+                b blob
+                )
+            """)
+        cur.execute("insert into test(t, i, f, n, b) values (?, ?, ?, ?, ?)",
+            ("foo", 5, 3.14, None, buffer("blob"),))
+
+        self.con.create_aggregate("nostep", 1, AggrNoStep)
+        self.con.create_aggregate("nofinalize", 1, AggrNoFinalize)
+        self.con.create_aggregate("excInit", 1, AggrExceptionInInit)
+        self.con.create_aggregate("excStep", 1, AggrExceptionInStep)
+        self.con.create_aggregate("excFinalize", 1, AggrExceptionInFinalize)
+        self.con.create_aggregate("checkType", 2, AggrCheckType)
+        self.con.create_aggregate("mysum", 1, AggrSum)
+
+    def tearDown(self):
+        #self.cur.close()
+        #self.con.close()
+        pass
+
+    def CheckAggrErrorOnCreate(self):
+        try:
+            self.con.create_function("bla", -100, AggrSum)
+            self.fail("should have raised an OperationalError")
+        except sqlite.OperationalError:
+            pass
+
+    def CheckAggrNoStep(self):
+        cur = self.con.cursor()
+        cur.execute("select nostep(t) from test")
+
+    def CheckAggrNoFinalize(self):
+        cur = self.con.cursor()
+        cur.execute("select nofinalize(t) from test")
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(val, None)
+
+    def CheckAggrExceptionInInit(self):
+        cur = self.con.cursor()
+        cur.execute("select excInit(t) from test")
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(val, None)
+
+    def CheckAggrExceptionInStep(self):
+        cur = self.con.cursor()
+        cur.execute("select excStep(t) from test")
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(val, 42)
+
+    def CheckAggrExceptionInFinalize(self):
+        cur = self.con.cursor()
+        cur.execute("select excFinalize(t) from test")
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(val, None)
+
+    def CheckAggrCheckParamStr(self):
+        cur = self.con.cursor()
+        cur.execute("select checkType('str', ?)", ("foo",))
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(val, 1)
+
+    def CheckAggrCheckParamInt(self):
+        cur = self.con.cursor()
+        cur.execute("select checkType('int', ?)", (42,))
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(val, 1)
+
+    def CheckAggrCheckParamFloat(self):
+        cur = self.con.cursor()
+        cur.execute("select checkType('float', ?)", (3.14,))
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(val, 1)
+
+    def CheckAggrCheckParamNone(self):
+        cur = self.con.cursor()
+        cur.execute("select checkType('None', ?)", (None,))
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(val, 1)
+
+    def CheckAggrCheckParamBlob(self):
+        cur = self.con.cursor()
+        cur.execute("select checkType('blob', ?)", (buffer("blob"),))
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(val, 1)
+
+    def CheckAggrCheckAggrSum(self):
+        cur = self.con.cursor()
+        cur.execute("delete from test")
+        cur.executemany("insert into test(i) values (?)", [(10,), (20,), (30,)])
+        cur.execute("select mysum(i) from test")
+        val = cur.fetchone()[0]
+        self.failUnlessEqual(val, 60)
+
+def suite():
+    function_suite = unittest.makeSuite(FunctionTests, "Check")
+    aggregate_suite = unittest.makeSuite(AggregateTests, "Check")
+    return unittest.TestSuite((function_suite, aggregate_suite))
+
+def test():
+    runner = unittest.TextTestRunner()
+    runner.run(suite())
+
+if __name__ == "__main__":
+    test()
diff --git a/setup.cfg b/setup.cfg
new file mode 100644 (file)
index 0000000..991cf7d
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,5 @@
+[build_ext]
+define=
+include_dirs=/usr/local/include
+library_dirs=/usr/local/lib
+libraries=sqlite3
diff --git a/setup.py b/setup.py
new file mode 100644 (file)
index 0000000..9fdda4a
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,160 @@
+#-*- coding: ISO-8859-1 -*-
+# setup.py: the distutils script
+#
+# Copyright (C) 2004-2006 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.
+
+import glob, os, re, sys
+
+from distutils.core import setup, Extension, Command
+
+# If you need to change anything, it should be enough to change setup.cfg.
+
+sqlite = "sqlite"
+
+sources = ["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"]
+
+include_dirs = []
+library_dirs = []
+libraries = []
+runtime_library_dirs = []
+extra_objects = []
+define_macros = []
+
+long_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."""
+
+if sys.platform != "win32":
+    define_macros.append(('MODULE_NAME', '"pysqlite2.dbapi2"'))
+else:
+    define_macros.append(('MODULE_NAME', '\\"pysqlite2.dbapi2\\"'))
+
+class DocBuilder(Command):
+    description = "Builds the documentation"
+    user_options = []
+
+    def initialize_options(self):
+        pass
+
+    def finalize_options(self):
+        pass
+
+    def run(self):
+        import os, stat
+
+        try:
+            import docutils.core
+            import docutilsupport
+        except ImportError:
+            print "Error: the build-docs command requires docutils and SilverCity to be installed"
+            return
+
+        docfiles = {
+            "usage-guide.html": "usage-guide.txt",
+            "install-source.html": "install-source.txt",
+            "install-source-win32.html": "install-source-win32.txt"
+        }
+
+        os.chdir("doc")
+        for dest, source in docfiles.items():
+            if not os.path.exists(dest) or os.stat(dest)[stat.ST_MTIME] < os.stat(source)[stat.ST_MTIME]:
+                print "Building documentation file %s." % dest
+                docutils.core.publish_cmdline(
+                    writer_name='html',
+                    argv=["--stylesheet=default.css", source, dest])
+
+        os.chdir("..")
+
+def get_setup_args():
+    PYSQLITE_VERSION = None
+
+    version_re = re.compile('#define PYSQLITE_VERSION "(.*)"')
+    f = open(os.path.join("src", "module.h"))
+    for line in f:
+        match = version_re.match(line)
+        if match:
+            PYSQLITE_VERSION = match.groups()[0]
+            break
+    f.close()
+
+    if not PYSQLITE_VERSION:
+        print "Fatal error: PYSQLITE_VERSION could not be detected!"
+        sys.exit(1)
+
+    data_files = [("pysqlite2-doc",
+                        glob.glob("doc/*.html") \
+                      + glob.glob("doc/*.txt") \
+                      + glob.glob("doc/*.css")),
+                   ("pysqlite2-doc/code",
+                        glob.glob("doc/code/*.py"))]
+
+    py_modules = ["sqlite"]
+    setup_args = dict(
+            name = "pysqlite",
+            version = PYSQLITE_VERSION,
+            description = "DB-API 2.0 interface for SQLite 3.x",
+            long_description=long_description,
+            author = "Gerhard Haering",
+            author_email = "gh@ghaering.de",
+            license = "zlib/libpng license",
+            platforms = "ALL",
+            url = "http://pysqlite.org/",
+            download_url = "http://initd.org/tracker/pysqlite/wiki/PysqliteDownloads",
+
+            # Description of the modules and packages in the distribution
+            package_dir = {"pysqlite2": "pysqlite2"},
+            packages = ["pysqlite2", "pysqlite2.test"],
+            scripts=[],
+            data_files = data_files,
+
+            ext_modules = [Extension( name="pysqlite2._sqlite",
+                                      sources=sources,
+                                      include_dirs=include_dirs,
+                                      library_dirs=library_dirs,
+                                      runtime_library_dirs=runtime_library_dirs,
+                                      libraries=libraries,
+                                      extra_objects=extra_objects,
+                                      define_macros=define_macros
+                                      )],
+            classifiers = [
+            "Development Status :: 5 - Production/Stable",
+            "Intended Audience :: Developers",
+            "License :: OSI Approved :: zlib/libpng License",
+            "Operating System :: MacOS :: MacOS X",
+            "Operating System :: Microsoft :: Windows",
+            "Operating System :: POSIX",
+            "Programming Language :: C",
+            "Programming Language :: Python",
+            "Topic :: Database :: Database Engines/Servers",
+            "Topic :: Software Development :: Libraries :: Python Modules"]
+            )
+    return setup_args
+
+def main():
+    setup(**get_setup_args())
+
+if __name__ == "__main__":
+    main()
diff --git a/src/cache.c b/src/cache.c
new file mode 100644 (file)
index 0000000..6962695
--- /dev/null
@@ -0,0 +1,375 @@
+/* cache .c - a LRU cache
+ *
+ * Copyright (C) 2004-2006 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 "cache.h"
+#include <limits.h>
+
+/* only used internally */
+Node* new_node(PyObject* key, PyObject* data)
+{
+    Node* node;
+
+    node = (Node*) (NodeType.tp_alloc(&NodeType, 0));
+    if (!node) {
+        return NULL;
+    }
+
+    Py_INCREF(key);
+    node->key = key;
+
+    Py_INCREF(data);
+    node->data = data;
+
+    node->prev = NULL;
+    node->next = NULL;
+
+    return node;
+}
+
+void node_dealloc(Node* self)
+{
+    Py_DECREF(self->key);
+    Py_DECREF(self->data);
+
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+int cache_init(Cache* self, PyObject* args, PyObject* kwargs)
+{
+    PyObject* factory;
+    int size = 10;
+
+    self->factory = NULL;
+
+    if (!PyArg_ParseTuple(args, "O|i", &factory, &size)) {
+        return -1;
+    }
+
+    /* minimum cache size is 5 entries */
+    if (size < 5) {
+        size = 5;
+    }
+    self->size = size;
+    self->first = NULL;
+    self->last = NULL;
+
+    self->mapping = PyDict_New();
+    if (!self->mapping) {
+        return -1;
+    }
+
+    Py_INCREF(factory);
+    self->factory = factory;
+
+    self->decref_factory = 1;
+
+    return 0;
+}
+
+void cache_dealloc(Cache* self)
+{
+    Node* node;
+    Node* delete_node;
+
+    if (!self->factory) {
+        /* constructor failed, just get out of here */
+        return;
+    }
+
+    /* iterate over all nodes and deallocate them */
+    node = self->first;
+    while (node) {
+        delete_node = node;
+        node = node->next;
+        Py_DECREF(delete_node);
+    }
+
+    if (self->decref_factory) {
+        Py_DECREF(self->factory);
+    }
+    Py_DECREF(self->mapping);
+
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+PyObject* cache_get(Cache* self, PyObject* args)
+{
+    PyObject* key = args;
+    Node* node;
+    Node* ptr;
+    PyObject* data;
+
+    node = (Node*)PyDict_GetItem(self->mapping, key);
+    if (node) {
+        /* an entry for this key already exists in the cache */
+
+        /* increase usage counter of the node found */
+        if (node->count < LONG_MAX) {
+            node->count++;
+        }
+
+        /* if necessary, reorder entries in the cache by swapping positions */
+        if (node->prev && node->count > node->prev->count) {
+            ptr = node->prev;
+
+            while (ptr->prev && node->count > ptr->prev->count) {
+                ptr = ptr->prev;
+            }
+
+            if (node->next) {
+                node->next->prev = node->prev;
+            } else {
+                self->last = node->prev;
+            }
+            if (node->prev) {
+                node->prev->next = node->next;
+            }
+            if (ptr->prev) {
+                ptr->prev->next = node;
+            } else {
+                self->first = node;
+            }
+
+            node->next = ptr;
+            node->prev = ptr->prev;
+            if (!node->prev) {
+                self->first = node;
+            }
+            ptr->prev = node;
+        }
+    } else {
+        /* There is no entry for this key in the cache, yet. We'll insert a new
+         * entry in the cache, and make space if necessary by throwing the
+         * least used item out of the cache. */
+
+        if (PyDict_Size(self->mapping) == self->size) {
+            if (self->last) {
+                node = self->last;
+
+                if (PyDict_DelItem(self->mapping, self->last->key) != 0) {
+                    return NULL;
+                }
+
+                if (node->prev) {
+                    node->prev->next = NULL;
+                }
+                self->last = node->prev;
+                node->prev = NULL;
+
+                Py_DECREF(node);
+            }
+        }
+
+        data = PyObject_CallFunction(self->factory, "O", key);
+
+        if (!data) {
+            return NULL;
+        }
+
+        node = new_node(key, data);
+        if (!node) {
+            return NULL;
+        }
+        node->prev = self->last;
+
+        Py_DECREF(data);
+
+        if (PyDict_SetItem(self->mapping, key, (PyObject*)node) != 0) {
+            Py_DECREF(node);
+            return NULL;
+        }
+
+        if (self->last) {
+            self->last->next = node;
+        } else {
+            self->first = node;
+        }
+        self->last = node;
+    }
+
+    Py_INCREF(node->data);
+    return node->data;
+}
+
+PyObject* cache_display(Cache* self, PyObject* args)
+{
+    Node* ptr;
+    PyObject* prevkey;
+    PyObject* nextkey;
+    PyObject* fmt_args;
+    PyObject* template;
+    PyObject* display_str;
+
+    ptr = self->first;
+
+    while (ptr) {
+        if (ptr->prev) {
+            prevkey = ptr->prev->key;
+        } else {
+            prevkey = Py_None;
+        }
+        Py_INCREF(prevkey);
+
+        if (ptr->next) {
+            nextkey = ptr->next->key;
+        } else {
+            nextkey = Py_None;
+        }
+        Py_INCREF(nextkey);
+
+        fmt_args = Py_BuildValue("OOO", prevkey, ptr->key, nextkey);
+        if (!fmt_args) {
+            return NULL;
+        }
+        template = PyString_FromString("%s <- %s ->%s\n");
+        if (!template) {
+            return NULL;
+        }
+        display_str = PyString_Format(template, fmt_args);
+        Py_DECREF(template);
+        Py_DECREF(fmt_args);
+        if (!display_str) {
+            return NULL;
+        }
+        PyObject_Print(display_str, stdout, Py_PRINT_RAW);
+        Py_DECREF(display_str);
+
+        Py_DECREF(prevkey);
+        Py_DECREF(nextkey);
+
+        ptr = ptr->next;
+    }
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyMethodDef cache_methods[] = {
+    {"get", (PyCFunction)cache_get, METH_O,
+        PyDoc_STR("Gets an entry from the cache or calls the factory function to produce one.")},
+    {"display", (PyCFunction)cache_display, METH_NOARGS,
+        PyDoc_STR("For debugging only.")},
+    {NULL, NULL}
+};
+
+PyTypeObject NodeType = {
+        PyObject_HEAD_INIT(NULL)
+        0,                                              /* ob_size */
+        MODULE_NAME "Node",                             /* tp_name */
+        sizeof(Node),                                   /* tp_basicsize */
+        0,                                              /* tp_itemsize */
+        (destructor)node_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|Py_TPFLAGS_BASETYPE,         /* tp_flags */
+        0,                                              /* tp_doc */
+        0,                                              /* tp_traverse */
+        0,                                              /* tp_clear */
+        0,                                              /* tp_richcompare */
+        0,                                              /* tp_weaklistoffset */
+        0,                                              /* tp_iter */
+        0,                                              /* tp_iternext */
+        0,                                              /* tp_methods */
+        0,                                              /* tp_members */
+        0,                                              /* 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 */
+};
+
+PyTypeObject CacheType = {
+        PyObject_HEAD_INIT(NULL)
+        0,                                              /* ob_size */
+        MODULE_NAME ".Cache",                           /* tp_name */
+        sizeof(Cache),                                  /* tp_basicsize */
+        0,                                              /* tp_itemsize */
+        (destructor)cache_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|Py_TPFLAGS_BASETYPE,         /* tp_flags */
+        0,                                              /* tp_doc */
+        0,                                              /* tp_traverse */
+        0,                                              /* tp_clear */
+        0,                                              /* tp_richcompare */
+        0,                                              /* tp_weaklistoffset */
+        0,                                              /* tp_iter */
+        0,                                              /* tp_iternext */
+        cache_methods,                                  /* tp_methods */
+        0,                                              /* tp_members */
+        0,                                              /* tp_getset */
+        0,                                              /* tp_base */
+        0,                                              /* tp_dict */
+        0,                                              /* tp_descr_get */
+        0,                                              /* tp_descr_set */
+        0,                                              /* tp_dictoffset */
+        (initproc)cache_init,                           /* tp_init */
+        0,                                              /* tp_alloc */
+        0,                                              /* tp_new */
+        0                                               /* tp_free */
+};
+
+extern int cache_setup_types(void)
+{
+    int rc;
+
+    NodeType.tp_new = PyType_GenericNew;
+    CacheType.tp_new = PyType_GenericNew;
+
+    rc = PyType_Ready(&NodeType);
+    if (rc < 0) {
+        return rc;
+    }
+
+    rc = PyType_Ready(&CacheType);
+    return rc;
+}
diff --git a/src/cache.h b/src/cache.h
new file mode 100644 (file)
index 0000000..1f13907
--- /dev/null
@@ -0,0 +1,73 @@
+/* cache.h - definitions for the LRU cache
+ *
+ * Copyright (C) 2004-2006 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.
+ */
+
+#ifndef PYSQLITE_CACHE_H
+#define PYSQLITE_CACHE_H
+#include "Python.h"
+
+/* The LRU cache is implemented as a combination of a doubly-linked with a
+ * dictionary. The list items are of type 'Node' and the dictionary has the
+ * nodes as values. */
+
+typedef struct _Node
+{
+    PyObject_HEAD
+    PyObject* key;
+    PyObject* data;
+    long count;
+    struct _Node* prev;
+    struct _Node* next;
+} Node;
+
+typedef struct
+{
+    PyObject_HEAD
+    int size;
+
+    /* a dictionary mapping keys to Node entries */
+    PyObject* mapping;
+
+    /* the factory callable */
+    PyObject* factory;
+
+    Node* first;
+    Node* last;
+
+    /* if set, decrement the factory function when the Cache is deallocated.
+     * this is almost always desirable, but not in the pysqlite context */
+    int decref_factory;
+} Cache;
+
+extern PyTypeObject NodeType;
+extern PyTypeObject CacheType;
+
+int node_init(Node* self, PyObject* args, PyObject* kwargs);
+void node_dealloc(Node* self);
+
+int cache_init(Cache* self, PyObject* args, PyObject* kwargs);
+void cache_dealloc(Cache* self);
+PyObject* cache_get(Cache* self, PyObject* args);
+
+int cache_setup_types(void);
+
+#endif
diff --git a/src/compat.h b/src/compat.h
new file mode 100644 (file)
index 0000000..d87eac9
--- /dev/null
@@ -0,0 +1,34 @@
+/* compat.h - compatibility macros
+ *
+ * Copyright (C) 2006 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.
+ */
+
+#ifndef PYSQLITE_COMPAT_H
+#define PYSQLITE_COMPAT_H
+
+/* define Py_ssize_t for pre-2.5 versions of Python */
+
+#if PY_VERSION_HEX < 0x02050000
+typedef int Py_ssize_t;
+typedef int (*lenfunc)(PyObject*);
+#endif
+
+#endif
diff --git a/src/connection.c b/src/connection.c
new file mode 100644 (file)
index 0000000..9058657
--- /dev/null
@@ -0,0 +1,1141 @@
+/* connection.c - the connection type
+ *
+ * Copyright (C) 2004-2006 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.
+ */