Skip to content
This repository
Browse code

PostgreSQL: use standard-conforming strings if possible

  • Loading branch information...
commit c9e15709aef6baed329157adeef58099f16501b2 1 parent cec44f5
Jeremy Kemper jeremy authored
68 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -261,20 +261,12 @@ def supports_primary_key? #:nodoc:
261 261 true
262 262 end
263 263
264   - # Does PostgreSQL support standard conforming strings?
265   - def supports_standard_conforming_strings?
266   - # Temporarily set the client message level above error to prevent unintentional
267   - # error messages in the logs when working on a PostgreSQL database server that
268   - # does not support standard conforming strings.
269   - client_min_messages_old = client_min_messages
270   - self.client_min_messages = 'panic'
271   -
272   - # postgres-pr does not raise an exception when client_min_messages is set higher
273   - # than error and "SHOW standard_conforming_strings" fails, but returns an empty
274   - # PGresult instead.
275   - has_support = query('SHOW standard_conforming_strings')[0][0] rescue false
276   - self.client_min_messages = client_min_messages_old
277   - has_support
  264 + # Enable standard-conforming strings if available.
  265 + def set_standard_conforming_strings
  266 + old, self.client_min_messages = client_min_messages, 'panic'
  267 + execute('SET standard_conforming_strings = on') rescue nil
  268 + ensure
  269 + self.client_min_messages = old
278 270 end
279 271
280 272 def supports_insert_with_returning?
@@ -331,42 +323,28 @@ def escape_bytea(original_value)
331 323 def unescape_bytea(original_value)
332 324 # In each case, check if the value actually is escaped PostgreSQL bytea output
333 325 # or an unescaped Active Record attribute that was just written.
334   - if PGconn.respond_to?(:unescape_bytea)
  326 + if @connection.respond_to?(:unescape_bytea)
335 327 self.class.instance_eval do
336 328 define_method(:unescape_bytea) do |value|
337 329 if value =~ /\\\d{3}/
338   - PGconn.unescape_bytea(value)
  330 + @connection.unescape_bytea(value)
339 331 else
340 332 value
341 333 end
342 334 end
343 335 end
344   - else
  336 + elsif PGconn.respond_to?(:unescape_bytea)
345 337 self.class.instance_eval do
346 338 define_method(:unescape_bytea) do |value|
347 339 if value =~ /\\\d{3}/
348   - result = ''
349   - i, max = 0, value.size
350   - while i < max
351   - char = value[i]
352   - if char == ?\\
353   - if value[i+1] == ?\\
354   - char = ?\\
355   - i += 1
356   - else
357   - char = value[i+1..i+3].oct
358   - i += 3
359   - end
360   - end
361   - result << char
362   - i += 1
363   - end
364   - result
  340 + PGconn.unescape_bytea(value)
365 341 else
366 342 value
367 343 end
368 344 end
369 345 end
  346 + else
  347 + raise 'Your PostgreSQL connection does not support unescape_bytea. Try upgrading to pg 0.9.0 or later.'
370 348 end
371 349 unescape_bytea(original_value)
372 350 end
@@ -374,10 +352,10 @@ def unescape_bytea(original_value)
374 352 # Quotes PostgreSQL-specific data types for SQL input.
375 353 def quote(value, column = nil) #:nodoc:
376 354 if value.kind_of?(String) && column && column.type == :binary
377   - "#{quoted_string_prefix}'#{escape_bytea(value)}'"
378   - elsif value.kind_of?(String) && column && column.sql_type =~ /^xml$/
379   - "xml E'#{quote_string(value)}'"
380   - elsif value.kind_of?(Numeric) && column && column.sql_type =~ /^money$/
  355 + "'#{escape_bytea(value)}'"
  356 + elsif value.kind_of?(String) && column && column.sql_type == 'xml'
  357 + "xml '#{quote_string(value)}'"
  358 + elsif value.kind_of?(Numeric) && column && column.sql_type == 'money'
381 359 # Not truly string input, so doesn't require (or allow) escape string syntax.
382 360 "'#{value.to_s}'"
383 361 elsif value.kind_of?(String) && column && column.sql_type =~ /^bit/
@@ -971,17 +949,6 @@ def connect
971 949 # Ignore async_exec and async_query when using postgres-pr.
972 950 @async = @config[:allow_concurrency] && @connection.respond_to?(:async_exec)
973 951
974   - # Use escape string syntax if available. We cannot do this lazily when encountering
975   - # the first string, because that could then break any transactions in progress.
976   - # See: http://www.postgresql.org/docs/current/static/runtime-config-compatible.html
977   - # If PostgreSQL doesn't know the standard_conforming_strings parameter then it doesn't
978   - # support escape string syntax. Don't override the inherited quoted_string_prefix.
979   - if supports_standard_conforming_strings?
980   - self.class.instance_eval do
981   - define_method(:quoted_string_prefix) { 'E' }
982   - end
983   - end
984   -
985 952 # Money type has a fixed precision of 10 in PostgreSQL 8.2 and below, and as of
986 953 # PostgreSQL 8.3 it has a fixed precision of 19. PostgreSQLColumn.extract_precision
987 954 # should know about this but can't detect it there, so deal with it here.
@@ -1011,6 +978,9 @@ def configure_connection
1011 978 end
1012 979 self.client_min_messages = @config[:min_messages] if @config[:min_messages]
1013 980 self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
  981 +
  982 + # Use standard-conforming strings if available so we don't have to do the E'...' dance.
  983 + set_standard_conforming_strings
1014 984 end
1015 985
1016 986 # Returns the current ID of a table's sequence.

0 comments on commit c9e1570

Please sign in to comment.
Something went wrong with that request. Please try again.