instance method
perform_query
Ruby on Rails edge
Since v8.0.5.1 Private — implementation detail, not part of the public APISignature
perform_query(raw_connection, intent)
No documentation comment.
Parameters
-
raw_connectionreq -
intentreq
Source
# File activerecord/lib/active_record/connection_adapters/mysql2/database_statements.rb, line 35
def perform_query(raw_connection, intent)
reset_multi_statement = if intent.batch && !multi_statements_enabled?
raw_connection.set_server_option(::Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)
true
end
# Make sure we carry over any changes to ActiveRecord.default_timezone that have been
# made since we established the connection
raw_connection.query_options[:database_timezone] = default_timezone
result = nil
affected_rows = nil
if !intent.has_binds?
result = raw_connection.query(intent.processed_sql)
# Ref: https://github.com/brianmario/mysql2/pull/1383
# As of mysql2 0.5.6 `#affected_rows` might raise Mysql2::Error if a prepared statement
# from that same connection was GCed while `#query` released the GVL.
# By avoiding to call `#affected_rows` when we have a result, we reduce the likeliness
# of hitting the bug.
affected_rows = result&.size || raw_connection.affected_rows
elsif intent.prepare
retry_count = 1
begin
stmt = @statements[intent.processed_sql] ||= raw_connection.prepare(intent.processed_sql)
result = stmt.execute(*intent.type_casted_binds)
affected_rows = stmt.affected_rows
rescue ::Mysql2::Error => error
@statements.delete(intent.processed_sql)
# Sometimes for an unknown reason, we get that error.
# It suggest somehow that the prepared statement was deallocated
# but the client doesn't know it.
# But we know that this error is safe to retry, so we do so after
# getting rid of the originally cached statement.
if error.error_number == Mysql2Adapter::ER_UNKNOWN_STMT_HANDLER
if retry_count.positive?
retry_count -= 1
retry
end
end
raise
end
else
stmt = raw_connection.prepare(intent.processed_sql)
begin
result = stmt.execute(*intent.type_casted_binds)
affected_rows = stmt.affected_rows
# Ref: https://github.com/brianmario/mysql2/pull/1383
# by eagerly closing uncached prepared statements, we also reduce the chances of
# that bug happening. It can still happen if `#execute` is used as we have no callback
# to eagerly close the statement.
if result
result.instance_variable_set(:@_ar_stmt_to_close, stmt)
else
stmt.close
end
rescue ::Mysql2::Error
stmt.close
raise
end
end
intent.notification_payload[:affected_rows] = affected_rows
intent.notification_payload[:row_count] = result&.size || 0
if result.nil?
result = ActiveRecord::Result.empty(affected_rows: affected_rows)
elsif result.fields.empty?
free_raw_result(result)
result = ActiveRecord::Result.empty(affected_rows: affected_rows)
end
raw_connection.abandon_results!
verified!
result
ensure
if reset_multi_statement && active?
raw_connection.set_server_option(::Mysql2::Client::OPTION_MULTI_STATEMENTS_OFF)
end
end
Defined in activerecord/lib/active_record/connection_adapters/mysql2/database_statements.rb line 35
· View on GitHub
· Improve this page
· Find usages on GitHub
Defined in ActiveRecord::ConnectionAdapters::Mysql2::DatabaseStatements