Permalink
Browse files

Merge pull request #7937 from arturopie/7914-defaults-on-domains-and-…

…multiple-schemas


Fixes #7914 - PostgreSQL adapter doesn't fetch column defaults when using multiple schemas and domains
  • Loading branch information...
rafaelfranca committed Oct 14, 2012
2 parents 7cc6ee7 + 8fb841b commit ca618d473dcb9b5cc4000d057df9322376900622
@@ -1,5 +1,9 @@
## Rails 4.0.0 (unreleased) ##
+* PostgreSQL adapter correctly fetches default values when using multiple schemas and domains in a db. Fixes #7914
+
+ *Arturo Pie*
+
* Learn ActiveRecord::QueryMethods#order work with hash arguments
When symbol or hash passed we convert it to Arel::Nodes::Ordering.
@@ -280,24 +280,21 @@ def pk_and_sequence_for(table) #:nodoc:
end_sql
if result.nil? or result.empty?
- # If that fails, try parsing the primary key's default value.
- # Support the 7.x and 8.0 nextval('foo'::text) as well as
- # the 8.1+ nextval('foo'::regclass).
result = query(<<-end_sql, 'SCHEMA')[0]
SELECT attr.attname,
CASE
- WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN
- substr(split_part(def.adsrc, '''', 2),
- strpos(split_part(def.adsrc, '''', 2), '.')+1)
- ELSE split_part(def.adsrc, '''', 2)
+ WHEN split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2) ~ '.' THEN
+ substr(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2),
+ strpos(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2), '.')+1)
+ ELSE split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2)
END
FROM pg_class t
JOIN pg_attribute attr ON (t.oid = attrelid)
JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
WHERE t.oid = '#{quote_table_name(table)}'::regclass
AND cons.contype = 'p'
- AND def.adsrc ~* 'nextval'
+ AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval'
end_sql
end
@@ -78,11 +78,8 @@ def self.extract_value_from_default(default)
when /\A\(?(-?\d+(\.\d*)?\)?)\z/
$1
# Character types
- when /\A'(.*)'::(?:character varying|bpchar|text)\z/m
+ when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m
$1
- # Character types (8.1 formatting)
- when /\AE'(.*)'::(?:character varying|bpchar|text)\z/m
- $1.gsub(/\\(\d\d\d)/) { $1.oct.chr }
# Binary data types
when /\A'(.*)'::bytea\z/m
$1
@@ -763,7 +760,8 @@ def select_raw(sql, name = nil)
# - ::regclass is a function that gives the id for a table name
def column_definitions(table_name) #:nodoc:
exec_query(<<-end_sql, 'SCHEMA').rows
- SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull, a.atttypid, a.atttypmod
+ SELECT a.attname, format_type(a.atttypid, a.atttypmod),
+ pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
FROM pg_attribute a LEFT JOIN pg_attrdef d
ON a.attrelid = d.adrelid AND a.attnum = d.adnum
WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
@@ -72,7 +72,7 @@ def teardown
end
def test_schema_names
- assert_equal ["public", "test_schema", "test_schema2"], @connection.schema_names
+ assert_equal ["public", "schema_1", "test_schema", "test_schema2"], @connection.schema_names
end
def test_create_schema
@@ -109,3 +109,43 @@ def test_mysql_integer_not_null_defaults
end
end
end
+
+if current_adapter?(:PostgreSQLAdapter)
+ class DefaultsUsingMultipleSchemasAndDomainTest < ActiveSupport::TestCase
+ def setup
+ @connection = ActiveRecord::Base.connection
+
+ @old_search_path = @connection.schema_search_path
+ @connection.schema_search_path = "schema_1, pg_catalog"
+ @connection.create_table "defaults" do |t|
+ t.text "text_col", :default => "some value"
+ t.string "string_col", :default => "some value"
+ end
+ Default.reset_column_information
+ end
+
+ def test_text_defaults_in_new_schema_when_overriding_domain
+ assert_equal "some value", Default.new.text_col, "Default of text column was not correctly parse"
+ end
+
+ def test_string_defaults_in_new_schema_when_overriding_domain
+ assert_equal "some value", Default.new.string_col, "Default of string column was not correctly parse"
+ end
+
+ def test_bpchar_defaults_in_new_schema_when_overriding_domain
+ @connection.execute "ALTER TABLE defaults ADD bpchar_col bpchar DEFAULT 'some value'"
+ Default.reset_column_information
+ assert_equal "some value", Default.new.bpchar_col, "Default of bpchar column was not correctly parse"
+ end
+
+ def test_text_defaults_after_updating_column_default
+ @connection.execute "ALTER TABLE defaults ALTER COLUMN text_col SET DEFAULT 'some text'::schema_1.text"
+ assert_equal "some text", Default.new.text_col, "Default of text column was not correctly parse after updating default using '::text' since postgreSQL will add parens to the default in db"
+ end
+
+ def teardown
+ @connection.schema_search_path = @old_search_path
+ Default.reset_column_information
+ end
+ end
+end
@@ -12,6 +12,8 @@
execute 'DROP FUNCTION IF EXISTS partitioned_insert_trigger()'
+ execute "DROP SCHEMA IF EXISTS schema_1 CASCADE"
+
%w(accounts_id_seq developers_id_seq projects_id_seq topics_id_seq customers_id_seq orders_id_seq).each do |seq_name|
execute "SELECT setval('#{seq_name}', 100)"
end
@@ -37,7 +39,12 @@
);
_SQL
- execute <<_SQL
+ execute "CREATE SCHEMA schema_1"
+ execute "CREATE DOMAIN schema_1.text AS text"
+ execute "CREATE DOMAIN schema_1.varchar AS varchar"
+ execute "CREATE DOMAIN schema_1.bpchar AS bpchar"
+
+ execute <<_SQL
CREATE TABLE geometrics (
id serial primary key,
a_point point,

0 comments on commit ca618d4

Please sign in to comment.