/* Another Python Sqlite Wrapper This wrapper aims to be the minimum necessary layer over SQLite 3 itself. It assumes we are running as 32 bit int with a 64 bit long long type available. Copyright (C) 2004-2005 Roger Binns 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. */ /* Get the version number */ #include "apswversion.h" /* Python headers */ #include #include #include "structmember.h" /* SQLite 3 headers */ #include "sqlite3.h" /* system headers */ #include /* used to decide if we will use int or long long */ #define INT32_MIN (-2147483647 - 1) #define INT32_MAX 2147483647 /* The encoding we use with SQLite. SQLite supports either utf8 or 16 bit unicode (host byte order). If the latter is used then all functions have "16" appended to their name. The encoding used also affects how strings are stored in the database. We use utf8 since it is more space efficient, and Python can't make its mind up about Unicode (it uses 16 or 32 bit unichars and often likes to use Byte Order Markers. */ #define STRENCODING "utf_8" /* Some macros used for frequent operations */ #define CHECK_THREAD(x,e) { if(x->thread_ident!=PyThread_get_thread_ident()) { if (!PyErr_Occurred()) PyErr_Format(ExcThreadingViolation, "All SQLite objects created in a thread can only be used in that same thread. " "The object was created in thread id %d and this is %d", (int)(x->thread_ident), (int)(PyThread_get_thread_ident())); return e; } } /* EXCEPTION TYPES */ static PyObject *APSWException; /* root exception class */ static PyObject *ExcThreadingViolation; /* thread misuse */ static PyObject *ExcIncomplete; /* didn't finish previous query */ static PyObject *ExcBindings; /* wrong number of bindings */ static PyObject *ExcComplete; /* query is finished */ static PyObject *ExcTraceAbort; /* aborted by exectrace */ static struct { int code; const char *name; PyObject *cls;} exc_descriptors[]= { /* Generic Errors */ {SQLITE_ERROR, "SQL"}, {SQLITE_MISMATCH, "Mismatch"}, /* Internal Errors */ {SQLITE_INTERNAL, "Internal"}, {SQLITE_PROTOCOL, "Protocol"}, {SQLITE_MISUSE, "Misuse"}, {SQLITE_RANGE, "Range"}, /* permissions etc */ {SQLITE_PERM, "Permissions"}, {SQLITE_READONLY, "ReadOnly"}, {SQLITE_CANTOPEN, "CantOpen"}, {SQLITE_AUTH, "Auth"}, /* abort/busy/etc */ {SQLITE_ABORT, "Abort"}, {SQLITE_BUSY, "Busy"}, {SQLITE_LOCKED, "Locked"}, {SQLITE_INTERRUPT,"Interrupt"}, {SQLITE_SCHEMA, "SchemaChange"}, {SQLITE_CONSTRAINT, "Constraint"}, /* memory/disk/corrupt etc */ {SQLITE_NOMEM, "NoMem"}, {SQLITE_IOERR, "IO"}, {SQLITE_CORRUPT, "Corrupt"}, {SQLITE_FULL, "Full"}, {SQLITE_TOOBIG, "TooBig"}, {SQLITE_NOLFS, "NoLFS"}, {SQLITE_EMPTY, "Empty"}, {SQLITE_FORMAT, "Format"}, {SQLITE_NOTADB, "NotADB"}, {-1, 0, 0} }; /* EXCEPTION CODE */ static int init_exceptions(PyObject *m) { char buffy[100]; /* more than enough for anyone :-) */ int i; PyObject *obj; /* PyModule_AddObject uses borrowed reference so we incref whatever we give to it, so we still have a copy to use */ /* custom ones first */ APSWException=PyErr_NewException("apsw.Error", NULL, NULL); if(!APSWException) return -1; Py_INCREF(APSWException); if(PyModule_AddObject(m, "Error", (PyObject *)APSWException)) return -1; #define EXC(varname,name) varname=PyErr_NewException("apsw." name, APSWException, NULL); if(!varname) return -1; Py_INCREF(varname); if(PyModule_AddObject(m, name, (PyObject *)varname)) return -1; EXC(ExcThreadingViolation, "ThreadingViolationError"); EXC(ExcIncomplete, "IncompleteExecutionError"); EXC(ExcBindings, "BindingsError"); EXC(ExcComplete, "ExecutionCompleteError"); EXC(ExcTraceAbort, "ExecTraceAbort"); #undef EXC /* all the ones corresponding to SQLITE error codes */ for(i=0;exc_descriptors[i].name;i++) { sprintf(buffy, "apsw.%sError", exc_descriptors[i].name); obj=PyErr_NewException(buffy, APSWException, NULL); if(!obj) return -1; Py_INCREF(obj); exc_descriptors[i].cls=obj; sprintf(buffy, "%sError", exc_descriptors[i].name); if(PyModule_AddObject(m, buffy, obj)) return -1; } return 0; } static void make_exception(int res, sqlite3 *db) { int i; for(i=0;exc_descriptors[i].name;i++) if (exc_descriptors[i].code==res) { assert(exc_descriptors[i].cls); PyErr_Format(exc_descriptors[i].cls, "%sError: %s", exc_descriptors[i].name, sqlite3_errmsg(db)); assert(PyErr_Occurred()); return; } PyErr_Format(APSWException, "Error %d: %s", res, sqlite3_errmsg(db)); } /* If res indicates an SQLite error then do all the exception creation work. We don't overwrite earlier exceptions hence the PyErr_Occurred check */ #define SET_EXC(db,res) { if(res != SQLITE_OK && !PyErr_Occurred()) make_exception(res,db); } /* CALLBACK INFO */ /* details of a registered function passed as user data to aqlite3_create_function */ typedef struct _funccbinfo { struct _funccbinfo *next; /* we use a linked list */ char *name; /* ascii function name which we uppercased */ PyObject *scalarfunc; /* the function to call for stepping */ PyObject *aggregatefactory; /* factory for aggregate functions */ } funccbinfo; /* a particular aggregate function instance used as sqlite3_aggregate_context */ typedef struct _aggregatefunctioncontext { PyObject *aggvalue; /* the aggregation value passed as first parameter */ PyObject *stepfunc; /* step function */ PyObject *finalfunc; /* final function */ } aggregatefunctioncontext; static funccbinfo *freefunccbinfo(funccbinfo *); typedef struct _collationcbinfo { struct _collationcbinfo *next; /* we use a linked list */ char *name; /* ascii collation name which we uppercased */ PyObject *func; /* the actual function to call */ } collationcbinfo; static collationcbinfo *freecollationcbinfo(collationcbinfo *); /* CONNECTION TYPE */ typedef struct { PyObject_HEAD sqlite3 *db; /* the actual database connection */ long thread_ident; /* which thread we were made in */ funccbinfo *functions; /* linked list of registered functions */ collationcbinfo *collations; /* linked list of registered collations */ /* registered hooks/handlers (NULL or callable) */ PyObject *busyhandler; PyObject *commithook; PyObject *progresshandler; PyObject *authorizer; } Connection; static PyTypeObject ConnectionType; /* CURSOR TYPE */ typedef struct { PyObject_HEAD Connection *connection; /* pointer to parent connection */ sqlite3_stmt *statement; /* current compiled statement */ /* see sqlite3_prepare for the origin of these */ const char *zsql; /* current sqlstatement (which may include multiple statements) */ const char *zsqlnextpos; /* the next statement to execute (or NULL if no more) */ /* what state we are in */ enum { C_BEGIN, C_ROW, C_DONE } status; /* bindings for query */ PyObject *bindings; /* dict or sequence */ int bindingsoffset; /* for sequence tracks how far along we are when dealing with multiple statements */ /* iterator for executemany */ PyObject *emiter; /* tracing functions */ PyObject *exectrace; PyObject *rowtrace; } Cursor; static PyTypeObject CursorType; /* CONVENIENCE FUNCTIONS */ /* Convert a NULL terminated UTF-8 string into a Python object. None is returned is NULL is passed in. */ static PyObject * convertutf8string(const char *str) { const char *chk=str; if(!str) { Py_INCREF(Py_None); return Py_None; } for(chk=str;*chk && !((*chk)&0x80); chk++) ; if(*chk) return PyUnicode_DecodeUTF8(str, strlen(str), NULL); else return PyString_FromString(str); } /* Convert a pointer and size UTF-8 string into a Python object. Pointer must be non-NULL. */ static PyObject * convertutf8stringsize(const char *str, int size) { const char *chk=str; int i; assert(str); assert(size>=0); for(i=0;ithread_ident!=PyThread_get_thread_ident()) { PyObject *err_type, *err_value, *err_traceback; int have_error=PyErr_Occurred()?1:0; if (have_error) PyErr_Fetch(&err_type, &err_value, &err_traceback); PyErr_Format(ExcThreadingViolation, "The destructor for Connection is called in a different thread than it" "was created in. All calls must be in the same thread. It was created in thread %d" "and this is %d. This SQLite database is not being closed as a result.", (int)(self->thread_ident), (int)(PyThread_get_thread_ident())); PyErr_WriteUnraisable((PyObject*)self); if (have_error) PyErr_Restore(err_type, err_value, err_traceback); return; } if (self->db) { int res; Py_BEGIN_ALLOW_THREADS res=sqlite3_close(self->db); Py_END_ALLOW_THREADS; if (res!=SQLITE_OK) { PyObject *err_type, *err_value, *err_traceback; int have_error=PyErr_Occurred()?1:0; if (have_error) PyErr_Fetch(&err_type, &err_value, &err_traceback); make_exception(res,self->db); if (have_error) { PyErr_WriteUnraisable((PyObject*)self); PyErr_Restore(err_type, err_value, err_traceback); } } else self->db=0; } /* free functions */ { funccbinfo *func=self->functions; while((func=freefunccbinfo(func))); } /* free collations */ { collationcbinfo *coll=self->collations; while((coll=freecollationcbinfo(coll))); } Py_XDECREF(self->busyhandler); self->busyhandler=0; Py_XDECREF(self->commithook); self->commithook=0; Py_XDECREF(self->progresshandler); self->progresshandler=0; Py_XDECREF(self->authorizer); self->authorizer=0; self->thread_ident=-1; self->ob_type->tp_free((PyObject*)self); } static PyObject* Connection_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { Connection *self; self = (Connection *)type->tp_alloc(type, 0); if (self != NULL) { /* Strictly speaking the memory was already zeroed. This is just defensive coding. */ self->db=0; self->thread_ident=PyThread_get_thread_ident(); self->functions=0; self->collations=0; self->busyhandler=0; self->commithook=0; self->progresshandler=0; self->authorizer=0; } return (PyObject *)self; } static int Connection_init(Connection *self, PyObject *args, PyObject *kwds) { char *filename=NULL; int res=0; CHECK_THREAD(self,-1); if(kwds && kwds!=Py_None) { if(!PyDict_Check(kwds)) { PyErr_Format(PyExc_TypeError, "Bad type for keyword args"); return -1; } if(PyDict_Size(kwds)) { PyErr_Format(PyExc_TypeError, "Connection constructor does not take keyword arguments"); return -1; } } if(!PyArg_ParseTuple(args, "es:Connection(filename)", STRENCODING, &filename)) return -1; Py_BEGIN_ALLOW_THREADS res=sqlite3_open(filename, &self->db); Py_END_ALLOW_THREADS; SET_EXC(self->db, res); /* nb sqlite3_open always allocates the db even on error */ PyMem_Free(filename); return (res==SQLITE_OK)?0:-1; } static PyObject * Connection_cursor(Connection *self) { Cursor* cursor = NULL; CHECK_THREAD(self,NULL); /* there is absolutely no documentation on how to allocate a new object in the Python C API. Actually there is documentation of 5 different methods, all of which take various parameters we don't have. This appears to be yet another (and undocumented) way of doing it. */ cursor = (Cursor*) (CursorType.tp_alloc(&CursorType, 0)); if(!cursor) return NULL; /* incref me since cursor holds a pointer */ Py_INCREF((PyObject*)self); cursor->connection=self; return (PyObject*)cursor; } static PyObject * Connection_setbusytimeout(Connection *self, PyObject *args) { int ms=0; int res; CHECK_THREAD(self,NULL); if(!PyArg_ParseTuple(args, "i:setbusytimeout(millseconds)", &ms)) return NULL; res=sqlite3_busy_timeout(self->db, ms); SET_EXC(self->db, res); if(res!=SQLITE_OK) return NULL; /* free any explicit busyhandler we may have had */ Py_XDECREF(self->busyhandler); self->busyhandler=0; return Py_BuildValue(""); } static PyObject * Connection_changes(Connection *self) { CHECK_THREAD(self,NULL); return Py_BuildValue("i", sqlite3_changes(self->db)); } static PyObject * Connection_totalchanges(Connection *self) { CHECK_THREAD(self,NULL); return Py_BuildValue("i", sqlite3_total_changes(self->db)); } static PyObject * Connection_last_insert_rowid(Connection *self) { long long int vint; CHECK_THREAD(self,NULL); vint=sqlite3_last_insert_rowid(self->db); if(vintINT32_MAX) return PyLong_FromLongLong(vint); else return PyInt_FromLong((long)vint); } static PyObject * Connection_complete(Connection *self, PyObject *args) { char *statements=NULL; int res; CHECK_THREAD(self,NULL); if(!PyArg_ParseTuple(args, "es:complete(statement)", STRENCODING, &statements)) return NULL; res=sqlite3_complete(statements); PyMem_Free(statements); if(res) { Py_INCREF(Py_True); return Py_True; } Py_INCREF(Py_False); return Py_False; } static PyObject * Connection_interrupt(Connection *self) { CHECK_THREAD(self, NULL); sqlite3_interrupt(self->db); /* no return value */ return Py_BuildValue(""); } #ifdef EXPERIMENTAL /* commit hook */ int commithookcb(void *context) { /* The hook returns 0 for commit to go ahead and non-zero to abort commit (turn into a rollback). We return non-zero for errors */ PyGILState_STATE gilstate; PyObject *retval=NULL, *args=NULL; int ok=1; /* error state */ Connection *self=(Connection *)context; assert(self); assert(self->commithook); assert(self->commithook!=Py_None); /* defensive coding */ if(!self->commithook) return 0; gilstate=PyGILState_Ensure(); if(PyErr_Occurred()) goto finally; /* abort hook due to outstanding exception */ args=PyTuple_New(0); if(!args) goto finally; /* abort hook on failure to allocate args */ retval=PyEval_CallObject(self->commithook, args); if(!retval) goto finally; /* abort hook due to exeception */ ok=PyObject_IsTrue(retval); assert(ok==-1 || ok==0 || ok==1); if(ok==-1) { ok=1; goto finally; /* abort due to exception in return value */ } finally: Py_XDECREF(retval); Py_XDECREF(args); PyGILState_Release(gilstate); return ok; } static PyObject * Connection_setcommithook(Connection *self, PyObject *callable) { /* sqlite3_commit_hook doesn't return an error code */ CHECK_THREAD(self,NULL); if(callable==Py_None) { sqlite3_commit_hook(self->db, NULL, NULL); callable=NULL; goto finally; } if(!PyCallable_Check(callable)) { PyErr_Format(PyExc_TypeError, "commit hook must be callable"); return NULL; } sqlite3_commit_hook(self->db, commithookcb, self); Py_INCREF(callable); finally: Py_XDECREF(self->commithook); self->commithook=callable; return Py_BuildValue(""); } #endif /* EXPERIMENTAL sqlite3_commit_hook */ #ifdef EXPERIMENTAL /* sqlite3_progress_handler */ int progresshandlercb(void *context) { /* The hook returns 0 for continue and non-zero to abort (rollback). We return non-zero for errors */ PyGILState_STATE gilstate; PyObject *retval=NULL, *args=NULL; int ok=1; /* error state */ Connection *self=(Connection *)context; assert(self); assert(self->progresshandler); /* defensive coding */ if(!self->progresshandler) return 0; gilstate=PyGILState_Ensure(); args=PyTuple_New(0); if(!args) goto finally; /* abort handler due to failure to allocate args */ retval=PyEval_CallObject(self->progresshandler, args); if(!retval) goto finally; /* abort due to exeception */ ok=PyObject_IsTrue(retval); assert(ok==-1 || ok==0 || ok==1); if(ok==-1) { ok=1; goto finally; /* abort due to exception in result */ } finally: Py_XDECREF(retval); Py_XDECREF(args); PyGILState_Release(gilstate); return ok; } static PyObject * Connection_setprogresshandler(Connection *self, PyObject *args) { /* sqlite3_progress_handler doesn't return an error code */ int nsteps=20; PyObject *callable=NULL; CHECK_THREAD(self,NULL); if(!PyArg_ParseTuple(args, "O|i:setprogresshandler(callable, nsteps=20)", &callable, &nsteps)) return NULL; if(callable==Py_None) { sqlite3_progress_handler(self->db, 0, NULL, NULL); callable=NULL; goto finally; } if(!PyCallable_Check(callable)) { PyErr_Format(PyExc_TypeError, "progress handler must be callable"); return NULL; } sqlite3_progress_handler(self->db, nsteps, progresshandlercb, self); Py_INCREF(callable); finally: Py_XDECREF(self->progresshandler); self->progresshandler=callable; return Py_BuildValue(""); } #endif /* EXPERIMENTAL sqlite3_progress_handler */ int authorizercb(void *context, int operation, const char *paramone, const char *paramtwo, const char *databasename, const char *triggerview) { /* should return one of SQLITE_OK, SQLITE_DENY, or SQLITE_IGNORE. (0, 1 or 2 respectively) */ PyGILState_STATE gilstate; PyObject *args=NULL, *retval=NULL; int result=SQLITE_DENY; /* default to deny */ Connection *self=(Connection *)context; PyObject *poperation=NULL, *pone=NULL, *ptwo=NULL, *pdatabasename=NULL, *ptriggerview=NULL; assert(self); assert(self->authorizer); assert(self->authorizer!=Py_None); /* defensive coding */ if(!self->authorizer) return SQLITE_OK; gilstate=PyGILState_Ensure(); if(PyErr_Occurred()) goto finally; /* abort due to earlier exception */ poperation=Py_BuildValue("i", operation); pone=convertutf8string(paramone); ptwo=convertutf8string(paramtwo); pdatabasename=convertutf8string(databasename); ptriggerview=convertutf8string(triggerview); args=PyTuple_New(5); if(!poperation || !pone || !ptwo || !pdatabasename || !ptriggerview || !args) goto finally; PyTuple_SET_ITEM(args, 0, poperation); PyTuple_SET_ITEM(args, 1, pone); PyTuple_SET_ITEM(args, 2, ptwo); PyTuple_SET_ITEM(args, 3, pdatabasename); PyTuple_SET_ITEM(args, 4, ptriggerview); poperation=pone=ptwo=pdatabasename=ptriggerview=NULL; /* owned by args now */ retval=PyEval_CallObject(self->authorizer, args); if(!retval) goto finally; /* abort due to exeception */ result=PyInt_AsLong(retval); if (PyErr_Occurred()) result=SQLITE_DENY; finally: Py_XDECREF(poperation); Py_XDECREF(pone); Py_XDECREF(ptwo); Py_XDECREF(pdatabasename); Py_XDECREF(ptriggerview); Py_XDECREF(args); Py_XDECREF(retval); PyGILState_Release(gilstate); return result; } static PyObject * Connection_setauthorizer(Connection *self, PyObject *callable) { int res; CHECK_THREAD(self,NULL); if(callable==Py_None) { res=sqlite3_set_authorizer(self->db, NULL, NULL); callable=NULL; goto finally; } if(!PyCallable_Check(callable)) { PyErr_Format(PyExc_TypeError, "authorizer must be callable"); return NULL; } res=sqlite3_set_authorizer(self->db, authorizercb, self); SET_EXC(self->db, res); Py_INCREF(callable); finally: Py_XDECREF(self->authorizer); self->authorizer=callable; return (res==SQLITE_OK)?Py_BuildValue(""):NULL; } int busyhandlercb(void *context, int ncall) { /* Return zero for caller to get SQLITE_BUSY error. We default to zero in case of error. */ PyGILState_STATE gilstate; PyObject *args, *retval; int result=0; /* default to fail with SQLITE_BUSY */ Connection *self=(Connection *)context; assert(self); assert(self->busyhandler); /* defensive coding */ if(!self->busyhandler) return result; gilstate=PyGILState_Ensure(); args=Py_BuildValue("(i)", ncall); if(!args) goto finally; /* abort busy due to memory allocation failure */ retval=PyEval_CallObject(self->busyhandler, args); Py_DECREF(args); if(!retval) goto finally; /* abort due to exeception */ result=PyObject_IsTrue(retval); assert(result==-1 || result==0 || result==1); Py_DECREF(retval); if(result==-1) { result=0; goto finally; /* abort due to exception converting retval */ } finally: PyGILState_Release(gilstate); return result; } static PyObject * Connection_setbusyhandler(Connection *self, PyObject *callable) { int res=SQLITE_OK; CHECK_THREAD(self,NULL); if(callable==Py_None) { res=sqlite3_busy_handler(self->db, NULL, NULL); callable=NULL; goto finally; } if(!PyCallable_Check(callable)) { PyErr_Format(PyExc_TypeError, "busyhandler must be callable"); return NULL; } res=sqlite3_busy_handler(self->db, busyhandlercb, self); SET_EXC(self->db, res); Py_INCREF(callable); finally: Py_XDECREF(self->busyhandler); self->busyhandler=callable; return (res==SQLITE_OK)?Py_BuildValue(""):NULL; } /* USER DEFINED FUNCTION CODE.*/ /* We store the registered functions in a linked list hooked into the connection object so we can free them. There is probably a better data structure to use but this was most convenient. */ static funccbinfo * freefunccbinfo(funccbinfo *func) { funccbinfo *fnext; if(!func) return NULL; if(func->name) PyMem_Free(func->name); Py_XDECREF(func->scalarfunc); Py_XDECREF(func->aggregatefactory); fnext=func->next; PyMem_Free(func); return fnext; } static funccbinfo * allocfunccbinfo(void) { funccbinfo *res=PyMem_Malloc(sizeof(funccbinfo)); if(res) memset(res, 0, sizeof(funccbinfo)); return res; } /* Converts sqlite3_value to PyObject. Returns a new reference. */ static PyObject * convert_value_to_pyobject(sqlite3_value *value) { /* DUPLICATE(ish) code: this is substantially similar to the code in Cursor_next. If you fix anything here then do it there as well. */ const int coltype=sqlite3_value_type(value); switch(coltype) { case SQLITE_INTEGER: { long long vint=sqlite3_value_int64(value); if(vintINT32_MAX) return PyLong_FromLongLong(vint); else return PyInt_FromLong((long)vint); } case SQLITE_FLOAT: return PyFloat_FromDouble(sqlite3_value_double(value)); case SQLITE_TEXT: return convertutf8string(sqlite3_value_text(value)); case SQLITE_NULL: Py_INCREF(Py_None); return Py_None; case SQLITE_BLOB: { PyObject *item; int sz=sqlite3_value_bytes(value); item=PyBuffer_New(sz); if(item) { void *buffy=0; int sz2=sz; if(!PyObject_AsWriteBuffer(item, &buffy, &sz2)) memcpy(buffy, sqlite3_value_blob(value), sz); else { Py_DECREF(item); return NULL; } } return NULL; } default: PyErr_Format(APSWException, "Unknown sqlite column type %d!", coltype); return NULL; } /* can't get here */ assert(0); return NULL; } static void set_context_result(sqlite3_context *context, PyObject *obj) { if(!obj) { assert(PyErr_Occurred()); /* TODO: possibly examine exception and return appropriate error code eg for BusyError set error to SQLITE_BUSY */ sqlite3_result_error(context, "executing scalarcallback failed", SQLITE_ERROR); return; } /* DUPLICATE(ish) code: this is substantially similar to the code in Cursor_dobinding. If you fix anything here then do it there as well. */ if(obj==Py_None) { sqlite3_result_null(context); return; } if(PyInt_Check(obj)) { sqlite3_result_int(context, PyInt_AS_LONG(obj)); return; } if (PyLong_Check(obj)) { sqlite3_result_int64(context, PyLong_AsLongLong(obj)); return; } if (PyFloat_CheckExact(obj)) { sqlite3_result_double(context, PyFloat_AS_DOUBLE(obj)); return; } if (PyUnicode_Check(obj)) { UNIDATABEGIN(obj) if(strdata) { if(use16) sqlite3_result_text16(context, strdata, strbytes, SQLITE_TRANSIENT); else sqlite3_result_text(context, strdata, strbytes, SQLITE_TRANSIENT); } else sqlite3_result_error(context, "Unicode conversions failed", SQLITE_ERROR); UNIDATAEND(obj); return; } if (PyString_Check(obj)) { const char *val=PyString_AS_STRING(obj); const char *chk=val; for(;*chk && !((*chk)&0x80); chk++); if(*chk) { PyObject *str2=PyUnicode_FromObject(obj); if(!str2) { sqlite3_result_error(context, "PyUnicode_FromObject failed", SQLITE_ERROR); return; } UNIDATABEGIN(str2) if(strdata) { if(use16) sqlite3_result_text16(context, strdata, strbytes, SQLITE_TRANSIENT); else sqlite3_result_text(context, strdata, strbytes, SQLITE_TRANSIENT); } else sqlite3_result_error(context, "Unicode conversions failed", SQLITE_ERROR); UNIDATAEND(str2); Py_DECREF(str2); } else sqlite3_result_text(context, val, PyString_GET_SIZE(obj), SQLITE_TRANSIENT); return; } if (PyBuffer_Check(obj)) { const char *buffer; int buflen; if(PyObject_AsCharBuffer(obj, &buffer, &buflen)) { sqlite3_result_error(context, "PyObject_AsCharBuffer failed", SQLITE_ERROR); return; } sqlite3_result_blob(context, buffer, buflen, SQLITE_TRANSIENT); return; } PyErr_Format(PyExc_TypeError, "Bad return type from function callback"); sqlite3_result_error(context, "Bad return type from function callback", SQLITE_ERROR); } /* Returns a new reference to a tuple formed from function parameters */ PyObject * getfunctionargs(sqlite3_context *context, PyObject *firstelement, int argc, sqlite3_value **argv) { PyObject *pyargs=NULL; int i; int extra=0; /* extra first item */ if(firstelement) extra=1; pyargs=PyTuple_New(argc+extra); if(!pyargs) { sqlite3_result_error(context, "PyTuple_New failed", SQLITE_ERROR); goto error; } if(extra) { Py_INCREF(firstelement); PyTuple_SET_ITEM(pyargs, 0, firstelement); } for(i=0;iscalarfunc); if(PyErr_Occurred()) { sqlite3_result_error(context, "Prior Python Error", SQLITE_ERROR); goto finally; } pyargs=getfunctionargs(context, NULL, argc, argv); if(!pyargs) goto finally; assert(!PyErr_Occurred()); retval=PyEval_CallObject(cbinfo->scalarfunc, pyargs); Py_DECREF(pyargs); set_context_result(context, retval); Py_XDECREF(retval); finally: PyGILState_Release(gilstate); } static aggregatefunctioncontext * getaggregatefunctioncontext(sqlite3_context *context) { aggregatefunctioncontext *aggfc=sqlite3_aggregate_context(context, sizeof(aggregatefunctioncontext)); funccbinfo *cbinfo; PyObject *retval; PyObject *args; /* have we seen it before? */ if(aggfc->aggvalue) return aggfc; /* fill in with Py_None so we know it is valid */ aggfc->aggvalue=Py_None; Py_INCREF(Py_None); cbinfo=(funccbinfo*)sqlite3_user_data(context); assert(cbinfo); assert(cbinfo->aggregatefactory); /* call the aggregatefactory to get our working objects */ args=PyTuple_New(0); if(!args) return aggfc; retval=PyEval_CallObject(cbinfo->aggregatefactory, args); Py_DECREF(args); if(!retval) return aggfc; /* it should have returned a tuple of 3 items: object, stepfunction and finalfunction */ if(!PyTuple_Check(retval)) { PyErr_Format(PyExc_TypeError, "Aggregate factory should return tuple of (object, stepfunction, finalfunction)"); goto finally; } if(PyTuple_GET_SIZE(retval)!=3) { PyErr_Format(PyExc_TypeError, "Aggregate factory should return 3 item tuple of (object, stepfunction, finalfunction)"); goto finally; } /* we don't care about the type of the zeroth item (object) ... */ /* stepfunc */ if (!PyCallable_Check(PyTuple_GET_ITEM(retval,1))) { PyErr_Format(PyExc_TypeError, "stepfunction must be callable"); goto finally; } /* finalfunc */ if (!PyCallable_Check(PyTuple_GET_ITEM(retval,2))) { PyErr_Format(PyExc_TypeError, "final function must be callable"); goto finally; } aggfc->aggvalue=PyTuple_GET_ITEM(retval,0); aggfc->stepfunc=PyTuple_GET_ITEM(retval,1); aggfc->finalfunc=PyTuple_GET_ITEM(retval,2); Py_INCREF(aggfc->aggvalue); Py_INCREF(aggfc->stepfunc); Py_INCREF(aggfc->finalfunc); Py_DECREF(Py_None); /* we used this earlier as a sentinel */ finally: assert(retval); Py_DECREF(retval); return aggfc; } static void cbdispatch_step(sqlite3_context *context, int argc, sqlite3_value **argv) { PyGILState_STATE gilstate; PyObject *pyargs; PyObject *retval; aggregatefunctioncontext *aggfc=NULL; gilstate=PyGILState_Ensure(); aggfc=getaggregatefunctioncontext(context); assert(aggfc); if(aggfc->aggvalue==Py_None) { assert(PyErr_Occurred()); sqlite3_result_error(context, "Prior Python Error", SQLITE_ERROR); goto finally; } pyargs=getfunctionargs(context, aggfc->aggvalue, argc, argv); if(!pyargs) goto finally; assert(!PyErr_Occurred()); retval=PyEval_CallObject(aggfc->stepfunc, pyargs); Py_DECREF(pyargs); Py_XDECREF(retval); if(!retval) sqlite3_result_error(context, "Error in step function", SQLITE_ERROR); finally: PyGILState_Release(gilstate); } /* this is somewhat similar to cbdispatch_step, except we also have to do some cleanup of the aggregatefunctioncontext */ static void cbdispatch_final(sqlite3_context *context) { PyGILState_STATE gilstate; PyObject *pyargs; PyObject *retval; aggregatefunctioncontext *aggfc=NULL; gilstate=PyGILState_Ensure(); aggfc=getaggregatefunctioncontext(context); assert(aggfc); if(!aggfc->finalfunc) { sqlite3_result_error(context, "Prior Python Error", SQLITE_ERROR); goto finally; } pyargs=PyTuple_New(1); if(!pyargs) goto finally; Py_INCREF(aggfc->aggvalue); PyTuple_SET_ITEM(pyargs, 0, aggfc->aggvalue); retval=PyEval_CallObject(aggfc->finalfunc, pyargs); Py_DECREF(pyargs); set_context_result(context, retval); Py_XDECREF(retval); finally: /* we also free the aggregatefunctioncontext here */ assert(aggfc->aggvalue); /* should always be set, perhaps to Py_None */ Py_XDECREF(aggfc->aggvalue); Py_XDECREF(aggfc->stepfunc); Py_XDECREF(aggfc->finalfunc); /* sqlite3 frees the actual underlying memory we used (aggfc itself) */ PyGILState_Release(gilstate); } static PyObject * Connection_createscalarfunction(Connection *self, PyObject *args) { int numargs=-1; PyObject *callable; char *name=0; char *chk; funccbinfo *cbinfo; int res; CHECK_THREAD(self,NULL); if(!PyArg_ParseTuple(args, "esO|i:createscalarfunction(name,callback, numargs=-1)", STRENCODING, &name, &callable, &numargs)) return NULL; assert(name); assert(callable); /* there isn't a C api to get a (potentially unicode) string and make it uppercase so we hack around */ /* validate the name */ for(chk=name;*chk && !((*chk)&0x80);chk++); if(*chk) { PyMem_Free(name); PyErr_SetString(PyExc_TypeError, "function name must be ascii characters only"); return NULL; } /* convert name to upper case */ for(chk=name;*chk;chk++) if(*chk>='a' && *chk<='z') *chk-='a'-'A'; /* ::TODO:: check if name points to already defined function and free relevant funccbinfo */ if(callable!=Py_None && !PyCallable_Check(callable)) { PyMem_Free(name); PyErr_SetString(PyExc_TypeError, "parameter must be callable"); return NULL; } Py_INCREF(callable); cbinfo=allocfunccbinfo(); cbinfo->name=name; cbinfo->scalarfunc=callable; res=sqlite3_create_function(self->db, name, numargs, SQLITE_UTF8, /* it isn't very clear what this parameter does */ (callable!=Py_None)?cbinfo:NULL, (callable!=Py_None)?cbdispatch_func:NULL, NULL, NULL); if(res) { freefunccbinfo(cbinfo); SET_EXC(self->db, res); return NULL; } if(callable!=Py_None) { /* put cbinfo into the linked list */ cbinfo->next=self->functions; self->functions=cbinfo; } else { /* free it since we cancelled the function */ freefunccbinfo(cbinfo); } return Py_BuildValue(""); } static PyObject * Connection_createaggregatefunction(Connection *self, PyObject *args) { int numargs=-1; PyObject *callable; char *name=0; char *chk; funccbinfo *cbinfo; int res; CHECK_THREAD(self,NULL); if(!PyArg_ParseTuple(args, "esO|i:createaggregatefunction(name, factorycallback, numargs=-1)", STRENCODING, &name, &callable, &numargs)) return NULL; assert(name); assert(callable); /* there isn't a C api to get a (potentially unicode) string and make it uppercase so we hack around */ /* validate the name */ for(chk=name;*chk && !((*chk)&0x80);chk++); if(*chk) { PyMem_Free(name); PyErr_SetString(PyExc_TypeError, "function name must be ascii characters only"); return NULL; } /* convert name to upper case */ for(chk=name;*chk;chk++) if(*chk>='a' && *chk<='z') *chk-='a'-'A'; /* ::TODO:: check if name points to already defined function and free relevant funccbinfo */ if(callable!=Py_None && !PyCallable_Check(callable)) { PyMem_Free(name); PyErr_SetString(PyExc_TypeError, "parameter must be callable"); return NULL; } Py_INCREF(callable); cbinfo=allocfunccbinfo(); cbinfo->name=name; cbinfo->aggregatefactory=callable; res=sqlite3_create_function(self->db, name, numargs, SQLITE_UTF8, /* it isn't very clear what this parameter does */ (callable!=Py_None)?cbinfo:NULL, NULL, (callable!=Py_None)?cbdispatch_step:NULL, (callable!=Py_None)?cbdispatch_final:NULL); if(res) { freefunccbinfo(cbinfo); SET_EXC(self->db, res); return NULL; } if(callable!=Py_None) { /* put cbinfo into the linked list */ cbinfo->next=self->functions; self->functions=cbinfo; } else { /* free things up */ freefunccbinfo(cbinfo); } return Py_BuildValue(""); } /* USER DEFINED COLLATION CODE.*/ /* We store the registered collations in a linked list hooked into the connection object so we can free them. There is probably a better data structure to use but this was most convenient. */ static collationcbinfo * freecollationcbinfo(collationcbinfo *collation) { collationcbinfo *cnext; if(!collation) return NULL; if(collation->name) PyMem_Free(collation->name); Py_XDECREF(collation->func); cnext=collation->next; PyMem_Free(collation); return cnext; } static collationcbinfo * alloccollationcbinfo(void) { collationcbinfo *res=PyMem_Malloc(sizeof(collationcbinfo)); memset(res, 0, sizeof(collationcbinfo)); return res; } int collation_cb(void *context, int stringonelen, const void *stringonedata, int stringtwolen, const void *stringtwodata) { PyGILState_STATE gilstate; collationcbinfo *cbinfo=(collationcbinfo*)context; PyObject *pys1=NULL, *pys2=NULL, *retval=NULL, *pyargs=NULL; int result=0; assert(cbinfo); gilstate=PyGILState_Ensure(); if(PyErr_Occurred()) goto finally; /* outstanding error */ pys1=convertutf8stringsize(stringonedata, stringonelen); pys2=convertutf8stringsize(stringtwodata, stringtwolen); if(!pys1 || !pys2) goto finally; /* failed to allocate strings */ pyargs=PyTuple_New(2); if(!pyargs) goto finally; /* failed to allocate arg tuple */ PyTuple_SET_ITEM(pyargs, 0, pys1); PyTuple_SET_ITEM(pyargs, 1, pys2); pys1=pys2=NULL; /* pyargs owns them now */ assert(!PyErr_Occurred()); retval=PyEval_CallObject(cbinfo->func, pyargs); if(!retval) goto finally; /* execution failed */ result=PyInt_AsLong(retval); if(PyErr_Occurred()) result=0; finally: Py_XDECREF(pys1); Py_XDECREF(pys2); Py_XDECREF(retval); Py_XDECREF(pyargs); PyGILState_Release(gilstate); return result; } static PyObject * Connection_createcollation(Connection *self, PyObject *args) { PyObject *callable; char *name=0; char *chk; collationcbinfo *cbinfo; int res; CHECK_THREAD(self,NULL); if(!PyArg_ParseTuple(args, "esO:createcollation(name,callback)", STRENCODING, &name, &callable)) return NULL; assert(name); assert(callable); /* there isn't a C api to get a (potentially unicode) string and make it uppercase so we hack around */ /* validate the name */ for(chk=name;*chk && !((*chk)&0x80);chk++); if(*chk) { PyMem_Free(name); PyErr_SetString(PyExc_TypeError, "function name must be ascii characters only"); return NULL; } /* convert name to upper case */ for(chk=name;*chk;chk++) if(*chk>='a' && *chk<='z') *chk-='a'-'A'; /* ::TODO:: check if name points to already defined collation and free relevant collationcbinfo */ if(callable!=Py_None && !PyCallable_Check(callable)) { PyMem_Free(name); PyErr_SetString(PyExc_TypeError, "parameter must be callable"); return NULL; } Py_INCREF(callable); cbinfo=alloccollationcbinfo(); cbinfo->name=name; cbinfo->func=callable; res=sqlite3_create_collation(self->db, name, SQLITE_UTF8, (callable!=Py_None)?cbinfo:NULL, (callable!=Py_None)?collation_cb:NULL); if(res) { freecollationcbinfo(cbinfo); SET_EXC(self->db, res); return NULL; } if (callable!=Py_None) { /* put cbinfo into the linked list */ cbinfo->next=self->collations; self->collations=cbinfo; } else { /* destroy info */ freecollationcbinfo(cbinfo); } return Py_BuildValue(""); } static PyMethodDef Connection_methods[] = { {"cursor", (PyCFunction)Connection_cursor, METH_NOARGS, "Create a new cursor" }, {"setbusytimeout", (PyCFunction)Connection_setbusytimeout, METH_VARARGS, "Sets the sqlite busy timeout in milliseconds. Use zero to disable the timeout"}, {"interrupt", (PyCFunction)Connection_interrupt, METH_NOARGS, "Causes any pending database operations to abort at the earliest opportunity"}, {"createscalarfunction", (PyCFunction)Connection_createscalarfunction, METH_VARARGS, "Creates a scalar function"}, {"createaggregatefunction", (PyCFunction)Connection_createaggregatefunction, METH_VARARGS, "Creates an aggregate function"}, {"setbusyhandler", (PyCFunction)Connection_setbusyhandler, METH_O, "Sets the busy handler"}, {"changes", (PyCFunction)Connection_changes, METH_NOARGS, "Returns the number of rows changed by last query"}, {"totalchanges", (PyCFunction)Connection_totalchanges, METH_NOARGS, "Returns the total number of changes to database since it was opened"}, {"createcollation", (PyCFunction)Connection_createcollation, METH_VARARGS, "Creates a collation function"}, {"last_insert_rowid", (PyCFunction)Connection_last_insert_rowid, METH_NOARGS, "Returns rowid for last insert"}, {"complete", (PyCFunction)Connection_complete, METH_VARARGS, "Checks if a SQL statement is complete"}, {"setauthorizer", (PyCFunction)Connection_setauthorizer, METH_O, "Sets an authorizer function"}, #ifdef EXPERIMENTAL {"setcommithook", (PyCFunction)Connection_setcommithook, METH_O, "Sets a callable invoked before each commit"}, {"setprogresshandler", (PyCFunction)Connection_setprogresshandler, METH_VARARGS, "Sets a callback invoked periodically during long running calls"}, #endif {NULL} /* Sentinel */ }; static PyTypeObject ConnectionType = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "apsw.Connection", /*tp_name*/ sizeof(Connection), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)Connection_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash */ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ "Connection object", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ Connection_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)Connection_init, /* tp_init */ 0, /* tp_alloc */ Connection_new, /* tp_new */ }; /* CURSOR CODE */ /* Do finalization and free resources. Returns the SQLITE error code */ static int resetcursor(Cursor *self) { int res=SQLITE_OK; Py_XDECREF(self->bindings); self->bindings=NULL; self->bindingsoffset=-1; if(self->statement) { res=sqlite3_finalize(self->statement); SET_EXC(self->connection->db, res); self->statement=0; } if(self->status!=C_DONE && self->zsqlnextpos) { if (*self->zsqlnextpos && res==SQLITE_OK) { /* We still have more, so this is actually an abort. */ res=SQLITE_ERROR; if(!PyErr_Occurred()) PyErr_Format(ExcIncomplete, "Error: there are still remaining sql statements to execute"); } } self->zsqlnextpos=NULL; if(self->status!=C_DONE && self->emiter) { PyObject *next=PyIter_Next(self->emiter); if(next) { Py_DECREF(next); res=SQLITE_ERROR; if (!PyErr_Occurred()) PyErr_Format(ExcIncomplete, "Error: there are still many remaining sql statements to execute"); } } Py_XDECREF(self->emiter); self->emiter=NULL; if(self->zsql) { PyMem_Free((void*)self->zsql); self->zsql=0; } self->status=C_DONE; return res; } static void Cursor_dealloc(Cursor * self) { /* thread check - we can't use macro as it returns*/ PyObject *err_type, *err_value, *err_traceback; int have_error=PyErr_Occurred()?1:0; if(self->connection->thread_ident!=PyThread_get_thread_ident()) { if (have_error) PyErr_Fetch(&err_type, &err_value, &err_traceback); PyErr_Format(PyExc_RuntimeError, "The destructor for Cursor is called in a different thread than it" "was created in. All calls must be in the same thread. It was created in thread %d" "and this is %d. SQLite is not being closed as a result.", (int)(self->connection->thread_ident), (int)(PyThread_get_thread_ident())); PyErr_WriteUnraisable((PyObject*)self); if (have_error) PyErr_Restore(err_type, err_value, err_traceback); return; } /* do our finalisation ... */ if (have_error) { /* remeber the existing error so that resetcursor won't immediately return */ PyErr_Fetch(&err_type, &err_value, &err_traceback); PyErr_Clear(); } resetcursor(self); if(PyErr_Occurred()) PyErr_Clear(); /* clear out any exceptions from resetcursor since we don't care */ if (have_error) /* restore earlier error if there was one */ PyErr_Restore(err_type, err_value, err_traceback); /* we no longer need connection */ if(self->connection) { Py_DECREF(self->connection); self->connection=0; } /* executemany iterator */ Py_XDECREF(self->emiter); self->emiter=NULL; /* no need for tracing */ Py_XDECREF(self->exectrace); Py_XDECREF(self->rowtrace); self->exectrace=self->rowtrace=0; self->ob_type->tp_free((PyObject*)self); } static PyObject * Cursor_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { Cursor *self; self = (Cursor *)type->tp_alloc(type, 0); if (self != NULL) { self->connection=0; self->statement=0; self->zsql=0; self->zsqlnextpos=0; self->status=C_DONE; self->bindings=0; self->bindingsoffset=0; self->emiter=0; self->exectrace=0; self->rowtrace=0; } return (PyObject *)self; } static int Cursor_init(Cursor *self, PyObject *args, PyObject *kwds) { CHECK_THREAD(self->connection,-1); if(!PyArg_ParseTupleAndKeywords(args, kwds, "", NULL)) return -1; return 0; } static PyObject * Cursor_getdescription(Cursor *self) { int ncols,i; PyObject *result=NULL; PyObject *pair=NULL; PyObject *first=NULL; PyObject *second=NULL; const char *str; CHECK_THREAD(self->connection,NULL); if(!self->statement) { PyErr_Format(ExcComplete, "Can't get description for statements that have completed execution"); return NULL; } ncols=sqlite3_column_count(self->statement); result=PyTuple_New(ncols); if(!result) goto error; for(i=0;istatement, i); first=convertutf8string(str); str=sqlite3_column_decltype(self->statement, i); second=convertutf8string(str); if(!first || !second) goto error; PyTuple_SET_ITEM(pair, 0, first); PyTuple_SET_ITEM(pair, 1, second); /* owned by pair now */ first=second=0; PyTuple_SET_ITEM(result, i, pair); /* owned by result now */ pair=0; } return result; error: Py_XDECREF(result); Py_XDECREF(pair); Py_XDECREF(first); Py_XDECREF(second); return NULL; } /* internal function - returns SQLite error code (ie SQLITE_OK if all is well) */ static int Cursor_dobinding(Cursor *self, int arg, PyObject *obj) { /* DUPLICATE(ish) code: this is substantially similar to the code in set_context_result. If you fix anything here then do it there as well. */ int res=SQLITE_OK; if(PyErr_Occurred()) return -1; if(obj==Py_None) res=sqlite3_bind_null(self->statement, arg); else if(PyInt_Check(obj)) res=sqlite3_bind_int(self->statement, arg, PyInt_AS_LONG(obj)); else if (PyLong_Check(obj)) /* nb: PyLong_AsLongLong can cause Python level error */ res=sqlite3_bind_int64(self->statement, arg, PyLong_AsLongLong(obj)); else if (PyFloat_Check(obj)) res=sqlite3_bind_double(self->statement, arg, PyFloat_AS_DOUBLE(obj)); else if (PyUnicode_Check(obj)) { const void *badptr=NULL; UNIDATABEGIN(obj) badptr=strdata; if(strdata) { if(use16) res=sqlite3_bind_text16(self->statement, arg, strdata, strbytes, SQLITE_TRANSIENT); else res=sqlite3_bind_text(self->statement, arg, strdata, strbytes, SQLITE_TRANSIENT); } UNIDATAEND(obj); if(!badptr) { assert(PyErr_Occurred()); return -1; } } else if (PyString_Check(obj)) { const char *val=PyString_AS_STRING(obj); const char *chk=val; for(;*chk && !((*chk)&0x80); chk++); if(*chk) { const void *badptr=NULL; PyObject *str2=PyUnicode_FromObject(obj); if(!str2) return -1; UNIDATABEGIN(str2) badptr=strdata; if(strdata) { if(use16) res=sqlite3_bind_text16(self->statement, arg, strdata, strbytes, SQLITE_TRANSIENT); else res=sqlite3_bind_text(self->statement, arg, strdata, strbytes, SQLITE_TRANSIENT); } UNIDATAEND(str2); Py_DECREF(str2); if(!badptr) { assert(PyErr_Occurred()); return -1; } } else res=sqlite3_bind_text(self->statement, arg, val, strlen(val), SQLITE_TRANSIENT); } else if (PyBuffer_Check(obj)) { const char *buffer; int buflen; if(PyObject_AsCharBuffer(obj, &buffer, &buflen)) return -1; res=sqlite3_bind_blob(self->statement, arg, buffer, buflen, SQLITE_TRANSIENT); } else { PyObject *strrep=PyObject_Str(obj); PyErr_Format(PyExc_TypeError, "Bad binding argument type supplied - argument #%d: %s", arg+self->bindingsoffset, strrep?PyString_AsString(strrep):""); Py_XDECREF(strrep); return -1; } if(res!=SQLITE_OK) { SET_EXC(self->connection->db, res); return -1; } if(PyErr_Occurred()) return -1; return 0; } /* internal function */ static int Cursor_dobindings(Cursor *self) { int nargs, arg, res, sz=0; PyObject *obj; if(PyErr_Occurred()) return -1; assert(self->bindingsoffset>=0); nargs=sqlite3_bind_parameter_count(self->statement); /* a dictionary? */ if (self->bindings && PyDict_Check(self->bindings)) { for(arg=1;arg<=nargs;arg++) { const char *key=sqlite3_bind_parameter_name(self->statement, arg); const char *chk; if(!key) { PyErr_Format(ExcBindings, "Binding %d has no name, but you supplied a dict (which only has names).", arg-1); return -1; } key++; /* first char is a colon which we skip */ for(chk=key;*chk && !((*chk)&0x80); chk++); if(*chk) { PyObject *keyo=PyUnicode_DecodeUTF8(key, strlen(key), NULL); if(!keyo) return -1; obj=PyDict_GetItem(self->bindings, keyo); Py_DECREF(keyo); } else obj=PyDict_GetItemString(self->bindings, key); if(!obj) /* this is where we could error on missing keys */ continue; if(Cursor_dobinding(self,arg,obj)) { assert(PyErr_Occurred()); return -1; } } return 0; } /* it must be a fast sequence */ /* verify the number of args supplied */ if (self->bindings) sz=PySequence_Fast_GET_SIZE(self->bindings); if(*self->zsqlnextpos && sz-self->bindingsoffsetbindings), self->bindingsoffset); return -1; } if(!*self->zsqlnextpos && sz-self->bindingsoffset!=nargs) { PyErr_Format(ExcBindings, "Incorrect number of bindings supplied. The current statement uses %d and there are %d supplied. Current offset is %d", nargs, PySequence_Fast_GET_SIZE(self->bindings), self->bindingsoffset); return -1; } res=SQLITE_OK; /* nb sqlite starts bind args at one not zero */ for(arg=1;arg<=nargs;arg++) { obj=PySequence_Fast_GET_ITEM(self->bindings, arg-1+self->bindingsoffset); if(Cursor_dobinding(self, arg, obj)) { assert(PyErr_Occurred()); return -1; } } self->bindingsoffset+=nargs; assert(res==0); return 0; } typedef struct { const char *previouszsqlpos; /* where the begining of the statement was */ int savedbindingsoffset; /* where the bindings began */ } exectrace_oldstate; static int Cursor_doexectrace(Cursor *self, exectrace_oldstate *etos) { PyObject *retval=NULL; PyObject *args=NULL; PyObject *sqlcmd=NULL; PyObject *bindings=NULL; int result; assert(self->exectrace); /* make a string of the command */ sqlcmd=convertutf8stringsize(etos->previouszsqlpos, self->zsqlnextpos-etos->previouszsqlpos); if(!sqlcmd) return -1; /* now deal with the bindings */ if(self->bindings) { if(PyDict_Check(self->bindings)) { bindings=self->bindings; Py_INCREF(self->bindings); } else { bindings=PySequence_GetSlice(self->bindings, etos->savedbindingsoffset, self->bindingsoffset); if(!bindings) { Py_DECREF(sqlcmd); return -1; } } } else { bindings=Py_None; Py_INCREF(bindings); } args=PyTuple_New(2); if(!args) { Py_DECREF(sqlcmd); Py_DECREF(bindings); return -1; } PyTuple_SET_ITEM(args, 0, sqlcmd); PyTuple_SET_ITEM(args, 1, bindings); retval=PyEval_CallObject(self->exectrace, args); Py_DECREF(args); if(!retval) { assert(PyErr_Occurred()); return -1; } result=PyObject_IsTrue(retval); Py_DECREF(retval); assert (result==-1 || result==0 || result ==1); if(result==-1) { assert(PyErr_Occurred()); return -1; } if(result) return 0; /* callback didn't want us to continue */ PyErr_Format(ExcTraceAbort, "Aborted by false/null return value of exec tracer"); return -1; } static PyObject* Cursor_dorowtrace(Cursor *self, PyObject *retval) { assert(self->rowtrace); retval=PyEval_CallObject(self->rowtrace, retval); if(!retval) return NULL; return retval; } /* Returns a borrowed reference to self if all is ok, else NULL on error */ static PyObject * Cursor_step(Cursor *self) { int res; exectrace_oldstate etos; if(self->status==C_DONE) { PyErr_Format(ExcComplete, "The statement(s) have finished or errored, so you can't keep running them"); return NULL; } for(;;) { assert(!PyErr_Occurred()); Py_BEGIN_ALLOW_THREADS res=sqlite3_step(self->statement); Py_END_ALLOW_THREADS; switch(res) { case SQLITE_ROW: self->status=C_ROW; return (PyObject*)self; case SQLITE_BUSY: self->status=C_BEGIN; SET_EXC(self->connection->db,res); return NULL; default: /* no other value should happen, but we'll defensively code and treat them the same as SQLITE_ERROR */ /* FALLTHRU */ case SQLITE_ERROR: /* there was an error - we need to get actual error code from sqlite3_finalize */ self->status=C_DONE; res=resetcursor(self); /* this will get the error code for us */ assert(res!=SQLITE_OK); return NULL; case SQLITE_MISUSE: /* this would be an error in apsw itself */ self->status=C_DONE; SET_EXC(self->connection->db,res); resetcursor(self); return NULL; case SQLITE_DONE: break; } assert(res==SQLITE_DONE); /* done with that statement, are there any more? */ self->status=C_DONE; if(!self->zsqlnextpos || !*self->zsqlnextpos) { PyObject *next; if(!self->emiter) { /* no more so we finalize */ if(resetcursor(self)!=SQLITE_OK) { assert(PyErr_Occurred()); return NULL; /* exception */ } return (PyObject*)self; } next=PyIter_Next(self->emiter); if(PyErr_Occurred()) return NULL; if(!next) { /* no more from executemanyiter so we finalize */ if(resetcursor(self)!=SQLITE_OK) { assert(PyErr_Occurred()); return NULL; } return (PyObject*)self; } self->zsqlnextpos=self->zsql; /* start at begining of string again */ /* don't need bindings from last round if emiter.next() */ Py_XDECREF(self->bindings); self->bindings=0; self->bindingsoffset=0; /* verify type of next before putting in bindings */ if(PyDict_Check(next)) self->bindings=next; else { self->bindings=PySequence_Fast(next, "You must supply a dict or a sequence"); if(!self->bindings) { Py_DECREF(next); return NULL; } } assert(self->bindings); } /* finalise and go again */ res=sqlite3_finalize(self->statement); self->statement=0; SET_EXC(self->connection->db,res); if (res!=SQLITE_OK) { assert(res!=SQLITE_BUSY); /* finalize shouldn't be returning busy, only step */ return NULL; } assert(!self->statement); if(self->exectrace) { etos.previouszsqlpos=self->zsqlnextpos; etos.savedbindingsoffset=self->bindingsoffset; } res=sqlite3_prepare(self->connection->db, self->zsqlnextpos, -1, &self->statement, &self->zsqlnextpos); SET_EXC(self->connection->db,res); if (res!=SQLITE_OK) { assert(res!=SQLITE_BUSY); /* prepare definitely shouldn't be returning busy */ return NULL; } if(self->bindings) if(Cursor_dobindings(self)) { assert(PyErr_Occurred()); return NULL; } if(self->exectrace) { if(Cursor_doexectrace(self, &etos)) { assert(self->status==C_DONE); assert(PyErr_Occurred()); return NULL; } } assert(self->status==C_DONE); self->status=C_BEGIN; } /* you can't actually get here */ assert(0); return NULL; } static PyObject * Cursor_execute(Cursor *self, PyObject *args) { int res; PyObject *retval=NULL; exectrace_oldstate etos; CHECK_THREAD(self->connection, NULL); res=resetcursor(self); if(res!=SQLITE_OK) return NULL; assert(!self->bindings); if(!PyArg_ParseTuple(args, "es|O:execute(statements,bindings=())", STRENCODING, &self->zsql, &self->bindings)) return NULL; if(self->bindings) { if(PyDict_Check(self->bindings)) Py_INCREF(self->bindings); else { self->bindings=PySequence_Fast(self->bindings, "You must supply a dict or a sequence"); if(!self->bindings) return NULL; } } assert(!self->statement); if(self->exectrace) { etos.previouszsqlpos=self->zsql; etos.savedbindingsoffset=0; } res=sqlite3_prepare(self->connection->db, self->zsql, -1, &self->statement, &self->zsqlnextpos); SET_EXC(self->connection->db,res); if (res!=SQLITE_OK) return NULL; self->bindingsoffset=0; if(Cursor_dobindings(self)) { assert(PyErr_Occurred()); return NULL; } if(self->exectrace) { if(Cursor_doexectrace(self, &etos)) { assert(PyErr_Occurred()); return NULL; } } self->status=C_BEGIN; retval=Cursor_step(self); if (!retval) { assert(PyErr_Occurred()); return NULL; } Py_INCREF(retval); return retval; } static PyObject * Cursor_executemany(Cursor *self, PyObject *args) { int res; PyObject *retval=NULL; PyObject *theiterable=NULL; PyObject *next=NULL; exectrace_oldstate etos; CHECK_THREAD(self->connection, NULL); res=resetcursor(self); if(res!=SQLITE_OK) return NULL; assert(!self->bindings); assert(!self->emiter); assert(!self->zsql); assert(self->status=C_DONE); if(!PyArg_ParseTuple(args, "esO:executemany(statements, sequenceofbindings)", STRENCODING, &self->zsql, &theiterable)) return NULL; self->emiter=PyObject_GetIter(theiterable); if (!self->emiter) { PyErr_Format(PyExc_TypeError, "2nd parameter must be iterable"); return NULL; } next=PyIter_Next(self->emiter); if(!next && PyErr_Occurred()) return NULL; if(!next) { /* empty list */ Py_INCREF(self); return (PyObject*)self; } if(PyDict_Check(next)) self->bindings=next; else { self->bindings=PySequence_Fast(next, "You must supply a dict or a sequence"); Py_DECREF(next); /* _Fast makes new reference */ if(!self->bindings) return NULL; } assert(!self->statement); if(self->exectrace) { etos.previouszsqlpos=self->zsql; etos.savedbindingsoffset=0; } res=sqlite3_prepare(self->connection->db, self->zsql, -1, &self->statement, &self->zsqlnextpos); SET_EXC(self->connection->db,res); if (res!=SQLITE_OK) return NULL; self->bindingsoffset=0; if(Cursor_dobindings(self)) { assert(PyErr_Occurred()); return NULL; } if(self->exectrace) { if(Cursor_doexectrace(self, &etos)) { assert(PyErr_Occurred()); return NULL; } } self->status=C_BEGIN; retval=Cursor_step(self); if (!retval) { assert(PyErr_Occurred()); return NULL; } Py_INCREF(retval); return retval; } static PyObject * Cursor_next(Cursor *self) { PyObject *retval; PyObject *item; int numcols=-1; int i; int coltype; CHECK_THREAD(self->connection, NULL); again: if(self->status==C_BEGIN) if(!Cursor_step(self)) { assert(PyErr_Occurred()); return NULL; } if(self->status==C_DONE) return NULL; assert(self->status==C_ROW); self->status=C_BEGIN; /* DUPLICATE(ish) code: this is substantially similar to the code in convert_value_to_pyobject. If you fix anything here then do it there as well. */ /* return the row of data */ numcols=sqlite3_data_count(self->statement); retval=PyTuple_New(numcols); if(!retval) return NULL; for(i=0;istatement, i); switch(coltype) { case SQLITE_INTEGER: { long long vint=sqlite3_column_int64(self->statement, i); if(vintINT32_MAX) item=PyLong_FromLongLong(vint); else item=PyInt_FromLong((long)vint); } break; case SQLITE_FLOAT: item=PyFloat_FromDouble(sqlite3_column_double(self->statement, i)); break; case SQLITE_TEXT: item=convertutf8string(sqlite3_column_text(self->statement, i)); break; case SQLITE_NULL: Py_INCREF(Py_None); item=Py_None; break; case SQLITE_BLOB: { int sz=sqlite3_column_bytes(self->statement, i); item=PyBuffer_New(sz); if(item) { void *buffy=0; int sz2=sz; if(!PyObject_AsWriteBuffer(item, &buffy, &sz2)) memcpy(buffy, sqlite3_column_blob(self->statement, i), sz); else { Py_DECREF(item); item=NULL; } } break; } default: PyErr_Format(APSWException, "Unknown sqlite column type %d!", coltype); item=NULL; } if(!item) return NULL; PyTuple_SET_ITEM(retval, i, item); } if(self->rowtrace) { PyObject *r2=Cursor_dorowtrace(self, retval); Py_DECREF(retval); if(!r2) return NULL; if (r2==Py_None) { Py_DECREF(r2); goto again; } return r2; } return retval; } static PyObject * Cursor_iter(Cursor *self) { CHECK_THREAD(self->connection, NULL); Py_INCREF(self); return (PyObject*)self; } static PyObject * Cursor_setexectrace(Cursor *self, PyObject *func) { CHECK_THREAD(self->connection, NULL); if(func!=Py_None && !PyCallable_Check(func)) { PyErr_SetString(PyExc_TypeError, "parameter must be callable"); return NULL; } if(func!=Py_None) Py_INCREF(func); Py_XDECREF(self->exectrace); self->exectrace=(func!=Py_None)?func:NULL; return Py_BuildValue(""); } static PyObject * Cursor_setrowtrace(Cursor *self, PyObject *func) { CHECK_THREAD(self->connection, NULL); if(func!=Py_None && !PyCallable_Check(func)) { PyErr_SetString(PyExc_TypeError, "parameter must be callable"); return NULL; } if(func!=Py_None) Py_INCREF(func); Py_XDECREF(self->rowtrace); self->rowtrace=(func!=Py_None)?func:NULL; return Py_BuildValue(""); } static PyObject * Cursor_getexectrace(Cursor *self) { PyObject *ret=(self->exectrace)?(self->exectrace):Py_None; Py_INCREF(ret); return ret; } static PyObject * Cursor_getrowtrace(Cursor *self) { PyObject *ret=(self->rowtrace)?(self->rowtrace):Py_None; Py_INCREF(ret); return ret; } static PyObject * Cursor_getconnection(Cursor *self) { CHECK_THREAD(self->connection, NULL); Py_INCREF(self->connection); return (PyObject*)self->connection; } static PyMethodDef Cursor_methods[] = { {"execute", (PyCFunction)Cursor_execute, METH_VARARGS, "Executes one or more statements" }, {"executemany", (PyCFunction)Cursor_executemany, METH_VARARGS, "Repeatedly executes statements on sequence" }, {"next", (PyCFunction)Cursor_next, METH_NOARGS, "Returns next row returned from query"}, {"setexectrace", (PyCFunction)Cursor_setexectrace, METH_O, "Installs a function called for every statement executed"}, {"setrowtrace", (PyCFunction)Cursor_setrowtrace, METH_O, "Installs a function called for every row returned"}, {"getexectrace", (PyCFunction)Cursor_getexectrace, METH_NOARGS, "Returns the current exec tracer function"}, {"getrowtrace", (PyCFunction)Cursor_getrowtrace, METH_NOARGS, "Returns the current row tracer function"}, {"getrowtrace", (PyCFunction)Cursor_getrowtrace, METH_NOARGS, "Returns the current row tracer function"}, {"getconnection", (PyCFunction)Cursor_getconnection, METH_NOARGS, "Returns the connection object for this cursor"}, {"getdescription", (PyCFunction)Cursor_getdescription, METH_NOARGS, "Returns the description for the current row"}, {NULL} /* Sentinel */ }; static PyTypeObject CursorType = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "apsw.Cursor", /*tp_name*/ sizeof(Cursor), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)Cursor_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash */ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_ITER , /*tp_flags*/ "Cursor object", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)Cursor_iter, /* tp_iter */ (iternextfunc)Cursor_next, /* tp_iternext */ Cursor_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)Cursor_init, /* tp_init */ 0, /* tp_alloc */ Cursor_new, /* tp_new */ }; /* MODULE METHODS */ static PyObject * getsqliteversion(void) { return PyString_FromString(sqlite3_libversion()); } static PyObject * getapswversion(void) { return PyString_FromString(APSW_VERSION); } static PyMethodDef module_methods[] = { {"sqlitelibversion", (PyCFunction)getsqliteversion, METH_NOARGS, "Return the version of the SQLite library"}, {"apswversion", (PyCFunction)getapswversion, METH_NOARGS, "Return the version of the APSW wrapper"}, {NULL} /* Sentinel */ }; #ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ #define PyMODINIT_FUNC void #endif PyMODINIT_FUNC initapsw(void) { PyObject* m; assert(sizeof(int)==sizeof(long)); /* Python treats PyIntObjects as long */ assert(sizeof(int)==4); /* we expect 32 bit ints */ if (PyType_Ready(&ConnectionType) < 0) return; if (PyType_Ready(&CursorType) < 0) return; /* ensure threads are available */ PyEval_InitThreads(); m = Py_InitModule3("apsw", module_methods, "Another Python SQLite Wrapper."); if (m == NULL) return; if(init_exceptions(m)) { fprintf(stderr, "init_exceptions failed\n"); return; } Py_INCREF(&ConnectionType); PyModule_AddObject(m, "Connection", (PyObject *)&ConnectionType); /* we don't add cursor to the module since users shouldn't be able to instantiate them directly */ /* add in some constants */ #define ADDINT(v) PyModule_AddObject(m, #v, Py_BuildValue("i", v)); ADDINT(SQLITE_DENY); ADDINT(SQLITE_IGNORE); ADDINT(SQLITE_OK); /* authorizer functions */ ADDINT(SQLITE_CREATE_INDEX); ADDINT(SQLITE_CREATE_TABLE); ADDINT(SQLITE_CREATE_TEMP_INDEX); ADDINT(SQLITE_CREATE_TEMP_TABLE); ADDINT(SQLITE_CREATE_TEMP_TRIGGER); ADDINT(SQLITE_CREATE_TEMP_VIEW); ADDINT(SQLITE_CREATE_TRIGGER); ADDINT(SQLITE_CREATE_VIEW); ADDINT(SQLITE_DELETE); ADDINT(SQLITE_DROP_INDEX); ADDINT(SQLITE_DROP_TABLE); ADDINT(SQLITE_DROP_TEMP_INDEX); ADDINT(SQLITE_DROP_TEMP_TABLE); ADDINT(SQLITE_DROP_TEMP_TRIGGER); ADDINT(SQLITE_DROP_TEMP_VIEW); ADDINT(SQLITE_DROP_TRIGGER); ADDINT(SQLITE_DROP_VIEW); ADDINT(SQLITE_INSERT); ADDINT(SQLITE_PRAGMA); ADDINT(SQLITE_READ); ADDINT(SQLITE_SELECT); ADDINT(SQLITE_TRANSACTION); ADDINT(SQLITE_UPDATE); ADDINT(SQLITE_ATTACH); ADDINT(SQLITE_DETACH); /* these constants were introduced in SQLite 3.1.3 */ #ifdef SQLITE_ALTER_TABLE ADDINT(SQLITE_ALTER_TABLE); #endif #ifdef SQLITE_REINDEX ADDINT(SQLITE_REINDEX); #endif }