vinzenz / vsqlite--

VSQLite++ Library - BSD-3 Licensed

Home Page:http://vsqlite.virtuosic-bytes.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Incorrect row count for query

michihenning opened this issue · comments

It looks like result::get_row_count() always returns zero after running a query. For example:

sqlite::query q(conn_, "SELECT key, size FROM cache ORDER BY access_time ASC;");
auto r = q.emit_result();
cerr << "row_count: " << r->get_row_count() << endl;

This prints 0 for a table with three records.

The problem I have is that I want to iterate over the results to do things with each record. But I can't. The approach in the example does not work:

do
{
cerr << "key: " << y->get_string(0) << endl;
} while (y->next_row());

The problem here is that the result set may be empty, in which case I don't want to do anything. But I cannot write a pre-tested loop without get_row_count(). The do loop will execute at least once, even if there are no results.

If I do run the above loop on an empty result set, I get

key: NULL

That's despite the fact that the corresponding table column is defined as NOT NULL.

What's the suggested way to process results row by row and doing nothing if there are no results?

Ok this will be a bit more tricky. This function did actually never work. I see that this is a big flaw :(

I'll figure something out.

The correct usage should be this:

boost::shared_ptr<sqlite::result> res = q.get_result();                 
while(res->next_row()) {                                                
    std::cout << res->get_int(0) << "|" << res->get_string(1) << std::endl;
}                                                                       

However it's very unfortunate that you won't be able, to check for the number of rows comming in. That would require another query with COUNT() to achieve this.

The result of this is, that I will have to mark get_row_count as DEPRECATED. As I cannot simply remove it. Due to ABI compability.

Just to explain what's going on:
emit_result immediately executes the first 'step' and fetches the first row, where get_result just builds the object, but doesn't perform the first step and it will fetch the first row once next_row() is called.

If I do it like that, I will have advanced the iterator already, and miss processing the first row. I'd rather not run two queries just to get the number of results that are returned. I don't need to know the actual number of rows (although that would be nice to have). But I need to be able to tell an empty result set from a non-empty one without trying to process a non-existent row.

Isn't there a way with the SQLite C API to test whether the cursor that's returned for a query has zero as opposed to non-zero results? I would expect the cursor to have some sort of "end" or "bottom" value if the result set is empty.

q.get_result() won't advance the cursor, only q.emit_result() will do so.

Does get_result() actually call step() behind the scenes to initialize the cursor?

No, only emit_result() does.

OK, I'll try this. Thanks for your help!

Calling get_result() followed by next_row() works, thanks!

I would recommend to update the doc and the example though. I looked at both, and there was no clue that this is how things are meant to work. In particular, the difference between get_result() and emit_result() is not explained.

Yeah, this and the fact that get_row_count is use less needs to be reflected, this is why I did not close this issue yet.
Thanks for reporting :-)