Skip to content

Commit

Permalink
Merge pull request #7937 from arturopie/7914-defaults-on-domains-and-…
Browse files Browse the repository at this point in the history
…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 ca618d4
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 15 deletions.
4 changes: 4 additions & 0 deletions activerecord/CHANGELOG.md
@@ -1,5 +1,9 @@
## Rails 4.0.0 (unreleased) ## ## 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 * Learn ActiveRecord::QueryMethods#order work with hash arguments


When symbol or hash passed we convert it to Arel::Nodes::Ordering. When symbol or hash passed we convert it to Arel::Nodes::Ordering.
Expand Down
Expand Up @@ -280,24 +280,21 @@ def pk_and_sequence_for(table) #:nodoc:
end_sql end_sql


if result.nil? or result.empty? 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] result = query(<<-end_sql, 'SCHEMA')[0]
SELECT attr.attname, SELECT attr.attname,
CASE CASE
WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN WHEN split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2) ~ '.' THEN
substr(split_part(def.adsrc, '''', 2), substr(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2),
strpos(split_part(def.adsrc, '''', 2), '.')+1) strpos(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2), '.')+1)
ELSE split_part(def.adsrc, '''', 2) ELSE split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2)
END END
FROM pg_class t FROM pg_class t
JOIN pg_attribute attr ON (t.oid = attrelid) JOIN pg_attribute attr ON (t.oid = attrelid)
JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum) JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1]) JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
WHERE t.oid = '#{quote_table_name(table)}'::regclass WHERE t.oid = '#{quote_table_name(table)}'::regclass
AND cons.contype = 'p' AND cons.contype = 'p'
AND def.adsrc ~* 'nextval' AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval'
end_sql end_sql
end end


Expand Down
Expand Up @@ -78,11 +78,8 @@ def self.extract_value_from_default(default)
when /\A\(?(-?\d+(\.\d*)?\)?)\z/ when /\A\(?(-?\d+(\.\d*)?\)?)\z/
$1 $1
# Character types # Character types
when /\A'(.*)'::(?:character varying|bpchar|text)\z/m when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m
$1 $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 # Binary data types
when /\A'(.*)'::bytea\z/m when /\A'(.*)'::bytea\z/m
$1 $1
Expand Down Expand Up @@ -763,7 +760,8 @@ def select_raw(sql, name = nil)
# - ::regclass is a function that gives the id for a table name # - ::regclass is a function that gives the id for a table name
def column_definitions(table_name) #:nodoc: def column_definitions(table_name) #:nodoc:
exec_query(<<-end_sql, 'SCHEMA').rows 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 FROM pg_attribute a LEFT JOIN pg_attrdef d
ON a.attrelid = d.adrelid AND a.attnum = d.adnum ON a.attrelid = d.adrelid AND a.attnum = d.adnum
WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
Expand Down
2 changes: 1 addition & 1 deletion activerecord/test/cases/adapters/postgresql/schema_test.rb
Expand Up @@ -72,7 +72,7 @@ def teardown
end end


def test_schema_names 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 end


def test_create_schema def test_create_schema
Expand Down
40 changes: 40 additions & 0 deletions activerecord/test/cases/defaults_test.rb
Expand Up @@ -109,3 +109,43 @@ def test_mysql_integer_not_null_defaults
end end
end 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
9 changes: 8 additions & 1 deletion activerecord/test/schema/postgresql_specific_schema.rb
Expand Up @@ -12,6 +12,8 @@


execute 'DROP FUNCTION IF EXISTS partitioned_insert_trigger()' 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| %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)" execute "SELECT setval('#{seq_name}', 100)"
end end
Expand All @@ -37,7 +39,12 @@
); );
_SQL _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 ( CREATE TABLE geometrics (
id serial primary key, id serial primary key,
a_point point, a_point point,
Expand Down

0 comments on commit ca618d4

Please sign in to comment.