crystal-db icon indicating copy to clipboard operation
crystal-db copied to clipboard

UNIQUE constraint causes `from_rs` to hang

Open fridgerator opened this issue 7 years ago • 7 comments

I wasn't sure whether to make this issue here, or in crystal-pg

Crystal: 0.21.1 Postgres: 9.6.2 (also replicated on 9.4) crystal-db: 0.4.0 crystal-pg: 0.13.3

If there is a UNIQUE constraint on a database field, Model.from_rs(rs) hangs without returning.

require "pg"

class User
  DB.mapping({
    name: String?
  }, false)
end

db = DB.open("postgres://localhost:5432/crecto")

db.query "INSERT INTO users (name) VALUES ($1) RETURNING *", "test" do |rs|
	puts User.from_rs(rs)
end

db.query "INSERT INTO users (name) VALUES ($1) RETURNING *", "test" do |rs|
	puts User.from_rs(rs)
end

db.close

If I remove the UNIQUE constraint when I create the table, the above code works just fine.

fridgerator avatar Mar 28 '17 16:03 fridgerator

If I switch back to: crystal-db: 0.3.3 and crystal-pg: 0.13.2

it correctly throws the duplicate key value violates unique constraint "users_name_key" (PQ::PQError) exception

fridgerator avatar Mar 28 '17 16:03 fridgerator

It's probably that the type of the exception is ~messing~ forcing the retries. IO::Error's are wrapped as DB::ConnectionLost to trigger a retry in some places like here. But PQ::PQError shouldn't be wrapped.

bcardiff avatar Mar 28 '17 16:03 bcardiff

I see

Should I open the issue on crystal-pg instead?

fridgerator avatar Mar 28 '17 17:03 fridgerator

I try to narrow it down. It seems an issue in crystal-pg.

I reduce a full script that repro the issue. From a nasty puts debugging the call to PQ::Connection.read_next_row_start assigns 'E' instead of 'D' probably (?) in type = soc.read_char

I haven't go any further than this.

require "pg"

`psql -c "DROP DATABASE IF EXISTS issue_db_46"`
`createdb issue_db_46`
`psql -d issue_db_46 -c "CREATE TABLE users (name varchar(50), CONSTRAINT key_name UNIQUE(name));"`
`psql -d issue_db_46 -c "INSERT INTO users (name) VALUES ('test');"`

db = DB.open("postgres://localhost/issue-db-46")

puts "A"

db.query "INSERT INTO users (name) VALUES ($1) RETURNING *", "test" do |rs|
  rs.move_next
end

puts "Z"

db.close

bcardiff avatar Mar 28 '17 20:03 bcardiff

Perhaps you could find the offending commit in crystal-pg?

rdp avatar Apr 05 '17 13:04 rdp

Also hangs if autoincrement is left off of the primary id field and the user tries to insert a record. see crecto issue. It seems an exception should also be raised in this case, and seems this may be related to this issue.

fridgerator avatar May 02 '17 16:05 fridgerator

I think this has been fixed

greenbigfrog avatar Jan 28 '18 12:01 greenbigfrog