Skip to content

Commit dc01977

Browse files
fix: Replace connection.select_value with connection.query_value (#131)
1 parent 40f9af3 commit dc01977

File tree

5 files changed

+29
-11
lines changed

5 files changed

+29
-11
lines changed

lib/with_advisory_lock/mysql_advisory.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def supports_database_timeout?
6565
private
6666

6767
def execute_successful?(mysql_function)
68-
select_value("SELECT #{mysql_function}") == 1
68+
query_value("SELECT #{mysql_function}") == 1
6969
end
7070
end
7171
end

lib/with_advisory_lock/postgresql_advisory.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def advisory_lock_exists_for?(lock_name, shared: false)
7171
LIMIT 1
7272
SQL
7373

74-
select_value(query).present?
74+
query_value(query).present?
7575
rescue ActiveRecord::StatementInvalid
7676
# If pg_locks is not accessible, fall back to nil to indicate we should use the default method
7777
nil
@@ -96,7 +96,7 @@ def advisory_unlock_function(shared)
9696
end
9797

9898
def execute_advisory(function, lock_keys, lock_name)
99-
result = select_value(prepare_sql(function, lock_keys, lock_name))
99+
result = query_value(prepare_sql(function, lock_keys, lock_name))
100100
LOCK_RESULT_VALUES.include?(result)
101101
end
102102

test/with_advisory_lock/lock_test.rb

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,25 @@ module LockTestCases
133133
# After the block, current_advisory_lock should be nil regardless
134134
assert_nil model_class.current_advisory_lock
135135
end
136+
137+
test 'does not write and read lock queries from the query cache' do
138+
model_class.connection.cache do
139+
model_class.with_advisory_lock!("lock", timeout_seconds: 0) {}
140+
assert_nil model_class.connection.query_cache["SELECT GET_LOCK('lock', 0)"]
141+
142+
# Blocker thread uses a different connection
143+
blocker = Thread.new do
144+
model_class.with_advisory_lock("lock", timeout_seconds: 0) { sleep 1 }
145+
end
146+
# blocker should get the lock and not release it in time
147+
sleep 0.5
148+
lock_result = model_class.with_advisory_lock_result("lock", timeout_seconds: 0) do
149+
raise "Successfully entered critical region while lock was held by other thread"
150+
end
151+
blocker.join
152+
assert_not(lock_result.lock_was_acquired?)
153+
end
154+
end
136155
end
137156
end
138157

@@ -177,7 +196,7 @@ def setup
177196
# Hold a lock in another connection - need to use the same prefixed name as the gem
178197
other_conn = model_class.connection_pool.checkout
179198
lock_keys = other_conn.lock_keys_for(lock_name)
180-
other_conn.select_value("SELECT GET_LOCK(#{other_conn.quote(lock_keys.first)}, 0)")
199+
other_conn.query_value("SELECT GET_LOCK(#{other_conn.quote(lock_keys.first)}, 0)")
181200

182201
begin
183202
# Attempt to acquire with a short timeout - should fail quickly
@@ -190,7 +209,7 @@ def setup
190209
assert_not result
191210
assert elapsed < 3.0, "Expected quick timeout, but took #{elapsed} seconds"
192211
ensure
193-
other_conn.select_value("SELECT RELEASE_LOCK(#{other_conn.quote(lock_keys.first)})")
212+
other_conn.query_value("SELECT RELEASE_LOCK(#{other_conn.quote(lock_keys.first)})")
194213
model_class.connection_pool.checkin(other_conn)
195214
end
196215
end

test/with_advisory_lock/mysql_release_lock_test.rb

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def setup
6969

7070
# Acquire lock using SQL (ActiveRecord doesn't provide get_advisory_lock method)
7171
lock_keys = model_class.connection.lock_keys_for(lock_name)
72-
result = model_class.connection.select_value("SELECT GET_LOCK(#{model_class.connection.quote(lock_keys.first)}, 0)")
72+
result = model_class.connection.query_value("SELECT GET_LOCK(#{model_class.connection.quote(lock_keys.first)}, 0)")
7373
assert_equal 1, result, 'Failed to acquire lock using SQL'
7474

7575
# Release using ActiveRecord signature (positional argument, as Rails does)
@@ -78,11 +78,11 @@ def setup
7878

7979
# Verify lock is released
8080
lock_keys = model_class.connection.lock_keys_for(lock_name)
81-
result = model_class.connection.select_value("SELECT GET_LOCK(#{model_class.connection.quote(lock_keys.first)}, 0)")
81+
result = model_class.connection.query_value("SELECT GET_LOCK(#{model_class.connection.quote(lock_keys.first)}, 0)")
8282
assert_equal 1, result, 'Lock was not properly released'
8383

8484
# Clean up
85-
model_class.connection.select_value("SELECT RELEASE_LOCK(#{model_class.connection.quote(lock_keys.first)})")
85+
model_class.connection.query_value("SELECT RELEASE_LOCK(#{model_class.connection.quote(lock_keys.first)})")
8686
end
8787

8888
test 'release_advisory_lock handles connection errors gracefully' do
@@ -116,4 +116,3 @@ def setup
116116
end
117117
end
118118
end
119-

test/with_advisory_lock/transaction_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ class PostgreSQLTransactionScopingTest < GemTestCase
77

88
setup do
99
@pg_lock_count = lambda do
10-
backend_pid = Tag.connection.select_value('SELECT pg_backend_pid()')
11-
Tag.connection.select_value("SELECT COUNT(*) FROM pg_locks WHERE locktype = 'advisory' AND pid = #{backend_pid};").to_i
10+
backend_pid = Tag.connection.query_value('SELECT pg_backend_pid()')
11+
Tag.connection.query_value("SELECT COUNT(*) FROM pg_locks WHERE locktype = 'advisory' AND pid = #{backend_pid};").to_i
1212
end
1313
end
1414

0 commit comments

Comments
 (0)