You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Execute SQL SELECT returning 0 rows shows stale data #1431
In the Execute SQL tab, execute a SELECT that returns a few rows of data, which display.
Modify the SELECT such that no rows are returned and execute that
What did you expect to see?
The results pane should be empty.
The status pane should say "no rows selected"
What did you see instead?
The results of the first select remain on the screen.
The status pane says 'query executed successfully: ...'
But it doesn't say "0 rows returned" and the results pane shows the data from the first SELECT.
This is very confusing - I'm seeing stale data from a previous command.
As I experiment with various queries, the stale data can be from several commands back.
There should be positive indication that the query returned no data, and the old results should be removed from the display.
Useful extra information
The info below often helps, please fill it out if you're able to. :)
If I had to guess, you probably classify statements into SELECT and non-SELECT statements. Likely looking for SELECT as the first token.
The compound statment (beginining with WITH) is probably masking the fact that my example is a SELECT.
So it's probably a matter of teaching your classifier more of the wonderous syntax at https://sqlite.org/lang_select.html. Fortunately, it's probably just accepting with [recursive] [cte]* in front of select when determining that a statement is a select. A full parser for SELECT would be a Project. (And you don't want to be fooled by select in an expression - e.g. within an UPDATE.)
It may suffice to simply look for with as well as select as the first token of a command...
Which you already handle looking for select, right? So one might hope it's 'just' looking for either token. Otherwise, it's a bigger bug, but the essence is the same.
Still, nothing takes 5 minutes. Not even the regression test.
If I had to guess, you probably classify statements into SELECT and non-SELECT statements. Likely looking for SELECT as the first token.
You guessed right.
This is the revelant function:
MainWindow::StatementType MainWindow::getQueryType(const QString& query) const
{
// Helper function for getting the type of a given queryif(query.startsWith("SELECT", Qt::CaseInsensitive)) return SelectStatement;
if(query.startsWith("ALTER", Qt::CaseInsensitive)) return AlterStatement;
if(query.startsWith("DROP", Qt::CaseInsensitive)) return DropStatement;
if(query.startsWith("ROLLBACK", Qt::CaseInsensitive)) return RollbackStatement;
if(query.startsWith("PRAGMA", Qt::CaseInsensitive)) return PragmaStatement;
if(query.startsWith("VACUUM", Qt::CaseInsensitive)) return VacuumStatement;
if(query.startsWith("INSERT", Qt::CaseInsensitive)) return InsertStatement;
if(query.startsWith("UPDATE", Qt::CaseInsensitive)) return UpdateStatement;
if(query.startsWith("DELETE", Qt::CaseInsensitive)) return DeleteStatement;
if(query.startsWith("CREATE", Qt::CaseInsensitive)) return CreateStatement;
if(query.startsWith("ATTACH", Qt::CaseInsensitive)) return AttachStatement;
if(query.startsWith("DETACH", Qt::CaseInsensitive)) return DetachStatement;
return OtherStatement;
}
And then:
// SQLite returns SQLITE_DONE when a valid SELECT statement was executed but returned no results. To run into the branch that updates// the status message and the table view anyway manipulate the status value here. This is also done for PRAGMA statements as they (sometimes)// return rows just like SELECT statements, too.if((query_part_type == SelectStatement || query_part_type == PragmaStatement) && sql3status == SQLITE_DONE)
sql3status = SQLITE_ROW;
Adding this to getQueryType, of course, solves your issue, but this naive approach has probably other problems. In fact, a WITH statement can be followed by a SELECT, INSERT, DELETE, or UPDATE statement. Maybe someone has a better idea.
My guesses are usually good - refined by those that weren't :-)
Here's what I'd try first:
If the query starts with WITH, you'll need to parse the optional RECURSIVE token and (required) CTE string to get to the verb. Fortunately, the CTE isn't bad. It's a name, then optional ( name,name,name,... ), then AS(select stmt).
That last bit looks ugly - but for your purposes, you can just count ()s (well, ignoring those in comments and any quoted strings.) So, the verb will be the first token after the last (matched) right parenthesis. Note that the parentheses are required syntax, so there will be a (possibly nested) string to parse.
In fact, you can skip parsing the column names by noting that AS is required, so after the table-name, skip everything up to AS, then skip matching parenthesis to the verb. You do need to ignore parenthesis within quoted strings though.
It won't be 5 minutes -- but it shouldn't be a big job if you take the shortcuts.
See the syntax diagram referenced in my earlier note.
@tlhackque Today's nightly build resets the results table with each query that is executed. This should fix the usability problem that you encountered (the results table will be our empty for your case). The underlaying problem with the CTE query is not solved for the moment.
Activity
tlhackque commentedon Jun 17, 2018
I did some experimenting, and found that a simple select does what's expected. It seems that a compound select is necessary to trigger the issue.
Here is a simple reproducer (distilled from the real case - the reproducer is valid, but somewhat silly).
Create a database with 1 record and one field, named 'diskid' with a value of 1.
Execute this SELECT statement:
As expected, you get one row, like this:
Now change the 'id=1' to 'id=10'
The results tab does NOT change.
The status tab says:
justinclift commentedon Jun 17, 2018
Thanks @tlhackque, yep that does sound like a bug. 😄
tlhackque commentedon Jun 18, 2018
If I had to guess, you probably classify statements into SELECT and non-SELECT statements. Likely looking for SELECT as the first token.
The compound statment (beginining with WITH) is probably masking the fact that my example is a SELECT.
So it's probably a matter of teaching your classifier more of the wonderous syntax at https://sqlite.org/lang_select.html. Fortunately, it's probably just accepting with [recursive] [cte]* in front of select when determining that a statement is a select. A full parser for SELECT would be a Project. (And you don't want to be fooled by select in an expression - e.g. within an UPDATE.)
It may suffice to simply look for with as well as select as the first token of a command...
Just a guess...
chrisjlocke commentedon Jun 18, 2018
.... and then add in comments, multi-line, whitespaces. Yes, its simple. 5 minute job....
tlhackque commentedon Jun 18, 2018
Which you already handle looking for select, right? So one might hope it's 'just' looking for either token. Otherwise, it's a bigger bug, but the essence is the same.
Still, nothing takes 5 minutes. Not even the regression test.
mgrojo commentedon Jun 18, 2018
You guessed right.
This is the revelant function:
And then:
Adding this to
getQueryType, of course, solves your issue, but this naive approach has probably other problems. In fact, a WITH statement can be followed by a SELECT, INSERT, DELETE, or UPDATE statement. Maybe someone has a better idea.tlhackque commentedon Jun 18, 2018
My guesses are usually good - refined by those that weren't :-)
Here's what I'd try first:
If the query starts with WITH, you'll need to parse the optional RECURSIVE token and (required) CTE string to get to the verb. Fortunately, the CTE isn't bad. It's a name, then optional ( name,name,name,... ), then AS (select stmt).
That last bit looks ugly - but for your purposes, you can just count ()s (well, ignoring those in comments and any quoted strings.) So, the verb will be the first token after the last (matched) right parenthesis. Note that the parentheses are required syntax, so there will be a (possibly nested) string to parse.
In fact, you can skip parsing the column names by noting that AS is required, so after the table-name, skip everything up to AS, then skip matching parenthesis to the verb. You do need to ignore parenthesis within quoted strings though.
It won't be 5 minutes -- but it shouldn't be a big job if you take the shortcuts.
See the syntax diagram referenced in my earlier note.
Still, it's not a full parser!
Thanks for digging into this.
Reset SQL results table when the query has not returned data
Reset SQL results table when the query has not returned data
mgrojo commentedon Jun 23, 2018
@tlhackque Today's nightly build resets the results table with each query that is executed. This should fix the usability problem that you encountered (the results table will be our empty for your case). The underlaying problem with the CTE query is not solved for the moment.
tlhackque commentedon Jun 24, 2018
Thanks, that's better.
Reset SQL results table when the query has not returned data