aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/connection_adapters/postgresql/oid
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters/postgresql/oid')
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb56
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb22
2 files changed, 23 insertions, 55 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
index f486c5ecb7..3de794f797 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
@@ -5,29 +5,20 @@ module ActiveRecord
class Array < Type::Value # :nodoc:
include Type::Helpers::Mutable
- # Loads pg_array_parser if available. String parsing can be
- # performed quicker by a native extension, which will not create
- # a large amount of Ruby objects that will need to be garbage
- # collected. pg_array_parser has a C and Java extension
- begin
- require 'pg_array_parser'
- include PgArrayParser
- rescue LoadError
- require 'active_record/connection_adapters/postgresql/array_parser'
- include PostgreSQL::ArrayParser
- end
-
attr_reader :subtype, :delimiter
delegate :type, :user_input_in_time_zone, :limit, to: :subtype
def initialize(subtype, delimiter = ',')
@subtype = subtype
@delimiter = delimiter
+
+ @pg_encoder = PG::TextEncoder::Array.new name: "#{type}[]", delimiter: delimiter
+ @pg_decoder = PG::TextDecoder::Array.new name: "#{type}[]", delimiter: delimiter
end
def deserialize(value)
if value.is_a?(::String)
- type_cast_array(parse_pg_array(value), :deserialize)
+ type_cast_array(@pg_decoder.decode(value), :deserialize)
else
super
end
@@ -35,14 +26,14 @@ module ActiveRecord
def cast(value)
if value.is_a?(::String)
- value = parse_pg_array(value)
+ value = @pg_decoder.decode(value)
end
type_cast_array(value, :cast)
end
def serialize(value)
if value.is_a?(::Array)
- cast_value_for_database(value)
+ @pg_encoder.encode(type_cast_array(value, :serialize))
else
super
end
@@ -63,41 +54,6 @@ module ActiveRecord
@subtype.public_send(method, value)
end
end
-
- def cast_value_for_database(value)
- if value.is_a?(::Array)
- casted_values = value.map { |item| cast_value_for_database(item) }
- "{#{casted_values.join(delimiter)}}"
- else
- quote_and_escape(subtype.serialize(value))
- end
- end
-
- ARRAY_ESCAPE = "\\" * 2 * 2 # escape the backslash twice for PG arrays
-
- def quote_and_escape(value)
- case value
- when ::String
- if string_requires_quoting?(value)
- value = value.gsub(/\\/, ARRAY_ESCAPE)
- value.gsub!(/"/,"\\\"")
- %("#{value}")
- else
- value
- end
- when nil then "NULL"
- else value
- end
- end
-
- # See http://www.postgresql.org/docs/9.2/static/arrays.html#ARRAYS-IO
- # for a list of all cases in which strings will be quoted.
- def string_requires_quoting?(string)
- string.empty? ||
- string == "NULL" ||
- string =~ /[\{\}"\\\s]/ ||
- string.include?(delimiter)
- end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb
index 9b3de41fab..191c828e60 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb
@@ -15,11 +15,11 @@ module ActiveRecord
def run(records)
nodes = records.reject { |row| @store.key? row['oid'].to_i }
mapped, nodes = nodes.partition { |row| @store.key? row['typname'] }
- ranges, nodes = nodes.partition { |row| row['typtype'] == 'r' }
- enums, nodes = nodes.partition { |row| row['typtype'] == 'e' }
- domains, nodes = nodes.partition { |row| row['typtype'] == 'd' }
- arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in' }
- composites, nodes = nodes.partition { |row| row['typelem'] != '0' }
+ ranges, nodes = nodes.partition { |row| row['typtype'] == 'r'.freeze }
+ enums, nodes = nodes.partition { |row| row['typtype'] == 'e'.freeze }
+ domains, nodes = nodes.partition { |row| row['typtype'] == 'd'.freeze }
+ arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in'.freeze }
+ composites, nodes = nodes.partition { |row| row['typelem'].to_i != 0 }
mapped.each { |row| register_mapped_type(row) }
enums.each { |row| register_enum_type(row) }
@@ -29,6 +29,18 @@ module ActiveRecord
composites.each { |row| register_composite_type(row) }
end
+ def query_conditions_for_initial_load(type_map)
+ known_type_names = type_map.keys.map { |n| "'#{n}'" }
+ known_type_types = %w('r' 'e' 'd')
+ <<-SQL % [known_type_names.join(", "), known_type_types.join(", ")]
+ WHERE
+ t.typname IN (%s)
+ OR t.typtype IN (%s)
+ OR t.typinput::varchar = 'array_in'
+ OR t.typelem != 0
+ SQL
+ end
+
private
def register_mapped_type(row)
alias_type row['oid'], row['typname']