method
perform_query
v8.1.1 -
Show latest stable
- Class:
ActiveRecord::ConnectionAdapters::Mysql2::DatabaseStatements
perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch: false)private
No documentation available.
# File activerecord/lib/active_record/connection_adapters/mysql2/database_statements.rb, line 41
def perform_query(raw_connection, sql, binds, type_casted_binds, prepare,, notification_payload,, batch: false)
reset_multi_statement = if 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
if binds.nil? || binds.empty?
result = raw_connection.query(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_before_warnings = result&.size || raw_connection.affected_rows
elsif prepare
retry_count = 1
begin
stmt = @statements[sql] ||= raw_connection.prepare(sql)
result = stmt.execute(*type_casted_binds)
@affected_rows_before_warnings = stmt.affected_rows
rescue ::Mysql2::Error => error
@statements.delete(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(sql)
begin
result = stmt.execute(*type_casted_binds)
@affected_rows_before_warnings = 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
notification_payload[:affected_rows] = @affected_rows_before_warnings
notification_payload[:row_count] = result&.size || 0
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