Checking for Null Statements in SQLite3 - sqlite

Does anyone know how to check if a statement has been prepared or not? I have searched through the SQLite documentation for statements and searched SO, DreamInCode, and DaniWeb but have found no references to my exact question.
I have a statement that I only call in specific circumstances and I only want to attempt to finalize it if it has been used since program crashes are happening by trying to finalize a statement that has not been used. I would rather use whatever SQLite has built-in instead of extra code but I will do just that if there is no null-checking for statements.

The documentation says:
Invoking sqlite3_finalize() on a NULL pointer is a harmless no-op.
So just ensure that your sqlite3_stmt* variables are initialized with NULL, and are reset to NULL when finalized.

Related

Having trouble understanding FLWOR expressions combined with inserts and return statements [duplicate]

I recognized that (insert/delete)-XQueries executed with the BaseX client always returning an empty string. I find this very confusing or unintuitive.
Is there a way to find out if the query was "successful" without querying the database again (and using potentially buggy "transitive" logic like "if I deleted a node, there must be 'oldNodeCount-1' nodes in the XML")?
XQuery Update statements do not return anything -- that's how they are defined. But you're not the only one who does not like those restrictions, and BaseX added two ways around this limitation:
Returning Results
By default, it is not possible to mix different types of expressions
in a query result. The outermost expression of a query must either be
a collection of updating or non-updating expressions. But there are
two ways out:
The BaseX-specific update:output() function bridges this gap: it caches the results of its arguments at runtime and returns them after
all updates have been processed. The following example performs an
update and returns a success message:
update:output("Update successful."), insert node <c/> into doc('factbook')/mondial
With the MIXUPDATES option, all updating constraints will be turned off. Returned nodes will be copied before they are modified by
updating expressions. An error is raised if items are returned within
a transform expression.
If you want to modify nodes in main memory, you can use the transform
expression.
The transform expression will not help you, as you seem to modify the data on disk. Enabling MIXUPDATES allows you to both update the document and return something at the same time, for example running something like
let $node := <c/>
return ($node, insert node $node into doc('factbook')/mondial)
MIXUPDATES allows you to return something which can be further processed. Results are copied before being returned, if you run multiple updates operations and do not get the expected results, make sure you got the concept of the pending update list.
The db:output() function intentionally breaks its interface contract: it is defined to be an updating function (not having any output), but at the same time it prints some information to the query info. You cannot further process these results, but the output can help you debugging some issues.
Pending Update List
Both ways, you will not be able to have an immediate result from the update, you have to add something on your own -- and be aware updates are not visible until the pending update list is applied, ie. after the query finished.
Compatibility
Obviously, these options are BaseX-specific. If you strongly require compatible and standard XQuery, you cannot use these expressions.

How to return results together with update operations in BaseX?

I recognized that (insert/delete)-XQueries executed with the BaseX client always returning an empty string. I find this very confusing or unintuitive.
Is there a way to find out if the query was "successful" without querying the database again (and using potentially buggy "transitive" logic like "if I deleted a node, there must be 'oldNodeCount-1' nodes in the XML")?
XQuery Update statements do not return anything -- that's how they are defined. But you're not the only one who does not like those restrictions, and BaseX added two ways around this limitation:
Returning Results
By default, it is not possible to mix different types of expressions
in a query result. The outermost expression of a query must either be
a collection of updating or non-updating expressions. But there are
two ways out:
The BaseX-specific update:output() function bridges this gap: it caches the results of its arguments at runtime and returns them after
all updates have been processed. The following example performs an
update and returns a success message:
update:output("Update successful."), insert node <c/> into doc('factbook')/mondial
With the MIXUPDATES option, all updating constraints will be turned off. Returned nodes will be copied before they are modified by
updating expressions. An error is raised if items are returned within
a transform expression.
If you want to modify nodes in main memory, you can use the transform
expression.
The transform expression will not help you, as you seem to modify the data on disk. Enabling MIXUPDATES allows you to both update the document and return something at the same time, for example running something like
let $node := <c/>
return ($node, insert node $node into doc('factbook')/mondial)
MIXUPDATES allows you to return something which can be further processed. Results are copied before being returned, if you run multiple updates operations and do not get the expected results, make sure you got the concept of the pending update list.
The db:output() function intentionally breaks its interface contract: it is defined to be an updating function (not having any output), but at the same time it prints some information to the query info. You cannot further process these results, but the output can help you debugging some issues.
Pending Update List
Both ways, you will not be able to have an immediate result from the update, you have to add something on your own -- and be aware updates are not visible until the pending update list is applied, ie. after the query finished.
Compatibility
Obviously, these options are BaseX-specific. If you strongly require compatible and standard XQuery, you cannot use these expressions.

QtSQL: "prepared statement "qpsqlpstmt_1" does not exist" on clear() of model

I am getting the following error message printed in the console:
Unable to free statement: ERROR: prepared statement "qpsqlpstmt_1" does not exist
It is printed when the the following function is called in the application (or when the object is deleted (if clear() is not called before delete):
sqlQueryModel->clear();
sqlQueryModel object is of type QSqlQueryModel and is used throughout a derived class to communicated with a PostgreSQL database. It also serves as a model for QCompleter. I have never declared or used the name "qpsqlpstmt_1".
Could someone help me interpret the error message please, and explain what might be causing it? Is this indicative of a problem in my code or a Qt bug? (likely the former :))
On reviewing the PostgreSQL log file on the server, the exact same statement appears plus an additional line:
STATEMENT: DEALLOCATE pqsqlpstmt_1
See these Qt issue tracker entries:
https://bugreports.qt.io/browse/QTBUG-8860
https://bugreports.qt.io/browse/QTBUG-16007
https://bugreports.qt.io/browse/QTBUG-15979
... all of which mention your prepared statement name and relate to deletion.
After a considerable amount of time, I realized that I was simply closing the connection to the database before calling clear... not a good strategy.

How to prevent Sqlite unbound parameters interpreted as NULL

As the Sqlite docs specify, unbound parameters in prepared statements are interpreted as NULL - my question is this then:
Is there a way to have Sqlite ensure that all parameters have been bound at least once, thereby ensuring none were missed by accident?
It is better to get an error and require calls to sqlite3_bind_null(statement_, col); then to get a subtle error because I forgot to call sqlite3_bind_* on the where clause of an update statement!
It is not possible to differentiate unbound parameters from parameters set to NULL using the current SQLite libraries.
If you have a look at the C source code for sqlite3_bind_null(), you will find that it simply calls the internal SQLite function that unbinds a parameter. Therefore there is no way to tell the two cases apart.
The only solution for this would be to wrap the SQLite C API functions with your own functions that will do a bit of book-keeping. You can bundle a bitmap with each sqlite3_stmt structure, with each bit set to true if and only if the corresponding parameter is bound. You would have to create wrappers for at least the sqlite3_bind_*() functions and sqlite3_clear_bindings().

Can I call SQLExecute after SQLFreeStmt without SQLPrepare?

I have the following sequence of code calls:
SQLPrepare
SQLExecute(hstmt, SQL_CLOSE);
SQLFreeStmt
//It works till here
SQLExecute //Now it fails.
Why am I required to call SQLPrepare again, I just freed the cursor. I shouldn't prepare the SQL statement again.
The correct behaviour is that SQLPrepare/SQLExecute/SQLFreStmt(stmt, SQL_CLOSE) should allow another SQLExecute on the same stmt handle without re-preparing. You can see this as a valid state transition in the ODBC Programmers Guide. You might use this sequence if you had done a SQLPrepare(sql) and only fetched some of the rows (instead of all of them) as without the SQLFreeStmt(stmt, SQL_CLOSE) or fetching until SQL_NO_DATA was returned you'd get an invalid cursor state if you issued another SQLExecute. SQLFreeStmt(stmt, SQL_DROP) is equivalent to SQLFreeHandle(SQL_HANDLESTMT,stmt) and frees the entire stmt handle meaning you cannot use it again at all.
SQLFreeStmt(hstmt, SQL_CLOSE) cleans up everything to do with that statement handle, take a look at the summary:
SQLFreeStmt stops processing
associated with a specific statement,
closes any open cursors associated
with the statement, discards pending
results, or, optionally, frees all
resources associated with the
statement handle.
If you don't want to use SQLPrepare again you can use SQLExecDirect instead.

Resources