module PgHero::Methods::Basic

Public Instance Methods

current_user() click to toggle source
# File lib/pghero/methods/basic.rb, line 21
def current_user
  select_one("SELECT current_user")
end
database_name() click to toggle source
# File lib/pghero/methods/basic.rb, line 17
def database_name
  select_one("SELECT current_database()")
end
quote_ident(value) click to toggle source
# File lib/pghero/methods/basic.rb, line 33
def quote_ident(value)
  connection.quote_column_name(value)
end
server_version() click to toggle source
# File lib/pghero/methods/basic.rb, line 25
def server_version
  @server_version ||= select_one("SHOW server_version")
end
server_version_num() click to toggle source
# File lib/pghero/methods/basic.rb, line 29
def server_version_num
  @server_version_num ||= select_one("SHOW server_version_num").to_i
end
ssl_used?() click to toggle source
# File lib/pghero/methods/basic.rb, line 4
def ssl_used?
  ssl_used = nil
  with_transaction(rollback: true) do
    begin
      execute("CREATE EXTENSION IF NOT EXISTS sslinfo")
    rescue ActiveRecord::StatementInvalid
      # not superuser
    end
    ssl_used = select_one("SELECT ssl_is_used()")
  end
  ssl_used
end

Private Instance Methods

add_source(sql) click to toggle source
# File lib/pghero/methods/basic.rb, line 126
def add_source(sql)
  "#{sql} /*pghero*/"
end
connection() click to toggle source
# File lib/pghero/methods/basic.rb, line 107
def connection
  connection_model.connection
end
execute(sql) click to toggle source
# File lib/pghero/methods/basic.rb, line 103
def execute(sql)
  connection.execute(add_source(sql))
end
insert_stats(table, columns, values) click to toggle source
# File lib/pghero/methods/basic.rb, line 115
def insert_stats(table, columns, values)
  values = values.map { |v| "(#{v.map { |v2| quote(v2) }.join(",")})" }.join(",")
  columns = columns.map { |v| quote_table_name(v) }.join(",")
  stats_connection.execute("INSERT INTO #{quote_table_name(table)} (#{columns}) VALUES #{values}")
end
quote(value) click to toggle source
# File lib/pghero/methods/basic.rb, line 130
def quote(value)
  connection.quote(value)
end
quote_table_name(value) click to toggle source
# File lib/pghero/methods/basic.rb, line 134
def quote_table_name(value)
  connection.quote_table_name(value)
end
select_all(sql, conn: nil, query_columns: []) click to toggle source
# File lib/pghero/methods/basic.rb, line 39
def select_all(sql, conn: nil, query_columns: [])
  conn ||= connection
  # squish for logs
  retries = 0
  begin
    result = conn.select_all(add_source(squish(sql)))
    if ActiveRecord::VERSION::STRING.to_f >= 6.1
      result = result.map(&:symbolize_keys)
    else
      result = result.map { |row| Hash[row.map { |col, val| [col.to_sym, result.column_types[col].send(:cast_value, val)] }] }
    end
    if filter_data
      query_columns.each do |column|
        result.each do |row|
          begin
            row[column] = PgQuery.normalize(row[column])
          rescue PgQuery::ParseError
            # try replacing "interval $1" with "$1::interval"
            # see https://github.com/lfittl/pg_query/issues/169 for more info
            # this is not ideal since it changes the query slightly
            # we could skip normalization
            # but this has a very small chance of data leakage
            begin
              row[column] = PgQuery.normalize(row[column].gsub(/\binterval\s+(\$\d+)\b/i, "\\1::interval"))
            rescue PgQuery::ParseError
              row[column] = "<unable to filter data>"
            end
          end
        end
      end
    end
    result
  rescue ActiveRecord::StatementInvalid => e
    # fix for random internal errors
    if e.message.include?("PG::InternalError") && retries < 2
      retries += 1
      sleep(0.1)
      retry
    else
      raise e
    end
  end
end
select_all_size(sql) click to toggle source
# File lib/pghero/methods/basic.rb, line 87
def select_all_size(sql)
  result = select_all(sql)
  result.each do |row|
    row[:size] = PgHero.pretty_size(row[:size_bytes])
  end
  result
end
select_all_stats(sql, **options) click to toggle source
# File lib/pghero/methods/basic.rb, line 83
def select_all_stats(sql, **options)
  select_all(sql, **options, conn: stats_connection)
end
select_one(sql, conn: nil) click to toggle source
# File lib/pghero/methods/basic.rb, line 95
def select_one(sql, conn: nil)
  select_all(sql, conn: conn).first.values.first
end
select_one_stats(sql) click to toggle source
# File lib/pghero/methods/basic.rb, line 99
def select_one_stats(sql)
  select_one(sql, conn: stats_connection)
end
squish(str) click to toggle source

from ActiveSupport

# File lib/pghero/methods/basic.rb, line 122
def squish(str)
  str.to_s.gsub(/\A[[:space:]]+/, "").gsub(/[[:space:]]+\z/, "").gsub(/[[:space:]]+/, " ")
end
stats_connection() click to toggle source
# File lib/pghero/methods/basic.rb, line 111
def stats_connection
  ::PgHero::Stats.connection
end
table_exists?(table) click to toggle source
# File lib/pghero/methods/basic.rb, line 155
def table_exists?(table)
  stats_connection.table_exists?(table)
end
unquote(part) click to toggle source
# File lib/pghero/methods/basic.rb, line 138
def unquote(part)
  if part && part.start_with?('"')
    part[1..-2]
  else
    part
  end
end
with_transaction(lock_timeout: nil, statement_timeout: nil, rollback: false) { || ... } click to toggle source
# File lib/pghero/methods/basic.rb, line 146
def with_transaction(lock_timeout: nil, statement_timeout: nil, rollback: false)
  connection_model.transaction do
    select_all "SET LOCAL statement_timeout = #{statement_timeout.to_i}" if statement_timeout
    select_all "SET LOCAL lock_timeout = #{lock_timeout.to_i}" if lock_timeout
    yield
    raise ActiveRecord::Rollback if rollback
  end
end