Why doesn't sqlite3_next_stmt() iterate all statements? - c

I'm working on an SQLite[3.6.20]-based C library, and I have encountered a behavior I don't understand. When it comes time to close the database connection, I perform a preemptive rollback, and then I attempt to use sqlite3_next_stmt() to iterate over all unfinalized prepared statements and finalize them:
sqlite3_stmt *stmt;
for (stmt = sqlite3_next_stmt(db, NULL);
stmt;
stmt = sqlite3_next_stmt(db, stmt)) {
sqlite3_finalize(stmt);
}
This indeed does iterate over several statements, and with a little instrumentation I can confirm that sqlite3_finalize() returns SQLITE_OK for each one.
In certain test cases, however, when I thereafter attempt to close the DB, I get SQLITE_BUSY (code 5) with an explanation that there are unfinalized statements. And indeed, if at that point I call sqlite3_next_stmt() again, it returns a statement that my program likely did prepare, but which was not among those previously returned by sqlite3_next_stmt().
So, am I wrong to think that the unfinalized statement should have been provided by sqlite3_next_stmt() on the first pass? Is there something extra I should do to ensure that my statements can be cleaned up this way?

You shouldn't trust stmt to contain anything meaningful (even to sqlite3_next_stmt()) after it's been finalized.
Instead:
while (stmt = sqlite3_next_stmt(db, NULL))
{
sqlite3_finalize(stmt);
}

Related

Understanding sqlite3_step and why it "takes time" between iterations

I'm wondering why sometimes the query results return quite quick and other times it seems to take a while between the sqlite3_step() calls. For example:
rc = sqlite3_prepare_v2(db, "SELECT * FROM mytable m GROUP BY field1, field2, field3, field4, field5 LIMIT 500", -1, &stmt, NULL);
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW);
Each sqlite3_step takes about the same time when I view the print statements, and the fetch statements add up to take about 6.5s
And then with a normal, fast unaggregated query, sqlite3_step is almost instant:
rc = sqlite3_prepare(db, "SELECT * FROM mytable LIMIT 500", -1, &stmt, NULL);
In the above query, everything takes under 0.1s to query and retrieve.
I understand why the query itself would be much slower, but it seems like sqlite3_stmt is not really "doing anything" and all the SQL-ing work goes into the sqlite3_step and is spread out within each step. A few questions from this:
Why aren't the resultset fetched once, and successive steps returned instantly (for a small queryset, such as the above where there are less than 1K records)?
What exactly is sqlite3_prepare doing? Does it touch the actual file (or in-memory) data, or is merely just "setting up" for the query to run?
What is SQLite doing between each sqlite3_step that it is taking additional time between steps (if the query has already been 'executed')?
The documentation of this method is listed here, but it doesn't say much about what it actually does other than saying what return codes it might give. From the docs:
This routine is used to evaluate a prepared statement that has been previously created by the sqlite3_prepare() interface. The statement is evaluated up to the point where the first row of results are available. To advance to the second row of results, invoke sqlite3_step() again. Continue invoking sqlite3_step() until the statement is complete. Statements that do not return results (ex: INSERT, UPDATE, or DELETE statements) run to completion on a single call to sqlite3_step().
What does "to completion" mean in this case? Does it basically just do a LIMIT 1 and the user needs to call it again to do an OFFSET 1, or what does that mean exactly?
sqlite3_prepare() compiles the statement into sqlite's internal bytecode. sqlite3_step() evaluates that bytecode up to the point where a row is returned or there are no more rows. The next call resumes evaluating at that point; it doesn't always calculate all result rows all at once, but often just one at a time. sqlite3_step() can take different times depending on how much work has to be done to get the next row (like processing groups of different sizes), if pages have to be fetched from disc instead of being present in the page cache, etc.

When do a PREPARE QUERY fails in PRO C?

When do a PREPARE QUERY fails in PRO C?
EXEC SQL AT :db_id PREPARE QUERY FROM :sql_query;
bool sql_status = (sqlca.sqlcode == OERR_ORACLE_SUCCESS);
if (sql_status)
{
}
else
{
}
I don't have this problem until recently, The code was working fine the PREPARE QUERY is working fine (going into if loop_, but all of a sudden it failed, and is not working after that (going into else loop).
Nothing has changed and it's the same binary.
Does anybody face a similar problem in the past?
I've written a LOT of pro*c in the past, and over time realized that you don't want to be checking the return code of the PREPARE statement as it never returns any value. Here is what I mean:
The PREPARE sqlca.sqlcode value is the return code of the statement that ran immediately BEFORE the PREPARE statement. In other words, if you check the output of the PREPARE statement and the statement that executed right before the PREPARE statement fails, then the return code of the prepare is failed. If the previous statement succeeded, then the PREPARE appears to have succeeded.
In other words, the prepare sqlca.sqlcode value is basically nothing (it doesn't ever fail on its own). So if the PREPARE is now failing, check the statement that executed right before the PREPARE statement and ensure you're checking the sqlca.sqlcode value of that one. My bet is that the previous statement is failing, and the error returned relates to that statement. Make sense?
-Jim

Table creation in sqlite3 isn't working

I have a problem in the creation of a one table in sqlite3. Basically, the code (language c) that I use in the creation is the following:
do{
sprintf(buffer, "CREATE TABLE new_tab AS SELECT * FROM fileslog WHERE file_owner='%s' AND state='%s';", file_owner, state);
rc = sqlite3_prepare(db, buffer, -1, &result, NULL);
}while((rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED));
My problem is that no any table is created when I execute this code. I have printed the rc variable to see the possible errors, but its value is 0 (SQLITE_OK). I don't know that it's happening neither where is the error.
You are only preparing the SQL statement for execution.
To actually execute it, call sqlite3_step.
The steps involved according to the the SQL Statement Object documentation are:
Create the object using sqlite3_prepare_v2() or a related function.
Bind values to host parameters using the sqlite3_bind_*() interfaces.
Run the SQL by calling sqlite3_step() one or more times.
Reset the statement using sqlite3_reset() then go back to step 2. Do this zero or more times.
Destroy the object using sqlite3_finalize().
(above list and links lifted from the official documentation.)
sqlite_prepare_v2() followed by sqlite3_step()s and `sqlite3_finalizer() as suggested by Lasse V. Karlsen is one way to run the SQL.
sqlite3_exec() is a simpler way for CREATE TABLE and other non-SELECT queries where you don't need to get result rows. As a side effect, you can't use variable binding (that can be useful for e.g. UPDATE and DELETE queries).

LINQ to SQL: errors from stored procedure are ignored after result set is returned

I'm using LINQ to SQL to call a stored procedure. This stored procedure currently returns a resultset and then has some raiserror statements being triggered after the resultset is retrieved (I'm writing tests for stored procedures, in case you're wondering why I'm doing this).
When LINQ to SQL calls the proc and it gets a resultset back, it seems to ignore all of the errors that I'm throwing because it got its resultset. Is there a way to make it always throw a SqlException when I do a raiserror from SQL?
Interesting; that is a problem I have seen before when using an IDataReader, which is why I now religiously consume all the tables (even if I am only expecting one) - for example, if I am only expecting one table, something like:
while (reader.Read())
{ // read data from first table
}
// read to end of stream
while (reader.NextResult()) { }
The problem is that the error goes into the TDS at the point you raise it; so if you raise it after the SELECT then in follows table in the TDS - and if the reader doesn't read to the end of the stream they might not see it.
I'll be honest - my preferred answer to this is: raise all errors before data. This might mean doing the main SELECT into a temp-table (#table) or table-variable (#table). Beyond that - if it is critical to catch this error (and if the inbuilt LINQ-to-SQL code isn't helping), then perhaps fall back to ExecuteReader and something like the above.
I suspect (but I haven't checked) that you could also use DataContext.Translate<T> to do some of the ORM heavy-lifting; for example:
// cmd is our DbCommand, and ctx is our DataContext
using(var reader = cmd.ExecuteReader()) {
var result = ctx.Translate<MyResultType>(reader).ToList();
while(reader.NextResult()) {}
return result;
}
Make sure that your Severity Level is greater than 10 when you call RAISERROR as per:
http://support.microsoft.com/default.aspx/kb/321903
RAISERROR('Stored Procedure Execution Failed',15,1)

PRINT statement in T-SQL

Why does the PRINT statement in T-SQL seem to only sometimes work? What are the constraints on using it? It seems sometimes if a result set is generated, it becomes a null function, I assumed to prevent corrupting the resultset, but could it's output not go out in another result set, such as the row count?
So, if you have a statement something like the following, you're saying that you get no 'print' result?
select * from sysobjects
PRINT 'Just selected * from sysobjects'
If you're using SQL Query Analyzer, you'll see that there are two tabs down at the bottom, one of which is "Messages" and that's where the 'print' statements will show up.
If you're concerned about the timing of seeing the print statements, you may want to try using something like
raiserror ('My Print Statement', 10,1) with nowait
This will give you the message immediately as the statement is reached, rather than buffering the output, as the Query Analyzer will do under most conditions.
The Print statement in TSQL is a misunderstood creature, probably because of its name. It actually sends a message to the error/message-handling mechanism that then transfers it to the calling application. PRINT is pretty dumb. You can only send 8000 characters (4000 unicode chars). You can send a literal string, a string variable (varchar or char) or a string expression. If you use RAISERROR, then you are limited to a string of just 2,044 characters. However, it is much easier to use it to send information to the calling application since it calls a formatting function similar to the old printf in the standard C library. RAISERROR can also specify an error number, a severity, and a state code in addition to the text message, and it can also be used to return user-defined messages created using the sp_addmessage system stored procedure. You can also force the messages to be logged.
Your error-handling routines won’t be any good for receiving messages, despite messages and errors being so similar. The technique varies, of course, according to the actual way you connect to the database (OLBC, OLEDB etc). In order to receive and deal with messages from the SQL Server Database Engine, when you’re using System.Data.SQLClient, you’ll need to create a SqlInfoMessageEventHandler delegate, identifying the method that handles the event, to listen for the InfoMessage event on the SqlConnection class. You’ll find that message-context information such as severity and state are passed as arguments to the callback, because from the system perspective, these messages are just like errors.
It is always a good idea to have a way of getting these messages in your application, even if you are just spooling to a file, because there is always going to be a use for them when you are trying to chase a really obscure problem. However, I can’t think I’d want the end users to ever see them unless you can reserve an informational level that displays stuff in the application.
Query Analyzer buffers messages. The PRINT and RAISERROR statements both use this buffer, but the RAISERROR statement has a WITH NOWAIT option. To print a message immediately use the following:
RAISERROR ('Your message', 0, 1) WITH NOWAIT
RAISERROR will only display 400 characters of your message and uses a syntax similar to the C printf function for formatting text.
Please note that the use of RAISERROR with the WITH NOWAIT option will flush the message buffer, so all previously buffered information will be output also.
I recently ran into this, and it ended up being because I had a convert statement on a null variable. Since that was causing errors, the entire print statement was rendering as null, and not printing at all.
Example - This will fail:
declare #myID int=null
print 'First Statement: ' + convert(varchar(4), #myID)
Example - This will print:
declare #myID int=null
print 'Second Statement: ' + coalesce(Convert(varchar(4), #myID),'#myID is null')
For the benefit of anyone else reading this question that really is missing print statements from their output, there actually are cases where the print executes but is not returned to the client. I can't tell you specifically what they are. I can tell you that if you put a go statement immediately before and after any print statement, you will see if it is executed.
Do you have variables that are associated with these print statements been output? if so, I have found that if the variable has no value then the print statement will not be ouput.

Resources