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

Invalid memory access if query inside rows iteration #70

Open
rsk700 opened this issue Mar 30, 2021 · 2 comments
Open

Invalid memory access if query inside rows iteration #70

rsk700 opened this issue Mar 30, 2021 · 2 comments

Comments

@rsk700
Copy link

rsk700 commented Mar 30, 2021

Crystal 1.0.0 [dd40a2442] (2021-03-22)
LLVM: 10.0.0
Default target: x86_64-unknown-linux-gnu
sqlite3: version: 0.18.0

Running this code with query inside iteration, fails with Invalid memory access error:

require "sqlite3"

DB.open "sqlite3://%3amemory%3a" do |db|
    db.exec "create table t1(id integer primary key autoincrement, t text)"
    db.exec "insert into t1 (t) values ('v1')"
    db.query "select id, t from t1" do |rs|
        rs.each do
            v = db.scalar "select id from t1 limit 1"
        end
    end
end

and error:

Invalid memory access (signal 11) at address 0x0
[0x55e447408396] *Exception::CallStack::print_backtrace:(Int32 | Nil) +118
[0x55e4473f783c] __crystal_sigfault_handler +316
[0x7fb5022963c0] ???
[0x7fb50228cfc4] pthread_mutex_lock +4
[0x7fb5024ea28f] sqlite3_reset +31
[0x55e4474da30b] *SQLite3::ResultSet#do_close:Int32 +27
[0x55e4474da2bf] *SQLite3::ResultSet +63
[0x55e4473e605a] __crystal_main +1658
[0x55e4474db386] *Crystal::main_user_code<Int32, Pointer(Pointer(UInt8))>:Nil +6
[0x55e4474db1fc] *Crystal::main<Int32, Pointer(Pointer(UInt8))>:Int32 +44
[0x55e4473f15e6] main +6
[0x7fb50203d0b3] __libc_start_main +243
[0x55e4473e591e] _start +46
[0x0] ???
@plambert
Copy link

I also see this, and can reproduce it easily.

As far as I can tell, the iteration actually works fine, everything works fine, and the crash occurs when closing the ResultSet.

Is there any workaround that'd still let me query the database inside of an iteration over the results of a query? I have a use case where I'm iterating hundreds of thousands of rows, and don't want to load them all into memory, or take the performance hit of using LIMIT/OFFSET to "page" through the results.

@plambert
Copy link

I think I have found a workaround that usually works. By ensuring the connection pool has at least two members, and checking out a connection outside of the main query, but using the checked-out connection for the read-only query inside the loop, it doesn't seem to fail.

However, with an in-memory database, it fails to see the table that was created. So I am using an on-disk file in this test:

require "sqlite3"

DB.open "sqlite3://./test.sqlite3?max_idle_pool_size=2&initial_pool_size=2" do |db|
    db.exec "create table t1(id integer primary key autoincrement, t text)"
    db.exec "insert into t1 (t) values ('v1')"
    db.using_connection do |connection|
      db.query "select id, t from t1" do |rs|
        rs.each do
          v = connection.scalar "select id from t1 limit 1"
        end
      end
    end
end

This seems to work pretty consistently.

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

No branches or pull requests

2 participants