Skip to content

Native Database Types Hash and Table Lookup from Rails' Postgresql Adapter #149

Merged
merged 5 commits into from Dec 22, 2011
View
129 lib/arjdbc/postgresql/adapter.rb
@@ -1,12 +1,5 @@
module ActiveRecord::ConnectionAdapters
PostgreSQLAdapter = Class.new(AbstractAdapter) unless const_defined?(:PostgreSQLAdapter)
-
- TableDefinition.class_eval do
- def xml(*args)
- options = args.extract_options!
- column(args[0], 'xml', options)
- end
- end
end
module ::ArJdbc
@@ -165,23 +158,28 @@ def simplified_type(field_type)
end
end
- def modify_types(tp)
- tp[:primary_key] = "serial primary key"
- tp[:string][:limit] = 255
- tp[:integer][:limit] = nil
- tp[:boolean] = { :name => "boolean" }
- tp[:float] = { :name => "float" }
- tp[:text] = { :name => "text" }
- tp[:datetime] = { :name => "timestamp" }
- tp[:timestamp] = { :name => "timestamp" }
- tp[:time] = { :name => "time" }
- tp[:date] = { :name => "date" }
- tp[:decimal] = { :name => "decimal" }
- tp
- end
+ # constants taken from postgresql_adapter in rails project
+ ADAPTER_NAME = 'PostgreSQL'
+
+ NATIVE_DATABASE_TYPES = {
+ :primary_key => "serial primary key",
+ :string => { :name => "character varying", :limit => 255 },
+ :text => { :name => "text" },
+ :integer => { :name => "integer" },
+ :float => { :name => "float" },
+ :decimal => { :name => "decimal" },
+ :datetime => { :name => "timestamp" },
+ :timestamp => { :name => "timestamp" },
+ :time => { :name => "time" },
+ :date => { :name => "date" },
+ :binary => { :name => "bytea" },
+ :boolean => { :name => "boolean" },
+ :xml => { :name => "xml" },
+ :tsvector => { :name => "tsvector" }
+ }
def adapter_name #:nodoc:
- 'PostgreSQL'
+ ADAPTER_NAME
end
def self.arel2_visitors(config)
@@ -201,7 +199,7 @@ def postgresql_version
end
def native_database_types
- super.merge(:string => { :name => "character varying", :limit => 255 })
+ NATIVE_DATABASE_TYPES
end
# Does PostgreSQL support migrations?
@@ -332,18 +330,9 @@ def pk_and_sequence_for(table) #:nodoc:
nil
end
- # Returns just a table's primary key
def primary_key(table)
- row = exec_query(<<-end_sql, 'SCHEMA', [[nil, table]]).rows.first
- SELECT DISTINCT(attr.attname)
- FROM pg_attribute attr
- INNER JOIN pg_depend dep ON attr.attrelid = dep.refobjid AND attr.attnum = dep.refobjsubid
- INNER JOIN pg_constraint cons ON attr.attrelid = cons.conrelid AND attr.attnum = cons.conkey[1]
- WHERE cons.contype = 'p'
- AND dep.refobjid = $1::regclass
- end_sql
-
- row && row.first
+ pk_and_sequence = pk_and_sequence_for(table)
+ pk_and_sequence && pk_and_sequence.first
end
# taken from rails postgresql adapter
@@ -466,11 +455,6 @@ def all_schemas
select('select nspname from pg_namespace').map {|r| r["nspname"] }
end
- def primary_key(table)
- pk_and_sequence = pk_and_sequence_for(table)
- pk_and_sequence && pk_and_sequence.first
- end
-
def structure_dump
database = @config[:database]
if database.nil?
@@ -681,8 +665,43 @@ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
end
end
- def tables
- @connection.tables(database_name, nil, nil, ["TABLE"])
+ def tables(name = nil)
+ exec_query(<<-SQL, 'SCHEMA').map { |row| row["tablename"] }
+ SELECT tablename
+ FROM pg_tables
+ WHERE schemaname = ANY (current_schemas(false))
+ SQL
+ end
+
+ def table_exists?(name)
+ schema, table = extract_schema_and_table(name.to_s)
+ return false unless table # Abstract classes is having nil table name
+
+ binds = [[nil, table.gsub(/(^"|"$)/,'')]]
+ binds << [nil, schema] if schema
+
+ exec_query(<<-SQL, 'SCHEMA', binds).first["table_count"] > 0
+ SELECT COUNT(*) as table_count
+ FROM pg_tables
+ WHERE tablename = ?
+ AND schemaname = #{schema ? "?" : "ANY (current_schemas(false))"}
+ SQL
+ end
+
+ # Extracts the table and schema name from +name+
+ def extract_schema_and_table(name)
+ schema, table = name.split('.', 2)
+
+ unless table # A table was provided without a schema
+ table = schema
+ schema = nil
+ end
+
+ if name =~ /^"/ # Handle quoted table names
+ table = name
+ schema = nil
+ end
+ [schema, table]
end
private
@@ -762,9 +781,37 @@ def call_discovered_column_callbacks(*)
end
end
+ class PostgresJdbcConnection < JdbcConnection
+ alias :java_native_database_types :set_native_database_types
+
+ # override to prevent connection from loading hash from jdbc
+ # metadata, which can be expensive. We can do this since
+ # native_database_types is defined in the adapter to use a static hash
+ # not relying on the driver's metadata
+ def set_native_database_types
+ @native_types = {}
+ end
+ end
+
class PostgreSQLAdapter < JdbcAdapter
include ArJdbc::PostgreSQL
+ class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
+ def xml(*args)
+ options = args.extract_options!
+ column(args[0], "xml", options)
+ end
+
+ def tsvector(*args)
+ options = args.extract_options!
+ column(args[0], "tsvector", options)
+ end
+ end
+
+ def table_definition
+ TableDefinition.new(self)
+ end
+
def jdbc_connection_class(spec)
::ArJdbc::PostgreSQL.jdbc_connection_class
end
View
16 test/mysql_simple_test.rb
@@ -102,6 +102,22 @@ def test_find_in_other_schema_with_include
User.set_table_name old_users_table_name
end
end
+
+ def test_create_xml_column
+ assert_nothing_raised do
+ @connection.create_table :xml_testings do |t|
+ t.xml :xml_test
+ end
+ end
+
+ xml_test = @connection.columns(:xml_testings).detect do |c|
+ c.name == "xml_test"
+ end
+
+ assert_equal "text", xml_test.sql_type
+ ensure
+ @connection.drop_table :xml_testings rescue nil
+ end
end
class MysqlHasManyThroughTest < Test::Unit::TestCase
View
15 test/sqlite3_simple_test.rb
@@ -189,6 +189,21 @@ def test_change_column
assert_equal col.type, :integer
end
+ def test_create_xml_column
+ assert_nothing_raised do
+ @connection.create_table :xml_testings do |t|
+ t.xml :xml_test
+ end
+ end
+
+ xml_test = @connection.columns(:xml_testings).detect do |c|
+ c.name == "xml_test"
+ end
+
+ assert_equal "text", xml_test.sql_type
+ ensure
+ @connection.drop_table :xml_testings rescue nil
+ end
end
# assert_raise ActiveRecord::RecordInvalid do
Something went wrong with that request. Please try again.