mirror of https://github.com/python/cpython
Merged changes from external pysqlite 2.3.0 release. Documentation updates will
follow in a few hours at the latest. Then we should be ready for beta1.
This commit is contained in:
parent
ea3912b0da
commit
1541ef08af
|
@ -61,6 +61,14 @@ class RegressionTests(unittest.TestCase):
|
||||||
|
|
||||||
con.rollback()
|
con.rollback()
|
||||||
|
|
||||||
|
def CheckColumnNameWithSpaces(self):
|
||||||
|
cur = self.con.cursor()
|
||||||
|
cur.execute('select 1 as "foo bar [datetime]"')
|
||||||
|
self.failUnlessEqual(cur.description[0][0], "foo bar")
|
||||||
|
|
||||||
|
cur.execute('select 1 as "foo baz"')
|
||||||
|
self.failUnlessEqual(cur.description[0][0], "foo baz")
|
||||||
|
|
||||||
def suite():
|
def suite():
|
||||||
regression_suite = unittest.makeSuite(RegressionTests, "Check")
|
regression_suite = unittest.makeSuite(RegressionTests, "Check")
|
||||||
return unittest.TestSuite((regression_suite,))
|
return unittest.TestSuite((regression_suite,))
|
||||||
|
|
|
@ -101,16 +101,16 @@ class DeclTypesTests(unittest.TestCase):
|
||||||
self.cur.execute("create table test(i int, s str, f float, b bool, u unicode, foo foo, bin blob)")
|
self.cur.execute("create table test(i int, s str, f float, b bool, u unicode, foo foo, bin blob)")
|
||||||
|
|
||||||
# override float, make them always return the same number
|
# override float, make them always return the same number
|
||||||
sqlite.converters["float"] = lambda x: 47.2
|
sqlite.converters["FLOAT"] = lambda x: 47.2
|
||||||
|
|
||||||
# and implement two custom ones
|
# and implement two custom ones
|
||||||
sqlite.converters["bool"] = lambda x: bool(int(x))
|
sqlite.converters["BOOL"] = lambda x: bool(int(x))
|
||||||
sqlite.converters["foo"] = DeclTypesTests.Foo
|
sqlite.converters["FOO"] = DeclTypesTests.Foo
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
del sqlite.converters["float"]
|
del sqlite.converters["FLOAT"]
|
||||||
del sqlite.converters["bool"]
|
del sqlite.converters["BOOL"]
|
||||||
del sqlite.converters["foo"]
|
del sqlite.converters["FOO"]
|
||||||
self.cur.close()
|
self.cur.close()
|
||||||
self.con.close()
|
self.con.close()
|
||||||
|
|
||||||
|
@ -208,14 +208,14 @@ class ColNamesTests(unittest.TestCase):
|
||||||
self.cur = self.con.cursor()
|
self.cur = self.con.cursor()
|
||||||
self.cur.execute("create table test(x foo)")
|
self.cur.execute("create table test(x foo)")
|
||||||
|
|
||||||
sqlite.converters["foo"] = lambda x: "[%s]" % x
|
sqlite.converters["FOO"] = lambda x: "[%s]" % x
|
||||||
sqlite.converters["bar"] = lambda x: "<%s>" % x
|
sqlite.converters["BAR"] = lambda x: "<%s>" % x
|
||||||
sqlite.converters["exc"] = lambda x: 5/0
|
sqlite.converters["EXC"] = lambda x: 5/0
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
del sqlite.converters["foo"]
|
del sqlite.converters["FOO"]
|
||||||
del sqlite.converters["bar"]
|
del sqlite.converters["BAR"]
|
||||||
del sqlite.converters["exc"]
|
del sqlite.converters["EXC"]
|
||||||
self.cur.close()
|
self.cur.close()
|
||||||
self.con.close()
|
self.con.close()
|
||||||
|
|
||||||
|
@ -231,12 +231,6 @@ class ColNamesTests(unittest.TestCase):
|
||||||
val = self.cur.fetchone()[0]
|
val = self.cur.fetchone()[0]
|
||||||
self.failUnlessEqual(val, None)
|
self.failUnlessEqual(val, None)
|
||||||
|
|
||||||
def CheckExc(self):
|
|
||||||
# Exceptions in type converters result in returned Nones
|
|
||||||
self.cur.execute('select 5 as "x [exc]"')
|
|
||||||
val = self.cur.fetchone()[0]
|
|
||||||
self.failUnlessEqual(val, None)
|
|
||||||
|
|
||||||
def CheckColName(self):
|
def CheckColName(self):
|
||||||
self.cur.execute("insert into test(x) values (?)", ("xxx",))
|
self.cur.execute("insert into test(x) values (?)", ("xxx",))
|
||||||
self.cur.execute('select x as "x [bar]" from test')
|
self.cur.execute('select x as "x [bar]" from test')
|
||||||
|
|
|
@ -55,6 +55,9 @@ class AggrNoStep:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def finalize(self):
|
||||||
|
return 1
|
||||||
|
|
||||||
class AggrNoFinalize:
|
class AggrNoFinalize:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
@ -144,9 +147,12 @@ class FunctionTests(unittest.TestCase):
|
||||||
def CheckFuncRefCount(self):
|
def CheckFuncRefCount(self):
|
||||||
def getfunc():
|
def getfunc():
|
||||||
def f():
|
def f():
|
||||||
return val
|
return 1
|
||||||
return f
|
return f
|
||||||
self.con.create_function("reftest", 0, getfunc())
|
f = getfunc()
|
||||||
|
globals()["foo"] = f
|
||||||
|
# self.con.create_function("reftest", 0, getfunc())
|
||||||
|
self.con.create_function("reftest", 0, f)
|
||||||
cur = self.con.cursor()
|
cur = self.con.cursor()
|
||||||
cur.execute("select reftest()")
|
cur.execute("select reftest()")
|
||||||
|
|
||||||
|
@ -195,9 +201,12 @@ class FunctionTests(unittest.TestCase):
|
||||||
|
|
||||||
def CheckFuncException(self):
|
def CheckFuncException(self):
|
||||||
cur = self.con.cursor()
|
cur = self.con.cursor()
|
||||||
cur.execute("select raiseexception()")
|
try:
|
||||||
val = cur.fetchone()[0]
|
cur.execute("select raiseexception()")
|
||||||
self.failUnlessEqual(val, None)
|
cur.fetchone()
|
||||||
|
self.fail("should have raised OperationalError")
|
||||||
|
except sqlite.OperationalError, e:
|
||||||
|
self.failUnlessEqual(e.args[0], 'user-defined function raised exception')
|
||||||
|
|
||||||
def CheckParamString(self):
|
def CheckParamString(self):
|
||||||
cur = self.con.cursor()
|
cur = self.con.cursor()
|
||||||
|
@ -267,31 +276,47 @@ class AggregateTests(unittest.TestCase):
|
||||||
|
|
||||||
def CheckAggrNoStep(self):
|
def CheckAggrNoStep(self):
|
||||||
cur = self.con.cursor()
|
cur = self.con.cursor()
|
||||||
cur.execute("select nostep(t) from test")
|
try:
|
||||||
|
cur.execute("select nostep(t) from test")
|
||||||
|
self.fail("should have raised an AttributeError")
|
||||||
|
except AttributeError, e:
|
||||||
|
self.failUnlessEqual(e.args[0], "AggrNoStep instance has no attribute 'step'")
|
||||||
|
|
||||||
def CheckAggrNoFinalize(self):
|
def CheckAggrNoFinalize(self):
|
||||||
cur = self.con.cursor()
|
cur = self.con.cursor()
|
||||||
cur.execute("select nofinalize(t) from test")
|
try:
|
||||||
val = cur.fetchone()[0]
|
cur.execute("select nofinalize(t) from test")
|
||||||
self.failUnlessEqual(val, None)
|
val = cur.fetchone()[0]
|
||||||
|
self.fail("should have raised an OperationalError")
|
||||||
|
except sqlite.OperationalError, e:
|
||||||
|
self.failUnlessEqual(e.args[0], "user-defined aggregate's 'finalize' method raised error")
|
||||||
|
|
||||||
def CheckAggrExceptionInInit(self):
|
def CheckAggrExceptionInInit(self):
|
||||||
cur = self.con.cursor()
|
cur = self.con.cursor()
|
||||||
cur.execute("select excInit(t) from test")
|
try:
|
||||||
val = cur.fetchone()[0]
|
cur.execute("select excInit(t) from test")
|
||||||
self.failUnlessEqual(val, None)
|
val = cur.fetchone()[0]
|
||||||
|
self.fail("should have raised an OperationalError")
|
||||||
|
except sqlite.OperationalError, e:
|
||||||
|
self.failUnlessEqual(e.args[0], "user-defined aggregate's '__init__' method raised error")
|
||||||
|
|
||||||
def CheckAggrExceptionInStep(self):
|
def CheckAggrExceptionInStep(self):
|
||||||
cur = self.con.cursor()
|
cur = self.con.cursor()
|
||||||
cur.execute("select excStep(t) from test")
|
try:
|
||||||
val = cur.fetchone()[0]
|
cur.execute("select excStep(t) from test")
|
||||||
self.failUnlessEqual(val, 42)
|
val = cur.fetchone()[0]
|
||||||
|
self.fail("should have raised an OperationalError")
|
||||||
|
except sqlite.OperationalError, e:
|
||||||
|
self.failUnlessEqual(e.args[0], "user-defined aggregate's 'step' method raised error")
|
||||||
|
|
||||||
def CheckAggrExceptionInFinalize(self):
|
def CheckAggrExceptionInFinalize(self):
|
||||||
cur = self.con.cursor()
|
cur = self.con.cursor()
|
||||||
cur.execute("select excFinalize(t) from test")
|
try:
|
||||||
val = cur.fetchone()[0]
|
cur.execute("select excFinalize(t) from test")
|
||||||
self.failUnlessEqual(val, None)
|
val = cur.fetchone()[0]
|
||||||
|
self.fail("should have raised an OperationalError")
|
||||||
|
except sqlite.OperationalError, e:
|
||||||
|
self.failUnlessEqual(e.args[0], "user-defined aggregate's 'finalize' method raised error")
|
||||||
|
|
||||||
def CheckAggrCheckParamStr(self):
|
def CheckAggrCheckParamStr(self):
|
||||||
cur = self.con.cursor()
|
cur = self.con.cursor()
|
||||||
|
@ -331,10 +356,55 @@ class AggregateTests(unittest.TestCase):
|
||||||
val = cur.fetchone()[0]
|
val = cur.fetchone()[0]
|
||||||
self.failUnlessEqual(val, 60)
|
self.failUnlessEqual(val, 60)
|
||||||
|
|
||||||
|
def authorizer_cb(action, arg1, arg2, dbname, source):
|
||||||
|
if action != sqlite.SQLITE_SELECT:
|
||||||
|
return sqlite.SQLITE_DENY
|
||||||
|
if arg2 == 'c2' or arg1 == 't2':
|
||||||
|
return sqlite.SQLITE_DENY
|
||||||
|
return sqlite.SQLITE_OK
|
||||||
|
|
||||||
|
class AuthorizerTests(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
sqlite.enable_callback_tracebacks(1)
|
||||||
|
self.con = sqlite.connect(":memory:")
|
||||||
|
self.con.executescript("""
|
||||||
|
create table t1 (c1, c2);
|
||||||
|
create table t2 (c1, c2);
|
||||||
|
insert into t1 (c1, c2) values (1, 2);
|
||||||
|
insert into t2 (c1, c2) values (4, 5);
|
||||||
|
""")
|
||||||
|
|
||||||
|
# For our security test:
|
||||||
|
self.con.execute("select c2 from t2")
|
||||||
|
|
||||||
|
self.con.set_authorizer(authorizer_cb)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def CheckTableAccess(self):
|
||||||
|
try:
|
||||||
|
self.con.execute("select * from t2")
|
||||||
|
except sqlite.DatabaseError, e:
|
||||||
|
if not e.args[0].endswith("prohibited"):
|
||||||
|
self.fail("wrong exception text: %s" % e.args[0])
|
||||||
|
return
|
||||||
|
self.fail("should have raised an exception due to missing privileges")
|
||||||
|
|
||||||
|
def CheckColumnAccess(self):
|
||||||
|
try:
|
||||||
|
self.con.execute("select c2 from t1")
|
||||||
|
except sqlite.DatabaseError, e:
|
||||||
|
if not e.args[0].endswith("prohibited"):
|
||||||
|
self.fail("wrong exception text: %s" % e.args[0])
|
||||||
|
return
|
||||||
|
self.fail("should have raised an exception due to missing privileges")
|
||||||
|
|
||||||
def suite():
|
def suite():
|
||||||
function_suite = unittest.makeSuite(FunctionTests, "Check")
|
function_suite = unittest.makeSuite(FunctionTests, "Check")
|
||||||
aggregate_suite = unittest.makeSuite(AggregateTests, "Check")
|
aggregate_suite = unittest.makeSuite(AggregateTests, "Check")
|
||||||
return unittest.TestSuite((function_suite, aggregate_suite))
|
authorizer_suite = unittest.makeSuite(AuthorizerTests, "Check")
|
||||||
|
return unittest.TestSuite((function_suite, aggregate_suite, authorizer_suite))
|
||||||
|
|
||||||
def test():
|
def test():
|
||||||
runner = unittest.TextTestRunner()
|
runner = unittest.TextTestRunner()
|
||||||
|
|
|
@ -405,8 +405,6 @@ void _set_result(sqlite3_context* context, PyObject* py_val)
|
||||||
PyObject* stringval;
|
PyObject* stringval;
|
||||||
|
|
||||||
if ((!py_val) || PyErr_Occurred()) {
|
if ((!py_val) || PyErr_Occurred()) {
|
||||||
/* Errors in callbacks are ignored, and we return NULL */
|
|
||||||
PyErr_Clear();
|
|
||||||
sqlite3_result_null(context);
|
sqlite3_result_null(context);
|
||||||
} else if (py_val == Py_None) {
|
} else if (py_val == Py_None) {
|
||||||
sqlite3_result_null(context);
|
sqlite3_result_null(context);
|
||||||
|
@ -519,8 +517,17 @@ void _func_callback(sqlite3_context* context, int argc, sqlite3_value** argv)
|
||||||
Py_DECREF(args);
|
Py_DECREF(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
_set_result(context, py_retval);
|
if (py_retval) {
|
||||||
Py_XDECREF(py_retval);
|
_set_result(context, py_retval);
|
||||||
|
Py_DECREF(py_retval);
|
||||||
|
} else {
|
||||||
|
if (_enable_callback_tracebacks) {
|
||||||
|
PyErr_Print();
|
||||||
|
} else {
|
||||||
|
PyErr_Clear();
|
||||||
|
}
|
||||||
|
sqlite3_result_error(context, "user-defined function raised exception", -1);
|
||||||
|
}
|
||||||
|
|
||||||
PyGILState_Release(threadstate);
|
PyGILState_Release(threadstate);
|
||||||
}
|
}
|
||||||
|
@ -545,8 +552,13 @@ static void _step_callback(sqlite3_context *context, int argc, sqlite3_value** p
|
||||||
*aggregate_instance = PyObject_CallFunction(aggregate_class, "");
|
*aggregate_instance = PyObject_CallFunction(aggregate_class, "");
|
||||||
|
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
PyErr_Clear();
|
|
||||||
*aggregate_instance = 0;
|
*aggregate_instance = 0;
|
||||||
|
if (_enable_callback_tracebacks) {
|
||||||
|
PyErr_Print();
|
||||||
|
} else {
|
||||||
|
PyErr_Clear();
|
||||||
|
}
|
||||||
|
sqlite3_result_error(context, "user-defined aggregate's '__init__' method raised error", -1);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -565,7 +577,12 @@ static void _step_callback(sqlite3_context *context, int argc, sqlite3_value** p
|
||||||
Py_DECREF(args);
|
Py_DECREF(args);
|
||||||
|
|
||||||
if (!function_result) {
|
if (!function_result) {
|
||||||
PyErr_Clear();
|
if (_enable_callback_tracebacks) {
|
||||||
|
PyErr_Print();
|
||||||
|
} else {
|
||||||
|
PyErr_Clear();
|
||||||
|
}
|
||||||
|
sqlite3_result_error(context, "user-defined aggregate's 'step' method raised error", -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
@ -597,13 +614,16 @@ void _final_callback(sqlite3_context* context)
|
||||||
|
|
||||||
function_result = PyObject_CallMethod(*aggregate_instance, "finalize", "");
|
function_result = PyObject_CallMethod(*aggregate_instance, "finalize", "");
|
||||||
if (!function_result) {
|
if (!function_result) {
|
||||||
PyErr_Clear();
|
if (_enable_callback_tracebacks) {
|
||||||
Py_INCREF(Py_None);
|
PyErr_Print();
|
||||||
function_result = Py_None;
|
} else {
|
||||||
|
PyErr_Clear();
|
||||||
|
}
|
||||||
|
sqlite3_result_error(context, "user-defined aggregate's 'finalize' method raised error", -1);
|
||||||
|
} else {
|
||||||
|
_set_result(context, function_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
_set_result(context, function_result);
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
Py_XDECREF(*aggregate_instance);
|
Py_XDECREF(*aggregate_instance);
|
||||||
Py_XDECREF(function_result);
|
Py_XDECREF(function_result);
|
||||||
|
@ -699,6 +719,61 @@ PyObject* connection_create_aggregate(Connection* self, PyObject* args, PyObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _authorizer_callback(void* user_arg, int action, const char* arg1, const char* arg2 , const char* dbname, const char* access_attempt_source)
|
||||||
|
{
|
||||||
|
PyObject *ret;
|
||||||
|
int rc;
|
||||||
|
PyGILState_STATE gilstate;
|
||||||
|
|
||||||
|
gilstate = PyGILState_Ensure();
|
||||||
|
ret = PyObject_CallFunction((PyObject*)user_arg, "issss", action, arg1, arg2, dbname, access_attempt_source);
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
if (_enable_callback_tracebacks) {
|
||||||
|
PyErr_Print();
|
||||||
|
} else {
|
||||||
|
PyErr_Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = SQLITE_DENY;
|
||||||
|
} else {
|
||||||
|
if (PyInt_Check(ret)) {
|
||||||
|
rc = (int)PyInt_AsLong(ret);
|
||||||
|
} else {
|
||||||
|
rc = SQLITE_DENY;
|
||||||
|
}
|
||||||
|
Py_DECREF(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyGILState_Release(gilstate);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* connection_set_authorizer(Connection* self, PyObject* args, PyObject* kwargs)
|
||||||
|
{
|
||||||
|
PyObject* authorizer_cb;
|
||||||
|
|
||||||
|
static char *kwlist[] = { "authorizer_callback", NULL };
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:set_authorizer",
|
||||||
|
kwlist, &authorizer_cb)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = sqlite3_set_authorizer(self->db, _authorizer_callback, (void*)authorizer_cb);
|
||||||
|
|
||||||
|
if (rc != SQLITE_OK) {
|
||||||
|
PyErr_SetString(OperationalError, "Error setting authorizer callback");
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
PyDict_SetItem(self->function_pinboard, authorizer_cb, Py_None);
|
||||||
|
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int check_thread(Connection* self)
|
int check_thread(Connection* self)
|
||||||
{
|
{
|
||||||
if (self->check_same_thread) {
|
if (self->check_same_thread) {
|
||||||
|
@ -974,6 +1049,24 @@ finally:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
connection_interrupt(Connection* self, PyObject* args)
|
||||||
|
{
|
||||||
|
PyObject* retval = NULL;
|
||||||
|
|
||||||
|
if (!check_connection(self)) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_interrupt(self->db);
|
||||||
|
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
retval = Py_None;
|
||||||
|
|
||||||
|
finally:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
connection_create_collation(Connection* self, PyObject* args)
|
connection_create_collation(Connection* self, PyObject* args)
|
||||||
{
|
{
|
||||||
|
@ -1067,6 +1160,8 @@ static PyMethodDef connection_methods[] = {
|
||||||
PyDoc_STR("Creates a new function. Non-standard.")},
|
PyDoc_STR("Creates a new function. Non-standard.")},
|
||||||
{"create_aggregate", (PyCFunction)connection_create_aggregate, METH_VARARGS|METH_KEYWORDS,
|
{"create_aggregate", (PyCFunction)connection_create_aggregate, METH_VARARGS|METH_KEYWORDS,
|
||||||
PyDoc_STR("Creates a new aggregate. Non-standard.")},
|
PyDoc_STR("Creates a new aggregate. Non-standard.")},
|
||||||
|
{"set_authorizer", (PyCFunction)connection_set_authorizer, METH_VARARGS|METH_KEYWORDS,
|
||||||
|
PyDoc_STR("Sets authorizer callback. Non-standard.")},
|
||||||
{"execute", (PyCFunction)connection_execute, METH_VARARGS,
|
{"execute", (PyCFunction)connection_execute, METH_VARARGS,
|
||||||
PyDoc_STR("Executes a SQL statement. Non-standard.")},
|
PyDoc_STR("Executes a SQL statement. Non-standard.")},
|
||||||
{"executemany", (PyCFunction)connection_executemany, METH_VARARGS,
|
{"executemany", (PyCFunction)connection_executemany, METH_VARARGS,
|
||||||
|
@ -1075,6 +1170,8 @@ static PyMethodDef connection_methods[] = {
|
||||||
PyDoc_STR("Executes a multiple SQL statements at once. Non-standard.")},
|
PyDoc_STR("Executes a multiple SQL statements at once. Non-standard.")},
|
||||||
{"create_collation", (PyCFunction)connection_create_collation, METH_VARARGS,
|
{"create_collation", (PyCFunction)connection_create_collation, METH_VARARGS,
|
||||||
PyDoc_STR("Creates a collation function. Non-standard.")},
|
PyDoc_STR("Creates a collation function. Non-standard.")},
|
||||||
|
{"interrupt", (PyCFunction)connection_interrupt, METH_NOARGS,
|
||||||
|
PyDoc_STR("Abort any pending database operation. Non-standard.")},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -137,6 +137,22 @@ void cursor_dealloc(Cursor* self)
|
||||||
self->ob_type->tp_free((PyObject*)self);
|
self->ob_type->tp_free((PyObject*)self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject* _get_converter(PyObject* key)
|
||||||
|
{
|
||||||
|
PyObject* upcase_key;
|
||||||
|
PyObject* retval;
|
||||||
|
|
||||||
|
upcase_key = PyObject_CallMethod(key, "upper", "");
|
||||||
|
if (!upcase_key) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = PyDict_GetItem(converters, upcase_key);
|
||||||
|
Py_DECREF(upcase_key);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
int build_row_cast_map(Cursor* self)
|
int build_row_cast_map(Cursor* self)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -174,7 +190,7 @@ int build_row_cast_map(Cursor* self)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
converter = PyDict_GetItem(converters, key);
|
converter = _get_converter(key);
|
||||||
Py_DECREF(key);
|
Py_DECREF(key);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -195,7 +211,7 @@ int build_row_cast_map(Cursor* self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
converter = PyDict_GetItem(converters, py_decltype);
|
converter = _get_converter(py_decltype);
|
||||||
Py_DECREF(py_decltype);
|
Py_DECREF(py_decltype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,7 +244,10 @@ PyObject* _build_column_name(const char* colname)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (pos = colname;; pos++) {
|
for (pos = colname;; pos++) {
|
||||||
if (*pos == 0 || *pos == ' ') {
|
if (*pos == 0 || *pos == '[') {
|
||||||
|
if ((*pos == '[') && (pos > colname) && (*(pos-1) == ' ')) {
|
||||||
|
pos--;
|
||||||
|
}
|
||||||
return PyString_FromStringAndSize(colname, pos - colname);
|
return PyString_FromStringAndSize(colname, pos - colname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -312,13 +331,10 @@ PyObject* _fetch_one_row(Cursor* self)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
converted = PyObject_CallFunction(converter, "O", item);
|
converted = PyObject_CallFunction(converter, "O", item);
|
||||||
if (!converted) {
|
|
||||||
/* TODO: have a way to log these errors */
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
converted = Py_None;
|
|
||||||
PyErr_Clear();
|
|
||||||
}
|
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
|
if (!converted) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
@ -346,10 +362,10 @@ PyObject* _fetch_one_row(Cursor* self)
|
||||||
|
|
||||||
if (!converted) {
|
if (!converted) {
|
||||||
colname = sqlite3_column_name(self->statement->st, i);
|
colname = sqlite3_column_name(self->statement->st, i);
|
||||||
if (colname) {
|
if (!colname) {
|
||||||
colname = "<unknown column name>";
|
colname = "<unknown column name>";
|
||||||
}
|
}
|
||||||
PyOS_snprintf(buf, sizeof(buf) - 1, "Could not decode to UTF-8 column %s with text %s",
|
PyOS_snprintf(buf, sizeof(buf) - 1, "Could not decode to UTF-8 column '%s' with text '%s'",
|
||||||
colname , val_str);
|
colname , val_str);
|
||||||
PyErr_SetString(OperationalError, buf);
|
PyErr_SetString(OperationalError, buf);
|
||||||
}
|
}
|
||||||
|
@ -373,7 +389,12 @@ PyObject* _fetch_one_row(Cursor* self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PyTuple_SetItem(row, i, converted);
|
if (converted) {
|
||||||
|
PyTuple_SetItem(row, i, converted);
|
||||||
|
} else {
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
PyTuple_SetItem(row, i, Py_None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
|
@ -598,6 +619,14 @@ PyObject* _query_execute(Cursor* self, int multiple, PyObject* args)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
/* there was an error that occured in a user-defined callback */
|
||||||
|
if (_enable_callback_tracebacks) {
|
||||||
|
PyErr_Print();
|
||||||
|
} else {
|
||||||
|
PyErr_Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
_seterror(self->connection->db);
|
_seterror(self->connection->db);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
/* module.c - the module itself
|
/* module.c - the module itself
|
||||||
*
|
*
|
||||||
* Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de>
|
* Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de>
|
||||||
*
|
*
|
||||||
* This file is part of pysqlite.
|
* This file is part of pysqlite.
|
||||||
*
|
*
|
||||||
* This software is provided 'as-is', without any express or implied
|
* This software is provided 'as-is', without any express or implied
|
||||||
* warranty. In no event will the authors be held liable for any damages
|
* warranty. In no event will the authors be held liable for any damages
|
||||||
* arising from the use of this software.
|
* arising from the use of this software.
|
||||||
*
|
*
|
||||||
* Permission is granted to anyone to use this software for any purpose,
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
* including commercial applications, and to alter it and redistribute it
|
* including commercial applications, and to alter it and redistribute it
|
||||||
* freely, subject to the following restrictions:
|
* freely, subject to the following restrictions:
|
||||||
*
|
*
|
||||||
* 1. The origin of this software must not be misrepresented; you must not
|
* 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
|
* claim that you wrote the original software. If you use this software
|
||||||
* in a product, an acknowledgment in the product documentation would be
|
* in a product, an acknowledgment in the product documentation would be
|
||||||
* appreciated but is not required.
|
* appreciated but is not required.
|
||||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
* misrepresented as being the original software.
|
* misrepresented as being the original software.
|
||||||
* 3. This notice may not be removed or altered from any source distribution.
|
* 3. This notice may not be removed or altered from any source distribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "statement.h"
|
#include "statement.h"
|
||||||
|
@ -40,6 +40,7 @@ PyObject* Error, *Warning, *InterfaceError, *DatabaseError, *InternalError,
|
||||||
*NotSupportedError, *OptimizedUnicode;
|
*NotSupportedError, *OptimizedUnicode;
|
||||||
|
|
||||||
PyObject* converters;
|
PyObject* converters;
|
||||||
|
int _enable_callback_tracebacks;
|
||||||
|
|
||||||
static PyObject* module_connect(PyObject* self, PyObject* args, PyObject*
|
static PyObject* module_connect(PyObject* self, PyObject* args, PyObject*
|
||||||
kwargs)
|
kwargs)
|
||||||
|
@ -140,14 +141,42 @@ static PyObject* module_register_adapter(PyObject* self, PyObject* args, PyObjec
|
||||||
|
|
||||||
static PyObject* module_register_converter(PyObject* self, PyObject* args, PyObject* kwargs)
|
static PyObject* module_register_converter(PyObject* self, PyObject* args, PyObject* kwargs)
|
||||||
{
|
{
|
||||||
PyObject* name;
|
char* orig_name;
|
||||||
|
char* name = NULL;
|
||||||
|
char* c;
|
||||||
PyObject* callable;
|
PyObject* callable;
|
||||||
|
PyObject* retval = NULL;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "OO", &name, &callable)) {
|
if (!PyArg_ParseTuple(args, "sO", &orig_name, &callable)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PyDict_SetItem(converters, name, callable) != 0) {
|
/* convert the name to lowercase */
|
||||||
|
name = PyMem_Malloc(strlen(orig_name) + 2);
|
||||||
|
if (!name) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
strcpy(name, orig_name);
|
||||||
|
for (c = name; *c != (char)0; c++) {
|
||||||
|
*c = (*c) & 0xDF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PyDict_SetItemString(converters, name, callable) != 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
retval = Py_None;
|
||||||
|
error:
|
||||||
|
if (name) {
|
||||||
|
PyMem_Free(name);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject* enable_callback_tracebacks(PyObject* self, PyObject* args, PyObject* kwargs)
|
||||||
|
{
|
||||||
|
if (!PyArg_ParseTuple(args, "i", &_enable_callback_tracebacks)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,13 +203,64 @@ static PyMethodDef module_methods[] = {
|
||||||
{"register_adapter", (PyCFunction)module_register_adapter, METH_VARARGS, PyDoc_STR("Registers an adapter with pysqlite's adapter registry. Non-standard.")},
|
{"register_adapter", (PyCFunction)module_register_adapter, METH_VARARGS, PyDoc_STR("Registers an adapter with pysqlite's adapter registry. Non-standard.")},
|
||||||
{"register_converter", (PyCFunction)module_register_converter, METH_VARARGS, PyDoc_STR("Registers a converter with pysqlite. Non-standard.")},
|
{"register_converter", (PyCFunction)module_register_converter, METH_VARARGS, PyDoc_STR("Registers a converter with pysqlite. Non-standard.")},
|
||||||
{"adapt", (PyCFunction)psyco_microprotocols_adapt, METH_VARARGS, psyco_microprotocols_adapt_doc},
|
{"adapt", (PyCFunction)psyco_microprotocols_adapt, METH_VARARGS, psyco_microprotocols_adapt_doc},
|
||||||
|
{"enable_callback_tracebacks", (PyCFunction)enable_callback_tracebacks, METH_VARARGS, PyDoc_STR("Enable or disable callback functions throwing errors to stderr.")},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _IntConstantPair {
|
||||||
|
char* constant_name;
|
||||||
|
int constant_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _IntConstantPair IntConstantPair;
|
||||||
|
|
||||||
|
static IntConstantPair _int_constants[] = {
|
||||||
|
{"PARSE_DECLTYPES", PARSE_DECLTYPES},
|
||||||
|
{"PARSE_COLNAMES", PARSE_COLNAMES},
|
||||||
|
|
||||||
|
{"SQLITE_OK", SQLITE_OK},
|
||||||
|
{"SQLITE_DENY", SQLITE_DENY},
|
||||||
|
{"SQLITE_IGNORE", SQLITE_IGNORE},
|
||||||
|
{"SQLITE_CREATE_INDEX", SQLITE_CREATE_INDEX},
|
||||||
|
{"SQLITE_CREATE_TABLE", SQLITE_CREATE_TABLE},
|
||||||
|
{"SQLITE_CREATE_TEMP_INDEX", SQLITE_CREATE_TEMP_INDEX},
|
||||||
|
{"SQLITE_CREATE_TEMP_TABLE", SQLITE_CREATE_TEMP_TABLE},
|
||||||
|
{"SQLITE_CREATE_TEMP_TRIGGER", SQLITE_CREATE_TEMP_TRIGGER},
|
||||||
|
{"SQLITE_CREATE_TEMP_VIEW", SQLITE_CREATE_TEMP_VIEW},
|
||||||
|
{"SQLITE_CREATE_TRIGGER", SQLITE_CREATE_TRIGGER},
|
||||||
|
{"SQLITE_CREATE_VIEW", SQLITE_CREATE_VIEW},
|
||||||
|
{"SQLITE_DELETE", SQLITE_DELETE},
|
||||||
|
{"SQLITE_DROP_INDEX", SQLITE_DROP_INDEX},
|
||||||
|
{"SQLITE_DROP_TABLE", SQLITE_DROP_TABLE},
|
||||||
|
{"SQLITE_DROP_TEMP_INDEX", SQLITE_DROP_TEMP_INDEX},
|
||||||
|
{"SQLITE_DROP_TEMP_TABLE", SQLITE_DROP_TEMP_TABLE},
|
||||||
|
{"SQLITE_DROP_TEMP_TRIGGER", SQLITE_DROP_TEMP_TRIGGER},
|
||||||
|
{"SQLITE_DROP_TEMP_VIEW", SQLITE_DROP_TEMP_VIEW},
|
||||||
|
{"SQLITE_DROP_TRIGGER", SQLITE_DROP_TRIGGER},
|
||||||
|
{"SQLITE_DROP_VIEW", SQLITE_DROP_VIEW},
|
||||||
|
{"SQLITE_INSERT", SQLITE_INSERT},
|
||||||
|
{"SQLITE_PRAGMA", SQLITE_PRAGMA},
|
||||||
|
{"SQLITE_READ", SQLITE_READ},
|
||||||
|
{"SQLITE_SELECT", SQLITE_SELECT},
|
||||||
|
{"SQLITE_TRANSACTION", SQLITE_TRANSACTION},
|
||||||
|
{"SQLITE_UPDATE", SQLITE_UPDATE},
|
||||||
|
{"SQLITE_ATTACH", SQLITE_ATTACH},
|
||||||
|
{"SQLITE_DETACH", SQLITE_DETACH},
|
||||||
|
#if SQLITE_VERSION_NUMBER >= 3002001
|
||||||
|
{"SQLITE_ALTER_TABLE", SQLITE_ALTER_TABLE},
|
||||||
|
{"SQLITE_REINDEX", SQLITE_REINDEX},
|
||||||
|
#endif
|
||||||
|
#if SQLITE_VERSION_NUMBER >= 3003000
|
||||||
|
{"SQLITE_ANALYZE", SQLITE_ANALYZE},
|
||||||
|
#endif
|
||||||
|
{(char*)NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
PyMODINIT_FUNC init_sqlite3(void)
|
PyMODINIT_FUNC init_sqlite3(void)
|
||||||
{
|
{
|
||||||
PyObject *module, *dict;
|
PyObject *module, *dict;
|
||||||
PyObject *tmp_obj;
|
PyObject *tmp_obj;
|
||||||
|
int i;
|
||||||
|
|
||||||
module = Py_InitModule("_sqlite3", module_methods);
|
module = Py_InitModule("_sqlite3", module_methods);
|
||||||
|
|
||||||
|
@ -276,17 +356,15 @@ PyMODINIT_FUNC init_sqlite3(void)
|
||||||
OptimizedUnicode = (PyObject*)&PyCell_Type;
|
OptimizedUnicode = (PyObject*)&PyCell_Type;
|
||||||
PyDict_SetItemString(dict, "OptimizedUnicode", OptimizedUnicode);
|
PyDict_SetItemString(dict, "OptimizedUnicode", OptimizedUnicode);
|
||||||
|
|
||||||
if (!(tmp_obj = PyInt_FromLong(PARSE_DECLTYPES))) {
|
/* Set integer constants */
|
||||||
goto error;
|
for (i = 0; _int_constants[i].constant_name != 0; i++) {
|
||||||
|
tmp_obj = PyInt_FromLong(_int_constants[i].constant_value);
|
||||||
|
if (!tmp_obj) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
PyDict_SetItemString(dict, _int_constants[i].constant_name, tmp_obj);
|
||||||
|
Py_DECREF(tmp_obj);
|
||||||
}
|
}
|
||||||
PyDict_SetItemString(dict, "PARSE_DECLTYPES", tmp_obj);
|
|
||||||
Py_DECREF(tmp_obj);
|
|
||||||
|
|
||||||
if (!(tmp_obj = PyInt_FromLong(PARSE_COLNAMES))) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
PyDict_SetItemString(dict, "PARSE_COLNAMES", tmp_obj);
|
|
||||||
Py_DECREF(tmp_obj);
|
|
||||||
|
|
||||||
if (!(tmp_obj = PyString_FromString(PYSQLITE_VERSION))) {
|
if (!(tmp_obj = PyString_FromString(PYSQLITE_VERSION))) {
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -306,6 +384,8 @@ PyMODINIT_FUNC init_sqlite3(void)
|
||||||
/* initialize the default converters */
|
/* initialize the default converters */
|
||||||
converters_init(dict);
|
converters_init(dict);
|
||||||
|
|
||||||
|
_enable_callback_tracebacks = 0;
|
||||||
|
|
||||||
/* Original comment form _bsddb.c in the Python core. This is also still
|
/* Original comment form _bsddb.c in the Python core. This is also still
|
||||||
* needed nowadays for Python 2.3/2.4.
|
* needed nowadays for Python 2.3/2.4.
|
||||||
*
|
*
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#define PYSQLITE_MODULE_H
|
#define PYSQLITE_MODULE_H
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
|
||||||
#define PYSQLITE_VERSION "2.2.2"
|
#define PYSQLITE_VERSION "2.3.0"
|
||||||
|
|
||||||
extern PyObject* Error;
|
extern PyObject* Error;
|
||||||
extern PyObject* Warning;
|
extern PyObject* Warning;
|
||||||
|
@ -50,6 +50,8 @@ extern PyObject* time_sleep;
|
||||||
*/
|
*/
|
||||||
extern PyObject* converters;
|
extern PyObject* converters;
|
||||||
|
|
||||||
|
extern int _enable_callback_tracebacks;
|
||||||
|
|
||||||
#define PARSE_DECLTYPES 1
|
#define PARSE_DECLTYPES 1
|
||||||
#define PARSE_COLNAMES 2
|
#define PARSE_COLNAMES 2
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue