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

diff --git a/LICENSE b/LICENSE
index a5b9fd2..268c33b 100644 (file)
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2004 Gerhard Häring
+Copyright (c) 2004-2007 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
index 4a50054..78c82b6 100644 (file)
@@ -1,5 +1,7 @@
 include MANIFEST.in
 include LICENSE
+include ez_setup.py
+include extended_setup.py
 include docutilsupport.py
 include src/*.h
 include doc/*.html
index 895db91..c3fbe13 100644 (file)
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,11 +1,12 @@
 Metadata-Version: 1.0
 Name: pysqlite
-Version: 2.3.3
+Version: 2.4.0
 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/pub/software/pysqlite/releases/2.4/2.4.0/
 Description: Python interface to SQLite 3
         
         pysqlite is an interface to the SQLite 3.x embedded relational database engine.
diff --git a/doc/code/adapter_datetime.py b/doc/code/adapter_datetime.py
deleted file mode 100644 (file)
index bf91997..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-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
deleted file mode 100644 (file)
index 9731c44..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-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
deleted file mode 100644 (file)
index e170343..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-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/authorizer.py b/doc/code/authorizer.py
deleted file mode 100644 (file)
index 5f89716..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-from pysqlite2 import dbapi2 as sqlite
-
-def authorizer_callback(action, arg1, arg2, dbname, source):
-    if action != sqlite.SQLITE_SELECT:
-        return sqlite.SQLITE_DENY
-    if arg1 == "private_table":
-        return sqlite.SQLITE_DENY
-    return sqlite.SQLITE_OK
-
-con = sqlite.connect(":memory:")
-con.executescript("""
-    create table public_table(c1, c2);
-    create table private_table(c1, c2);
-    """)
-con.set_authorizer(authorizer_callback)
-
-try:
-    con.execute("select * from private_table")
-except sqlite.DatabaseError, e:
-    print "SELECT FROM private_table =>", e.args[0]     # access ... prohibited
-
-try:
-    con.execute("insert into public_table(c1, c2) values (1, 2)")
-except sqlite.DatabaseError, e:
-    print "DML command =>", e.args[0]     # access ... prohibited
-
diff --git a/doc/code/collation_reverse.py b/doc/code/collation_reverse.py
deleted file mode 100644 (file)
index 40f7a5f..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-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
deleted file mode 100644 (file)
index 3a5ef34..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-# 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
deleted file mode 100644 (file)
index cf13825..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-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
deleted file mode 100644 (file)
index c9c853a..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-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
deleted file mode 100644 (file)
index 47467f4..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-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
deleted file mode 100644 (file)
index e8f64d5..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-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
deleted file mode 100644 (file)
index 59766b1..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-# 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
deleted file mode 100644 (file)
index 6a33067..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-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
deleted file mode 100644 (file)
index 436fc6d..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-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
deleted file mode 100644 (file)
index b9799ce..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-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
deleted file mode 100644 (file)
index 4dd0a67..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-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
deleted file mode 100644 (file)
index 46be8a9..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-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
deleted file mode 100644 (file)
index 3f0be35..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-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
deleted file mode 100644 (file)
index 49d4855..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-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
deleted file mode 100644 (file)
index 4ec04aa..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-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
deleted file mode 100644 (file)
index 6d2ae77..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-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
deleted file mode 100644 (file)
index d0ebd02..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-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
deleted file mode 100644 (file)
index 46abdda..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-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
deleted file mode 100644 (file)
index eedd79e..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-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
deleted file mode 100644 (file)
index b077856..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-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
deleted file mode 100644 (file)
index 79fd5d3..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-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
deleted file mode 100644 (file)
index 4d85f40..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-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
deleted file mode 100644 (file)
index f6cde80..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-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
deleted file mode 100644 (file)
index f3be82f..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-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
deleted file mode 100644 (file)
index 223cb11..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-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
deleted file mode 100644 (file)
index 0916e88..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-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/install-source-win32.html b/doc/install-source-win32.html
new file mode 100644 (file)
index 0000000..c030632
--- /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.1: 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.html b/doc/install-source.html
new file mode 100644 (file)
index 0000000..60222da
--- /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.1: 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/usage-guide.html b/doc/usage-guide.html
new file mode 100644 (file)
index 0000000..ce4972e
--- /dev/null
@@ -0,0 +1,1469 @@
+<?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.1: 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-2007 Gerhard Häring</div>
+</div>
+<p>Last updated for pysqlite 2.4.0</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 class="line"><a class="reference" href="#setting-an-authorizer-callback">3.6 Setting an authorizer callback</a></div>
+<div class="line"><a class="reference" href="#setting-a-progress-handler">3.7 Setting a progress handler</a></div>
+<div class="line"><a class="reference" href="#using-the-connection-as-a-context-manager">3.8 Using the connection as a context manager</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 class="line"><a class="reference" href="#combining-apsw-and-pysqlite">7. Combining APSW and pysqlite</a></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.</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!</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_identifier">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_identifier">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.</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>enable_callback_tracebacks</strong> function - <tt class="docutils literal"><span class="pre">enable_callback_tracebacks(flag)</span></tt>
+Can be used to enable displaying tracebacks of exceptions in user-defined functions, aggregates and other callbacks being printed to stderr.
+methods should never raise any exception. This feature is off by default.</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_identifier">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_identifier">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>
+</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_identifier">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_identifier">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>
+</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_identifier">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>
+</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_identifier">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_identifier">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>
+<li><p class="first"><strong>executescript</strong> method</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">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_identifier">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>
+</li>
+<li><p class="first"><strong>interrupt</strong> method</p>
+<p>This method has no arguments. You can call it from a different thread to
+abort any queries that are currently executing on the connection. This can
+be used to let the user abort runaway queries, for example.</p>
+</li>
+<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 -1 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_identifier">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_identifier">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_identifier">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_identifier">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_identifier">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_identifier">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>
+</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.  Any exception in the user-defined
+function leads to the SQL statement executed being aborted.</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_identifier">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. Any exception in the
+aggregate's <em>__init__</em>, <em>step</em> or <em>finalize</em> methods lead to the SQL
+statement executed being aborted.</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_identifier">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_identifier">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_identifier">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;occurred:"</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_identifier">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 class="section">
+<h2><a id="setting-an-authorizer-callback" name="setting-an-authorizer-callback">3.6 Setting an authorizer callback</a></h2>
+<p>You can set an authorizer callback if you want to restrict what your users can
+do with the database. This is mostly useful if you accept arbitrary SQL from
+users and want to execute it safely. See the relevant section in the SQL
+documentation for details:
+<a class="reference" href="http://sqlite.org/capi3ref.html#sqlite3_set_authorizer">http://sqlite.org/capi3ref.html#sqlite3_set_authorizer</a></p>
+<p>All necessary constants like SQLITE_OK, SQLITE_DENY, SQLITE_IGNORE,
+SQLITE_SELECT, SQLITE_CREATE_INDEX and all other authorizer-related constants
+are available through the dbapi2 module.</p>
+<p>Here's an example that demonstrates the usage of this function:</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_identifier">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">authorizer_callback</span><span class="p_operator">(</span><span class="p_identifier">action</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">arg1</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">arg2</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">dbname</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">source</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">action</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">SQLITE_SELECT</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">sqlite</span><span class="p_operator">.</span><span class="p_identifier">SQLITE_DENY</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">arg1</span><span class="p_default">&nbsp;</span><span class="p_operator">==</span><span class="p_default">&nbsp;</span><span class="p_string">"private_table"</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">sqlite</span><span class="p_operator">.</span><span class="p_identifier">SQLITE_DENY</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">sqlite</span><span class="p_operator">.</span><span class="p_identifier">SQLITE_OK</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">executescript</span><span class="p_operator">(</span><span class="p_tripledouble">"""<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;create&nbsp;table&nbsp;public_table(c1,&nbsp;c2);<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;create&nbsp;table&nbsp;private_table(c1,&nbsp;c2);<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;"""</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">set_authorizer</span><span class="p_operator">(</span><span class="p_identifier">authorizer_callback</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">try</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&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;*&nbsp;from&nbsp;private_table"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</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">DatabaseError</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;</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_string">"SELECT&nbsp;FROM&nbsp;private_table&nbsp;=&gt;"</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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_commentline">#&nbsp;access&nbsp;...&nbsp;prohibited</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_word">try</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&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">"insert&nbsp;into&nbsp;public_table(c1,&nbsp;c2)&nbsp;values&nbsp;(1,&nbsp;2)"</span><span class="p_operator">)</span><span class="p_default"><br/>
+</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">DatabaseError</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;</span><span class="p_word">print</span><span class="p_default">&nbsp;</span><span class="p_string">"DML&nbsp;command&nbsp;=&gt;"</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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_commentline">#&nbsp;access&nbsp;...&nbsp;prohibited</span><span class="p_default"><br/>
+</span>
+</div>
+</blockquote>
+</div>
+<div class="section">
+<h2><a id="setting-a-progress-handler" name="setting-a-progress-handler">3.7 Setting a progress handler</a></h2>
+<p>If you want to get called by SQLite during long-running operations, you can set
+a progress handler. An example use for this is to keep a GUI updated during a
+long-running query.</p>
+<blockquote>
+<div class="code-block">
+<span class="p_word">def</span><span class="p_default">&nbsp;</span><span class="p_defname">set_progress_handler</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">handler</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_identifier">n</span><span class="p_operator">)</span>
+</div>
+</blockquote>
+<p>The progress handler will be called every n SQLite virtual machine opcodes. If
+handler returns a nonzero value, the query is aborted with an OperationalError.</p>
+<p>Here's an example that demonstrates the usage of this function:</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_identifier">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">progress</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_string">"Query&nbsp;still&nbsp;executing.&nbsp;Please&nbsp;wait&nbsp;..."</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">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/>
+<br/>
+</span><span class="p_commentline">#&nbsp;Let's&nbsp;create&nbsp;some&nbsp;data</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;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_identifier">x</span><span class="p_operator">,)</span><span class="p_default">&nbsp;</span><span class="p_word">for</span><span class="p_default">&nbsp;</span><span class="p_identifier">x</span><span class="p_default">&nbsp;</span><span class="p_word">in</span><span class="p_default">&nbsp;</span><span class="p_identifier">xrange</span><span class="p_operator">(</span><span class="p_number">300</span><span class="p_operator">)])</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;A&nbsp;progress&nbsp;handler,&nbsp;executed&nbsp;every&nbsp;10&nbsp;million&nbsp;opcodes</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">set_progress_handler</span><span class="p_operator">(</span><span class="p_identifier">progress</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_number">10000000</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;A&nbsp;particularly&nbsp;long-running&nbsp;query</span><span class="p_default"><br/>
+</span><span class="p_identifier">killer_stament</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_tripledouble">"""<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;select&nbsp;count(*)&nbsp;from&nbsp;(<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;select&nbsp;t1.x&nbsp;from&nbsp;test&nbsp;t1,&nbsp;test&nbsp;t2,&nbsp;test&nbsp;t3<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;)<br/>
+&nbsp;&nbsp;&nbsp;&nbsp;"""</span><span class="p_default"><br/>
+<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_identifier">killer_stament</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">"-"</span><span class="p_default">&nbsp;</span><span class="p_operator">*</span><span class="p_default">&nbsp;</span><span class="p_number">50</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;Clear&nbsp;the&nbsp;progress&nbsp;handler</span><span class="p_default"><br/>
+</span><span class="p_identifier">con</span><span class="p_operator">.</span><span class="p_identifier">set_progress_handler</span><span class="p_operator">(</span><span class="p_word">None</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_number">0</span><span class="p_operator">)</span><span class="p_default"><br/>
+<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_identifier">killer_stament</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span>
+</div>
+</blockquote>
+</div>
+<div class="section">
+<h2><a id="using-the-connection-as-a-context-manager" name="using-the-connection-as-a-context-manager">3.8 Using the connection as a context manager</a></h2>
+<p>With Python 2.5 or higher, pysqlite's connection objects can be used as context
+managers that automatically commit or rollback transactions.  In the event of
+an exception, the transaction is rolled back; otherwise, the transaction is
+committed:</p>
+<blockquote>
+<div class="code-block">
+<span class="p_word">from</span><span class="p_default">&nbsp;</span><span class="p_identifier">__future__</span><span class="p_default">&nbsp;</span><span class="p_word">import</span><span class="p_default">&nbsp;</span><span class="p_identifier">with_statement</span><span class="p_default"><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_identifier">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">execute</span><span class="p_operator">(</span><span class="p_string">"create&nbsp;table&nbsp;person&nbsp;(id&nbsp;integer&nbsp;primary&nbsp;key,&nbsp;firstname&nbsp;varchar&nbsp;unique)"</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;Successful,&nbsp;con.commit()&nbsp;is&nbsp;called&nbsp;automatically&nbsp;afterwards</span><span class="p_default"><br/>
+</span><span class="p_identifier">with</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&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">"insert&nbsp;into&nbsp;person(firstname)&nbsp;values&nbsp;(?)"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_string">"Joe"</span><span class="p_operator">,))</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;con.rollback()&nbsp;is&nbsp;called&nbsp;after&nbsp;the&nbsp;with&nbsp;block&nbsp;finishes&nbsp;with&nbsp;an&nbsp;exception,&nbsp;the</span><span class="p_default"><br/>
+</span><span class="p_commentline">#&nbsp;exception&nbsp;is&nbsp;still&nbsp;raised&nbsp;and&nbsp;must&nbsp;be&nbsp;catched</span><span class="p_default"><br/>
+</span><span class="p_word">try</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p_identifier">with</span><span class="p_default">&nbsp;</span><span class="p_identifier">con</span><span class="p_operator">:</span><span class="p_default"><br/>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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">"insert&nbsp;into&nbsp;person(firstname)&nbsp;values&nbsp;(?)"</span><span class="p_operator">,</span><span class="p_default">&nbsp;</span><span class="p_operator">(</span><span class="p_string">"Joe"</span><span class="p_operator">,))</span><span class="p_default"><br/>
+</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">IntegrityError</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_string">"couldn't&nbsp;add&nbsp;Joe&nbsp;twice"</span><span class="p_default"><br/>
+<br/>
+</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_identifier">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>
+</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_identifier">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>
+</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_identifier">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>
+<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_identifier">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_identifier">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>
+</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_identifier">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>
+</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_identifier">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 class="section">
+<h2><a id="combining-apsw-and-pysqlite" name="combining-apsw-and-pysqlite">7. Combining APSW and pysqlite</a></h2>
+<p>APSW is &quot;Another Python SQLite Wrapper&quot;. Its goal is to directly wrap the
+SQLite API for Python. If there's SQLite functionality that is only wrapped via
+APSW, but not (yet) via pysqlite, then you can still use the APSW functionality
+in pysqlite.</p>
+<p>Just use the APSW Connection as a parameter to the connect function and reuse
+an existing APSW connection like 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_identifier">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">apsw</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_identifier">apsw_con</span><span class="p_default">&nbsp;</span><span class="p_operator">=</span><span class="p_default">&nbsp;</span><span class="p_identifier">apsw</span><span class="p_operator">.</span><span class="p_identifier">Connection</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">apsw_con</span><span class="p_operator">.</span><span class="p_identifier">createscalarfunction</span><span class="p_operator">(</span><span class="p_string">"times_two"</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_number">2</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_number">1</span><span class="p_operator">)</span><span class="p_default"><br/>
+<br/>
+</span><span class="p_commentline">#&nbsp;Create&nbsp;pysqlite&nbsp;connection&nbsp;from&nbsp;APSW&nbsp;connection</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_identifier">apsw_con</span><span class="p_operator">)</span><span class="p_default"><br/>
+</span><span class="p_identifier">result</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">execute</span><span class="p_operator">(</span><span class="p_string">"select&nbsp;times_two(15)"</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">assert</span><span class="p_default">&nbsp;</span><span class="p_identifier">result</span><span class="p_default">&nbsp;</span><span class="p_operator">==</span><span class="p_default">&nbsp;</span><span class="p_number">30</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/>
+</span>
+</div>
+<p>This feature only works if both APSW and pysqlite are dynamically linked
+against the same SQLite shared library. I. e. it will <em>not</em> work on Windows
+without a custom built pysqlite and APSW.</p>
+</div>
+</div>
+</div>
+</body>
+</html>
index 0a74245..24b0d8d 100644 (file)
@@ -3,9 +3,9 @@ pysqlite usage guide
 --------------------
 
 | (c) 2004-2005 David Rushby
-| (c) 2005-2006 Gerhard Häring
+| (c) 2005-2007 Gerhard Häring
 
-Last updated for pysqlite 2.3.0
+Last updated for pysqlite 2.4.0
 
 Table Of Contents
 =================
@@ -26,6 +26,8 @@ Table Of Contents
 |   `3.4 Checking for complete statements`_
 |   `3.5 Enabling SQLite's shared cache`_
 |   `3.6 Setting an authorizer callback`_
+|   `3.7 Setting a progress handler`_
+|   `3.8 Using the connection as a context manager`_
 | `4. SQLite and Python types`_
 |   `4.1 Introduction`_
 |   `4.2 Using adapters to store additional Python types in SQLite databases`_
@@ -37,6 +39,7 @@ Table Of Contents
 | `6. Using pysqlite efficiently`_
 |   `6.1 Using shortcut methods`_
 |   `6.2 Accessing columns by name instead of by index`_
+| `7. Combining APSW and pysqlite`_
 
 0. Introduction
 ===============
@@ -194,7 +197,7 @@ Python DB API.
 
       .. code-block::
        :language: Python
-       :source-file: code/parse_colnames.py
+       :source-file: includes/sqlite3/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
@@ -211,7 +214,7 @@ Python DB API.
 
     .. code-block::
      :language: Python
-     :source-file: code/countcursors.py
+     :source-file: includes/sqlite3/countcursors.py
 
   * **cached_statements** - pysqlite internally uses a statement cache to avoid
     SQL parsing overhead. If you want to explicitly set the number of
@@ -278,7 +281,7 @@ Python DB API.
 
     .. code-block::
      :language: Python
-     :source-file: code/row_factory.py
+     :source-file: includes/sqlite3/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
@@ -305,7 +308,7 @@ Python DB API.
 
      .. code-block::
       :language: Python
-      :source-file: code/text_factory.py
+      :source-file: includes/sqlite3/text_factory.py
 
   * **total_changes** attribute (read-only)
 
@@ -325,7 +328,7 @@ Python DB API.
 
     .. code-block::
      :language: Python
-     :source-file: code/execute_1.py
+     :source-file: includes/sqlite3/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
@@ -334,7 +337,7 @@ Python DB API.
 
     .. code-block::
      :language: Python
-     :source-file: code/execute_2.py
+     :source-file: includes/sqlite3/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.
@@ -342,7 +345,7 @@ Python DB API.
 
     .. code-block::
      :language: Python
-     :source-file: code/execute_3.py
+     :source-file: includes/sqlite3/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
@@ -366,14 +369,14 @@ Python DB API.
 
     .. code-block::
      :language: Python
-     :source-file: code/executemany_1.py
+     :source-file: includes/sqlite3/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
+     :source-file: includes/sqlite3/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
@@ -395,7 +398,7 @@ Python DB API.
 
     .. code-block::
      :language: Python
-     :source-file: code/executescript.py
+     :source-file: includes/sqlite3/executescript.py
 
   * **interrupt** method
 
@@ -445,7 +448,7 @@ is it comprehensive in its coverage of anything else.
 
     .. code-block::
      :language: Python
-     :source-file: code/connect_db_1.py
+     :source-file: includes/sqlite3/connect_db_1.py
 
 
     **Example 2**
@@ -454,7 +457,7 @@ is it comprehensive in its coverage of anything else.
 
     .. code-block::
      :language: Python
-     :source-file: code/connect_db_2.py
+     :source-file: includes/sqlite3/connect_db_2.py
 
 
 2.2 Executing SQL statements
@@ -480,7 +483,7 @@ This example shows the simplest way to print the entire contents of the ``people
 
 .. code-block::
  :language: Python
- :source-file: code/execsql_printall_1.py
+ :source-file: includes/sqlite3/execsql_printall_1.py
 
 Sample output::
 
@@ -493,7 +496,7 @@ single row at a time from a SELECT-cursor:
 
 .. code-block::
  :language: Python
- :source-file: code/execsql_fetchonerow.py
+ :source-file: includes/sqlite3/execsql_fetchonerow.py
 
 Sample output::
 
@@ -509,7 +512,7 @@ people)
 
 .. code-block::
  :language: Python
- :source-file: code/simple_tableprinter.py
+ :source-file: includes/sqlite3/simple_tableprinter.py
 
 Sample output::
 
@@ -524,7 +527,7 @@ Let's insert more people into the people table:
 
 .. code-block::
  :language: Python
- :source-file: code/insert_more_people.py
+ :source-file: includes/sqlite3/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
@@ -589,7 +592,7 @@ functions with the connection's **create_function** method:
 
   .. code-block::
    :language: Python
-   :source-file: code/md5func.py
+   :source-file: includes/sqlite3/md5func.py
 
 3.2 Creating user-defined aggregates
 ------------------------------------
@@ -614,7 +617,7 @@ create new aggregate functions with the connection's *create_aggregate* method.
 
   .. code-block::
    :language: Python
-   :source-file: code/mysumaggr.py
+   :source-file: includes/sqlite3/mysumaggr.py
 
 3.3 Creating and using collations
 ---------------------------------
@@ -638,7 +641,7 @@ The following example shows a custom collation that sorts "the wrong way":
 
   .. code-block::
    :language: Python
-   :source-file: code/collation_reverse.py
+   :source-file: includes/sqlite3/collation_reverse.py
 
 To remove a collation, call `create_collation` with None as callable:
 
@@ -658,7 +661,7 @@ 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
+   :source-file: includes/sqlite3/complete_statement.py
 
 3.5 Enabling SQLite's shared cache
 ----------------------------------
@@ -668,7 +671,7 @@ To enable SQLite's shared cache for the calling thread, call the function
 
   .. code-block::
    :language: Python
-   :source-file: code/shared_cache.py
+   :source-file: includes/sqlite3/shared_cache.py
 
 3.6 Setting an authorizer callback
 ----------------------------------
@@ -687,8 +690,39 @@ Here's an example that demonstrates the usage of this function:
 
   .. code-block::
    :language: Python
-   :source-file: code/authorizer.py
+   :source-file: includes/sqlite3/authorizer.py
 
+3.7 Setting a progress handler
+------------------------------
+
+If you want to get called by SQLite during long-running operations, you can set
+a progress handler. An example use for this is to keep a GUI updated during a
+long-running query. 
+
+  .. code-block:: Python
+
+    def set_progress_handler(self, handler, n)
+
+The progress handler will be called every n SQLite virtual machine opcodes. If
+handler returns a nonzero value, the query is aborted with an OperationalError.
+
+Here's an example that demonstrates the usage of this function:
+
+  .. code-block::
+   :language: Python
+   :source-file: includes/sqlite3/progress.py
+
+3.8 Using the connection as a context manager
+---------------------------------------------
+
+With Python 2.5 or higher, pysqlite's connection objects can be used as context
+managers that automatically commit or rollback transactions.  In the event of
+an exception, the transaction is rolled back; otherwise, the transaction is
+committed:
+
+  .. code-block::
+    :language: Python
+    :source-file: includes/sqlite3/ctx_manager.py
 
 4. SQLite and Python types
 ==========================
@@ -766,7 +800,7 @@ return the converted value. The parameter ``protocol`` will be
 
 .. code-block::
  :language: Python
- :source-file: code/adapter_point_1.py
+ :source-file: includes/sqlite3/adapter_point_1.py
 
 4.2.2 Registering an adapter callable
 -------------------------------------
@@ -776,7 +810,7 @@ string representation and register the function with ``register_adapter``.
 
 .. code-block::
  :language: Python
- :source-file: code/adapter_point_2.py
+ :source-file: includes/sqlite3/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!!!
@@ -787,7 +821,7 @@ representation, but as Unix timestamp.
 
 .. code-block::
  :language: Python
- :source-file: code/adapter_datetime.py
+ :source-file: includes/sqlite3/adapter_datetime.py
 
 4.3 Converting SQLite values to custom Python types
 ---------------------------------------------------
@@ -826,7 +860,7 @@ The following example illustrates both ways.
 
 .. code-block::
  :language: Python
- :source-file: code/converter_point.py
+ :source-file: includes/sqlite3/converter_point.py
 
 4.4 Default pysqlite adapters and converters
 --------------------------------------------
@@ -845,7 +879,7 @@ The following example demonstrates this.
 
 .. code-block::
  :language: Python
- :source-file: code/pysqlite_datetime.py
+ :source-file: includes/sqlite3/pysqlite_datetime.py
 
 5. Controlling Transactions
 ---------------------------
@@ -872,10 +906,6 @@ 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
 -----------------------------
 
@@ -892,7 +922,7 @@ only a single call on the Connection object.
 
 .. code-block::
  :language: Python
- :source-file: code/shortcut_methods.py
+ :source-file: includes/sqlite3/shortcut_methods.py
 
 6.2 Accessing columns by name instead of by index
 -------------------------------------------------
@@ -905,5 +935,24 @@ case-insensitively by name:
 
 .. code-block::
  :language: Python
- :source-file: code/rowclass.py
+ :source-file: includes/sqlite3/rowclass.py
+
+7. Combining APSW and pysqlite
+------------------------------
+
+APSW is "Another Python SQLite Wrapper". Its goal is to directly wrap the
+SQLite API for Python. If there's SQLite functionality that is only wrapped via
+APSW, but not (yet) via pysqlite, then you can still use the APSW functionality
+in pysqlite.
+
+Just use the APSW Connection as a parameter to the connect function and reuse
+an existing APSW connection like this.
+
+.. code-block::
+  :language: Python
+  :source-file: includes/sqlite3/apsw_example.py
+
+This feature only works if both APSW and pysqlite are dynamically linked
+against the same SQLite shared library. I. e. it will *not* work on Windows
+without a custom built pysqlite and APSW.
 
diff --git a/extended_setup.py b/extended_setup.py
new file mode 100644 (file)
index 0000000..1155e49
--- /dev/null
@@ -0,0 +1,101 @@
+#-*- coding: ISO-8859-1 -*-
+# ext_setup.py: setuptools extensions for the distutils script
+#
+# Copyright (C) 2004-2007 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, sys
+
+from ez_setup import use_setuptools
+from distutils.command.build import build
+from distutils.command.build_ext import build_ext
+use_setuptools()
+
+import setuptools
+import setup
+
+class DocBuilder(setuptools.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("..")
+
+class AmalgamationBuilder(build):
+    description = "Build a statically built pysqlite using the amalgamtion."
+
+    def __init__(self, *args, **kwargs):
+        MyBuildExt.amalgamation = True
+        build.__init__(self, *args, **kwargs)
+
+class MyBuildExt(build_ext):
+    amalgamation = False
+
+    def build_extension(self, ext):
+        if self.amalgamation:
+            ext.sources.append("sqlite3.c")
+        build_ext.build_extension(self, ext)
+
+    def __setattr__(self, k, v):
+        # Make sure we don't link against the SQLite library, no matter what setup.cfg says
+        if self.amalgamation and k == "libraries":
+            v = None
+        self.__dict__[k] = v
+
+
+def main():
+    setup_args = setup.get_setup_args()
+    setup_args["extras_require"] = {"build_docs": ["docutils", "SilverCity"]}
+    setup_args["test_suite"] = "pysqlite2.test.suite"
+    setup_args["cmdclass"] = {"build_docs": DocBuilder, "build_ext": MyBuildExt, "build_static": AmalgamationBuilder}
+    setup_args["extras_require"] = {"build_docs": ["docutils", "SilverCity"]}
+    setuptools.setup(**setup_args)
+
+if __name__ == "__main__":
+    main()
diff --git a/ez_setup.py b/ez_setup.py
new file mode 100644 (file)
index 0000000..bfda8cd
--- /dev/null
@@ -0,0 +1,231 @@
+#!python
+"""Bootstrap setuptools installation
+
+If you want to use setuptools in your package's setup.py, just include this
+file in the same directory with it, and add this to the top of your setup.py::
+
+    from ez_setup import use_setuptools
+    use_setuptools()
+
+If you want to require a specific version of setuptools, set a download
+mirror, or use an alternate download directory, you can do so by supplying
+the appropriate options to ``use_setuptools()``.
+
+This file can also be run as a script to install or upgrade setuptools.
+"""
+import sys
+DEFAULT_VERSION = "0.6c6"
+DEFAULT_URL     = "http://cheeseshop.python.org/packages/%s/s/setuptools/" % sys.version[:3]
+
+md5_data = {
+    'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
+    'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
+    'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
+    'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
+    'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
+    'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
+    'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
+    'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
+    'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
+    'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
+    'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
+    'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
+    'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
+    'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
+    'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
+    'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
+    'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
+    'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
+    'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
+    'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
+    'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
+    'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
+    'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
+    'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
+}
+
+import sys, os
+
+def _validate_md5(egg_name, data):
+    if egg_name in md5_data:
+        from md5 import md5
+        digest = md5(data).hexdigest()
+        if digest != md5_data[egg_name]:
+            print >>sys.stderr, (
+                "md5 validation of %s failed!  (Possible download problem?)"
+                % egg_name
+            )
+            sys.exit(2)
+    return data
+
+
+def use_setuptools(
+    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+    download_delay=15
+):
+    """Automatically find/download setuptools and make it available on sys.path
+
+    `version` should be a valid setuptools version number that is available
+    as an egg for download under the `download_base` URL (which should end with
+    a '/').  `to_dir` is the directory where setuptools will be downloaded, if
+    it is not already available.  If `download_delay` is specified, it should
+    be the number of seconds that will be paused before initiating a download,
+    should one be required.  If an older version of setuptools is installed,
+    this routine will print a message to ``sys.stderr`` and raise SystemExit in
+    an attempt to abort the calling script.
+    """
+    try:
+        import setuptools
+        if setuptools.__version__ == '0.0.1':
+            print >>sys.stderr, (
+            "You have an obsolete version of setuptools installed.  Please\n"
+            "remove it from your system entirely before rerunning this script."
+            )
+            sys.exit(2)
+    except ImportError:
+        egg = download_setuptools(version, download_base, to_dir, download_delay)
+        sys.path.insert(0, egg)
+        import setuptools; setuptools.bootstrap_install_from = egg
+
+    import pkg_resources
+    try:
+        pkg_resources.require("setuptools>="+version)
+
+    except pkg_resources.VersionConflict, e:
+        # XXX could we install in a subprocess here?
+        print >>sys.stderr, (
+            "The required version of setuptools (>=%s) is not available, and\n"
+            "can't be installed while this script is running. Please install\n"
+            " a more recent version first.\n\n(Currently using %r)"
+        ) % (version, e.args[0])
+        sys.exit(2)
+
+def download_setuptools(
+    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+    delay = 15
+):
+    """Download setuptools from a specified location and return its filename
+
+    `version` should be a valid setuptools version number that is available
+    as an egg for download under the `download_base` URL (which should end
+    with a '/'). `to_dir` is the directory where the egg will be downloaded.
+    `delay` is the number of seconds to pause before an actual download attempt.
+    """
+    import urllib2, shutil
+    egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
+    url = download_base + egg_name
+    saveto = os.path.join(to_dir, egg_name)
+    src = dst = None
+    if not os.path.exists(saveto):  # Avoid repeated downloads
+        try:
+            from distutils import log
+            if delay:
+                log.warn("""
+---------------------------------------------------------------------------
+This script requires setuptools version %s to run (even to display
+help).  I will attempt to download it for you (from
+%s), but
+you may need to enable firewall access for this script first.
+I will start the download in %d seconds.
+
+(Note: if this machine does not have network access, please obtain the file
+
+   %s
+
+and place it in this directory before rerunning this script.)
+---------------------------------------------------------------------------""",
+                    version, download_base, delay, url
+                ); from time import sleep; sleep(delay)
+            log.warn("Downloading %s", url)
+            src = urllib2.urlopen(url)
+            # Read/write all in one block, so we don't create a corrupt file
+            # if the download is interrupted.
+            data = _validate_md5(egg_name, src.read())
+            dst = open(saveto,"wb"); dst.write(data)
+        finally:
+            if src: src.close()
+            if dst: dst.close()
+    return os.path.realpath(saveto)
+
+def main(argv, version=DEFAULT_VERSION):
+    """Install or upgrade setuptools and EasyInstall"""
+
+    try:
+        import setuptools
+    except ImportError:
+        egg = None
+        try:
+            egg = download_setuptools(version, delay=0)
+            sys.path.insert(0,egg)
+            from setuptools.command.easy_install import main
+            return main(list(argv)+[egg])   # we're done here
+        finally:
+            if egg and os.path.exists(egg):
+                os.unlink(egg)
+    else:
+        if setuptools.__version__ == '0.0.1':
+            # tell the user to uninstall obsolete version
+            use_setuptools(version)
+
+    req = "setuptools>="+version
+    import pkg_resources
+    try:
+        pkg_resources.require(req)
+    except pkg_resources.VersionConflict:
+        try:
+            from setuptools.command.easy_install import main
+        except ImportError:
+            from easy_install import main
+        main(list(argv)+[download_setuptools(delay=0)])
+        sys.exit(0) # try to force an exit
+    else:
+        if argv:
+            from setuptools.command.easy_install import main
+            main(argv)
+        else:
+            print "Setuptools version",version,"or greater has been installed."
+            print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
+
+
+
+def update_md5(filenames):
+    """Update our built-in md5 registry"""
+
+    import re
+    from md5 import md5
+
+    for name in filenames:
+        base = os.path.basename(name)
+        f = open(name,'rb')
+        md5_data[base] = md5(f.read()).hexdigest()
+        f.close()
+
+    data = ["    %r: %r,\n" % it for it in md5_data.items()]
+    data.sort()
+    repl = "".join(data)
+
+    import inspect
+    srcfile = inspect.getsourcefile(sys.modules[__name__])
+    f = open(srcfile, 'rb'); src = f.read(); f.close()
+
+    match = re.search("\nmd5_data = {\n([^}]+)}", src)
+    if not match:
+        print >>sys.stderr, "Internal error!"
+        sys.exit(2)
+
+    src = src[:match.start(1)] + repl + src[match.end(1):]
+    f = open(srcfile,'w')
+    f.write(src)
+    f.close()
+
+
+if __name__=='__main__':
+    if len(sys.argv)>2 and sys.argv[1]=='--md5update':
+        update_md5(sys.argv[2:])
+    else:
+        main(sys.argv[1:])
+
+
+
+
+
index f6c5eff..4028868 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/__init__.py: the pysqlite2 package.
 #
-# Copyright (C) 2005 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
index d89e4c4..d07f7f0 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/dbapi2.py: the DB-API 2.0 interface
 #
-# Copyright (C) 2004-2005 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
@@ -48,7 +48,7 @@ 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(".")]) 
+sqlite_version_info = tuple([int(x) for x in sqlite_version.split(".")])
 
 Binary = buffer
 
index bef87e5..5b10c77 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/test/__init__.py: the package containing the test suite
 #
-# Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
 #    misrepresented as being the original software.
 # 3. This notice may not be removed or altered from any source distribution.
 
+import os, sys
 import unittest
+
+if os.path.exists("extended_setup.py"):
+    print "-" * 75
+    print "You should not run the test suite from the pysqlite build directory."
+    print "This does not work well because the extension module cannot be found."
+    print "Just run the test suite from somewhere else, please!"
+    print "-" * 75
+    sys.exit(1)
+
 from pysqlite2.test import dbapi, types, userfunctions, factory, transactions,\
     hooks, regression
 from pysqlite2 import dbapi2 as sqlite
 
 def suite():
-    return unittest.TestSuite(
-        (dbapi.suite(), types.suite(), userfunctions.suite(), factory.suite(),\
-         transactions.suite(), hooks.suite(), regression.suite()))
+    tests = [dbapi.suite(), types.suite(), userfunctions.suite(),
+      factory.suite(), transactions.suite(), hooks.suite(), regression.suite()]
+    if sys.version_info >= (2, 5, 0):
+        from pysqlite2.test import py25tests
+        tests.append(py25tests.suite())
+
+    return unittest.TestSuite(tuple(tests))
 
 def test():
     runner = unittest.TextTestRunner()
index 408836a..f715217 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/test/dbapi.py: tests for DB-API compliance
 #
-# Copyright (C) 2004-2005 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
@@ -22,6 +22,7 @@
 # 3. This notice may not be removed or altered from any source distribution.
 
 import unittest
+import sys
 import threading
 import pysqlite2.dbapi2 as sqlite
 
@@ -223,12 +224,45 @@ class CursorTests(unittest.TestCase):
         except sqlite.ProgrammingError:
             pass
 
+    def CheckExecuteParamList(self):
+        self.cu.execute("insert into test(name) values ('foo')")
+        self.cu.execute("select name from test where name=?", ["foo"])
+        row = self.cu.fetchone()
+        self.failUnlessEqual(row[0], "foo")
+
+    def CheckExecuteParamSequence(self):
+        class L(object):
+            def __len__(self):
+                return 1
+            def __getitem__(self, x):
+                assert x == 0
+                return "foo"
+
+        self.cu.execute("insert into test(name) values ('foo')")
+        self.cu.execute("select name from test where name=?", L())
+        row = self.cu.fetchone()
+        self.failUnlessEqual(row[0], "foo")
+
     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 CheckExecuteDictMapping_Mapping(self):
+        # Test only works with Python 2.5 or later
+        if sys.version_info < (2, 5, 0):
+            return
+
+        class D(dict):
+            def __missing__(self, key):
+                return "foo"
+
+        self.cu.execute("insert into test(name) values ('foo')")
+        self.cu.execute("select name from test where name=:name", D())
+        row = self.cu.fetchone()
+        self.failUnlessEqual(row[0], "foo")
+
     def CheckExecuteDictMappingTooLittleArgs(self):
         self.cu.execute("insert into test(name) values ('foo')")
         try:
@@ -378,6 +412,12 @@ class CursorTests(unittest.TestCase):
         res = self.cu.fetchmany(100)
         self.failUnlessEqual(res, [])
 
+    def CheckFetchmanyKwArg(self):
+        """Checks if fetchmany works with keyword arguments"""
+        self.cu.execute("select name from test")
+        res = self.cu.fetchmany(size=100)
+        self.failUnlessEqual(len(res), 1)
+
     def CheckFetchall(self):
         self.cu.execute("select name from test")
         res = self.cu.fetchall()
index 4fabd07..de32c75 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/test/factory.py: tests for the various factories in pysqlite
 #
-# Copyright (C) 2005 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
index f205b42..4b37f79 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/test/hooks.py: tests for various SQLite-specific hooks
 #
-# Copyright (C) 2006 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2006-2007 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
@@ -105,9 +105,80 @@ class CollationTests(unittest.TestCase):
             if not e.args[0].startswith("no such collation sequence"):
                 self.fail("wrong OperationalError raised")
 
+class ProgressTests(unittest.TestCase):
+    def CheckProgressHandlerUsed(self):
+        """
+        Test that the progress handler is invoked once it is set.
+        """
+        con = sqlite.connect(":memory:")
+        progress_calls = []
+        def progress():
+            progress_calls.append(None)
+            return 0
+        con.set_progress_handler(progress, 1)
+        con.execute("""
+            create table foo(a, b)
+            """)
+        self.failUnless(progress_calls)
+
+
+    def CheckOpcodeCount(self):
+        """
+        Test that the opcode argument is respected.
+        """
+        con = sqlite.connect(":memory:")
+        progress_calls = []
+        def progress():
+            progress_calls.append(None)
+            return 0
+        con.set_progress_handler(progress, 1)
+        curs = con.cursor()
+        curs.execute("""
+            create table foo (a, b)
+            """)
+        first_count = len(progress_calls)
+        progress_calls = []
+        con.set_progress_handler(progress, 2)
+        curs.execute("""
+            create table bar (a, b)
+            """)
+        second_count = len(progress_calls)
+        self.failUnless(first_count > second_count)
+
+    def CheckCancelOperation(self):
+        """
+        Test that returning a non-zero value stops the operation in progress.
+        """
+        con = sqlite.connect(":memory:")
+        progress_calls = []
+        def progress():
+            progress_calls.append(None)
+            return 1
+        con.set_progress_handler(progress, 1)
+        curs = con.cursor()
+        self.assertRaises(
+            sqlite.OperationalError,
+            curs.execute,
+            "create table bar (a, b)")
+
+    def CheckClearHandler(self):
+        """
+        Test that setting the progress handler to None clears the previously set handler.
+        """
+        con = sqlite.connect(":memory:")
+        action = 0
+        def progress():
+            action = 1
+            return 0
+        con.set_progress_handler(progress, 1)
+        con.set_progress_handler(None, 1)
+        con.execute("select 1 union select 2 union select 3").fetchall()
+        self.failUnlessEqual(action, 0, "progress handler was not cleared")
+
 def suite():
     collation_suite = unittest.makeSuite(CollationTests, "Check")
-    return unittest.TestSuite((collation_suite,))
+    progress_suite = unittest.makeSuite(ProgressTests, "Check")
+    return unittest.TestSuite((collation_suite, progress_suite))
 
 def test():
     runner = unittest.TextTestRunner()
diff --git a/pysqlite2/test/py25tests.py b/pysqlite2/test/py25tests.py
new file mode 100644 (file)
index 0000000..fcc0c85
--- /dev/null
@@ -0,0 +1,80 @@
+#-*- coding: ISO-8859-1 -*-
+# pysqlite2/test/regression.py: pysqlite regression tests
+#
+# Copyright (C) 2007 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.
+
+from __future__ import with_statement
+import unittest
+import pysqlite2.dbapi2 as sqlite
+
+did_rollback = False
+
+class MyConnection(sqlite.Connection):
+    def rollback(self):
+        global did_rollback
+        did_rollback = True
+        sqlite.Connection.rollback(self)
+
+class ContextTests(unittest.TestCase):
+    def setUp(self):
+        global did_rollback
+        self.con = sqlite.connect(":memory:", factory=MyConnection)
+        self.con.execute("create table test(c unique)")
+        did_rollback = False
+
+    def tearDown(self):
+        self.con.close()
+
+    def CheckContextManager(self):
+        """Can the connection be used as a context manager at all?"""
+        with self.con:
+            pass
+
+    def CheckContextManagerCommit(self):
+        """Is a commit called in the context manager?"""
+        with self.con:
+            self.con.execute("insert into test(c) values ('foo')")
+        self.con.rollback()
+        count = self.con.execute("select count(*) from test").fetchone()[0]
+        self.failUnlessEqual(count, 1)
+
+    def CheckContextManagerRollback(self):
+        """Is a rollback called in the context manager?"""
+        global did_rollback
+        self.failUnlessEqual(did_rollback, False)
+        try:
+            with self.con:
+                self.con.execute("insert into test(c) values (4)")
+                self.con.execute("insert into test(c) values (4)")
+        except sqlite.IntegrityError:
+            pass
+        self.failUnlessEqual(did_rollback, True)
+
+def suite():
+    ctx_suite = unittest.makeSuite(ContextTests, "Check")
+    return unittest.TestSuite((ctx_suite,))
+
+def test():
+    runner = unittest.TextTestRunner()
+    runner.run(suite())
+
+if __name__ == "__main__":
+    test()
index 068f5b8..29bb9f9 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/test/regression.py: pysqlite regression tests
 #
-# Copyright (C) 2006 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2006-2007 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
@@ -79,6 +79,51 @@ class RegressionTests(unittest.TestCase):
         cur.fetchone()
         cur.fetchone()
 
+    def CheckStatementFinalizationOnCloseDb(self):
+        # pysqlite versions <= 2.3.3 only finalized statements in the statement
+        # cache when closing the database. statements that were still
+        # referenced in cursors weren't closed an could provoke "
+        # "OperationalError: Unable to close due to unfinalised statements".
+        con = sqlite.connect(":memory:")
+        cursors = []
+        # default statement cache size is 100
+        for i in range(105):
+            cur = con.cursor()
+            cursors.append(cur)
+            cur.execute("select 1 x union select " + str(i))
+        con.close()
+
+    def CheckOnConflictRollback(self):
+        if sqlite.sqlite_version_info < (3, 2, 2):
+            return
+        con = sqlite.connect(":memory:")
+        con.execute("create table foo(x, unique(x) on conflict rollback)")
+        con.execute("insert into foo(x) values (1)")
+        try:
+            con.execute("insert into foo(x) values (1)")
+        except sqlite.DatabaseError:
+            pass
+        con.execute("insert into foo(x) values (2)")
+        try:
+            con.commit()
+        except sqlite.OperationalError:
+            self.fail("pysqlite knew nothing about the implicit ROLLBACK")
+
+    def CheckWorkaroundForBuggySqliteTransferBindings(self):
+        """
+        pysqlite would crash with older SQLite versions unless
+        a workaround is implemented.
+        """
+        self.con.execute("create table if not exists foo(bar)")
+        self.con.execute("create table if not exists foo(bar)")
+
+    def CheckEmptyStatement(self):
+        """
+        pysqlite used to segfault with SQLite versions 3.5.x. These return NULL
+        for "no-operation" statements
+        """
+        self.con.execute("")
+
 def suite():
     regression_suite = unittest.makeSuite(RegressionTests, "Check")
     return unittest.TestSuite((regression_suite,))
index 4452b54..130b82d 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/test/transactions.py: tests transactions
 #
-# Copyright (C) 2005 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
@@ -21,6 +21,7 @@
 #    misrepresented as being the original software.
 # 3. This notice may not be removed or altered from any source distribution.
 
+import sys
 import os, unittest
 import pysqlite2.dbapi2 as sqlite
 
@@ -119,6 +120,23 @@ class TransactionTests(unittest.TestCase):
         except:
             self.fail("should have raised an OperationalError")
 
+    def CheckLocking(self):
+        """
+        This tests the improved concurrency with pysqlite 2.3.4. You needed
+        to roll back con2 before you could commit con1.
+        """
+        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")
+        # NO self.con2.rollback() HERE!!!
+        self.con1.commit()
+
 class SpecialCommandTests(unittest.TestCase):
     def setUp(self):
         self.con = sqlite.connect(":memory:")
index 973fb84..d7a2df2 100644 (file)
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # pysqlite2/test/types.py: tests for type conversion and detection
 #
-# Copyright (C) 2005 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
@@ -21,7 +21,7 @@
 #    misrepresented as being the original software.
 # 3. This notice may not be removed or altered from any source distribution.
 
-import bz2, datetime
+import zlib, datetime
 import unittest
 import pysqlite2.dbapi2 as sqlite
 
@@ -287,7 +287,7 @@ class ObjectAdaptationTests(unittest.TestCase):
 
 class BinaryConverterTests(unittest.TestCase):
     def convert(s):
-        return bz2.decompress(s)
+        return zlib.decompress(s)
     convert = staticmethod(convert)
 
     def setUp(self):
@@ -299,7 +299,7 @@ class BinaryConverterTests(unittest.TestCase):
 
     def CheckBinaryInputForConverter(self):
         testdata = "abcdefg" * 10
-        result = self.con.execute('select ? as "x [bin]"', (buffer(bz2.compress(testdata)),)).fetchone()[0]
+        result = self.con.execute('select ? as "x [bin]"', (buffer(zlib.compress(testdata)),)).fetchone()[0]
         self.failUnlessEqual(testdata, result)
 
 class DateTimeTests(unittest.TestCase):
index 8d6bc39..5b0cb32 100644 (file)
@@ -2,7 +2,7 @@
 # pysqlite2/test/userfunctions.py: tests for user-defined functions and
 #                                  aggregates.
 #
-# Copyright (C) 2005 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
index 08d826b..1f5b7d6 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -1,7 +1,7 @@
 #-*- coding: ISO-8859-1 -*-
 # setup.py: the distutils script
 #
-# Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
 #
 # This file is part of pysqlite.
 #
@@ -97,6 +97,7 @@ def get_setup_args():
         match = version_re.match(line)
         if match:
             PYSQLITE_VERSION = match.groups()[0]
+            PYSQLITE_MINOR_VERSION = ".".join(PYSQLITE_VERSION.split('.')[:2])
             break
     f.close()
 
@@ -122,6 +123,9 @@ def get_setup_args():
             license = "zlib/libpng license",
             platforms = "ALL",
             url = "http://pysqlite.org/",
+            download_url = "http://initd.org/pub/software/pysqlite/releases/%s/%s/" % \
+                (PYSQLITE_MINOR_VERSION, PYSQLITE_VERSION),
+
 
             # Description of the modules and packages in the distribution
             package_dir = {"pysqlite2": "pysqlite2"},
index 18a4066..fc87701 100644 (file)
@@ -1,6 +1,6 @@
 /* cache .c - a LRU cache
  *
- * Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
@@ -243,6 +243,7 @@ PyObject* pysqlite_cache_display(pysqlite_Cache* self, PyObject* args)
         }
         template = PyString_FromString("%s <- %s ->%s\n");
         if (!template) {
+            Py_DECREF(fmt_args);
             return NULL;
         }
         display_str = PyString_Format(template, fmt_args);
index 158bf5a..d6f7f13 100644 (file)
@@ -1,6 +1,6 @@
 /* cache.h - definitions for the LRU cache
  *
- * Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
index 924d582..815595e 100644 (file)
@@ -1,6 +1,6 @@
 /* connection.c - the connection type
  *
- * Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  * 
@@ -32,6 +32,9 @@
 
 #include "pythread.h"
 
+#define ACTION_FINALIZE 1
+#define ACTION_RESET 2
+
 static int pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level);
 
 
@@ -51,7 +54,7 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
 {
     static char *kwlist[] = {"database", "timeout", "detect_types", "isolation_level", "check_same_thread", "factory", "cached_statements", NULL, NULL};
 
-    char* database;
+    PyObject* database;
     int detect_types = 0;
     PyObject* isolation_level = NULL;
     PyObject* factory = NULL;
@@ -59,11 +62,14 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
     int cached_statements = 100;
     double timeout = 5.0;
     int rc;
+    PyObject* class_attr = NULL;
+    PyObject* class_attr_str = NULL;
+    int is_apsw_connection = 0;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|diOiOi", kwlist,
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|diOiOi", kwlist,
                                      &database, &timeout, &detect_types, &isolation_level, &check_same_thread, &factory, &cached_statements))
     {
-        return -1; 
+        return -1;
     }
 
     self->begin_statement = NULL;
@@ -77,13 +83,41 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
     Py_INCREF(&PyUnicode_Type);
     self->text_factory = (PyObject*)&PyUnicode_Type;
 
-    Py_BEGIN_ALLOW_THREADS
-    rc = sqlite3_open(database, &self->db);
-    Py_END_ALLOW_THREADS
+    if (PyString_Check(database)) {
+        Py_BEGIN_ALLOW_THREADS
+        rc = sqlite3_open(PyString_AsString(database), &self->db);
+        Py_END_ALLOW_THREADS
 
-    if (rc != SQLITE_OK) {
-        _pysqlite_seterror(self->db);
-        return -1;
+        if (rc != SQLITE_OK) {
+            _pysqlite_seterror(self->db, NULL);
+            return -1;
+        }
+    } else {
+        /* Create a pysqlite connection from a APSW connection */
+        class_attr = PyObject_GetAttrString(database, "__class__");
+        if (class_attr) {
+            class_attr_str = PyObject_Str(class_attr);
+            if (class_attr_str) {
+                if (strcmp(PyString_AsString(class_attr_str), "<type 'apsw.Connection'>") == 0) {
+                    /* In the APSW Connection object, the first entry after
+                     * PyObject_HEAD is the sqlite3* we want to get hold of.
+                     * Luckily, this is the same layout as we have in our
+                     * pysqlite_Connection */
+                    self->db = ((pysqlite_Connection*)database)->db;
+
+                    Py_INCREF(database);
+                    self->apsw_connection = database;
+                    is_apsw_connection = 1;
+                }
+            }
+        }
+        Py_XDECREF(class_attr_str);
+        Py_XDECREF(class_attr);
+
+        if (!is_apsw_connection) {
+            PyErr_SetString(PyExc_ValueError, "database parameter must be string or APSW Connection object");
+            return -1;
+        }
     }
 
     if (!isolation_level) {
@@ -169,7 +203,8 @@ void pysqlite_flush_statement_cache(pysqlite_Connection* self)
     self->statement_cache->decref_factory = 0;
 }
 
-void pysqlite_reset_all_statements(pysqlite_Connection* self)
+/* action in (ACTION_RESET, ACTION_FINALIZE) */
+void pysqlite_do_all_statements(pysqlite_Connection* self, int action)
 {
     int i;
     PyObject* weakref;
@@ -179,13 +214,19 @@ void pysqlite_reset_all_statements(pysqlite_Connection* self)
         weakref = PyList_GetItem(self->statements, i);
         statement = PyWeakref_GetObject(weakref);
         if (statement != Py_None) {
-            (void)pysqlite_statement_reset((pysqlite_Statement*)statement);
+            if (action == ACTION_RESET) {
+                (void)pysqlite_statement_reset((pysqlite_Statement*)statement);
+            } else {
+                (void)pysqlite_statement_finalize((pysqlite_Statement*)statement);
+            }
         }
     }
 }
 
 void pysqlite_connection_dealloc(pysqlite_Connection* self)
 {
+    PyObject* ret = NULL;
+
     Py_XDECREF(self->statement_cache);
 
     /* Clean up if user has not called .close() explicitly. */
@@ -193,6 +234,10 @@ void pysqlite_connection_dealloc(pysqlite_Connection* self)
         Py_BEGIN_ALLOW_THREADS
         sqlite3_close(self->db);
         Py_END_ALLOW_THREADS
+    } else if (self->apsw_connection) {
+        ret = PyObject_CallMethod(self->apsw_connection, "close", "");
+        Py_XDECREF(ret);
+        Py_XDECREF(self->apsw_connection);
     }
 
     if (self->begin_statement) {
@@ -241,24 +286,33 @@ PyObject* pysqlite_connection_cursor(pysqlite_Connection* self, PyObject* args,
 
 PyObject* pysqlite_connection_close(pysqlite_Connection* self, PyObject* args)
 {
+    PyObject* ret;
     int rc;
 
     if (!pysqlite_check_thread(self)) {
         return NULL;
     }
 
-    pysqlite_flush_statement_cache(self);
+    pysqlite_do_all_statements(self, ACTION_FINALIZE);
 
     if (self->db) {
-        Py_BEGIN_ALLOW_THREADS
-        rc = sqlite3_close(self->db);
-        Py_END_ALLOW_THREADS
-
-        if (rc != SQLITE_OK) {
-            _pysqlite_seterror(self->db);
-            return NULL;
-        } else {
+        if (self->apsw_connection) {
+            ret = PyObject_CallMethod(self->apsw_connection, "close", "");
+            Py_XDECREF(ret);
+            Py_XDECREF(self->apsw_connection);
+            self->apsw_connection = NULL;
             self->db = NULL;
+        } else {
+            Py_BEGIN_ALLOW_THREADS
+            rc = sqlite3_close(self->db);
+            Py_END_ALLOW_THREADS
+
+            if (rc != SQLITE_OK) {
+                _pysqlite_seterror(self->db, NULL);
+                return NULL;
+            } else {
+                self->db = NULL;
+            }
         }
     }
 
@@ -292,7 +346,7 @@ PyObject* _pysqlite_connection_begin(pysqlite_Connection* self)
     Py_END_ALLOW_THREADS
 
     if (rc != SQLITE_OK) {
-        _pysqlite_seterror(self->db);
+        _pysqlite_seterror(self->db, statement);
         goto error;
     }
 
@@ -300,7 +354,7 @@ PyObject* _pysqlite_connection_begin(pysqlite_Connection* self)
     if (rc == SQLITE_DONE) {
         self->inTransaction = 1;
     } else {
-        _pysqlite_seterror(self->db);
+        _pysqlite_seterror(self->db, statement);
     }
 
     Py_BEGIN_ALLOW_THREADS
@@ -308,7 +362,7 @@ PyObject* _pysqlite_connection_begin(pysqlite_Connection* self)
     Py_END_ALLOW_THREADS
 
     if (rc != SQLITE_OK && !PyErr_Occurred()) {
-        _pysqlite_seterror(self->db);
+        _pysqlite_seterror(self->db, NULL);
     }
 
 error:
@@ -335,7 +389,7 @@ PyObject* pysqlite_connection_commit(pysqlite_Connection* self, PyObject* args)
         rc = sqlite3_prepare(self->db, "COMMIT", -1, &statement, &tail);
         Py_END_ALLOW_THREADS
         if (rc != SQLITE_OK) {
-            _pysqlite_seterror(self->db);
+            _pysqlite_seterror(self->db, NULL);
             goto error;
         }
 
@@ -343,14 +397,14 @@ PyObject* pysqlite_connection_commit(pysqlite_Connection* self, PyObject* args)
         if (rc == SQLITE_DONE) {
             self->inTransaction = 0;
         } else {
-            _pysqlite_seterror(self->db);
+            _pysqlite_seterror(self->db, statement);
         }
 
         Py_BEGIN_ALLOW_THREADS
         rc = sqlite3_finalize(statement);
         Py_END_ALLOW_THREADS
         if (rc != SQLITE_OK && !PyErr_Occurred()) {
-            _pysqlite_seterror(self->db);
+            _pysqlite_seterror(self->db, NULL);
         }
 
     }
@@ -375,13 +429,13 @@ PyObject* pysqlite_connection_rollback(pysqlite_Connection* self, PyObject* args
     }
 
     if (self->inTransaction) {
-        pysqlite_reset_all_statements(self);
+        pysqlite_do_all_statements(self, ACTION_RESET);
 
         Py_BEGIN_ALLOW_THREADS
         rc = sqlite3_prepare(self->db, "ROLLBACK", -1, &statement, &tail);
         Py_END_ALLOW_THREADS
         if (rc != SQLITE_OK) {
-            _pysqlite_seterror(self->db);
+            _pysqlite_seterror(self->db, NULL);
             goto error;
         }
 
@@ -389,14 +443,14 @@ PyObject* pysqlite_connection_rollback(pysqlite_Connection* self, PyObject* args
         if (rc == SQLITE_DONE) {
             self->inTransaction = 0;
         } else {
-            _pysqlite_seterror(self->db);
+            _pysqlite_seterror(self->db, statement);
         }
 
         Py_BEGIN_ALLOW_THREADS
         rc = sqlite3_finalize(statement);
         Py_END_ALLOW_THREADS
         if (rc != SQLITE_OK && !PyErr_Occurred()) {
-            _pysqlite_seterror(self->db);
+            _pysqlite_seterror(self->db, NULL);
         }
 
     }
@@ -762,6 +816,33 @@ static int _authorizer_callback(void* user_arg, int action, const char* arg1, co
     return rc;
 }
 
+static int _progress_handler(void* user_arg)
+{
+    int rc;
+    PyObject *ret;
+    PyGILState_STATE gilstate;
+
+    gilstate = PyGILState_Ensure();
+    ret = PyObject_CallFunction((PyObject*)user_arg, "");
+
+    if (!ret) {
+        if (_enable_callback_tracebacks) {
+            PyErr_Print();
+        } else {
+            PyErr_Clear();
+        }
+
+        /* abort query if error occured */
+        rc = 1; 
+    } else {
+        rc = (int)PyObject_IsTrue(ret);
+    }
+
+    Py_DECREF(ret);
+    PyGILState_Release(gilstate);
+    return rc;
+}
+
 PyObject* pysqlite_connection_set_authorizer(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
 {
     PyObject* authorizer_cb;
@@ -787,6 +868,30 @@ PyObject* pysqlite_connection_set_authorizer(pysqlite_Connection* self, PyObject
     }
 }
 
+PyObject* pysqlite_connection_set_progress_handler(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
+{
+    PyObject* progress_handler;
+    int n;
+
+    static char *kwlist[] = { "progress_handler", "n", NULL };
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi:set_progress_handler",
+                                      kwlist, &progress_handler, &n)) {
+        return NULL;
+    }
+
+    if (progress_handler == Py_None) {
+        /* None clears the progress handler previously set */
+        sqlite3_progress_handler(self->db, 0, 0, (void*)0);
+    } else {
+        sqlite3_progress_handler(self->db, n, _progress_handler, progress_handler);
+        PyDict_SetItem(self->function_pinboard, progress_handler, Py_None);
+    }
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
 int pysqlite_check_thread(pysqlite_Connection* self)
 {
     if (self->check_same_thread) {
@@ -892,7 +997,8 @@ PyObject* pysqlite_connection_call(pysqlite_Connection* self, PyObject* args, Py
         } else if (rc == PYSQLITE_SQL_WRONG_TYPE) {
             PyErr_SetString(pysqlite_Warning, "SQL is of wrong type. Must be string or unicode.");
         } else {
-            _pysqlite_seterror(self->db);
+            (void)pysqlite_statement_reset(statement);
+            _pysqlite_seterror(self->db, NULL);
         }
 
         Py_DECREF(statement);
@@ -1134,7 +1240,7 @@ pysqlite_connection_create_collation(pysqlite_Connection* self, PyObject* args)
                                   (callable != Py_None) ? pysqlite_collation_callback : NULL);
     if (rc != SQLITE_OK) {
         PyDict_DelItem(self->collations, uppercase_name);
-        _pysqlite_seterror(self->db);
+        _pysqlite_seterror(self->db, NULL);
         goto finally;
     }
 
@@ -1151,6 +1257,44 @@ finally:
     return retval;
 }
 
+/* Called when the connection is used as a context manager. Returns itself as a
+ * convenience to the caller. */
+static PyObject *
+pysqlite_connection_enter(pysqlite_Connection* self, PyObject* args)
+{
+    Py_INCREF(self);
+    return (PyObject*)self;
+}
+
+/** Called when the connection is used as a context manager. If there was any
+ * exception, a rollback takes place; otherwise we commit. */
+static PyObject *
+pysqlite_connection_exit(pysqlite_Connection* self, PyObject* args)
+{
+    PyObject* exc_type, *exc_value, *exc_tb;
+    char* method_name;
+    PyObject* result;
+
+    if (!PyArg_ParseTuple(args, "OOO", &exc_type, &exc_value, &exc_tb)) {
+        return NULL;
+    }
+
+    if (exc_type == Py_None && exc_value == Py_None && exc_tb == Py_None) {
+        method_name = "commit";
+    } else {
+        method_name = "rollback";
+    }
+
+    result = PyObject_CallMethod((PyObject*)self, method_name, "");
+    if (!result) {
+        return NULL;
+    }
+    Py_DECREF(result);
+
+    Py_INCREF(Py_False);
+    return Py_False;
+}
+
 static char connection_doc[] =
 PyDoc_STR("SQLite database connection object.");
 
@@ -1175,6 +1319,8 @@ static PyMethodDef connection_methods[] = {
         PyDoc_STR("Creates a new aggregate. Non-standard.")},
     {"set_authorizer", (PyCFunction)pysqlite_connection_set_authorizer, METH_VARARGS|METH_KEYWORDS,
         PyDoc_STR("Sets authorizer callback. Non-standard.")},
+    {"set_progress_handler", (PyCFunction)pysqlite_connection_set_progress_handler, METH_VARARGS|METH_KEYWORDS,
+        PyDoc_STR("Sets progress handler callback. Non-standard.")},
     {"execute", (PyCFunction)pysqlite_connection_execute, METH_VARARGS,
         PyDoc_STR("Executes a SQL statement. Non-standard.")},
     {"executemany", (PyCFunction)pysqlite_connection_executemany, METH_VARARGS,
@@ -1185,6 +1331,10 @@ static PyMethodDef connection_methods[] = {
         PyDoc_STR("Creates a collation function. Non-standard.")},
     {"interrupt", (PyCFunction)pysqlite_connection_interrupt, METH_NOARGS,
         PyDoc_STR("Abort any pending database operation. Non-standard.")},
+    {"__enter__", (PyCFunction)pysqlite_connection_enter, METH_NOARGS,
+        PyDoc_STR("For context manager. Non-standard.")},
+    {"__exit__", (PyCFunction)pysqlite_connection_exit, METH_VARARGS,
+        PyDoc_STR("For context manager. Non-standard.")},
     {NULL, NULL}
 };
 
index 21fcd2a..3b1c632 100644 (file)
@@ -1,6 +1,6 @@
 /* connection.h - definitions for the connection type
  *
- * Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
@@ -95,6 +95,11 @@ typedef struct
     /* a dictionary of registered collation name => collation callable mappings */
     PyObject* collations;
 
+    /* if our connection was created from a APSW connection, we keep a
+     * reference to the APSW connection around and get rid of it in our
+     * destructor */
+    PyObject* apsw_connection;
+
     /* Exception objects */
     PyObject* Warning;
     PyObject* Error;
index ec203be..a9a2815 100644 (file)
@@ -1,6 +1,6 @@
 /* cursor.c - the cursor type
  *
- * Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
@@ -80,7 +80,7 @@ int pysqlite_cursor_init(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs
 
     if (!PyArg_ParseTuple(args, "O!", &pysqlite_ConnectionType, &connection))
     {
-        return -1; 
+        return -1;
     }
 
     Py_INCREF(connection);
@@ -435,7 +435,7 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
     if (multiple) {
         /* executemany() */
         if (!PyArg_ParseTuple(args, "OO", &operation, &second_argument)) {
-            return NULL; 
+            return NULL;
         }
 
         if (!PyString_Check(operation) && !PyUnicode_Check(operation)) {
@@ -457,7 +457,7 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
     } else {
         /* execute() */
         if (!PyArg_ParseTuple(args, "O|O", &operation, &second_argument)) {
-            return NULL; 
+            return NULL;
         }
 
         if (!PyString_Check(operation) && !PyUnicode_Check(operation)) {
@@ -506,17 +506,48 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
         operation_cstr = PyString_AsString(operation_bytestr);
     }
 
-    /* reset description and rowcount */
+    /* reset description */
     Py_DECREF(self->description);
     Py_INCREF(Py_None);
     self->description = Py_None;
 
-    Py_DECREF(self->rowcount);
-    self->rowcount = PyInt_FromLong(-1L);
-    if (!self->rowcount) {
+    func_args = PyTuple_New(1);
+    if (!func_args) {
+        goto error;
+    }
+    Py_INCREF(operation);
+    if (PyTuple_SetItem(func_args, 0, operation) != 0) {
+        goto error;
+    }
+
+    if (self->statement) {
+        (void)pysqlite_statement_reset(self->statement);
+        Py_DECREF(self->statement);
+    }
+
+    self->statement = (pysqlite_Statement*)pysqlite_cache_get(self->connection->statement_cache, func_args);
+    Py_DECREF(func_args);
+
+    if (!self->statement) {
         goto error;
     }
 
+    if (self->statement->in_use) {
+        Py_DECREF(self->statement);
+        self->statement = PyObject_New(pysqlite_Statement, &pysqlite_StatementType);
+        if (!self->statement) {
+            goto error;
+        }
+        rc = pysqlite_statement_create(self->statement, self->connection, operation);
+        if (rc != SQLITE_OK) {
+            self->statement = 0;
+            goto error;
+        }
+    }
+
+    pysqlite_statement_reset(self->statement);
+    pysqlite_statement_mark_dirty(self->statement);
+
     statement_type = detect_statement_type(operation_cstr);
     if (self->connection->begin_statement) {
         switch (statement_type) {
@@ -553,43 +584,6 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
         }
     }
 
-    func_args = PyTuple_New(1);
-    if (!func_args) {
-        goto error;
-    }
-    Py_INCREF(operation);
-    if (PyTuple_SetItem(func_args, 0, operation) != 0) {
-        goto error;
-    }
-
-    if (self->statement) {
-        (void)pysqlite_statement_reset(self->statement);
-        Py_DECREF(self->statement);
-    }
-
-    self->statement = (pysqlite_Statement*)pysqlite_cache_get(self->connection->statement_cache, func_args);
-    Py_DECREF(func_args);
-
-    if (!self->statement) {
-        goto error;
-    }
-
-    if (self->statement->in_use) {
-        Py_DECREF(self->statement);
-        self->statement = PyObject_New(pysqlite_Statement, &pysqlite_StatementType);
-        if (!self->statement) {
-            goto error;
-        }
-        rc = pysqlite_statement_create(self->statement, self->connection, operation);
-        if (rc != SQLITE_OK) {
-            self->statement = 0;
-            goto error;
-        }
-    }
-
-    pysqlite_statement_reset(self->statement);
-    pysqlite_statement_mark_dirty(self->statement);
-
     while (1) {
         parameters = PyIter_Next(parameters_iter);
         if (!parameters) {
@@ -626,29 +620,31 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
                     continue;
                 } else {
                     /* If the database gave us an error, promote it to Python. */
-                    _pysqlite_seterror(self->connection->db);
+                    (void)pysqlite_statement_reset(self->statement);
+                    _pysqlite_seterror(self->connection->db, NULL);
                     goto error;
                 }
             } else {
                 if (PyErr_Occurred()) {
-                    /* there was an error that occured in a user-defined callback */
+                    /* there was an error that occurred in a user-defined callback */
                     if (_enable_callback_tracebacks) {
                         PyErr_Print();
                     } else {
                         PyErr_Clear();
                     }
                 }
-                _pysqlite_seterror(self->connection->db);
+                (void)pysqlite_statement_reset(self->statement);
+                _pysqlite_seterror(self->connection->db, NULL);
                 goto error;
             }
         }
 
         if (rc == SQLITE_ROW || (rc == SQLITE_DONE && statement_type == STATEMENT_SELECT)) {
-            Py_BEGIN_ALLOW_THREADS
-            numcols = sqlite3_column_count(self->statement->st);
-            Py_END_ALLOW_THREADS
-
             if (self->description == Py_None) {
+                Py_BEGIN_ALLOW_THREADS
+                numcols = sqlite3_column_count(self->statement->st);
+                Py_END_ALLOW_THREADS
+
                 Py_DECREF(self->description);
                 self->description = PyTuple_New(numcols);
                 if (!self->description) {
@@ -689,15 +685,11 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
             case STATEMENT_DELETE:
             case STATEMENT_INSERT:
             case STATEMENT_REPLACE:
-                Py_BEGIN_ALLOW_THREADS
                 rowcount += (long)sqlite3_changes(self->connection->db);
-                Py_END_ALLOW_THREADS
-                Py_DECREF(self->rowcount);
-                self->rowcount = PyInt_FromLong(rowcount);
         }
 
         Py_DECREF(self->lastrowid);
-        if (statement_type == STATEMENT_INSERT) {
+        if (!multiple && statement_type == STATEMENT_INSERT) {
             Py_BEGIN_ALLOW_THREADS
             lastrowid = sqlite3_last_insert_rowid(self->connection->db);
             Py_END_ALLOW_THREADS
@@ -714,14 +706,27 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
     }
 
 error:
+    /* just to be sure (implicit ROLLBACKs with ON CONFLICT ROLLBACK/OR
+     * ROLLBACK could have happened */
+    #ifdef SQLITE_VERSION_NUMBER
+    #if SQLITE_VERSION_NUMBER >= 3002002
+    self->connection->inTransaction = !sqlite3_get_autocommit(self->connection->db);
+    #endif
+    #endif
+
     Py_XDECREF(operation_bytestr);
     Py_XDECREF(parameters);
     Py_XDECREF(parameters_iter);
     Py_XDECREF(parameters_list);
 
     if (PyErr_Occurred()) {
+        Py_DECREF(self->rowcount);
+        self->rowcount = PyInt_FromLong(-1L);
         return NULL;
     } else {
+        Py_DECREF(self->rowcount);
+        self->rowcount = PyInt_FromLong(rowcount);
+
         Py_INCREF(self);
         return (PyObject*)self;
     }
@@ -748,7 +753,7 @@ PyObject* pysqlite_cursor_executescript(pysqlite_Cursor* self, PyObject* args)
     int statement_completed = 0;
 
     if (!PyArg_ParseTuple(args, "O", &script_obj)) {
-        return NULL; 
+        return NULL;
     }
 
     if (!pysqlite_check_thread(self->connection) || !pysqlite_check_connection(self->connection)) {
@@ -788,7 +793,7 @@ PyObject* pysqlite_cursor_executescript(pysqlite_Cursor* self, PyObject* args)
                              &statement,
                              &script_cstr);
         if (rc != SQLITE_OK) {
-            _pysqlite_seterror(self->connection->db);
+            _pysqlite_seterror(self->connection->db, NULL);
             goto error;
         }
 
@@ -796,17 +801,18 @@ PyObject* pysqlite_cursor_executescript(pysqlite_Cursor* self, PyObject* args)
         rc = SQLITE_ROW;
         while (rc == SQLITE_ROW) {
             rc = _sqlite_step_with_busyhandler(statement, self->connection);
+            /* TODO: we probably need more error handling here */
         }
 
         if (rc != SQLITE_DONE) {
             (void)sqlite3_finalize(statement);
-            _pysqlite_seterror(self->connection->db);
+            _pysqlite_seterror(self->connection->db, NULL);
             goto error;
         }
 
         rc = sqlite3_finalize(statement);
         if (rc != SQLITE_OK) {
-            _pysqlite_seterror(self->connection->db);
+            _pysqlite_seterror(self->connection->db, NULL);
             goto error;
         }
     }
@@ -864,8 +870,9 @@ PyObject* pysqlite_cursor_iternext(pysqlite_Cursor *self)
     if (self->statement) {
         rc = _sqlite_step_with_busyhandler(self->statement->st, self->connection);
         if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
+            (void)pysqlite_statement_reset(self->statement);
             Py_DECREF(next_row);
-            _pysqlite_seterror(self->connection->db);
+            _pysqlite_seterror(self->connection->db, NULL);
             return NULL;
         }
 
@@ -890,15 +897,17 @@ PyObject* pysqlite_cursor_fetchone(pysqlite_Cursor* self, PyObject* args)
     return row;
 }
 
-PyObject* pysqlite_cursor_fetchmany(pysqlite_Cursor* self, PyObject* args)
+PyObject* pysqlite_cursor_fetchmany(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs)
 {
+    static char *kwlist[] = {"size", NULL, NULL};
+
     PyObject* row;
     PyObject* list;
     int maxrows = self->arraysize;
     int counter = 0;
 
-    if (!PyArg_ParseTuple(args, "|i", &maxrows)) {
-        return NULL; 
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:fetchmany", kwlist, &maxrows)) {
+        return NULL;
     }
 
     list = PyList_New(0);
@@ -991,11 +1000,11 @@ static PyMethodDef cursor_methods[] = {
     {"executescript", (PyCFunction)pysqlite_cursor_executescript, METH_VARARGS,
         PyDoc_STR("Executes a multiple SQL statements at once. Non-standard.")},
     {"fetchone", (PyCFunction)pysqlite_cursor_fetchone, METH_NOARGS,
+        PyDoc_STR("Fetches one row from the resultset.")},
+    {"fetchmany", (PyCFunction)pysqlite_cursor_fetchmany, METH_VARARGS|METH_KEYWORDS,
         PyDoc_STR("Fetches several rows from the resultset.")},
-    {"fetchmany", (PyCFunction)pysqlite_cursor_fetchmany, METH_VARARGS,
-        PyDoc_STR("Fetches all rows from the resultset.")},
     {"fetchall", (PyCFunction)pysqlite_cursor_fetchall, METH_NOARGS,
-        PyDoc_STR("Fetches one row from the resultset.")},
+        PyDoc_STR("Fetches all rows from the resultset.")},
     {"close", (PyCFunction)pysqlite_cursor_close, METH_NOARGS,
         PyDoc_STR("Closes the cursor.")},
     {"setinputsizes", (PyCFunction)pysqlite_noop, METH_VARARGS,
index 5fce64a..d916ca5 100644 (file)
@@ -1,6 +1,6 @@
 /* cursor.h - definitions for the cursor type
  *
- * Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
@@ -60,7 +60,7 @@ PyObject* pysqlite_cursor_executemany(pysqlite_Cursor* self, PyObject* args);
 PyObject* pysqlite_cursor_getiter(pysqlite_Cursor *self);
 PyObject* pysqlite_cursor_iternext(pysqlite_Cursor *self);
 PyObject* pysqlite_cursor_fetchone(pysqlite_Cursor* self, PyObject* args);
-PyObject* pysqlite_cursor_fetchmany(pysqlite_Cursor* self, PyObject* args);
+PyObject* pysqlite_cursor_fetchmany(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs);
 PyObject* pysqlite_cursor_fetchall(pysqlite_Cursor* self, PyObject* args);
 PyObject* pysqlite_noop(pysqlite_Connection* self, PyObject* args);
 PyObject* pysqlite_cursor_close(pysqlite_Cursor* self, PyObject* args);
index d84ec93..c911c81 100644 (file)
 
 #include <Python.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** adapters registry **/
 
 extern PyObject *psyco_adapters;
index d066d9b..3995aca 100644 (file)
@@ -1,25 +1,25 @@
-    /* module.c - the module itself
    *
    * 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.
    */
+/* module.c - the module itself
+ *
* Copyright (C) 2004-2007 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 "connection.h"
 #include "statement.h"
@@ -41,6 +41,7 @@ PyObject* pysqlite_Error, *pysqlite_Warning, *pysqlite_InterfaceError, *pysqlite
 
 PyObject* converters;
 int _enable_callback_tracebacks;
+int pysqlite_BaseTypeAdapted;
 
 static PyObject* module_connect(PyObject* self, PyObject* args, PyObject*
         kwargs)
@@ -50,7 +51,7 @@ static PyObject* module_connect(PyObject* self, PyObject* args, PyObject*
      * connection.c and must always be copied from there ... */
 
     static char *kwlist[] = {"database", "timeout", "detect_types", "isolation_level", "check_same_thread", "factory", "cached_statements", NULL, NULL};
-    char* database;
+    PyObject* database;
     int detect_types = 0;
     PyObject* isolation_level;
     PyObject* factory = NULL;
@@ -60,7 +61,7 @@ static PyObject* module_connect(PyObject* self, PyObject* args, PyObject*
 
     PyObject* result;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|diOiOi", kwlist,
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|diOiOi", kwlist,
                                      &database, &timeout, &detect_types, &isolation_level, &check_same_thread, &factory, &cached_statements))
     {
         return NULL; 
@@ -133,6 +134,13 @@ static PyObject* module_register_adapter(PyObject* self, PyObject* args, PyObjec
         return NULL;
     }
 
+    /* a basic type is adapted; there's a performance optimization if that's not the case
+     * (99 % of all usages) */
+    if (type == &PyInt_Type || type == &PyLong_Type || type == &PyFloat_Type
+            || type == &PyString_Type || type == &PyUnicode_Type || type == &PyBuffer_Type) {
+        pysqlite_BaseTypeAdapted = 1;
+    }
+
     microprotocols_add(type, (PyObject*)&pysqlite_PrepareProtocolType, caster);
 
     Py_INCREF(Py_None);
@@ -379,6 +387,8 @@ PyMODINIT_FUNC init_sqlite(void)
 
     _enable_callback_tracebacks = 0;
 
+    pysqlite_BaseTypeAdapted = 0;
+
     /* Original comment form _bsddb.c in the Python core. This is also still
      * needed nowadays for Python 2.3/2.4.
      * 
index ada6b4c..13ab881 100644 (file)
@@ -1,6 +1,6 @@
 /* module.h - definitions for the module
  *
- * Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
@@ -25,7 +25,7 @@
 #define PYSQLITE_MODULE_H
 #include "Python.h"
 
-#define PYSQLITE_VERSION "2.3.3"
+#define PYSQLITE_VERSION "2.4.0"
 
 extern PyObject* pysqlite_Error;
 extern PyObject* pysqlite_Warning;
@@ -51,6 +51,7 @@ extern PyObject* time_sleep;
 extern PyObject* converters;
 
 extern int _enable_callback_tracebacks;
+extern int pysqlite_BaseTypeAdapted;
 
 #define PARSE_DECLTYPES 1
 #define PARSE_COLNAMES 2
index a8ca518..8b30b00 100644 (file)
@@ -1,6 +1,6 @@
 /* prepare_protocol.c - the protocol for preparing values for SQLite
  *
- * Copyright (C) 2005-2006 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
index 4c1e4f3..153472e 100644 (file)
@@ -1,6 +1,6 @@
 /* prepare_protocol.h - the protocol for preparing values for SQLite
  *
- * Copyright (C) 2005 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
index 7cfcfc3..a7c641c 100644 (file)
--- a/src/row.c
+++ b/src/row.c
@@ -1,6 +1,6 @@
 /* row.c - an enhanced tuple for database rows
  *
- * Copyright (C) 2005-2006 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
index b92225b..8ed69ae 100644 (file)
--- a/src/row.h
+++ b/src/row.h
@@ -1,6 +1,6 @@
 /* row.h - an enhanced tuple for database rows
  *
- * Copyright (C) 2005 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
index c379825..9eafe11 100644 (file)
@@ -1,6 +1,6 @@
 /* sqlitecompat.h - compatibility macros
  *
- * Copyright (C) 2006 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2006-2007 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
@@ -31,4 +31,9 @@ typedef int Py_ssize_t;
 typedef int (*lenfunc)(PyObject*);
 #endif
 
+/* define PyDict_CheckExact for pre-2.4 versions of Python */
+#ifndef PyDict_CheckExact
+#define PyDict_CheckExact(op) ((op)->ob_type == &PyDict_Type)
+#endif
+
 #endif
index 86d2178..bdbecc8 100644 (file)
@@ -1,6 +1,6 @@
 /* statement.c - the statement type
  *
- * Copyright (C) 2005-2006 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
@@ -40,6 +40,16 @@ typedef enum {
     NORMAL
 } parse_remaining_sql_state;
 
+typedef enum {
+    TYPE_INT,
+    TYPE_LONG,
+    TYPE_FLOAT,
+    TYPE_STRING,
+    TYPE_UNICODE,
+    TYPE_BUFFER,
+    TYPE_UNKNOWN
+} parameter_type;
+
 int pysqlite_statement_create(pysqlite_Statement* self, pysqlite_Connection* connection, PyObject* sql)
 {
     const char* tail;
@@ -97,42 +107,96 @@ int pysqlite_statement_bind_parameter(pysqlite_Statement* self, int pos, PyObjec
     char* string;
     Py_ssize_t buflen;
     PyObject* stringval;
+    parameter_type paramtype;
 
     if (parameter == Py_None) {
         rc = sqlite3_bind_null(self->st, pos);
+        goto final;
+    }
+
+    if (PyInt_CheckExact(parameter)) {
+        paramtype = TYPE_INT;
+    } else if (PyLong_CheckExact(parameter)) {
+        paramtype = TYPE_LONG;
+    } else if (PyFloat_CheckExact(parameter)) {
+        paramtype = TYPE_FLOAT;
+    } else if (PyString_CheckExact(parameter)) {
+        paramtype = TYPE_STRING;
+    } else if (PyUnicode_CheckExact(parameter)) {
+        paramtype = TYPE_UNICODE;
+    } else if (PyBuffer_Check(parameter)) {
+        paramtype = TYPE_BUFFER;
     } else if (PyInt_Check(parameter)) {
-        longval = PyInt_AsLong(parameter);
-        rc = sqlite3_bind_int64(self->st, pos, (sqlite_int64)longval);
-#ifdef HAVE_LONG_LONG
+        paramtype = TYPE_INT;
     } else if (PyLong_Check(parameter)) {
-        longlongval = PyLong_AsLongLong(parameter);
-        /* in the overflow error case, longlongval is -1, and an exception is set */
-        rc = sqlite3_bind_int64(self->st, pos, (sqlite_int64)longlongval);
-#endif
+        paramtype = TYPE_LONG;
     } else if (PyFloat_Check(parameter)) {
-        rc = sqlite3_bind_double(self->st, pos, PyFloat_AsDouble(parameter));
-    } else if (PyBuffer_Check(parameter)) {
-        if (PyObject_AsCharBuffer(parameter, &buffer, &buflen) == 0) {
-            rc = sqlite3_bind_blob(self->st, pos, buffer, buflen, SQLITE_TRANSIENT);
-        } else {
-            PyErr_SetString(PyExc_ValueError, "could not convert BLOB to buffer");
-            rc = -1;
-        }
-    } else if PyString_Check(parameter) {
-        string = PyString_AsString(parameter);
-        rc = sqlite3_bind_text(self->st, pos, string, -1, SQLITE_TRANSIENT);
-    } else if PyUnicode_Check(parameter) {
-        stringval = PyUnicode_AsUTF8String(parameter);
-        string = PyString_AsString(stringval);
-        rc = sqlite3_bind_text(self->st, pos, string, -1, SQLITE_TRANSIENT);
-        Py_DECREF(stringval);
+        paramtype = TYPE_FLOAT;
+    } else if (PyString_Check(parameter)) {
+        paramtype = TYPE_STRING;
+    } else if (PyUnicode_Check(parameter)) {
+        paramtype = TYPE_UNICODE;
     } else {
-        rc = -1;
+        paramtype = TYPE_UNKNOWN;
     }
 
+    switch (paramtype) {
+        case TYPE_INT:
+            longval = PyInt_AsLong(parameter);
+            rc = sqlite3_bind_int64(self->st, pos, (sqlite_int64)longval);
+            break;
+#ifdef HAVE_LONG_LONG
+        case TYPE_LONG:
+            longlongval = PyLong_AsLongLong(parameter);
+            /* in the overflow error case, longlongval is -1, and an exception is set */
+            rc = sqlite3_bind_int64(self->st, pos, (sqlite_int64)longlongval);
+            break;
+#endif
+        case TYPE_FLOAT:
+            rc = sqlite3_bind_double(self->st, pos, PyFloat_AsDouble(parameter));
+            break;
+        case TYPE_STRING:
+            string = PyString_AS_STRING(parameter);
+            rc = sqlite3_bind_text(self->st, pos, string, -1, SQLITE_TRANSIENT);
+            break;
+        case TYPE_UNICODE:
+            stringval = PyUnicode_AsUTF8String(parameter);
+            string = PyString_AsString(stringval);
+            rc = sqlite3_bind_text(self->st, pos, string, -1, SQLITE_TRANSIENT);
+            Py_DECREF(stringval);
+            break;
+        case TYPE_BUFFER:
+            if (PyObject_AsCharBuffer(parameter, &buffer, &buflen) == 0) {
+                rc = sqlite3_bind_blob(self->st, pos, buffer, buflen, SQLITE_TRANSIENT);
+            } else {
+                PyErr_SetString(PyExc_ValueError, "could not convert BLOB to buffer");
+                rc = -1;
+            }
+            break;
+        case TYPE_UNKNOWN:
+            rc = -1;
+    }
+
+final:
     return rc;
 }
 
+/* returns 0 if the object is one of Python's internal ones that don't need to be adapted */
+static int _need_adapt(PyObject* obj)
+{
+    if (pysqlite_BaseTypeAdapted) {
+        return 1;
+    }
+
+    if (PyInt_CheckExact(obj) || PyLong_CheckExact(obj) 
+            || PyFloat_CheckExact(obj) || PyString_CheckExact(obj)
+            || PyUnicode_CheckExact(obj) || PyBuffer_Check(obj)) {
+        return 0;
+    } else {
+        return 1;
+    }
+}
+
 void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* parameters)
 {
     PyObject* current_param;
@@ -147,7 +211,55 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
     num_params_needed = sqlite3_bind_parameter_count(self->st);
     Py_END_ALLOW_THREADS
 
-    if (PyDict_Check(parameters)) {
+    if (PyTuple_CheckExact(parameters) || PyList_CheckExact(parameters) || (!PyDict_Check(parameters) && PySequence_Check(parameters))) {
+        /* parameters passed as sequence */
+        if (PyTuple_CheckExact(parameters)) {
+            num_params = PyTuple_GET_SIZE(parameters);
+        } else if (PyList_CheckExact(parameters)) {
+            num_params = PyList_GET_SIZE(parameters);
+        } else {
+            num_params = PySequence_Size(parameters);
+        }
+        if (num_params != num_params_needed) {
+            PyErr_Format(pysqlite_ProgrammingError, "Incorrect number of bindings supplied. The current statement uses %d, and there are %d supplied.",
+                         num_params_needed, num_params);
+            return;
+        }
+        for (i = 0; i < num_params; i++) {
+            if (PyTuple_CheckExact(parameters)) {
+                current_param = PyTuple_GET_ITEM(parameters, i);
+                Py_XINCREF(current_param);
+            } else if (PyList_CheckExact(parameters)) {
+                current_param = PyList_GET_ITEM(parameters, i);
+                Py_XINCREF(current_param);
+            } else {
+                current_param = PySequence_GetItem(parameters, i);
+            }
+            if (!current_param) {
+                return;
+            }
+
+            if (!_need_adapt(current_param)) {
+                adapted = current_param;
+            } else {
+                adapted = microprotocols_adapt(current_param, (PyObject*)&pysqlite_PrepareProtocolType, NULL);
+                if (adapted) {
+                    Py_DECREF(current_param);
+                } else {
+                    PyErr_Clear();
+                    adapted = current_param;
+                }
+            }
+
+            rc = pysqlite_statement_bind_parameter(self, i + 1, adapted);
+            Py_DECREF(adapted);
+
+            if (rc != SQLITE_OK) {
+                PyErr_Format(pysqlite_InterfaceError, "Error binding parameter %d - probably unsupported type.", i);
+                return;
+            }
+        }
+    } else if (PyDict_Check(parameters)) {
         /* parameters passed as dictionary */
         for (i = 1; i <= num_params_needed; i++) {
             Py_BEGIN_ALLOW_THREADS
@@ -159,19 +271,27 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
             }
 
             binding_name++; /* skip first char (the colon) */
-            current_param = PyDict_GetItemString(parameters, binding_name);
+            if (PyDict_CheckExact(parameters)) {
+                current_param = PyDict_GetItemString(parameters, binding_name);
+                Py_XINCREF(current_param);
+            } else {
+                current_param = PyMapping_GetItemString(parameters, (char*)binding_name);
+            }
             if (!current_param) {
                 PyErr_Format(pysqlite_ProgrammingError, "You did not supply a value for binding %d.", i);
                 return;
             }
 
-            Py_INCREF(current_param);
-            adapted = microprotocols_adapt(current_param, (PyObject*)&pysqlite_PrepareProtocolType, NULL);
-            if (adapted) {
-                Py_DECREF(current_param);
-            } else {
-                PyErr_Clear();
+            if (!_need_adapt(current_param)) {
                 adapted = current_param;
+            } else {
+                adapted = microprotocols_adapt(current_param, (PyObject*)&pysqlite_PrepareProtocolType, NULL);
+                if (adapted) {
+                    Py_DECREF(current_param);
+                } else {
+                    PyErr_Clear();
+                    adapted = current_param;
+                }
             }
 
             rc = pysqlite_statement_bind_parameter(self, i, adapted);
@@ -183,35 +303,7 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
            }
         }
     } else {
-        /* parameters passed as sequence */
-        num_params = PySequence_Length(parameters);
-        if (num_params != num_params_needed) {
-            PyErr_Format(pysqlite_ProgrammingError, "Incorrect number of bindings supplied. The current statement uses %d, and there are %d supplied.",
-                         num_params_needed, num_params);
-            return;
-        }
-        for (i = 0; i < num_params; i++) {
-            current_param = PySequence_GetItem(parameters, i);
-            if (!current_param) {
-                return;
-            }
-            adapted = microprotocols_adapt(current_param, (PyObject*)&pysqlite_PrepareProtocolType, NULL);
-
-            if (adapted) {
-                Py_DECREF(current_param);
-            } else {
-                PyErr_Clear();
-                adapted = current_param;
-            }
-
-            rc = pysqlite_statement_bind_parameter(self, i + 1, adapted);
-            Py_DECREF(adapted);
-
-            if (rc != SQLITE_OK) {
-                PyErr_Format(pysqlite_InterfaceError, "Error binding parameter %d - probably unsupported type.", i);
-                return;
-            }
-        }
+        PyErr_SetString(PyExc_ValueError, "parameters are of unsupported type");
     }
 }
 
@@ -237,7 +329,11 @@ int pysqlite_statement_recompile(pysqlite_Statement* self, PyObject* params)
          */
         #ifdef SQLITE_VERSION_NUMBER
         #if SQLITE_VERSION_NUMBER >= 3002002
-        (void)sqlite3_transfer_bindings(self->st, new_st);
+        /* The check for the number of parameters is necessary to not trigger a
+         * bug in certain SQLite versions (experienced in 3.2.8 and 3.3.4). */
+        if (sqlite3_bind_parameter_count(self->st) > 0) {
+            (void)sqlite3_transfer_bindings(self->st, new_st);
+        }
         #endif
         #else
         statement_bind_parameters(self, params);
index 10b8823..4bd7036 100644 (file)
@@ -1,6 +1,6 @@
 /* statement.h - definitions for the statement type
  *
- * Copyright (C) 2005 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
index 2cb45ab..fd730da 100644 (file)
@@ -1,6 +1,6 @@
 /* util.c - various utility functions
  *
- * Copyright (C) 2005-2006 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
@@ -28,21 +28,29 @@ int _sqlite_step_with_busyhandler(sqlite3_stmt* statement, pysqlite_Connection*
 {
     int rc;
 
-    Py_BEGIN_ALLOW_THREADS
-    rc = sqlite3_step(statement);
-    Py_END_ALLOW_THREADS
+    if (statement == NULL) {
+        /* this is a workaround for SQLite 3.5 and later. it now apparently
+         * returns NULL for "no-operation" statements */
+        rc = SQLITE_OK;
+    } else {
+        Py_BEGIN_ALLOW_THREADS
+        rc = sqlite3_step(statement);
+        Py_END_ALLOW_THREADS
+    }
 
     return rc;
 }
 
-/**
- * Checks the SQLite error code and sets the appropriate DB-API exception.
- * Returns the error code (0 means no error occured).
- */
-int _pysqlite_seterror(sqlite3* db)
+
+int _pysqlite_seterror(sqlite3* db, sqlite3_stmt* st)
 {
     int errorcode;
 
+    /* SQLite often doesn't report anything useful, unless you reset the statement first */
+    if (st != NULL) {
+        (void)sqlite3_reset(st);
+    }
+
     errorcode = sqlite3_errcode(db);
 
     switch (errorcode)
index b00fe81..179be78 100644 (file)
@@ -1,6 +1,6 @@
 /* util.h - various utility functions
  *
- * Copyright (C) 2005-2006 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
  *
  * This file is part of pysqlite.
  *
@@ -32,7 +32,7 @@ int _sqlite_step_with_busyhandler(sqlite3_stmt* statement, pysqlite_Connection*
 
 /**
  * Checks the SQLite error code and sets the appropriate DB-API exception.
- * Returns the error code (0 means no error occured).
+ * Returns the error code (0 means no error occurred).
  */
-int _pysqlite_seterror(sqlite3* db);
+int _pysqlite_seterror(sqlite3* db, sqlite3_stmt* st);
 #endif