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