module TingYun::Agent::Database::ExplainPlanHelpers
Constants
- EMPTY_STRING
- KNOWN_OPERATIONS
- MYSQL2_PREFIX
- MYSQL_PREFIX
- POSTGRES_PREFIX
- QUERY_PLAN
- SQLITE_EXPLAIN_COLUMNS
- SQLITE_PREFIX
- SQL_COMMENT_REGEX
Public Instance Methods
handle_exception_in_explain() { || ... }
click to toggle source
# File lib/ting_yun/agent/database/explain_plan_helpers.rb, line 9 def handle_exception_in_explain yield rescue => e begin # guarantees no throw from explain_sql ::TingYun::Agent.logger.error("Error getting query plan:", e) nil rescue # double exception. throw up your hands nil end end
is_select?(sql)
click to toggle source
# File lib/ting_yun/agent/database/explain_plan_helpers.rb, line 22 def is_select?(sql) parse_operation_from_query(sql) == 'select' end
parameterized?(sql)
click to toggle source
# File lib/ting_yun/agent/database/explain_plan_helpers.rb, line 26 def parameterized?(sql) TingYun::Agent::Database::Obfuscator.instance.obfuscate_single_quote_literals(sql) =~ /\$\d+/ end
parse_operation_from_query(sql)
click to toggle source
# File lib/ting_yun/agent/database/explain_plan_helpers.rb, line 48 def parse_operation_from_query(sql) sql = TingYun::Helper.correctly_encoded(sql).gsub(SQL_COMMENT_REGEX, EMPTY_STRING) if sql =~ /(\w+)/ op = $1.downcase return op if KNOWN_OPERATIONS.include?(op) end end
process_explain_results_mysql(results)
click to toggle source
# File lib/ting_yun/agent/database/explain_plan_helpers.rb, line 136 def process_explain_results_mysql(results) headers = [] values = [] if results.is_a?(Array) # We're probably using the jdbc-mysql gem for JRuby, which will give # us an array of hashes. headers = results.first.keys results.each do |row| values << headers.map { |h| row[h] } end else # We're probably using the native mysql driver gem, which will give us # a Mysql::Result object that responds to each_hash results.each_hash do |row| headers = row.keys values << headers.map { |h| row[h] } end end {"dialect"=> "MySQL", "keys"=>headers, "values"=>values} end
process_explain_results_mysql2(results)
click to toggle source
# File lib/ting_yun/agent/database/explain_plan_helpers.rb, line 129 def process_explain_results_mysql2(results) headers = results.fields values = [] results.each { |row| values << row } {"dialect"=> "MySQL", "keys"=>headers, "values"=>values} end
process_explain_results_postgres(results)
click to toggle source
# File lib/ting_yun/agent/database/explain_plan_helpers.rb, line 105 def process_explain_results_postgres(results) if defined?(::ActiveRecord::Result) && results.is_a?(::ActiveRecord::Result) query_plan_string = results.rows.join("\n") elsif results.is_a?(String) query_plan_string = results else lines = [] results.each { |row| lines << row[QUERY_PLAN] } query_plan_string = lines.join("\n") end unless TingYun::Agent::Database.record_sql_method("nbs.action_tracer.record_sql") == :raw query_plan_string = TingYun::Agent::Database::Obfuscator.instance.obfuscate_postgres_explain(query_plan_string) end values = query_plan_string.split("\n").map { |line| [line] } {"dialect"=> "PostgreSQL", "keys"=>[QUERY_PLAN], "values"=>values} end
process_explain_results_sqlite(results)
click to toggle source
# File lib/ting_yun/agent/database/explain_plan_helpers.rb, line 159 def process_explain_results_sqlite(results) headers = SQLITE_EXPLAIN_COLUMNS values = [] results.each do |row| values << headers.map { |h| row[h] } end {"dialect"=> "sqlite", "keys"=>headers, "values"=>values} end
process_resultset(results, adapter)
click to toggle source
# File lib/ting_yun/agent/database/explain_plan_helpers.rb, line 81 def process_resultset(results, adapter) if adapter == :postgres return process_explain_results_postgres(results) elsif defined?(::ActiveRecord::Result) && results.is_a?(::ActiveRecord::Result) # Note if adapter is mysql, will only have headers, not values return [results.columns, results.rows] elsif results.is_a?(String) return string_explain_plan_results(results) end case adapter when :mysql2 process_explain_results_mysql2(results) when :mysql process_explain_results_mysql(results) when :sqlite process_explain_results_sqlite(results) else return {} end end
string_explain_plan_results(adpater, results)
click to toggle source
# File lib/ting_yun/agent/database/explain_plan_helpers.rb, line 125 def string_explain_plan_results(adpater, results) {"dialect"=> adpater, "keys"=>[], "values"=>[results]} end
symbolized_adapter(adapter)
click to toggle source
# File lib/ting_yun/agent/database/explain_plan_helpers.rb, line 64 def symbolized_adapter(adapter) if adapter.start_with? POSTGRES_PREFIX :postgres elsif adapter == MYSQL_PREFIX :mysql # For the purpose of fetching explain plans, we need to maintain the distinction # between usage of mysql and mysql2. Obfuscation is the same, though. elsif adapter == MYSQL2_PREFIX :mysql2 elsif adapter.start_with? SQLITE_PREFIX :sqlite else adapter.to_sym end end