Skip to content

Commit

Permalink
Support multiple schemas in table names for postgresql [#390 state:re…
Browse files Browse the repository at this point in the history
…solved]

Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
  • Loading branch information
maxlapshin authored and lifo committed Apr 21, 2009
1 parent fc2421b commit 6060123
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -392,9 +392,28 @@ def quote_string(s) #:nodoc:
quote_string(s)
end

# Checks the following cases:
#
# - table_name
# - "table.name"
# - schema_name.table_name
# - schema_name."table.name"
# - "schema.name".table_name
# - "schema.name"."table.name"
def quote_table_name(name)
schema, name_part = extract_pg_identifier_from_name(name.to_s)

unless name_part
quote_column_name(schema)
else
table_name, name_part = extract_pg_identifier_from_name(name_part)
"#{quote_column_name(schema)}.#{quote_column_name(table_name)}"
end
end

# Quotes column names for use in SQL queries.
def quote_column_name(name) #:nodoc:
%("#{name}")
PGconn.quote_ident(name.to_s)

This comment has been minimized.

Copy link
@tekkub

tekkub May 1, 2009

This change is throwing an error for me. I'm using the postgres-pr (0.6.1) gem.

undefined method `quote_ident' for PGconn:Class
end

# Quote date/time values for use in SQL input. Includes microseconds
Expand Down Expand Up @@ -1045,6 +1064,16 @@ def column_definitions(table_name) #:nodoc:
ORDER BY a.attnum
end_sql
end

def extract_pg_identifier_from_name(name)
match_data = name[0,1] == '"' ? name.match(/\"([^\"]+)\"/) : name.match(/([^\.]+)/)

if match_data
rest = name[match_data[0].length..-1]
rest = rest[1..-1] if rest[0,1] == "."
[match_data[1], (rest.length > 0 ? rest : nil)]
end
end
end
end
end
44 changes: 44 additions & 0 deletions activerecord/test/cases/schema_test_postgresql.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,22 @@ class SchemaTest < ActiveRecord::TestCase
'moment timestamp without time zone default now()'
]

class Thing1 < ActiveRecord::Base
set_table_name "test_schema.things"
end

class Thing2 < ActiveRecord::Base
set_table_name "test_schema2.things"
end

class Thing3 < ActiveRecord::Base
set_table_name 'test_schema."things.table"'
end

def setup
@connection = ActiveRecord::Base.connection
@connection.execute "CREATE SCHEMA #{SCHEMA_NAME} CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})"
@connection.execute "CREATE TABLE #{SCHEMA_NAME}.\"#{TABLE_NAME}.table\" (#{COLUMNS.join(',')})"
@connection.execute "CREATE SCHEMA #{SCHEMA2_NAME} CREATE TABLE #{TABLE_NAME} (#{COLUMNS.join(',')})"
@connection.execute "CREATE INDEX #{INDEX_A_NAME} ON #{SCHEMA_NAME}.#{TABLE_NAME} USING btree (#{INDEX_A_COLUMN});"
@connection.execute "CREATE INDEX #{INDEX_A_NAME} ON #{SCHEMA2_NAME}.#{TABLE_NAME} USING btree (#{INDEX_A_COLUMN});"
Expand All @@ -47,6 +60,37 @@ def test_with_schema_search_path
end
end


def test_proper_encoding_of_table_name
assert_equal '"table_name"', @connection.quote_table_name('table_name')
assert_equal '"table.name"', @connection.quote_table_name('"table.name"')
assert_equal '"schema_name"."table_name"', @connection.quote_table_name('schema_name.table_name')
assert_equal '"schema_name"."table.name"', @connection.quote_table_name('schema_name."table.name"')
assert_equal '"schema.name"."table_name"', @connection.quote_table_name('"schema.name".table_name')
assert_equal '"schema.name"."table.name"', @connection.quote_table_name('"schema.name"."table.name"')
end

def test_classes_with_qualified_schema_name
assert_equal 0, Thing1.count
assert_equal 0, Thing2.count
assert_equal 0, Thing3.count

Thing1.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now)
assert_equal 1, Thing1.count
assert_equal 0, Thing2.count
assert_equal 0, Thing3.count

Thing2.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now)
assert_equal 1, Thing1.count
assert_equal 1, Thing2.count
assert_equal 0, Thing3.count

Thing3.create(:id => 1, :name => "thing1", :email => "thing1@localhost", :moment => Time.now)
assert_equal 1, Thing1.count
assert_equal 1, Thing2.count
assert_equal 1, Thing3.count
end

def test_raise_on_unquoted_schema_name
assert_raise(ActiveRecord::StatementInvalid) do
with_schema_search_path '$user,public'
Expand Down

6 comments on commit 6060123

@wallace
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm getting an error also: http://gist.github.com/115477 This is with gem postgres (0.7.9.2008.01.28).

@wallace
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tekkub: try gem install pg

@wallace
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tekkub: try 'gem install pg'

@njakobsen
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have the same problem, and I'm using the same postgres-pr 0.6.1 gem. However, colleague of mine is running the same gem with the same Rails Application, and can migrate without any problems.

@gregd
Copy link

@gregd gregd commented on 6060123 Jul 21, 2009

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I work on Windows Vista. After update to Rails 2.3.3 I had the same problem with the "postgres-pr" gem. So I installed newer "pg" gem which has the problematic quote_ident method implemented. For some reason the new gem didn't work. After googling the problem I've copied ssleay32.dll and libeay32.dll from Postgresql bin directory to Ruby bin dir. And as for now the "pg" gem works.

@kwilcox
Copy link

@kwilcox kwilcox commented on 6060123 Oct 5, 2009

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you are having problems with "undefined method 'quote_ident' for PGConn:Class", install the "pg" gem (version 0.8.x) and everything should work.

Please sign in to comment.