README.md in upsert-2.2.0 vs README.md in upsert-2.2.1

- old
+ new

@@ -21,11 +21,11 @@ You pass a __selector__ that uniquely identifies a row, whether it exists or not. You also pass a __setter__, attributes that should be set on that row. Syntax inspired by [mongo-ruby-driver's update method](http://api.mongodb.org/ruby/1.6.4/Mongo/Collection.html#update-instance_method). ### Basic - + ```ruby connection = Mysql2::Client.new([...]) table_name = :pets upsert = Upsert.new connection, table_name # N times... @@ -57,14 +57,16 @@ Batch mode is tested to be about 80% faster on PostgreSQL, MySQL, and SQLite3 than other ways to emulate upsert (see the tests, which fail if they are not faster). ### Native Postgres upsert -`INSERT ... ON CONFLICT DO UPDATE` is used when Postgres 9.5+ is detected and *unique indexes are in place.* +`INSERT ... ON CONFLICT DO UPDATE` is used when Postgres 9.5+ is detected and *unique constraint are in place.* -If you don't have unique indexes, it will fall back to the classic Upsert gem user-defined function, which does not require indexes. +**Note: ** You must have a **unique constraint** on the column(s) you're using as a selector. A unique index won't work. See https://github.com/seamusabshere/upsert/issues/98#issuecomment-295341405 for more information and some ways to check. +If you don't have unique constraints, it will fall back to the classic Upsert gem user-defined function, which does not require a constraint. + ### ActiveRecord helper method ```ruby require 'upsert/active_record_upsert' # N times... @@ -171,28 +173,28 @@ CREATE PROCEDURE upsert_pets_SEL_name_A_tag_number_SET_name_A_tag_number(`name_sel` varchar(255), `tag_number_sel` int(11), `name_set` varchar(255), `tag_number_set` int(11)) BEGIN DECLARE done BOOLEAN; REPEAT BEGIN - -- If there is a unique key constraint error then + -- If there is a unique key constraint error then -- someone made a concurrent insert. Reset the sentinel -- and try again. DECLARE ER_DUP_UNIQUE CONDITION FOR 23000; DECLARE ER_INTEG CONDITION FOR 1062; DECLARE CONTINUE HANDLER FOR ER_DUP_UNIQUE BEGIN SET done = FALSE; END; - + DECLARE CONTINUE HANDLER FOR ER_INTEG BEGIN SET done = TRUE; END; SET done = TRUE; SELECT COUNT(*) INTO @count FROM `pets` WHERE `name` = `name_sel` AND `tag_number` = `tag_number_sel`; -- Race condition here. If a concurrent INSERT is made after -- the SELECT but before the INSERT below we'll get a duplicate -- key error. But the handler above will take care of that. - IF @count > 0 THEN + IF @count > 0 THEN -- UPDATE table_name SET b = b_SET WHERE a = a_SEL; UPDATE `pets` SET `name` = `name_set`, `tag_number` = `tag_number_set` WHERE `name` = `name_sel` AND `tag_number` = `tag_number_sel`; ELSE -- INSERT INTO table_name (a, b) VALUES (k, data); INSERT INTO `pets` (`name`, `tag_number`) VALUES (`name_set`, `tag_number_set`);