module Sequel::SQLLogNormalizer

  1. lib/sequel/extensions/sql_log_normalizer.rb

Methods

Public Class

  1. extended

Public Instance

  1. log_connection_yield
  2. normalize_logged_sql

Public Class methods

extended(db)
[show source]
   # File lib/sequel/extensions/sql_log_normalizer.rb
33 def self.extended(db)
34   type = case db.literal("'")
35   when "''''"
36     :standard
37   when "'\\''"
38     :backslash
39   when "N''''"
40     :n_standard
41   else
42     raise Error, "SQL log normalization is not supported on this database (' literalized as #{db.literal("'").inspect})"
43   end
44   db.instance_variable_set(:@sql_string_escape_type, type)
45 end

Public Instance methods

log_connection_yield(sql, conn, args=nil)

Normalize the SQL before calling super.

[show source]
   # File lib/sequel/extensions/sql_log_normalizer.rb
48 def log_connection_yield(sql, conn, args=nil)
49   unless skip_logging?
50     sql = normalize_logged_sql(sql)
51     args = nil
52   end
53   super
54 end
normalize_logged_sql(sql)

Replace literal strings and numbers in SQL with question mark placeholders.

[show source]
    # File lib/sequel/extensions/sql_log_normalizer.rb
 57 def normalize_logged_sql(sql)
 58   sql = sql.dup
 59   sql.force_encoding('BINARY')
 60   start_index = 0
 61   check_n = @sql_string_escape_type == :n_standard
 62   outside_string = true
 63 
 64   if @sql_string_escape_type == :backslash
 65     search_char = /[\\']/
 66     escape_char_offset = 0
 67     escape_char_value = 92 # backslash
 68   else
 69     search_char = "'"
 70     escape_char_offset = 1
 71     escape_char_value = 39 # apostrophe
 72   end
 73 
 74   # The approach used here goes against Sequel's philosophy of never attempting
 75   # to parse SQL.  However, parsing the SQL is basically the only way to implement
 76   # this support with Sequel's design, and it's better to be pragmatic and accept
 77   # this than not be able to support this.
 78 
 79   # Replace literal strings
 80   while outside_string && (index = start_index = sql.index("'", start_index))
 81     if check_n && index != 0 && sql.getbyte(index-1) == 78 # N' start
 82       start_index -= 1
 83     end
 84     index += 1
 85     outside_string = false
 86 
 87     while (index = sql.index(search_char, index)) && (sql.getbyte(index + escape_char_offset) == escape_char_value)
 88       # skip escaped characters inside string literal
 89       index += 2
 90     end
 91 
 92     if index
 93       # Found end of string
 94       sql[start_index..index] = '?'
 95       start_index += 1
 96       outside_string = true
 97     end
 98   end
 99 
100   # Replace integer and decimal floating point numbers
101   sql.gsub!(/\b-?\d+(?:\.\d+)?\b/, '?')
102 
103   sql
104 end