提交 f814585b 编写于 作者: R Ryuta Kamizono

Pass `type_casted_binds` to log subscriber for logging bind values properly

Address to https://github.com/rails/rails/commit/5a302bf553af0e6fedfc63299fc5cd6e79599ef3#commitcomment-18288388.
上级 5a302bf5
...@@ -579,14 +579,15 @@ def translate_exception_class(e, sql) ...@@ -579,14 +579,15 @@ def translate_exception_class(e, sql)
exception exception
end end
def log(sql, name = "SQL", binds = [], statement_name = nil) def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil)
@instrumenter.instrument( @instrumenter.instrument(
"sql.active_record", "sql.active_record",
:sql => sql, sql: sql,
:name => name, name: name,
:connection_id => object_id, binds: binds,
:statement_name => statement_name, type_casted_binds: type_casted_binds,
:binds => binds) { yield } statement_name: statement_name,
connection_id: object_id) { yield }
rescue => e rescue => e
raise translate_exception_class(e, sql) raise translate_exception_class(e, sql)
end end
......
...@@ -79,7 +79,7 @@ def exec_stmt_and_free(sql, name, binds, cache_stmt: false) ...@@ -79,7 +79,7 @@ def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) } type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
log(sql, name, binds) do log(sql, name, binds, type_casted_binds) do
if cache_stmt if cache_stmt
cache = @statements[sql] ||= { cache = @statements[sql] ||= {
stmt: @connection.prepare(sql) stmt: @connection.prepare(sql)
......
...@@ -598,14 +598,14 @@ def execute_and_clear(sql, name, binds, prepare: false) ...@@ -598,14 +598,14 @@ def execute_and_clear(sql, name, binds, prepare: false)
def exec_no_cache(sql, name, binds) def exec_no_cache(sql, name, binds)
type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) } type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
log(sql, name, binds) { @connection.async_exec(sql, type_casted_binds) } log(sql, name, binds, type_casted_binds) { @connection.async_exec(sql, type_casted_binds) }
end end
def exec_cache(sql, name, binds) def exec_cache(sql, name, binds)
stmt_key = prepare_statement(sql) stmt_key = prepare_statement(sql)
type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) } type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
log(sql, name, binds, stmt_key) do log(sql, name, binds, type_casted_binds, stmt_key) do
@connection.exec_prepared(stmt_key, type_casted_binds) @connection.exec_prepared(stmt_key, type_casted_binds)
end end
rescue ActiveRecord::StatementInvalid => e rescue ActiveRecord::StatementInvalid => e
......
...@@ -190,7 +190,7 @@ def explain(arel, binds = []) ...@@ -190,7 +190,7 @@ def explain(arel, binds = [])
def exec_query(sql, name = nil, binds = [], prepare: false) def exec_query(sql, name = nil, binds = [], prepare: false)
type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) } type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
log(sql, name, binds) do log(sql, name, binds, type_casted_binds) do
# Don't cache statements if they are not prepared # Don't cache statements if they are not prepared
unless prepare unless prepare
stmt = @connection.prepare(sql) stmt = @connection.prepare(sql)
......
...@@ -20,18 +20,14 @@ def initialize ...@@ -20,18 +20,14 @@ def initialize
@odd = false @odd = false
end end
def render_bind(attribute) def render_bind(attr, type_casted_value)
value = if attribute.type.binary? && attribute.value value = if attr.type.binary? && attr.value
if attribute.value.is_a?(Hash) "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
"<#{attribute.value_for_database.to_s.bytesize} bytes of binary data>"
else
"<#{attribute.value.bytesize} bytes of binary data>"
end
else else
type_cast(attribute.value_for_database) type_casted_value
end end
[attribute.name, value] [attr.name, value]
end end
def sql(event) def sql(event)
...@@ -48,7 +44,9 @@ def sql(event) ...@@ -48,7 +44,9 @@ def sql(event)
binds = nil binds = nil
unless (payload[:binds] || []).empty? unless (payload[:binds] || []).empty?
binds = " " + payload[:binds].map { |attr| render_bind(attr) }.inspect binds = " " + payload[:binds].zip(payload[:type_casted_binds]).map { |attr, value|
render_bind(attr, value)
}.inspect
end end
name = colorize_payload_name(name, payload[:name]) name = colorize_payload_name(name, payload[:name])
...@@ -91,10 +89,6 @@ def sql_color(sql) ...@@ -91,10 +89,6 @@ def sql_color(sql)
def logger def logger
ActiveRecord::Base.logger ActiveRecord::Base.logger
end end
def type_cast(value)
ActiveRecord::Base.connection.type_cast(value)
end
end end
end end
......
...@@ -57,10 +57,13 @@ def test_find_one_uses_binds ...@@ -57,10 +57,13 @@ def test_find_one_uses_binds
end end
def test_logs_bind_vars_after_type_cast def test_logs_bind_vars_after_type_cast
binds = [Relation::QueryAttribute.new("id", "10", Type::Integer.new)]
type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
payload = { payload = {
:name => 'SQL', :name => 'SQL',
:sql => 'select * from topics where id = ?', :sql => 'select * from topics where id = ?',
:binds => [Relation::QueryAttribute.new("id", "10", Type::Integer.new)] :binds => binds,
:type_casted_binds => type_casted_binds
} }
event = ActiveSupport::Notifications::Event.new( event = ActiveSupport::Notifications::Event.new(
'foo', 'foo',
...@@ -84,6 +87,12 @@ def debug str ...@@ -84,6 +87,12 @@ def debug str
logger.sql event logger.sql event
assert_match([[@pk.name, 10]].inspect, logger.debugs.first) assert_match([[@pk.name, 10]].inspect, logger.debugs.first)
end end
private
def type_cast(value)
ActiveRecord::Base.connection.type_cast(value)
end
end end
end end
end end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册