Eric Scouten wrote:

The question really boils down to "can SQLite offer enough information to help me diagnose the problem it's telling me I have?"

Or to put it another way, this is essentially a memory leak problem. SQLite obviously knows that I've lost track of one or more prepared statements that haven't run to completion, it isn't telling me *what* statements those are. I'm wondering if there is any way of getting that information. Armed with that knowledge, I can probably fix my code fairly quickly.

Eric,

I don't think there is an API to let you check this directly, but one of the fields in the sqlite3 structure (yes it is supposed to be opaque, but it can be useful to look inside it for debugging purposes) pointed at by the pointer returned from sqlite3_open is a pointer to a list of prepared VMs. It is called pVdbe in the sqlite source. It is followed by a count of the number of currently executing VMs, called activeVdbeCnt.

 struct sqlite3 {
 ...
 struct Vdbe *pVdbe;           /* List of active virtual machines */
 int activeVdbeCnt;            /* Number of vdbes currently executing */
 ...
 }

You should be able to locate this pointer by checking for a value that matches the statement pointer returned from sqlite3_prepare(). It should be about 16 or 17 words (32 bit) into the structure but may be elsewhere depending upon the compiler. Once you know where this pointer is, you can use it to locate all the outstanding VMs at any time, including after your error. Each VM structure returned from sqlite3_prepare() begins with a pointer to the sqlite3 structure above, and a pointer to the next VM on this linked list.

 struct Vdbe {
 sqlite3 *db;        /* The whole database */
 Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
 ...
 }

Simply follow the linked list to get the addresses of the active VMs. You can compare these to the addresses returned when the statements were prepared.

It might be easier (if you are using C++ anyway) to simply create a global vector of structures like this

 struct stmt {
   sqlite3_stmt* s;
   char* file;         // fill with __FILE__
   int line;            //fill with __LINE__
   string sql;
 };

 vector<struct stmt> stmts;

Then simply add each statement to the vector when it is prepared, and delete it from the vector when the statement is finalized. Anything left on the vector when you get your error is what you are looking for.

HTH
Dennis Cote

Reply via email to