From 0c391b46fb39b697bbae1493caade23e2ddbd8a6 Mon Sep 17 00:00:00 2001 From: Leonardo Borges Date: Sun, 9 Aug 2009 12:56:25 +0400 Subject: PostgreSQL: XML datatype support [#1874 state:committed] Signed-off-by: Jeremy Kemper --- .../abstract/schema_definitions.rb | 15 ++++++++++ .../connection_adapters/postgresql_adapter.rb | 34 +++++++++++++--------- 2 files changed, 36 insertions(+), 13 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index f346e3ebc8..520f3c8c0c 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -315,6 +315,20 @@ module ActiveRecord @base = base end + #Handles non supported datatypes - e.g. XML + def method_missing(symbol, *args) + if symbol.to_s == 'xml' + xml_column_fallback(args) + end + end + + def xml_column_fallback(*args) + case @base.adapter_name.downcase + when 'sqlite', 'mysql' + options = args.extract_options! + column(args[0], :text, options) + end + end # Appends a primary key definition to the table definition. # Can be called multiple times, but this is probably not a good idea. def primary_key(name) @@ -705,3 +719,4 @@ module ActiveRecord end end + diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 224c007f3c..84cf1ad9fd 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -40,6 +40,12 @@ module ActiveRecord end module ConnectionAdapters + class TableDefinition + def xml(*args) + options = args.extract_options! + column(args[0], 'xml', options) + end + end # PostgreSQL-specific extensions to column definitions in a table. class PostgreSQLColumn < Column #:nodoc: # Instantiates a new PostgreSQL column definition in a table. @@ -68,7 +74,7 @@ module ActiveRecord # depending on the server specifics super end - + # Maps PostgreSQL-specific data types to logical Rails types. def simplified_type(field_type) case field_type @@ -100,10 +106,10 @@ module ActiveRecord :string # XML type when /^xml$/ - :string + :xml # Arrays when /^\D+\[\]$/ - :string + :string # Object identifier types when /^oid$/ :integer @@ -112,7 +118,7 @@ module ActiveRecord super end end - + # Extracts the value from a PostgreSQL column default definition. def self.extract_value_from_default(default) case default @@ -195,7 +201,8 @@ module ActiveRecord :time => { :name => "time" }, :date => { :name => "date" }, :binary => { :name => "bytea" }, - :boolean => { :name => "boolean" } + :boolean => { :name => "boolean" }, + :xml => { :name => "xml" } } # Returns 'PostgreSQL' as adapter name for identification purposes. @@ -278,7 +285,7 @@ module ActiveRecord def supports_ddl_transactions? true end - + def supports_savepoints? true end @@ -370,7 +377,7 @@ module ActiveRecord if value.kind_of?(String) && column && column.type == :binary "#{quoted_string_prefix}'#{escape_bytea(value)}'" elsif value.kind_of?(String) && column && column.sql_type =~ /^xml$/ - "xml '#{quote_string(value)}'" + "xml E'#{quote_string(value)}'" elsif value.kind_of?(Numeric) && column && column.sql_type =~ /^money$/ # Not truly string input, so doesn't require (or allow) escape string syntax. "'#{value.to_s}'" @@ -569,7 +576,7 @@ module ActiveRecord def rollback_db_transaction execute "ROLLBACK" end - + if defined?(PGconn::PQTRANS_IDLE) # The ruby-pg driver supports inspecting the transaction status, # while the ruby-postgres driver does not. @@ -920,18 +927,18 @@ module ActiveRecord sql = "DISTINCT ON (#{columns}) #{columns}, " sql << order_columns * ', ' end - + # Returns an ORDER BY clause for the passed order option. - # + # # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON, so we work around this # by wrapping the +sql+ string as a sub-select and ordering in that query. def add_order_by_for_association_limiting!(sql, options) #:nodoc: return sql if options[:order].blank? - + order = options[:order].split(',').collect { |s| s.strip }.reject(&:blank?) order.map! { |s| 'DESC' if s =~ /\bdesc$/i } order = order.zip((0...order.size).to_a).map { |s,i| "id_list.alias_#{i} #{s}" }.join(', ') - + sql.replace "SELECT * FROM (#{sql}) AS id_list ORDER BY #{order}" end @@ -1055,7 +1062,7 @@ module ActiveRecord if res.ftype(cell_index) == MONEY_COLUMN_TYPE_OID # Because money output is formatted according to the locale, there are two # cases to consider (note the decimal separators): - # (1) $12,345,678.12 + # (1) $12,345,678.12 # (2) $12.345.678,12 case column = row[cell_index] when /^-?\D+[\d,]+\.\d{2}$/ # (1) @@ -1115,3 +1122,4 @@ module ActiveRecord end end end + -- cgit v1.2.3