Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Weird iteration behavior #251

Closed
aplavin opened this issue Jul 31, 2021 · 4 comments · Fixed by #262
Closed

Weird iteration behavior #251

aplavin opened this issue Jul 31, 2021 · 4 comments · Fixed by #262

Comments

@aplavin
Copy link
Contributor

aplavin commented Jul 31, 2021

Create an empty DB:

julia> using SQLite, DBInterface
julia> db = SQLite.DB(":memory:")
SQLite.DB(":memory:")

Taking the first element of query results works:

julia> DBInterface.execute(db, "select 123 as x") |> first
SQLite.Row: (x = 123,)

Explicit iteration also works:

julia> for r in DBInterface.execute(db, "select 123 as x")
           @show r
       end
r = SQLite.Row:
 :x  123

But other related functions return results that make no sense.
E.g., collect() and only() return missings:

julia> DBInterface.execute(db, "select 123 as x") |> collect
1-element Vector{SQLite.Row}:
 SQLite.Row: (x = missing,)

julia> DBInterface.execute(db, "select 123 as x") |> only
SQLite.Row: (x = missing,)
@ulinares
Copy link

Same behavior here, any solutions?

@quinnj
Copy link
Member

quinnj commented Aug 1, 2021

This behavior is mentioned in the docs:

Note that the returned result row iterator only supports a single-pass, forward-only iteration of the result rows. Calling SQLite.reset!(result) will re-execute the query and reset the iterator back to the beginning.

but maybe we can make it more clear. In short, you're only allowed to iterate each row once, and each row is only valid when it's currently being iterated. Once you iterate to the next row, any previous row "objects" are invalid. That's why collect doesn't work, because the rows become invalid. If you convert each row to something that "saves" the values, then that will work, like:

rows = [NamedTuple(row) for row in result]

@aplavin
Copy link
Contributor Author

aplavin commented Aug 1, 2021

Thanks, I see. Using Tables.rowtable instead of collect does this transformation and saves row values.
It's just very unintuitive. Can row access after it's been invalidated be made an error somehow?

quinnj added a commit that referenced this issue Oct 20, 2021
Fixes #251 amongst other issues. This PR makes `SQLite.Row` explicitly
error when values are attempted to be accessed and it's not the
currently iterated row. It borrows the idea from the MySQL.jl package,
which as a similar "sync" of row numbers between the `Row` and `Query`
objects.
@quinnj
Copy link
Member

quinnj commented Oct 20, 2021

PR to make invalid row access an explicit error: #262

@quinnj quinnj closed this as completed Oct 20, 2021
quinnj added a commit that referenced this issue Oct 20, 2021
Fixes #251 amongst other issues. This PR makes `SQLite.Row` explicitly
error when values are attempted to be accessed and it's not the
currently iterated row. It borrows the idea from the MySQL.jl package,
which as a similar "sync" of row numbers between the `Row` and `Query`
objects.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants