diff -r 0df85a2ebe4d Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst Wed Jan 11 03:32:43 2012 -0500 +++ b/Doc/library/sqlite3.rst Wed Jan 11 23:33:15 2012 +0100 @@ -136,7 +136,7 @@ first blank for the column name: the column name would simply be "x". -.. function:: connect(database[, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements]) +.. function:: connect(database[, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri]) Opens a connection to the SQLite database file *database*. You can use ``":memory:"`` to open a database connection to a database that resides in RAM @@ -172,6 +172,12 @@ for the connection, you can set the *cached_statements* parameter. The currently implemented default is to cache 100 statements. + If *uri* is :const:`True`, *database* is interpreted as a URI. This allows you + to specify options. For example, to open a database in read-only mode you can + use:: + + db = sqlite3.connect('file:path/to/database?mode=ro', uri=True) + .. function:: register_converter(typename, callable) diff -r 0df85a2ebe4d Lib/sqlite3/test/dbapi.py --- a/Lib/sqlite3/test/dbapi.py Wed Jan 11 03:32:43 2012 -0500 +++ b/Lib/sqlite3/test/dbapi.py Wed Jan 11 23:33:15 2012 +0100 @@ -22,6 +22,8 @@ # 3. This notice may not be removed or altered from any source distribution. import unittest +from test.support import TESTFN +import os import sqlite3 as sqlite try: import threading @@ -162,6 +164,21 @@ def CheckInTransactionRO(self): with self.assertRaises(AttributeError): self.cx.in_transaction = True + + def CheckOpenUri(self): + if sqlite.sqlite_version_info < (3, 7, 7): + with self.assertRaises(sqlite.OperationalError): + sqlite.connect(':memory:', uri=True) + else: + with sqlite.connect(TESTFN) as cx: + cx.execute('create table test(id integer)') + with sqlite.connect('file:' + TESTFN, uri=True) as cx: + cx.execute('insert into test(id) values(0)') + with sqlite.connect('file:' + TESTFN + '?mode=ro', uri=True) as cx: + with self.assertRaises(sqlite.OperationalError): + cx.execute('insert into test(id) values(1)') + os.remove(TESTFN) + class CursorTests(unittest.TestCase): def setUp(self): diff -r 0df85a2ebe4d Lib/sqlite3/test/hooks.py --- a/Lib/sqlite3/test/hooks.py Wed Jan 11 03:32:43 2012 -0500 +++ b/Lib/sqlite3/test/hooks.py Wed Jan 11 23:33:15 2012 +0100 @@ -48,7 +48,7 @@ pass def CheckCollationIsUsed(self): - if sqlite.version_info < (3, 2, 1): # old SQLite versions crash on this test + if sqlite.sqlite_version_info < (3, 2, 1): # old SQLite versions crash on this test return def mycoll(x, y): # reverse order diff -r 0df85a2ebe4d Modules/_sqlite/connection.c --- a/Modules/_sqlite/connection.c Wed Jan 11 03:32:43 2012 -0500 +++ b/Modules/_sqlite/connection.c Wed Jan 11 23:33:15 2012 +0100 @@ -60,7 +60,7 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject* kwargs) { - static char *kwlist[] = {"database", "timeout", "detect_types", "isolation_level", "check_same_thread", "factory", "cached_statements", NULL, NULL}; + static char *kwlist[] = {"database", "timeout", "detect_types", "isolation_level", "check_same_thread", "factory", "cached_statements", "uri", NULL, NULL}; char* database; int detect_types = 0; @@ -68,11 +68,12 @@ PyObject* factory = NULL; int check_same_thread = 1; int cached_statements = 100; + int uri = 0; double timeout = 5.0; int rc; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|diOiOi", kwlist, - &database, &timeout, &detect_types, &isolation_level, &check_same_thread, &factory, &cached_statements)) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|diOiOii", kwlist, + &database, &timeout, &detect_types, &isolation_level, &check_same_thread, &factory, &cached_statements, &uri)) { return -1; } @@ -91,8 +92,19 @@ Py_INCREF(&PyUnicode_Type); self->text_factory = (PyObject*)&PyUnicode_Type; +#ifdef SQLITE_OPEN_URI + Py_BEGIN_ALLOW_THREADS + rc = sqlite3_open_v2(database, &self->db, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | + (uri ? SQLITE_OPEN_URI : 0), NULL); +#else + if (uri) { + PyErr_SetString(pysqlite_OperationalError, "URIs not supported"); + return -1; + } Py_BEGIN_ALLOW_THREADS rc = sqlite3_open(database, &self->db); +#endif Py_END_ALLOW_THREADS if (rc != SQLITE_OK) { diff -r 0df85a2ebe4d Modules/_sqlite/module.c --- a/Modules/_sqlite/module.c Wed Jan 11 03:32:43 2012 -0500 +++ b/Modules/_sqlite/module.c Wed Jan 11 23:33:15 2012 +0100 @@ -50,19 +50,20 @@ * C-level, so this code is redundant with the one in connection_init in * 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}; + static char *kwlist[] = {"database", "timeout", "detect_types", "isolation_level", "check_same_thread", "factory", "cached_statements", "uri", NULL, NULL}; char* database; int detect_types = 0; PyObject* isolation_level; PyObject* factory = NULL; int check_same_thread = 1; int cached_statements; + int uri = 0; double timeout = 5.0; PyObject* result; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|diOiOi", kwlist, - &database, &timeout, &detect_types, &isolation_level, &check_same_thread, &factory, &cached_statements)) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|diOiOii", kwlist, + &database, &timeout, &detect_types, &isolation_level, &check_same_thread, &factory, &cached_statements, &uri)) { return NULL; } @@ -77,7 +78,8 @@ } PyDoc_STRVAR(module_connect_doc, -"connect(database[, timeout, isolation_level, detect_types, factory])\n\ +"connect(database[, timeout, detect_types, isolation_level,\n\ + check_same_thread, factory, cached_statements, uri])\n\ \n\ Opens a connection to the SQLite database file *database*. You can use\n\ \":memory:\" to open a database connection to a database that resides in\n\