提交 351e39c2 编写于 作者: R Ryuta Kamizono

Extract `ExplainPrettyPrinter` to appropriate files

上级 43dff0a7
require 'active_record/connection_adapters/abstract_adapter'
require 'active_record/connection_adapters/mysql/column'
require 'active_record/connection_adapters/mysql/explain_pretty_printer'
require 'active_record/connection_adapters/mysql/schema_creation'
require 'active_record/connection_adapters/mysql/schema_definitions'
require 'active_record/connection_adapters/mysql/schema_dumper'
......@@ -232,72 +233,7 @@ def explain(arel, binds = [])
result = exec_query(sql, 'EXPLAIN', binds)
elapsed = Time.now - start
ExplainPrettyPrinter.new.pp(result, elapsed)
end
class ExplainPrettyPrinter # :nodoc:
# Pretty prints the result of an EXPLAIN in a way that resembles the output of the
# MySQL shell:
#
# +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
# | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
# +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
# | 1 | SIMPLE | users | const | PRIMARY | PRIMARY | 4 | const | 1 | |
# | 1 | SIMPLE | posts | ALL | NULL | NULL | NULL | NULL | 1 | Using where |
# +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
# 2 rows in set (0.00 sec)
#
# This is an exercise in Ruby hyperrealism :).
def pp(result, elapsed)
widths = compute_column_widths(result)
separator = build_separator(widths)
pp = []
pp << separator
pp << build_cells(result.columns, widths)
pp << separator
result.rows.each do |row|
pp << build_cells(row, widths)
end
pp << separator
pp << build_footer(result.rows.length, elapsed)
pp.join("\n") + "\n"
end
private
def compute_column_widths(result)
[].tap do |widths|
result.columns.each_with_index do |column, i|
cells_in_column = [column] + result.rows.map {|r| r[i].nil? ? 'NULL' : r[i].to_s}
widths << cells_in_column.map(&:length).max
end
end
end
def build_separator(widths)
padding = 1
'+' + widths.map {|w| '-' * (w + (padding*2))}.join('+') + '+'
end
def build_cells(items, widths)
cells = []
items.each_with_index do |item, i|
item = 'NULL' if item.nil?
justifier = item.is_a?(Numeric) ? 'rjust' : 'ljust'
cells << item.to_s.send(justifier, widths[i])
end
'| ' + cells.join(' | ') + ' |'
end
def build_footer(nrows, elapsed)
rows_label = nrows == 1 ? 'row' : 'rows'
"#{nrows} #{rows_label} in set (%.2f sec)" % elapsed
end
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
end
def clear_cache!
......
module ActiveRecord
module ConnectionAdapters
module MySQL
class ExplainPrettyPrinter # :nodoc:
# Pretty prints the result of an EXPLAIN in a way that resembles the output of the
# MySQL shell:
#
# +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
# | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
# +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
# | 1 | SIMPLE | users | const | PRIMARY | PRIMARY | 4 | const | 1 | |
# | 1 | SIMPLE | posts | ALL | NULL | NULL | NULL | NULL | 1 | Using where |
# +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
# 2 rows in set (0.00 sec)
#
# This is an exercise in Ruby hyperrealism :).
def pp(result, elapsed)
widths = compute_column_widths(result)
separator = build_separator(widths)
pp = []
pp << separator
pp << build_cells(result.columns, widths)
pp << separator
result.rows.each do |row|
pp << build_cells(row, widths)
end
pp << separator
pp << build_footer(result.rows.length, elapsed)
pp.join("\n") + "\n"
end
private
def compute_column_widths(result)
[].tap do |widths|
result.columns.each_with_index do |column, i|
cells_in_column = [column] + result.rows.map {|r| r[i].nil? ? 'NULL' : r[i].to_s}
widths << cells_in_column.map(&:length).max
end
end
end
def build_separator(widths)
padding = 1
'+' + widths.map {|w| '-' * (w + (padding*2))}.join('+') + '+'
end
def build_cells(items, widths)
cells = []
items.each_with_index do |item, i|
item = 'NULL' if item.nil?
justifier = item.is_a?(Numeric) ? 'rjust' : 'ljust'
cells << item.to_s.send(justifier, widths[i])
end
'| ' + cells.join(' | ') + ' |'
end
def build_footer(nrows, elapsed)
rows_label = nrows == 1 ? 'row' : 'rows'
"#{nrows} #{rows_label} in set (%.2f sec)" % elapsed
end
end
end
end
end
......@@ -4,44 +4,7 @@ module PostgreSQL
module DatabaseStatements
def explain(arel, binds = [])
sql = "EXPLAIN #{to_sql(arel, binds)}"
ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', binds))
end
class ExplainPrettyPrinter # :nodoc:
# Pretty prints the result of an EXPLAIN in a way that resembles the output of the
# PostgreSQL shell:
#
# QUERY PLAN
# ------------------------------------------------------------------------------
# Nested Loop Left Join (cost=0.00..37.24 rows=8 width=0)
# Join Filter: (posts.user_id = users.id)
# -> Index Scan using users_pkey on users (cost=0.00..8.27 rows=1 width=4)
# Index Cond: (id = 1)
# -> Seq Scan on posts (cost=0.00..28.88 rows=8 width=4)
# Filter: (posts.user_id = 1)
# (6 rows)
#
def pp(result)
header = result.columns.first
lines = result.rows.map(&:first)
# We add 2 because there's one char of padding at both sides, note
# the extra hyphens in the example above.
width = [header, *lines].map(&:length).max + 2
pp = []
pp << header.center(width).rstrip
pp << '-' * width
pp += lines.map {|line| " #{line}"}
nrows = result.rows.length
rows_label = nrows == 1 ? 'row' : 'rows'
pp << "(#{nrows} #{rows_label})"
pp.join("\n") + "\n"
end
PostgreSQL::ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', binds))
end
def select_value(arel, name = nil, binds = [])
......
module ActiveRecord
module ConnectionAdapters
module PostgreSQL
class ExplainPrettyPrinter # :nodoc:
# Pretty prints the result of an EXPLAIN in a way that resembles the output of the
# PostgreSQL shell:
#
# QUERY PLAN
# ------------------------------------------------------------------------------
# Nested Loop Left Join (cost=0.00..37.24 rows=8 width=0)
# Join Filter: (posts.user_id = users.id)
# -> Index Scan using users_pkey on users (cost=0.00..8.27 rows=1 width=4)
# Index Cond: (id = 1)
# -> Seq Scan on posts (cost=0.00..28.88 rows=8 width=4)
# Filter: (posts.user_id = 1)
# (6 rows)
#
def pp(result)
header = result.columns.first
lines = result.rows.map(&:first)
# We add 2 because there's one char of padding at both sides, note
# the extra hyphens in the example above.
width = [header, *lines].map(&:length).max + 2
pp = []
pp << header.center(width).rstrip
pp << '-' * width
pp += lines.map {|line| " #{line}"}
nrows = result.rows.length
rows_label = nrows == 1 ? 'row' : 'rows'
pp << "(#{nrows} #{rows_label})"
pp.join("\n") + "\n"
end
end
end
end
end
......@@ -5,6 +5,7 @@
require "active_record/connection_adapters/abstract_adapter"
require "active_record/connection_adapters/postgresql/column"
require "active_record/connection_adapters/postgresql/database_statements"
require "active_record/connection_adapters/postgresql/explain_pretty_printer"
require "active_record/connection_adapters/postgresql/oid"
require "active_record/connection_adapters/postgresql/quoting"
require "active_record/connection_adapters/postgresql/referential_integrity"
......
module ActiveRecord
module ConnectionAdapters
module SQLite3
class ExplainPrettyPrinter # :nodoc:
# Pretty prints the result of an EXPLAIN QUERY PLAN in a way that resembles
# the output of the SQLite shell:
#
# 0|0|0|SEARCH TABLE users USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
# 0|1|1|SCAN TABLE posts (~100000 rows)
#
def pp(result)
result.rows.map do |row|
row.join('|')
end.join("\n") + "\n"
end
end
end
end
end
require 'active_record/connection_adapters/abstract_adapter'
require 'active_record/connection_adapters/statement_pool'
require 'active_record/connection_adapters/sqlite3/explain_pretty_printer'
require 'active_record/connection_adapters/sqlite3/schema_creation'
gem 'sqlite3', '~> 1.3.6'
......@@ -218,21 +219,7 @@ def quote_column_name(name) #:nodoc:
def explain(arel, binds = [])
sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', []))
end
class ExplainPrettyPrinter
# Pretty prints the result of an EXPLAIN QUERY PLAN in a way that resembles
# the output of the SQLite shell:
#
# 0|0|0|SEARCH TABLE users USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
# 0|1|1|SCAN TABLE posts (~100000 rows)
#
def pp(result) # :nodoc:
result.rows.map do |row|
row.join('|')
end.join("\n") + "\n"
end
SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', []))
end
def exec_query(sql, name = nil, binds = [], prepare: false)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册